internal VisibilityEdge FindPerpendicularOrContainingEdge(VisibilityVertex startVertex , Directions dir, Point pointLocation) { // Return the edge in 'dir' from startVertex that is perpendicular to pointLocation. // startVertex must therefore be located such that pointLocation is in 'dir' direction from it, // or is on the same line. StaticGraphUtility.Assert(0 == (CompassVector.OppositeDir(dir) & PointComparer.GetDirections(startVertex.Point, pointLocation)) , "the ray from 'dir' is away from pointLocation", ObstacleTree, VisGraph); while (true) { VisibilityVertex nextVertex = StaticGraphUtility.FindNextVertex(startVertex, dir); if (null == nextVertex) { break; } Directions dirCheck = PointComparer.GetDirections(nextVertex.Point, pointLocation); // If the next vertex is past the intersection with pointLocation, this edge brackets it. if (0 != (CompassVector.OppositeDir(dir) & dirCheck)) { return(VisGraph.FindEdge(startVertex.Point, nextVertex.Point)); } startVertex = nextVertex; } return(null); }
static internal VisibilityVertex GetVertex(VisibilityEdge edge, Directions dir) { Directions edgeDir = EdgeDirection(edge); Debug.Assert(0 != (dir & (edgeDir | CompassVector.OppositeDir(edgeDir))), "dir is orthogonal to edge"); return((dir == edgeDir) ? edge.Target : edge.Source); }
private void AddGroupIntersectionsToRestrictedRay(Obstacle obstacle, IList <IntersectionInfo> intersections) { // We'll let the lines punch through any intersections with groups, but track the location so we can enable/disable crossing. foreach (var intersectionInfo in intersections) { var intersect = SpliceUtility.RawIntersection(intersectionInfo, currentRestrictedRay.Start); // Skip intersections that are past the end of the restricted segment (though there may still be some // there if we shorten it later, but we'll skip them later). var distSquared = (intersect - currentRestrictedRay.Start).LengthSquared; if (distSquared > restrictedRayLengthSquared) { continue; } var dirTowardIntersect = PointComparer.GetPureDirection(currentRestrictedRay.Start, currentRestrictedRay.End); var polyline = (Polyline)intersectionInfo.Segment1; // this is the second arg to GetAllIntersections var dirsOfSide = CompassVector.VectorDirection(polyline.Derivative(intersectionInfo.Par1)); // The derivative is always clockwise, so if the side contains the rightward rotation of the // direction from the ray origin, then we're hitting it from the inside; otherwise from the outside. var dirToInsideOfGroup = dirTowardIntersect; if (0 != (dirsOfSide & CompassVector.RotateRight(dirTowardIntersect))) { dirToInsideOfGroup = CompassVector.OppositeDir(dirToInsideOfGroup); } CurrentGroupBoundaryCrossingMap.AddIntersection(intersect, obstacle, dirToInsideOfGroup); } }
private static void GetBrackets(VisibilityVertex sourceVertex, VisibilityVertex targetVertex, Direction dirToTarget, out VisibilityVertex bracketSource, out VisibilityVertex bracketTarget, out VisibilityVertex splitVertex) { // Is there an edge in the chain from sourceVertex in the direction of targetVertex // that brackets targetvertex? // <sourceVertex> -> ..1.. -> ..2.. <end> 3 // Yes if targetVertex is at the x above 1 or 2, No if it is at 3. If false, bracketSource // will be set to the vertex at <end> (if there are any edges in that direction at all). splitVertex = targetVertex; if (!FindBracketingVertices(sourceVertex, targetVertex.Point, dirToTarget , out bracketSource, out bracketTarget)) { // No bracketing of targetVertex from sourceVertex but bracketSource has been updated. // Is there a bracket of bracketSource from the targetVertex direction? // 3 <end> ..2.. <- ..1.. <targetVertex> // Yes if bracketSource is at the x above 1 or 2, No if it is at 3. If false, bracketTarget // will be set to the vertex at <end> (if there are any edges in that direction at all). // If true, then bracketSource and splitVertex must be updated. VisibilityVertex tempSource; if (FindBracketingVertices(targetVertex, sourceVertex.Point, CompassVector.OppositeDir(dirToTarget) , out bracketTarget, out tempSource)) { Debug.Assert(bracketSource == sourceVertex, "Mismatched bracketing detection"); bracketSource = tempSource; splitVertex = sourceVertex; } } }
private void LookForCloserNonGroupIntersectionToRestrictRay(IList <IntersectionInfo> intersections) { int numberOfGoodIntersections = 0; IntersectionInfo closestIntersectionInfo = null; var localLeastDistSquared = this.restrictedRayLengthSquared; var testDirection = PointComparer.GetDirections(restrictedIntersectionTestSegment.Start, restrictedIntersectionTestSegment.End); foreach (var intersectionInfo in intersections) { var intersect = SpliceUtility.RawIntersection(intersectionInfo, currentRestrictedRay.Start); var dirToIntersect = PointComparer.GetDirections(currentRestrictedRay.Start, intersect); if (dirToIntersect == CompassVector.OppositeDir(testDirection)) { continue; } ++numberOfGoodIntersections; if (Directions.None == dirToIntersect) { localLeastDistSquared = 0.0; closestIntersectionInfo = intersectionInfo; continue; } var distSquared = (intersect - currentRestrictedRay.Start).LengthSquared; if (distSquared < localLeastDistSquared) { // Rounding may falsely report two intersections as different when they are actually "Close", // e.g. a horizontal vs. vertical intersection on a slanted edge. var rawDistSquared = (intersectionInfo.IntersectionPoint - currentRestrictedRay.Start).LengthSquared; if (rawDistSquared < ApproximateComparer.SquareOfDistanceEpsilon) { continue; } localLeastDistSquared = distSquared; closestIntersectionInfo = intersectionInfo; } } if (null != closestIntersectionInfo) { // If there was only one intersection and it is quite close to an end, ignore it. // If there is more than one intersection, we have crossed the obstacle so we want it. if (numberOfGoodIntersections == 1) { var intersect = SpliceUtility.RawIntersection(closestIntersectionInfo, currentRestrictedRay.Start); if (ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.Start) || ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.End)) { return; } } this.restrictedRayLengthSquared = localLeastDistSquared; currentRestrictedRay.End = SpliceUtility.MungeClosestIntersectionInfo(currentRestrictedRay.Start, closestIntersectionInfo , !StaticGraphUtility.IsVertical(currentRestrictedRay.Start, currentRestrictedRay.End)); } }
void GoOverPathAndCreateLongSegs(Path path) { LongestNudgedSegment currentLongestSeg = null; var oppositeDir = CompassVector.OppositeDir(NudgingDirection); foreach (var edge in path.PathEdges) { var edgeDir = edge.Direction; if (edgeDir == NudgingDirection || edgeDir == oppositeDir) { if (currentLongestSeg == null) #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=368 { edge.LongestNudgedSegment = currentLongestSeg = new LongestNudgedSegment(LongestNudgedSegs.Count); LongestNudgedSegs.Add(edge.LongestNudgedSegment); } #else { LongestNudgedSegs.Add( edge.LongestNudgedSegment = currentLongestSeg = new LongestNudgedSegment(LongestNudgedSegs.Count)); } #endif else { edge.LongestNudgedSegment = currentLongestSeg; } if (edge.IsFixed) { currentLongestSeg.IsFixed = true; } }
private void SpliceGroupBoundaryCrossings(PointAndCrossingsList crossingList, VisibilityVertex startVertex, LineSegment maxSegment) { if ((null == crossingList) || (0 == crossingList.Count)) { return; } crossingList.Reset(); var start = maxSegment.Start; var end = maxSegment.End; var dir = PointComparer.GetPureDirection(start, end); // Make sure we are going in the ascending direction. if (!StaticGraphUtility.IsAscending(dir)) { start = maxSegment.End; end = maxSegment.Start; dir = CompassVector.OppositeDir(dir); } // We need to back up to handle group crossings that are between a VisibilityBorderIntersect on a sloped border and the // incoming startVertex (which is on the first ScanSegment in Perpendicular(dir) that is outside that padded border). startVertex = TraverseToFirstVertexAtOrAbove(startVertex, start, CompassVector.OppositeDir(dir)); // Splice into the Vertices between and including the start/end points. for (var currentVertex = startVertex; null != currentVertex; currentVertex = StaticGraphUtility.FindNextVertex(currentVertex, dir)) { bool isFinalVertex = (PointComparer.Compare(currentVertex.Point, end) >= 0); while (crossingList.CurrentIsBeforeOrAt(currentVertex.Point)) { PointAndCrossings pac = crossingList.Pop(); // If it's past the start and at or before the end, splice in the crossings in the descending direction. if (PointComparer.Compare(pac.Location, startVertex.Point) > 0) { if (PointComparer.Compare(pac.Location, end) <= 0) { SpliceGroupBoundaryCrossing(currentVertex, pac, CompassVector.OppositeDir(dir)); } } // If it's at or past the start and before the end, splice in the crossings in the descending direction. if (PointComparer.Compare(pac.Location, startVertex.Point) >= 0) { if (PointComparer.Compare(pac.Location, end) < 0) { SpliceGroupBoundaryCrossing(currentVertex, pac, dir); } } } if (isFinalVertex) { break; } } }
// Use the internal static xxxInstance properties to get an instance. private ScanDirection(Directions directionAlongScanLine) { System.Diagnostics.Debug.Assert(StaticGraphUtility.IsAscending(directionAlongScanLine), "directionAlongScanLine must be ascending"); Direction = directionAlongScanLine; DirectionAsPoint = CompassVector.ToPoint(Direction); PerpDirection = (Directions.North == directionAlongScanLine) ? Directions.East : Directions.North; PerpDirectionAsPoint = CompassVector.ToPoint(PerpDirection); OppositeDirection = CompassVector.OppositeDir(directionAlongScanLine); }
static Directions FindContinuedDirection(AxisEdge edge, Directions direction, AxisEdge nextAxisEdge) { if (edge.Direction == direction) { return(nextAxisEdge.Source == edge.Target ? nextAxisEdge.Direction : CompassVector.OppositeDir(nextAxisEdge.Direction)); } return(nextAxisEdge.Source == edge.Source ? nextAxisEdge.Direction : CompassVector.OppositeDir(nextAxisEdge.Direction)); }
bool IsSkippableSpliceSourceWithNullSpliceTarget(VisibilityVertex spliceSource, Direction extendDir) { if (IsSkippableSpliceSourceEdgeWithNullTarget(StaticGraphUtility.FindAdjacentEdge(spliceSource, extendDir))) { return(true); } var spliceSourceEdge = StaticGraphUtility.FindAdjacentEdge(spliceSource, CompassVector.OppositeDir(extendDir)); // Since target is null, if this is a reflection, it is bouncing off an outer side of a group or // obstacle at spliceSource. In that case, we don't want to splice from it because then we could // cut through the group and outside again; instead we should just stay outside it. return(IsSkippableSpliceSourceEdgeWithNullTarget(spliceSourceEdge) || IsReflectionEdge(spliceSourceEdge)); }
private void ExtendEdgeChain(VisibilityVertex startVertex, Directions extendDir , LineSegment maxDesiredSegment, LineSegment maxVisibilitySegment , PointAndCrossingsList pacList, bool isOverlapped) { StaticGraphUtility.Assert(PointComparer.GetPureDirection(maxDesiredSegment.Start, maxDesiredSegment.End) == extendDir , "maxDesiredSegment is reversed", ObstacleTree, VisGraph); // Direction*s*, because it may return None, which is valid and means startVertex is on the // border of an obstacle and we don't want to go inside it. Directions segmentDir = PointComparer.GetDirections(startVertex.Point, maxDesiredSegment.End); if (segmentDir != extendDir) { // OppositeDir may happen on overlaps where the boundary has a gap in its ScanSegments due to other obstacles // overlapping it and each other. This works because the port has an edge connected to startVertex, // which is on a ScanSegment outside the obstacle. StaticGraphUtility.Assert(isOverlapped || (segmentDir != CompassVector.OppositeDir(extendDir)) , "obstacle encountered between prevPoint and startVertex", ObstacleTree, VisGraph); return; } // We'll find the segment to the left (or right if to the left doesn't exist), // then splice across in the opposite direction. Directions spliceSourceDir = CompassVector.RotateLeft(extendDir); VisibilityVertex spliceSource = StaticGraphUtility.FindNextVertex(startVertex, spliceSourceDir); if (null == spliceSource) { spliceSourceDir = CompassVector.OppositeDir(spliceSourceDir); spliceSource = StaticGraphUtility.FindNextVertex(startVertex, spliceSourceDir); if (null == spliceSource) { return; } } // Store this off before ExtendSpliceWorker, which overwrites it. Directions spliceTargetDir = CompassVector.OppositeDir(spliceSourceDir); VisibilityVertex spliceTarget; if (ExtendSpliceWorker(spliceSource, extendDir, spliceTargetDir, maxDesiredSegment, maxVisibilitySegment, isOverlapped, out spliceTarget)) { // We ended on the source side and may have dead-ends on the target side so reverse sides. ExtendSpliceWorker(spliceTarget, extendDir, spliceSourceDir, maxDesiredSegment, maxVisibilitySegment, isOverlapped, out spliceTarget); } SpliceGroupBoundaryCrossings(pacList, startVertex, maxDesiredSegment); }
internal VisibilityEdge FindNearestPerpendicularOrContainingEdge(VisibilityVertex startVertex , Directions dir, Point pointLocation) { // Similar to FindPerpendicularEdge, but first try to move closer to pointLocation, // as long as there are edges going in 'dir' that extend to pointLocation. Directions dirTowardLocation = ~dir& PointComparer.GetDirections(startVertex.Point, pointLocation); // If Directions. None then pointLocation is collinear. VisibilityVertex currentVertex = startVertex; Directions currentDirTowardLocation = dirTowardLocation; // First move toward pointLocation far as we can. while (Directions.None != currentDirTowardLocation) { VisibilityVertex nextVertex = StaticGraphUtility.FindNextVertex(currentVertex, dirTowardLocation); if (null == nextVertex) { break; } if (0 != (CompassVector.OppositeDir(dirTowardLocation) & PointComparer.GetDirections(nextVertex.Point, pointLocation))) { break; } currentVertex = nextVertex; currentDirTowardLocation = ~dir& PointComparer.GetDirections(currentVertex.Point, pointLocation); } // Now find the first vertex that has a chain that intersects pointLocation, if any, moving away // from pointLocation until we find it or arrive back at startVertex. VisibilityEdge perpEdge; while (true) { perpEdge = FindPerpendicularOrContainingEdge(currentVertex, dir, pointLocation); if ((null != perpEdge) || (currentVertex == startVertex)) { break; } currentVertex = StaticGraphUtility.FindNextVertex(currentVertex, CompassVector.OppositeDir(dirTowardLocation)); } return(perpEdge); }
private static VisibilityVertex TraverseToFirstVertexAtOrAbove(VisibilityVertex startVertex, Point start, Directions dir) { var returnVertex = startVertex; var oppositeDir = CompassVector.OppositeDir(dir); for ( ; ;) { var nextVertex = StaticGraphUtility.FindNextVertex(returnVertex, dir); // This returns Directions. None on a match. if ((null == nextVertex) || (PointComparer.GetDirections(nextVertex.Point, start) == oppositeDir)) { break; } returnVertex = nextVertex; } return(returnVertex); }
internal VisibilityEdge FindOrAddEdge(VisibilityVertex sourceVertex, VisibilityVertex targetVertex, double weight) { // Since we're adding transient edges into the graph, we're not doing full intersection // evaluation; thus there may already be an edge from the source vertex in the direction // of the target vertex, but ending before or after the target vertex. Directions dirToTarget = PointComparer.GetPureDirection(sourceVertex, targetVertex); VisibilityVertex bracketSource, bracketTarget; // Is there an edge in the chain from sourceVertex in the direction of targetVertex // that brackets targetvertex? // <sourceVertex> -> ..1.. -> ..2.. <end> 3 // Yes if targetVertex is at the x above 1 or 2, No if it is at 3. If false, bracketSource // will be set to the vertex at <end> (if there are any edges in that direction at all). VisibilityVertex splitVertex = targetVertex; if (!FindBracketingVertices(sourceVertex, targetVertex.Point, dirToTarget , out bracketSource, out bracketTarget)) { // No bracketing of targetVertex from sourceVertex but bracketSource has been updated. // Is there a bracket of bracketSource from the targetVertex direction? // 3 <end> ..2.. <- ..1.. <targetVertex> // Yes if bracketSource is at the x above 1 or 2, No if it is at 3. If false, bracketTarget // will be set to the vertex at <end> (if there are any edges in that direction at all). // If true, then bracketSource and splitVertex must be updated. VisibilityVertex tempSource; if (FindBracketingVertices(targetVertex, sourceVertex.Point, CompassVector.OppositeDir(dirToTarget) , out bracketTarget, out tempSource)) { Debug.Assert(bracketSource == sourceVertex, "Mismatched bracketing detection"); bracketSource = tempSource; splitVertex = sourceVertex; } } // If null != edge then targetVertex is between bracketSource and bracketTarget and SplitEdge returns the // first half-edge (and weight is ignored as the split uses the edge weight). var edge = VisGraph.FindEdge(bracketSource.Point, bracketTarget.Point); edge = (null != edge) ? this.SplitEdge(edge, splitVertex) : CreateEdge(bracketSource, bracketTarget, weight); DevTrace_VerifyEdge(edge); return(edge); }
// 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); }
bool EdgeIsParallelToSweepDir(AxisEdge edge) { return(edge.Direction == SweepPole || edge.Direction == CompassVector.OppositeDir(SweepPole)); }
static int CompareTwoPathEdges(PathEdge x, PathEdge y) { if (x == y) { return(0); } Debug.Assert(x.AxisEdge == y.AxisEdge); //Nudger.ShowOrderedPaths(null, new[] { x.Path, y.Path }, x.AxisEdge.SourcePoint, x.AxisEdge.TargetPoint); int r = CompareInDirectionStartingFromAxisEdge(x, y, x.AxisEdge, x.AxisEdge.Direction); return(r != 0 ? r : -CompareInDirectionStartingFromAxisEdge(x, y, x.AxisEdge, CompassVector.OppositeDir(x.AxisEdge.Direction))); }
private static bool GetNextSpliceSource(ref VisibilityVertex spliceSource, Directions spliceTargetDir, Directions extendDir) { VisibilityVertex nextSpliceSource = StaticGraphUtility.FindNextVertex(spliceSource, extendDir); if (null == nextSpliceSource) { // See if there is a source further away from the extension line - we might have // been on freePoint line (or another nearby PortEntry line) that dead-ended. // Look laterally from the previous spliceSource first. nextSpliceSource = spliceSource; for (;;) { nextSpliceSource = StaticGraphUtility.FindNextVertex(nextSpliceSource, CompassVector.OppositeDir(spliceTargetDir)); if (null == nextSpliceSource) { return(false); } var nextSpliceSourceExtend = StaticGraphUtility.FindNextVertex(nextSpliceSource, extendDir); if (null != nextSpliceSourceExtend) { nextSpliceSource = nextSpliceSourceExtend; break; } } } spliceSource = nextSpliceSource; return(true); }