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);
        }
        /// <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);
        }
Example #3
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));
 }
Example #4
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;
        }
Example #5
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));
 }
            /// <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);
                    }
                }
            }
        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);
        }
Example #8
0
 internal bool CurrentIsBeforeOrAt(Point comparand)
 {
     if (index >= ListOfPointsAndCrossings.Count)
     {
         return(false);
     }
     return(PointComparer.Compare(ListOfPointsAndCrossings[index].Location, comparand) <= 0);
 }
        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;
                }
            }
        }
Example #10
0
        internal void Trim(Point start, Point end)
        {
            Reset();
            if ((null == ListOfPointsAndCrossings) || (0 == ListOfPointsAndCrossings.Count))
            {
                return;
            }

            ListOfPointsAndCrossings = new List <PointAndCrossings>(ListOfPointsAndCrossings.Where(
                                                                        pair => (PointComparer.Compare(pair.Location, start) >= 0) && (PointComparer.Compare(pair.Location, end) <= 0)));
        }
Example #11
0
        private bool AppendGroupCrossingsThroughPoint(VisibilityGraph vg, Point lastPoint)
        {
            if (null == GroupBoundaryPointAndCrossingsList)
            {
                return(false);
            }

            bool found = false;

            while (GroupBoundaryPointAndCrossingsList.CurrentIsBeforeOrAt(lastPoint))
            {
                // We will only create crossing Edges that the segment actually crosses, not those it ends before crossing.
                // For those terminal crossings, the adjacent segment creates the interior vertex and crossing edge.
                PointAndCrossings       pac              = GroupBoundaryPointAndCrossingsList.Pop();
                GroupBoundaryCrossing[] lowDirCrossings  = null;
                GroupBoundaryCrossing[] highDirCrossings = null;
                if (PointComparer.Compare(pac.Location, Start) > 0)
                {
                    lowDirCrossings = PointAndCrossingsList.ToCrossingArray(pac.Crossings,
                                                                            ScanDirection.OppositeDirection);
                }
                if (PointComparer.Compare(pac.Location, End) < 0)
                {
                    highDirCrossings = PointAndCrossingsList.ToCrossingArray(pac.Crossings, ScanDirection.Direction);
                }

                found = true;
                VisibilityVertex crossingVertex = vg.FindVertex(pac.Location) ?? vg.AddVertex(pac.Location);

                if ((null != lowDirCrossings) || (null != highDirCrossings))
                {
                    AddLowCrossings(vg, crossingVertex, lowDirCrossings);
                    AddHighCrossings(vg, crossingVertex, highDirCrossings);
                }
                else
                {
                    // This is at this.Start with only lower-direction toward group interior(s), or at this.End with only
                    // higher-direction toward group interior(s).  Therefore an adjacent ScanSegment will create the crossing
                    // edge, so create the crossing vertex here and we'll link to it.
                    if (null == LowestVisibilityVertex)
                    {
                        SetInitialVisibilityVertex(crossingVertex);
                    }
                    else
                    {
                        Debug.Assert(PointComparer.Equal(End, crossingVertex.Point), "Expected this.End crossingVertex");
                        AppendHighestVisibilityVertex(crossingVertex);
                    }
                }
            }
            return(found);
        }
Example #12
0
 bool IsVSegInHSegRange(ScanSegment v)
 {
     return(PointComparer.Compare(v.Start.X, findFirstHSeg.Start.X) >= 0);
 }
Example #13
0
        // end ScanIntersect()

        #endregion // Scanline utilities

        #region IComparer<SegEvent>

        /// <summary>
        /// For ordering events first by Y, then X, then by whether it's an H or V seg.
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public int Compare(SegEvent first, SegEvent second)
        {
            if (first == second)
            {
                return(0);
            }

            if (first == null)
            {
                return(-1);
            }

            if (second == null)
            {
                return(1);
            }

            // Unlike the ScanSegment-generating scanline in VisibilityGraphGenerator, this scanline has no slope
            // calculations so no additional rounding error is introduced.
            int cmp = PointComparer.Compare(first.Site.Y, second.Site.Y);

            if (0 != cmp)
            {
                return(cmp);
            }

            // Both are at same Y so we must ensure that for equivalent Y, VClose comes after
            // HOpen which comes after VOpen, thus make sure VOpen comes before VClose.
            if (first.IsVertical && second.IsVertical)
            {
                // Separate segments may join at Start and End due to overlap.
                Debug.Assert(!StaticGraphUtility.IntervalsOverlap(first.Segment, second.Segment) ||
                             (0 == PointComparer.Compare(first.Segment.Start, second.Segment.End)) ||
                             (0 == PointComparer.Compare(first.Segment.End, second.Segment.Start))
                             , "V subsumption failure detected in SegEvent comparison");
                if (0 == cmp)
                {
                    // false is < true.
                    cmp = (SegEventType.VClose == first.EventType).CompareTo(SegEventType.VClose == second.EventType);
                }
                return(cmp);
            }

            // If both are H segs, then sub-order by X.
            if (!first.IsVertical && !second.IsVertical)
            {
                // Separate segments may join at Start and End due to overlap, so compare by Start.X;
                // the ending segment (lowest Start.X) comes before the Open (higher Start.X).
                Debug.Assert(!StaticGraphUtility.IntervalsOverlap(first.Segment, second.Segment) ||
                             (0 == PointComparer.Compare(first.Segment.Start, second.Segment.End)) ||
                             (0 == PointComparer.Compare(first.Segment.End, second.Segment.Start))
                             , "H subsumption failure detected in SegEvent comparison");
                cmp = PointComparer.Compare(first.Site.X, second.Site.X);
                return(cmp);
            }

            // One is Vertical and one is Horizontal; we are only interested in the vertical at this point.
            SegEvent vEvent = first.IsVertical ? first : second;

            // Make sure that we have opened all V segs before and closed them after opening
            // an H seg at the same Y coord. Otherwise we'll miss "T" or "corner" intersections.
            // (RectilinearTests.Connected_Vertical_Segments_Are_Intersected tests that we get the expected count here.)
            // Start assuming Vevent is 'first' and it's VOpen, which should come before HOpen.
            cmp = -1; // Start with first == VOpen
            if (SegEventType.VClose == vEvent.EventType)
            {
                cmp = 1; // change to first == VClose
            }
            if (vEvent != first)
            {
                cmp *= -1; // undo the swap.
            }
            return(cmp);
        }
Example #14
0
 static internal bool IntervalsOverlap(Point start1, Point end1, Point start2, Point end2)
 {
     return(IntervalsAreCollinear(start1, end1, start2, end2) &&
            PointComparer.Compare(start1, end2) != PointComparer.Compare(end1, start2));
 }
 internal int ComparePerpCoord(Point lhs, Point rhs)
 {
     return(PointComparer.Compare((lhs - rhs) * PerpDirectionAsPoint, 0.0));
 }