public int Compare(BasicObstacleSide first, BasicObstacleSide second) { ValidateArg.IsNotNull(first, "first"); ValidateArg.IsNotNull(second, "second"); // If these are two sides of the same obstacle then the ordering is obvious. if (first.Obstacle == second.Obstacle) { if (first == second) { return(0); } return((first is LowObstacleSide) ? -1 : 1); } Debug_VerifySidesDoNotIntersect(first, second); // Other than intersecting sides at vertices of the same obstacle, there should be no interior intersections... Point firstIntersect = VisibilityGraphGenerator.ScanLineIntersectSide(this.linePositionAtLastInsertOrRemove, first, scanDirection); Point secondIntersect = VisibilityGraphGenerator.ScanLineIntersectSide(this.linePositionAtLastInsertOrRemove, second, scanDirection); var cmp = firstIntersect.CompareTo(secondIntersect); // ... but we may still have rectangular sides that coincide, or angled sides that are close enough here but // are not detected by the convex-hull overlap calculations. In those cases, we refine the comparison by side // type, with High coming before Low, and then by obstacle ordinal if needed. Because there are no interior // intersections, this ordering will remain valid as long as the side(s) are in the scanline. if (0 == cmp) { bool firstIsLow = first is LowObstacleSide; bool secondIsLow = second is LowObstacleSide; cmp = firstIsLow.CompareTo(secondIsLow); if (0 == cmp) { cmp = first.Obstacle.Ordinal.CompareTo(second.Obstacle.Ordinal); } } DevTraceInfo(4, "Compare {0} @ {1:F5} {2:F5} and {3:F5} {4:F5}: {5} {6}", cmp, firstIntersect.X, firstIntersect.Y, secondIntersect.X, secondIntersect.Y, first, second); return(cmp); }