Added new tech tree layout implementation using Microsoft Automatic Graph Layouts Added some functionality to the database editor tools
165 lines
No EOL
6.7 KiB
C#
165 lines
No EOL
6.7 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using Microsoft.Msagl.Core.Geometry;
|
|
using Microsoft.Msagl.Routing.Visibility;
|
|
|
|
namespace Microsoft.Msagl.Routing.Rectilinear {
|
|
internal class PointComparer {
|
|
// Due to the vagaries of rounding, we may encounter a result that is not quite 0
|
|
// when subtracting two numbers that are close.
|
|
// ReSharper disable InconsistentNaming
|
|
private static readonly double differenceEpsilon = ApproximateComparer.DistanceEpsilon / 2;
|
|
// ReSharper restore InconsistentNaming
|
|
|
|
static internal double DifferenceEpsilon {
|
|
get { return differenceEpsilon; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified Points, which are assumed to have been Round()ed,
|
|
/// are close enough to be considered equal.
|
|
/// </summary>
|
|
/// <param name="a">The first object of type Point to compare.</param>
|
|
/// <param name="b">The second object of type Point to compare.</param>
|
|
/// <returns>True if the inputs are close enough to be considered equal, else false</returns>
|
|
public static bool Equal(Point a, Point b) {
|
|
return Equal(a.X, b.X) && Equal(a.Y, b.Y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified double values, which are assumed to have been Round()ed,
|
|
/// are close enough to be considered equal.
|
|
/// </summary>
|
|
/// <param name="x">The first double value to compare.</param>
|
|
/// <param name="y">The second double value to compare.</param>
|
|
/// <returns>True if the inputs are close enough to be considered equal, else false</returns>
|
|
public static bool Equal(double x, double y) {
|
|
return (0 == Compare(x, y));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The usual Compare operation, with inputs that are assumed to have been Round()ed.
|
|
/// </summary>
|
|
/// <param name="lhs"></param>
|
|
/// <param name="rhs"></param>
|
|
/// <returns>0 if the inputs are close enough to be considered equal, else -1 if lhs is
|
|
/// less than rhs, else 1.</returns>
|
|
public static int Compare(double lhs, double rhs) {
|
|
// If the inputs are not rounded, then two numbers that are close together at the
|
|
// middle of the rounding range may Compare as 0 but Round to different values
|
|
// (e.g., with rounding to 6 digits, xxx.yyyyyy49 and xxx.yyyyyy51 will exhibit this).
|
|
Assert_Rounded(lhs);
|
|
Assert_Rounded(rhs);
|
|
|
|
int cmp = 0;
|
|
if (lhs + DifferenceEpsilon < rhs) {
|
|
cmp = -1;
|
|
} else if (rhs + DifferenceEpsilon < lhs) {
|
|
cmp = 1;
|
|
}
|
|
|
|
// Just to be sure we're in sync with CompassVector
|
|
Debug.Assert((cmp < 0) == (Directions.East == CompassVector.VectorDirection(new Point(lhs, 0), new Point(rhs, 0))));
|
|
Debug.Assert((0 == cmp) == (Directions. None == CompassVector.VectorDirection(new Point(lhs, 0), new Point(rhs, 0))));
|
|
return cmp;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The usual Compare operation, with inputs that are assumed to have been Round()ed.
|
|
/// </summary>
|
|
/// <param name="lhs"></param>
|
|
/// <param name="rhs"></param>
|
|
/// <returns>0 if the inputs are close enough to be considered equal, else -1 if lhs is
|
|
/// less than rhs, else 1.</returns>
|
|
public static int Compare(Point lhs, Point rhs) {
|
|
int cmp = Compare(lhs.X, rhs.X);
|
|
if (0 == cmp) {
|
|
cmp = Compare(lhs.Y, rhs.Y);
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
/// <summary>
|
|
/// return true if less or equal holds for two values that are assumed to have been Round()ed
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static bool LessOrEqual(double a, double b){
|
|
int comp = Compare(a, b);
|
|
return comp < 0 || comp == 0;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// return true if less holds for two values that are assumed to have been Round()ed
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public static bool Less(double a, double b) {
|
|
return Compare(a, b) < 0;
|
|
}
|
|
|
|
[Conditional("DEBUG")]
|
|
// ReSharper disable InconsistentNaming
|
|
static void Assert_Rounded(double d) {
|
|
// Be sure there is enough precision to round that far; anything larger than this is
|
|
// unlikely to be a graph coordinate (it's probably a line intersection way out of range).
|
|
if (Math.Log10(Math.Abs(d)) < (14 - ApproximateComparer.DistanceEpsilonPrecision)) {
|
|
Debug.Assert(Math.Abs(ApproximateComparer.Round(d) - d) < DifferenceEpsilon, "unRounded value passed");
|
|
}
|
|
}
|
|
|
|
[Conditional("DEBUG")]
|
|
static void Assert_Rounded(Point p) {
|
|
Assert_Rounded(p.X);
|
|
Assert_Rounded(p.Y);
|
|
}
|
|
// ReSharper restore InconsistentNaming
|
|
|
|
#region Direction_Utilities
|
|
|
|
// These call through to CompassVector methods, assuming operands that use PointComparer rounding.
|
|
internal static Directions GetDirections(Point a, Point b) {
|
|
Assert_Rounded(a);
|
|
Assert_Rounded(b);
|
|
return CompassVector.DirectionsFromPointToPoint(a, b);
|
|
}
|
|
|
|
internal static Directions GetPureDirection(Point a, Point b) {
|
|
Assert_Rounded(a);
|
|
Assert_Rounded(b);
|
|
Directions dir = GetDirections(a, b);
|
|
Debug.Assert(CompassVector.IsPureDirection(dir), "Impure direction found");
|
|
return dir;
|
|
}
|
|
|
|
internal static bool IsPureDirection(Point a, Point b) {
|
|
Assert_Rounded(a);
|
|
Assert_Rounded(b);
|
|
return CompassVector.IsPureDirection(GetDirections(a, b));
|
|
}
|
|
internal static bool IsPureDirection(Directions dir) {
|
|
return CompassVector.IsPureDirection(dir);
|
|
}
|
|
|
|
internal static bool IsPureLower(Point a, Point b) {
|
|
Assert_Rounded(a);
|
|
Assert_Rounded(b);
|
|
|
|
// Is a lower than b along the orthogonal line segment? That means moving
|
|
// from a to b is in the increasing direction.
|
|
Directions dir = GetDirections(a, b);
|
|
return (Directions.East == dir) || (Directions.North == dir);
|
|
}
|
|
|
|
static internal Directions GetPureDirection(VisibilityVertex first, VisibilityVertex second) {
|
|
Assert_Rounded(first.Point);
|
|
Assert_Rounded(second.Point);
|
|
return GetPureDirection(first.Point, second.Point);
|
|
}
|
|
|
|
#endregion // Direction_Utilities
|
|
}
|
|
} |