internal ObstaclePortEntrance(ObstaclePort oport, Point unpaddedBorderIntersect, Directions outDir, ObstacleTree obstacleTree) { ObstaclePort = oport; UnpaddedBorderIntersect = unpaddedBorderIntersect; OutwardDirection = outDir; // Get the padded intersection. var lineSeg = new LineSegment(UnpaddedBorderIntersect, StaticGraphUtility.RectangleBorderIntersect( oport.Obstacle.VisibilityBoundingBox, UnpaddedBorderIntersect, outDir)); IList<IntersectionInfo> xxs = Curve.GetAllIntersections(lineSeg, oport.Obstacle.VisibilityPolyline, true /*liftIntersections*/); Debug.Assert(1 == xxs.Count, "Expected one intersection"); this.VisibilityBorderIntersect = ApproximateComparer.Round(SpliceUtility.RawIntersection(xxs[0], UnpaddedBorderIntersect)); this.MaxVisibilitySegment = obstacleTree.CreateMaxVisibilitySegment(this.VisibilityBorderIntersect, this.OutwardDirection, out this.pointAndCrossingsList); // Groups are never in a clump (overlapped) but they may still have their port entrance overlapped. if (this.Obstacle.IsOverlapped || (this.Obstacle.IsGroup && !this.Obstacle.IsInConvexHull)) { this.IsOverlapped = obstacleTree.IntersectionIsInsideAnotherObstacle(/*sideObstacle:*/ null, this.Obstacle , this.VisibilityBorderIntersect, ScanDirection.GetInstance(OutwardDirection)); if (!this.Obstacle.IsGroup || this.IsOverlapped || this.InteriorEdgeCrossesObstacle(obstacleTree)) { unpaddedToPaddedBorderWeight = ScanSegment.OverlappedWeight; } } if (this.Obstacle.IsInConvexHull && (unpaddedToPaddedBorderWeight == ScanSegment.NormalWeight)) { SetUnpaddedToPaddedBorderWeightFromHullSiblingOverlaps(obstacleTree); } }
static internal void Test_DumpScanSegments(ObstacleTree obstacleTree, ScanSegmentTree hSegs, ScanSegmentTree vSegs) { var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetScanSegmentCurves(hSegs)); debugCurves.AddRange(Test_GetScanSegmentCurves(vSegs)); DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("ScanSegments")); }
static internal void Test_DumpPathsAfterNudging(ObstacleTree obstacleTree, IEnumerable <Path> edgePaths) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetPostNudgedPathDebugCurves(edgePaths)); DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("PostNudgedPaths")); #endif // TEST }
static internal void Test_DumpVisibilityGraph(ObstacleTree obstacleTree, VisibilityGraph vg) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetVisibilityGraphDebugCurves(vg)); DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("VisibilityGraph")); #endif // TEST }
static internal void Test_ShowPathsAfterNudging(ObstacleTree obstacleTree, IEnumerable <Path> edgePaths) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetPostNudgedPathDebugCurves(edgePaths)); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(debugCurves); #endif // TEST }
// ReSharper disable InconsistentNaming static internal void Test_ShowVisibilityGraph(ObstacleTree obstacleTree, VisibilityGraph vg) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetVisibilityGraphDebugCurves(vg)); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(debugCurves); #endif // TEST }
private bool InteriorEdgeCrossesObstacle(ObstacleTree obstacleTree) { // File Test: Nudger_Overlap4 // Use the VisibilityBoundingBox for groups because those are what the tree consists of. var rect = new Rectangle(this.UnpaddedBorderIntersect, this.VisibilityBorderIntersect); return InteriorEdgeCrossesObstacle(rect, obs => obs.VisibilityPolyline, obstacleTree.Root.GetLeafRectangleNodesIntersectingRectangle(rect) .Where(node => !node.UserData.IsGroup && (node.UserData != this.Obstacle)).Select(node => node.UserData)); }
static internal void Assert(bool condition, string message, ObstacleTree obstacleTree, VisibilityGraph vg) { if (!condition) { Test_DumpVisibilityGraph(obstacleTree, vg); Debug.Assert(condition, message); } }
static internal void Test_ShowScanSegments(ObstacleTree obstacleTree, ScanSegmentTree hSegs, ScanSegmentTree vSegs) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetScanSegmentCurves(hSegs)); debugCurves.AddRange(Test_GetScanSegmentCurves(vSegs)); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(debugCurves); #endif // TEST }
private bool InteriorEdgeCrossesObstacle(ObstacleTree obstacleTree) { // File Test: Nudger_Overlap4 // Use the VisibilityBoundingBox for groups because those are what the tree consists of. var rect = new Rectangle(this.UnpaddedBorderIntersect, this.VisibilityBorderIntersect); return(InteriorEdgeCrossesObstacle(rect, obs => obs.VisibilityPolyline, obstacleTree.Root.GetLeafRectangleNodesIntersectingRectangle(rect) .Where(node => !node.UserData.IsGroup && (node.UserData != this.Obstacle)).Select(node => node.UserData))); }
internal void CreatePortEntrance(Point unpaddedBorderIntersect, Directions outDir, ObstacleTree obstacleTree) { var entrance = new ObstaclePortEntrance(this, unpaddedBorderIntersect, outDir, obstacleTree); PortEntrances.Add(entrance); this.VisibilityRectangle.Add(entrance.MaxVisibilitySegment.End); #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=370 this.HasCollinearEntrances = this.HasCollinearEntrances | entrance.IsCollinearWithPort; #else this.HasCollinearEntrances |= entrance.IsCollinearWithPort; #endif }
// obstacleToIgnore is the event obstacle if we're looking at intersections along its boundary. private bool IntersectionAtSideIsInsideAnotherObstacle(BasicObstacleSide side, Obstacle eventObstacle, Point intersect) { // See if the intersection with an obstacle side is inside another obstacle (that encloses // at least the part of side.Obstacle containing the intersection). This will only happen // if side.Obstacle is overlapped and in the same clump (if it's not the same clump, we must // be hitting it from the outside). if (!side.Obstacle.IsOverlapped) { return(false); } if (!side.Obstacle.IsGroup && !eventObstacle.IsGroup && (side.Obstacle.Clump != eventObstacle.Clump)) { return(false); } return(ObstacleTree.IntersectionIsInsideAnotherObstacle(side.Obstacle, eventObstacle, intersect, ScanDirection)); }
static internal List<DebugCurve> Test_GetObstacleDebugCurves(ObstacleTree obstacleTree, bool noPadPoly, bool noVisPoly) { return Test_GetObstacleDebugCurves(obstacleTree.GetAllObstacles(), noPadPoly, noVisPoly); }
static internal List<DebugCurve> Test_GetObstacleDebugCurves(ObstacleTree obstacleTree) { return Test_GetObstacleDebugCurves(obstacleTree, false, false); }
static internal void Test_DumpScanSegments(ObstacleTree obstacleTree, ScanSegmentTree hSegs, ScanSegmentTree vSegs) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetScanSegmentCurves(hSegs)); debugCurves.AddRange(Test_GetScanSegmentCurves(vSegs)); DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("ScanSegments")); #endif // TEST }
static internal void Test_DumpPathsAfterNudging(ObstacleTree obstacleTree, IEnumerable<Path> edgePaths) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetPostNudgedPathDebugCurves(edgePaths)); DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("PostNudgedPaths")); #endif // TEST }
static internal void Test_ShowPathsAfterNudging(ObstacleTree obstacleTree, IEnumerable<Path> edgePaths) { #if TEST_MSAGL var debugCurves = Test_GetObstacleDebugCurves(obstacleTree); debugCurves.AddRange(Test_GetPostNudgedPathDebugCurves(edgePaths)); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(debugCurves); #endif // TEST }
static internal List <DebugCurve> Test_GetObstacleDebugCurves(ObstacleTree obstacleTree, bool noPadPoly, bool noVisPoly) { return(Test_GetObstacleDebugCurves(obstacleTree.GetAllObstacles(), noPadPoly, noVisPoly)); }
internal ObstaclePortEntrance(ObstaclePort oport, Point unpaddedBorderIntersect, Direction outDir, ObstacleTree obstacleTree) { ObstaclePort = oport; UnpaddedBorderIntersect = unpaddedBorderIntersect; OutwardDirection = outDir; // Get the padded intersection. var lineSeg = new LineSegment(UnpaddedBorderIntersect, StaticGraphUtility.RectangleBorderIntersect( oport.Obstacle.VisibilityBoundingBox, UnpaddedBorderIntersect, outDir)); IList <IntersectionInfo> xxs = Curve.GetAllIntersections(lineSeg, oport.Obstacle.VisibilityPolyline, true /*liftIntersections*/); Debug.Assert(1 == xxs.Count, "Expected one intersection"); this.VisibilityBorderIntersect = ApproximateComparer.Round(SpliceUtility.RawIntersection(xxs[0], UnpaddedBorderIntersect)); this.MaxVisibilitySegment = obstacleTree.CreateMaxVisibilitySegment(this.VisibilityBorderIntersect, this.OutwardDirection, out this.pointAndCrossingsList); // Groups are never in a clump (overlapped) but they may still have their port entrance overlapped. if (this.Obstacle.IsOverlapped || (this.Obstacle.IsGroup && !this.Obstacle.IsInConvexHull)) { this.IsOverlapped = obstacleTree.IntersectionIsInsideAnotherObstacle(/*sideObstacle:*/ null, this.Obstacle , this.VisibilityBorderIntersect, ScanDirection.GetInstance(OutwardDirection)); if (!this.Obstacle.IsGroup || this.IsOverlapped || this.InteriorEdgeCrossesObstacle(obstacleTree)) { unpaddedToPaddedBorderWeight = ScanSegment.OverlappedWeight; } } if (this.Obstacle.IsInConvexHull && (unpaddedToPaddedBorderWeight == ScanSegment.NormalWeight)) { SetUnpaddedToPaddedBorderWeightFromHullSiblingOverlaps(obstacleTree); } }
private void SetUnpaddedToPaddedBorderWeightFromHullSiblingOverlaps(ObstacleTree obstacleTree) { if (this.Obstacle.IsGroup ? this.InteriorEdgeCrossesObstacle(obstacleTree) : this.InteriorEdgeCrossesConvexHullSiblings()) { this.unpaddedToPaddedBorderWeight = ScanSegment.OverlappedWeight; } }
// The return value is whether we should try a second pass if this is called on the first pass, // using spliceTarget to wrap up dead-ends on the target side. bool ExtendSpliceWorker(VisibilityVertex spliceSource, Directions extendDir, Directions spliceTargetDir , LineSegment maxDesiredSegment, LineSegment maxVisibilitySegment , bool isOverlapped, out VisibilityVertex spliceTarget) { // This is called after having created at least one extension vertex (initially, the // first one added outside the obstacle), so we know extendVertex will be there. spliceSource // is the vertex to the OppositeDir(spliceTargetDir) of that extendVertex. VisibilityVertex extendVertex = StaticGraphUtility.FindNextVertex(spliceSource, spliceTargetDir); spliceTarget = StaticGraphUtility.FindNextVertex(extendVertex, spliceTargetDir); for (; ;) { if (!GetNextSpliceSource(ref spliceSource, spliceTargetDir, extendDir)) { break; } // spliceSource is now on the correct edge relative to the desired nextExtendPoint. // spliceTarget is in the opposite direction of the extension-line-to-spliceSource. Point nextExtendPoint = StaticGraphUtility.FindBendPointBetween(extendVertex.Point , spliceSource.Point, CompassVector.OppositeDir(spliceTargetDir)); // We test below for being on or past maxDesiredSegment; here we may be skipping // over maxDesiredSegmentEnd which is valid since we want to be sure to go to or // past limitRect, but be sure to stay within maxVisibilitySegment. if (IsPointPastSegmentEnd(maxVisibilitySegment, nextExtendPoint)) { break; } spliceTarget = GetSpliceTarget(ref spliceSource, spliceTargetDir, nextExtendPoint); //StaticGraphUtility.Test_DumpVisibilityGraph(ObstacleTree, VisGraph); if (null == spliceTarget) { // This may be because spliceSource was created just for Group boundaries. If so, // skip to the next nextExtendVertex location. if (this.IsSkippableSpliceSourceWithNullSpliceTarget(spliceSource, extendDir)) { continue; } // We're at a dead-end extending from the source side, or there is an intervening obstacle, or both. // Don't splice across lateral group boundaries. if (ObstacleTree.SegmentCrossesAnObstacle(spliceSource.Point, nextExtendPoint)) { return(false); } } // We might be walking through a point where a previous chain dead-ended. VisibilityVertex nextExtendVertex = VisGraph.FindVertex(nextExtendPoint); if (null != nextExtendVertex) { if ((null == spliceTarget) || (null != this.VisGraph.FindEdge(extendVertex.Point, nextExtendPoint))) { // We are probably along a ScanSegment so visibility in this direction has already been determined. // Stop and don't try to continue extension from the opposite side. If we continue splicing here // it might go across an obstacle. if (null == spliceTarget) { Debug_VerifyNonOverlappedExtension(isOverlapped, extendVertex, nextExtendVertex, spliceSource: null, spliceTarget: null); FindOrAddEdge(extendVertex, nextExtendVertex, isOverlapped ? ScanSegment.OverlappedWeight : ScanSegment.NormalWeight); } return(false); } // This should always have been found in the find-the-next-target loop above if there is // a vertex (which would be nextExtendVertex, which we just found) between spliceSource // and spliceTarget. Even for a sparse graph, an edge should not skip over a vertex. StaticGraphUtility.Assert(spliceTarget == StaticGraphUtility.FindNextVertex(nextExtendVertex, spliceTargetDir) , "no edge exists between an existing nextExtendVertex and spliceTarget" , ObstacleTree, VisGraph); } else { StaticGraphUtility.Assert((null == spliceTarget) || spliceTargetDir == PointComparer.GetPureDirection(nextExtendPoint, spliceTarget.Point) , "spliceTarget is not to spliceTargetDir of nextExtendVertex" , ObstacleTree, VisGraph); nextExtendVertex = this.AddVertex(nextExtendPoint); } FindOrAddEdge(extendVertex, nextExtendVertex, isOverlapped ? ScanSegment.OverlappedWeight : ScanSegment.NormalWeight); Debug_VerifyNonOverlappedExtension(isOverlapped, extendVertex, nextExtendVertex, spliceSource, spliceTarget); // This will split the edge if targetVertex is non-null; otherwise we are at a dead-end // on the target side so must not create a vertex as it would be inside an obstacle. FindOrAddEdge(spliceSource, nextExtendVertex, isOverlapped ? ScanSegment.OverlappedWeight : ScanSegment.NormalWeight); if (isOverlapped) { isOverlapped = this.SeeIfSpliceIsStillOverlapped(extendDir, nextExtendVertex); } extendVertex = nextExtendVertex; // Test GetDirections because it may return Directions. None. if (0 == (extendDir & PointComparer.GetDirections(nextExtendPoint, maxDesiredSegment.End))) { // At or past the desired max extension point, so we're done. spliceTarget = null; break; } } return(null != spliceTarget); }
static internal List <DebugCurve> Test_GetObstacleDebugCurves(ObstacleTree obstacleTree) { return(Test_GetObstacleDebugCurves(obstacleTree, false, false)); }
// ReSharper disable InconsistentNaming protected static void Debug_AssertGraphIsRectilinear(VisibilityGraph graph, ObstacleTree obstacleTree) // ReSharper restore InconsistentNaming { #if DEBUG if (graph.Edges.Any(edge => !PointComparer.IsPureDirection(PointComparer.GetDirections(edge.SourcePoint, edge.TargetPoint)))) { StaticGraphUtility.Assert(false, "Generated VisibilityGraph contains non-rectilinear lines", obstacleTree, graph); return; } #endif }