internal RBNode <ScanSegment> FindLowestIntersectorNode(Point start, Point end) { Debug.Assert(ScanDirection.IsPerpendicular(start, end), "non-perpendicular segment passed"); // Find the last segment that starts at or before 'start'. this.lookupSegment.Update(start, start); RBNode <ScanSegment> node = this.segmentTree.FindLast(this.findIntersectorPred); // We have a segment that intersects start/end, or one that ends before 'start' and thus we // must iterate to find the lowest bisector. TODOperf: see how much that iteration costs us // (here and Highest); consider a BSP tree or interval tree (maybe 2-d RBTree for updatability). if (PointComparer.Equal(start, end)) { if ((null != node) && (ScanDirection.Compare(node.Item.End, start) < 0)) { node = null; } } else { this.lookupSegment.Update(start, end); while ((null != node) && !node.Item.IntersectsSegment(this.lookupSegment)) { // If the node segment starts after 'end', no intersection was found. if (ScanDirection.Compare(node.Item.Start, end) > 0) { return(null); } node = this.segmentTree.Next(node); } } return(node); }
// Find the highest perpendicular scanseg that intersects the segment endpoints. internal ScanSegment FindHighestIntersector(Point start, Point end) { Debug.Assert(ScanDirection.IsPerpendicular(start, end), "non-perpendicular segment passed"); // Find the last segment that starts at or before 'end'. this.lookupSegment.Update(end, end); RBNode <ScanSegment> node = this.segmentTree.FindLast(this.findIntersectorPred); // Now we either have a segment that intersects start/end, or one that ends before // 'end' and need to iterate to find the highest bisector. if (PointComparer.Equal(start, end)) { if ((null != node) && (ScanDirection.Compare(node.Item.End, start) < 0)) { node = null; } } else { this.lookupSegment.Update(start, end); while ((null != node) && !node.Item.IntersectsSegment(this.lookupSegment)) { // If the node segment ends before 'start', no intersection was found. if (ScanDirection.Compare(node.Item.End, start) < 0) { return(null); } node = this.segmentTree.Previous(node); } } return((null != node) ? node.Item : null); }
// Append a vertex before LowestVisibilityVertex or after HighestVisibilityVertex. internal void AppendVisibilityVertex(VisibilityGraph vg, VisibilityVertex newVertex) { Debug.Assert(null != newVertex, "newVertex must not be null"); Debug.Assert((null == LowestVisibilityVertex) == (null == HighestVisibilityVertex), "Mismatched null Lowest/HighestVisibilityVertex"); Debug.Assert(StaticGraphUtility.PointIsOnSegment(this, newVertex.Point), "newVertex is out of segment range"); if (null == HighestVisibilityVertex) { if (!AddGroupCrossingsBeforeHighestVisibilityVertex(vg, newVertex)) { SetInitialVisibilityVertex(newVertex); } } else { // In the event of overlaps where ScanSegments share a Start/End at a border, SegmentIntersector // may be appending the same Vertex twice. If that point is on the border of a group, // then we may have just added the border-crossing edge as well. if (PointComparer.IsPureLower(newVertex.Point, HighestVisibilityVertex.Point)) { Debug.Assert(null != vg.FindEdge(newVertex.Point, HighestVisibilityVertex.Point) , "unexpected low/middle insertion to ScanSegment"); return; } // Add the new edge. This will always be in the ascending direction. if (!AddGroupCrossingsBeforeHighestVisibilityVertex(vg, newVertex)) { AppendHighestVisibilityVertex(newVertex); } } }
/// <summary> /// For ordering V segments in the scanline by X. /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public int Compare(ScanSegment first, ScanSegment second) { if (first == second) { return(0); } if (first == null) { return(-1); } if (second == null) { return(1); } // Note: Unlike the ScanSegment-generating scanline, this scanline has no slope // calculations so no additional rounding error is introduced. int cmp = PointComparer.Compare(first.Start.X, second.Start.X); // Separate segments may join at Start and End due to overlap, so compare the Y positions; // the Close (lowest Y) comes before the Open. if (0 == cmp) { cmp = PointComparer.Compare(first.Start.Y, second.Start.Y); } return(cmp); }
private static VisibilityVertex GetSpliceTarget(ref VisibilityVertex spliceSource, Directions spliceTargetDir, Point nextExtendPoint) { // Look for the target. There may be a dead-ended edge starting at the current spliceSource // edge that has a vertex closer to the extension line; in that case keep walking until we // have the closest vertex on the Source side of the extension line as spliceSource. Directions prevDir = PointComparer.GetPureDirection(spliceSource.Point, nextExtendPoint); Directions nextDir = prevDir; var spliceTarget = spliceSource; while (nextDir == prevDir) { spliceSource = spliceTarget; spliceTarget = StaticGraphUtility.FindNextVertex(spliceSource, spliceTargetDir); if (null == spliceTarget) { break; } if (PointComparer.Equal(spliceTarget.Point, nextExtendPoint)) { // If we encountered an existing vertex for the extension chain, update spliceTarget // to be after it and we're done with this loop. spliceTarget = StaticGraphUtility.FindNextVertex(spliceTarget, spliceTargetDir); break; } nextDir = PointComparer.GetPureDirection(spliceTarget.Point, nextExtendPoint); } return(spliceTarget); }
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); }
internal void ConnectVertexToTargetVertex(VisibilityVertex sourceVertex, VisibilityVertex targetVertex, Directions finalEdgeDir, double weight) { // finalDir is the required direction of the final edge to the targetIntersect // (there will be two edges if we have to add a bend vertex). StaticGraphUtility.Assert(PointComparer.IsPureDirection(finalEdgeDir), "finalEdgeDir is not pure", ObstacleTree, VisGraph); // targetIntersect may be CenterVertex if that is on an extreme bend or a flat border. if (PointComparer.Equal(sourceVertex.Point, targetVertex.Point)) { return; } // If the target is collinear with sourceVertex we can just create one edge to it. Directions targetDirs = PointComparer.GetDirections(sourceVertex.Point, targetVertex.Point); if (PointComparer.IsPureDirection(targetDirs)) { FindOrAddEdge(sourceVertex, targetVertex); return; } // Not collinear so we need to create a bend vertex and edge if they don't yet exist. Point bendPoint = StaticGraphUtility.FindBendPointBetween(sourceVertex.Point, targetVertex.Point, finalEdgeDir); VisibilityVertex bendVertex = FindOrAddVertex(bendPoint); FindOrAddEdge(sourceVertex, bendVertex, weight); // Now create the outer target vertex if it doesn't exist. FindOrAddEdge(bendVertex, targetVertex, weight); }
void DevTrace_VerifyVertex(VisibilityVertex vertex) { if (transGraphVerify.IsLevel(1)) { Directions dir = Directions.North; for (int idir = 0; idir < 4; ++idir, dir = CompassVector.RotateRight(dir)) { int count = 0; int cEdges = vertex.InEdges.Count; // indexing is faster than foreach for Lists for (int ii = 0; ii < cEdges; ++ii) { var edge = vertex.InEdges[ii]; if (PointComparer.GetPureDirection(vertex.Point, edge.SourcePoint) == dir) { ++count; } } // Avoid GetEnumerator overhead. var outEdgeNode = vertex.OutEdges.IsEmpty() ? null : vertex.OutEdges.TreeMinimum(); for (; outEdgeNode != null; outEdgeNode = vertex.OutEdges.Next(outEdgeNode)) { var edge = outEdgeNode.Item; if (PointComparer.GetPureDirection(vertex.Point, edge.TargetPoint) == dir) { ++count; } } Debug.Assert(count < 2, "vertex has multiple edges in one direction"); } } }
internal static bool FindBracketingVertices(VisibilityVertex sourceVertex, Point targetPoint, Directions dirToTarget , out VisibilityVertex bracketSource, out VisibilityVertex bracketTarget) { // Walk from the source to target until we bracket target or there is no nextVertex // in the desired direction. bracketSource = sourceVertex; for (; ;) { bracketTarget = StaticGraphUtility.FindNextVertex(bracketSource, dirToTarget); if (null == bracketTarget) { break; } if (PointComparer.Equal(bracketTarget.Point, targetPoint)) { // Desired edge already exists. return(true); } if (dirToTarget != PointComparer.GetPureDirection(bracketTarget.Point, targetPoint)) { // bracketTarget is past vertex in the traversal direction. break; } bracketSource = bracketTarget; } return(null != bracketTarget); }
static internal Point RawIntersection(IntersectionInfo xx, Point origin) { // If this fires, then you didn't pass the LineSegment as the first argument to GetAllIntersections. Debug.Assert(xx.Segment0 is LineSegment, "LineSegment was not first arg to GetAllIntersections"); // The intersection snaps the end of the intersection to the PolylinePoint at the start/end // of the interesecting segment on the obstacle if the intersection is Curve.CloseIntersections // to that segment endpoint, which can return a point that is just more than Curve.DistanceEpsilon // off the line. Therefore, re-create the intersection using the LineSegment and intersection // parameters (this assumes the LineSegment.End is not Curve.CloseIntersections to the intersection). Point point = xx.Segment0[xx.Par0]; #if TEST_MSAGL // This may legitimately be rounding-error'd in the same way as xx.IntersectionPoint (and the // caller addresses this later). The purpose of the assert is to verify that the LineSegment // interception is not outside the bbox in the perpendicular direction. var lineSeg = (LineSegment)xx.Segment0; if (StaticGraphUtility.IsVertical(PointComparer.GetDirections(lineSeg.Start, lineSeg.End))) { Debug.Assert(PointComparer.Equal(point.X, origin.X), "segment0 obstacle intersection is off the vertical line"); } else { Debug.Assert(PointComparer.Equal(point.Y, origin.Y), "segment0 obstacle intersection is off the horizontal line"); } #endif // TEST_MSAGL return(ApproximateComparer.Round(point)); }
/// <summary> /// Move along the linked list until we hit the ScanSegment that contains the point. /// </summary> internal bool TraverseToSegmentContainingPoint(Point point) { // This is not a simple Next() because scan segments are extended "through" obstacles // (intermixing overlapped and non-overlapped) and thus a ScanSegment's Start and End // may not be in the vertexPoints collection and the ScanSegment must be skipped. if (this.CurrentSegment.ContainsPoint(point)) { return(true); } var pointCoord = this.IsHorizontal ? point.Y : point.X; if (!PointComparer.Equal(this.Coord, pointCoord)) { Debug.Assert(PointComparer.Compare(this.Coord, pointCoord) == -1, "point is before current Coord"); while (this.MoveNext()) { // Skip to the end of the linked list if this point is not on the same coordinate. } return(false); } for (;;) { // In the event of mismatched rounding on horizontal versus vertical intersections // with a sloped obstacle side, we may have a point that is just before or just // after the current segment. If the point is in some space that doesn't have a // scansegment, and if we are "close enough" to one end or the other of a scansegment, // then grow the scansegment enough to include the new point. if ((null == this.CurrentSegment.NextSegment) || PointComparer.GetDirections(this.CurrentSegment.End, point) == PointComparer.GetDirections(point, this.CurrentSegment.NextSegment.Start)) { if (ApproximateComparer.CloseIntersections(this.CurrentSegment.End, point)) { this.CurrentSegment.Update(this.CurrentSegment.Start, point); return(true); } } if (!this.MoveNext()) { return(false); } if (this.CurrentSegment.ContainsPoint(point)) { return(true); } // This is likely the reverse of the above; the point rounding mismatched to just before // rather than just after the current segment. if (PointComparer.IsPureLower(point, this.CurrentSegment.Start)) { Debug.Assert(ApproximateComparer.CloseIntersections(this.CurrentSegment.Start, point), "Skipped over the point in the ScanSegment linked list"); this.CurrentSegment.Update(point, this.CurrentSegment.End); return(true); } } }
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)); } }
internal void MergeFrom(PointAndCrossingsList other) { Reset(); if ((null == other) || (0 == other.ListOfPointsAndCrossings.Count)) { return; } if (0 == this.ListOfPointsAndCrossings.Count) { this.ListOfPointsAndCrossings.AddRange(other.ListOfPointsAndCrossings); } if (null == this.ListOfPointsAndCrossings) { this.ListOfPointsAndCrossings = new List <PointAndCrossings>(other.ListOfPointsAndCrossings); return; } // Do the usual sorted-list merge. int thisIndex = 0, thisMax = this.ListOfPointsAndCrossings.Count; int otherIndex = 0, otherMax = other.ListOfPointsAndCrossings.Count; var newCrossingsList = new List <PointAndCrossings>(this.ListOfPointsAndCrossings.Count); while ((thisIndex < thisMax) || (otherIndex < otherMax)) { if (thisIndex >= thisMax) { newCrossingsList.Add(other.ListOfPointsAndCrossings[otherIndex++]); continue; } if (otherIndex >= otherMax) { newCrossingsList.Add(this.ListOfPointsAndCrossings[thisIndex++]); continue; } PointAndCrossings thisPac = this.ListOfPointsAndCrossings[thisIndex]; PointAndCrossings otherPac = other.ListOfPointsAndCrossings[otherIndex]; int cmp = PointComparer.Compare(thisPac.Location, otherPac.Location); if (0 == cmp) { // No duplicates newCrossingsList.Add(thisPac); ++thisIndex; ++otherIndex; } else if (-1 == cmp) { newCrossingsList.Add(thisPac); ++thisIndex; } else { newCrossingsList.Add(otherPac); ++otherIndex; } } this.ListOfPointsAndCrossings = newCrossingsList; }
HitTestBehavior InsideObstacleHitTest(Point location, Obstacle obstacle) { if ((obstacle == insideHitTestIgnoreObstacle1) || (obstacle == insideHitTestIgnoreObstacle2)) { // It's one of the two obstacles we already know about. return(HitTestBehavior.Continue); } if (obstacle.IsGroup) { // Groups are handled differently from overlaps; we create ScanSegments (overlapped // if within a non-group obstacle, else non-overlapped), and turn on/off access across // the Group boundary vertices. return(HitTestBehavior.Continue); } if (!StaticGraphUtility.PointIsInRectangleInterior(location, obstacle.VisibilityBoundingBox)) { // The point is on the obstacle boundary, not inside it. return(HitTestBehavior.Continue); } // Note: There are rounding issues using Curve.PointRelativeToCurveLocation at angled // obstacle boundaries, hence this function. Point high = StaticGraphUtility.RectangleBorderIntersect(obstacle.VisibilityBoundingBox, location , insideHitTestScanDirection.Direction) + insideHitTestScanDirection.DirectionAsPoint; Point low = StaticGraphUtility.RectangleBorderIntersect(obstacle.VisibilityBoundingBox, location , insideHitTestScanDirection.OppositeDirection) - insideHitTestScanDirection.DirectionAsPoint; var testSeg = new LineSegment(low, high); IList <IntersectionInfo> xxs = Curve.GetAllIntersections(testSeg, obstacle.VisibilityPolyline, true /*liftIntersections*/); // If this is an extreme point it can have one intersection, in which case we're either on the border // or outside; if it's a collinear flat boundary, there can be 3 intersections to this point which again // means we're on the border (and 3 shouldn't happen anymore with the curve intersection fixes and // PointIsInsideRectangle check above). So the interesting case is that we have 2 intersections. if (2 == xxs.Count) { Point firstInt = SpliceUtility.RawIntersection(xxs[0], location); Point secondInt = SpliceUtility.RawIntersection(xxs[1], location); // If we're on either intersection, we're on the border rather than inside. if (!PointComparer.Equal(location, firstInt) && !PointComparer.Equal(location, secondInt) && (location.CompareTo(firstInt) != location.CompareTo(secondInt))) { // We're inside. However, this may be an almost-flat side, in which case rounding // could have reported the intersection with the start or end of the same side and // a point somewhere on the interior of that side. Therefore if both intersections // are on the same side (integral portion of the parameter), we consider location // to be on the border. testSeg is always xxs[*].Segment0. Debug.Assert(testSeg == xxs[0].Segment0, "incorrect parameter ordering to GetAllIntersections"); if (!ApproximateComparer.Close(Math.Floor(xxs[0].Par1), Math.Floor(xxs[1].Par1))) { return(HitTestBehavior.Stop); } } } return(HitTestBehavior.Continue); }
static internal VisibilityVertex FindNextVertex(VisibilityVertex vertex, Directions dir) { // This function finds the next vertex in the desired direction relative to the // current vertex, not necessarily the edge orientation, hence it does not use // EdgeDirection(). This is so the caller can operate on a desired movement // direction without having to track whether we're going forward or backward // through the In/OutEdge chain. int cEdges = vertex.InEdges.Count; // indexing is faster than foreach for Lists for (int ii = 0; ii < cEdges; ++ii) { var edge = vertex.InEdges[ii]; if (PointComparer.GetPureDirection(vertex.Point, edge.SourcePoint) == dir) { return(edge.Source); } } // Avoid GetEnumerator overhead. var outEdgeNode = vertex.OutEdges.IsEmpty() ? null : vertex.OutEdges.TreeMinimum(); for (; outEdgeNode != null; outEdgeNode = vertex.OutEdges.Next(outEdgeNode)) { var edge = outEdgeNode.Item; if (PointComparer.GetPureDirection(vertex.Point, edge.TargetPoint) == dir) { return(edge.Target); } } return(null); }
static internal Point SegmentIntersection(Point first, Point second, Point from) { Directions dir = PointComparer.GetPureDirection(first, second); Point intersect = IsVertical(dir) ? new Point(first.X, from.Y) : new Point(from.X, first.Y); return(intersect); }
static internal bool RectangleInteriorsIntersect(Rectangle a, Rectangle b) { return((PointComparer.Compare(a.Bottom, b.Top) < 0) && (PointComparer.Compare(b.Bottom, a.Top) < 0) && (PointComparer.Compare(a.Left, b.Right) < 0) && (PointComparer.Compare(b.Left, a.Right) < 0)); }
static internal bool PointIsInRectangleInterior(Point point, Rectangle rect) { return((PointComparer.Compare(point.Y, rect.Top) < 0) && (PointComparer.Compare(rect.Bottom, point.Y) < 0) && (PointComparer.Compare(point.X, rect.Right) < 0) && (PointComparer.Compare(rect.Left, point.X) < 0)); }
internal bool ContainsPoint(Point test) { // This may be off the line so do not use GetPureDirections. return(PointComparer.Equal(this.Start, test) || PointComparer.Equal(this.End, test) || (PointComparer.GetDirections(this.Start, test) == PointComparer.GetDirections(test, this.End))); }
static internal Tuple <Point, Point> SortAscending(Point a, Point b) { Directions dir = PointComparer.GetDirections(a, b); Debug.Assert((Directions.None == dir) || PointComparer.IsPureDirection(dir), "SortAscending with impure direction"); return(((Directions.None == dir) || IsAscending(dir)) ? new Tuple <Point, Point>(a, b) : new Tuple <Point, Point>(b, a)); }
internal PointAndCrossingsList GetOrderedListBetween(Point start, Point end) { if (0 == pointCrossingMap.Count) { return(null); } if (PointComparer.Compare(start, end) > 0) { Point temp = start; start = end; end = temp; } // Start and end are inclusive. pointList.Clear(); foreach (var intersection in pointCrossingMap.Keys) { if ((PointComparer.Compare(intersection, start) >= 0) && (PointComparer.Compare(intersection, end) <= 0)) { pointList.Add(intersection); } } pointList.Sort(); var pointAndCrossingList = new PointAndCrossingsList(); var numCrossings = pointList.Count; for (int ii = 0; ii < numCrossings; ++ii) { Point intersect = pointList[ii]; pointAndCrossingList.Add(intersect, pointCrossingMap[intersect]); } return(pointAndCrossingList); }
void ScanIntersect(ScanSegment hSeg) { // Find the VSeg in the scanline with the lowest X-intersection with HSeg, then iterate // all VSegs in the scan line after that until we leave the HSeg range. // We only use FindFirstHSeg in this routine, to find the first satisfying node, // so we don't care that we leave leftovers in it. findFirstHSeg = hSeg; RBNode <ScanSegment> segNode = verticalSegmentsScanLine.FindFirst(findFirstPred); for (; null != segNode; segNode = verticalSegmentsScanLine.Next(segNode)) { ScanSegment vSeg = segNode.Item; if (1 == PointComparer.Compare(vSeg.Start.X, hSeg.End.X)) { break; // Out of HSeg range } VisibilityVertex newVertex = visGraph.AddVertex(new Point(vSeg.Start.X, hSeg.Start.Y)); // HSeg has just opened so if we are overlapped and newVertex already existed, // it was because we just closed a previous HSeg or VSeg and are now opening one // whose Start is the same as previous. So we may be appending a vertex that // is already the *Seg.HighestVisibilityVertex, which will be a no-op. Otherwise // this will add a (possibly Overlapped)VisibilityEdge in the *Seg direction. hSeg.AppendVisibilityVertex(visGraph, newVertex); vSeg.AppendVisibilityVertex(visGraph, newVertex); } // endforeach scanline VSeg in range OnSegmentClose(hSeg); }
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); } }
internal bool SegmentCrossesANonGroupObstacle(Point startPoint, Point endPoint) { stopAtGroups = false; wantGroupCrossings = false; LineSegment obstacleIntersectSeg = RestrictSegmentPrivate(startPoint, endPoint); return(!PointComparer.Equal(obstacleIntersectSeg.End, endPoint)); }
// ctor internal void Update(Point start, Point end) { Debug.Assert(PointComparer.Equal(start, end) || StaticGraphUtility.IsAscending(PointComparer.GetPureDirection(start, end)) , "non-ascending segment"); startPoint = start; endPoint = end; }
internal bool CurrentIsBeforeOrAt(Point comparand) { if (index >= ListOfPointsAndCrossings.Count) { return(false); } return(PointComparer.Compare(ListOfPointsAndCrossings[index].Location, comparand) <= 0); }
private void AppendHighestVisibilityVertex(VisibilityVertex newVertex) { if (!PointComparer.Equal(HighestVisibilityVertex.Point, newVertex.Point)) { AddVisibilityEdge(HighestVisibilityVertex, newVertex); HighestVisibilityVertex = newVertex; } }
static internal bool PointIsOnSegmentInterior(Point first, Point second, Point test) { Directions firstDir = PointComparer.GetDirections(first, test); Directions secondDir = PointComparer.GetDirections(test, second); Debug.Assert((Directions.None != firstDir) || (Directions.None != secondDir), "zero-length segment"); return(firstDir == secondDir); }
internal void OnSegmentIntersectorEnd(VisibilityGraph vg) { AppendGroupCrossingsThroughPoint(vg, End); GroupBoundaryPointAndCrossingsList = null; if ((null == HighestVisibilityVertex) || (PointComparer.IsPureLower(HighestVisibilityVertex.Point, End))) { LoadEndOverlapVertexIfNeeded(vg); } }
internal void AddOobEdgesFromGraphCorner(TransientGraphUtility transUtil, Point cornerPoint) { Directions dirs = PointComparer.GetDirections(cornerPoint, Vertex.Point); VisibilityVertex cornerVertex = transUtil.VisGraph.FindVertex(cornerPoint); // For waypoints we want to be able to enter in both directions. transUtil.ConnectVertexToTargetVertex(cornerVertex, this.Vertex, dirs & (Directions.North | Directions.South), ScanSegment.NormalWeight); transUtil.ConnectVertexToTargetVertex(cornerVertex, this.Vertex, dirs & (Directions.East | Directions.West), ScanSegment.NormalWeight); }