예제 #1
0
        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);
        }
예제 #2
0
        // 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);
        }
예제 #3
0
        // 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);
                }
            }
        }
예제 #4
0
        /// <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));
        }
예제 #11
0
            /// <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);
                    }
                }
            }
예제 #12
0
        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));
            }
        }
예제 #13
0
        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);
        }
예제 #15
0
        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);
        }
예제 #16
0
        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);
        }
예제 #17
0
 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));
 }
예제 #18
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));
 }
예제 #19
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)));
 }
예제 #20
0
        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));
        }
예제 #21
0
        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);
        }
예제 #22
0
        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));
        }
예제 #25
0
        // 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;
        }
예제 #26
0
 internal bool CurrentIsBeforeOrAt(Point comparand)
 {
     if (index >= ListOfPointsAndCrossings.Count)
     {
         return(false);
     }
     return(PointComparer.Compare(ListOfPointsAndCrossings[index].Location, comparand) <= 0);
 }
예제 #27
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);
        }
예제 #29
0
 internal void OnSegmentIntersectorEnd(VisibilityGraph vg)
 {
     AppendGroupCrossingsThroughPoint(vg, End);
     GroupBoundaryPointAndCrossingsList = null;
     if ((null == HighestVisibilityVertex) || (PointComparer.IsPureLower(HighestVisibilityVertex.Point, End)))
     {
         LoadEndOverlapVertexIfNeeded(vg);
     }
 }
예제 #30
0
        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);
        }