示例#1
0
        /// <summary>
        /// For ordering events in the event list.
        /// Assuming vertical sweep (sweeping up from bottom, scanning horizontally) then order events
        /// first by lowest Y coord, then by lowest X coord (thus assuming we use Cartesian coordinates
        /// (negative is downward == bottom).
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public int Compare(SweepEvent lhs, SweepEvent rhs)
        {
            if (lhs == rhs)
            {
                return(0);
            }

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

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

            // First see if it's at the same scanline level (perpendicular coordinate).
            int cmp = scanDirection.ComparePerpCoord(lhs.Site, rhs.Site);

            if (0 == cmp)
            {
                // Event sites are at the same scanline level. Make sure that any reflection events are lowest (come before
                // any side events, which could remove the side the reflection event was queued for).  We may have two
                // reflection events at same coordinate, because we enqueue in two situations: when a side is opened,
                // and when a side that is within that side's scanline-parallel span is closed.
                bool lhsIsNotReflection = !(lhs is BasicReflectionEvent);
                bool rhsIsNotReflection = !(rhs is BasicReflectionEvent);
                cmp = lhsIsNotReflection.CompareTo(rhsIsNotReflection);

                // If the scanline-parallel coordinate is the same these events are at the same point.
                if (0 == cmp)
                {
                    cmp = scanDirection.CompareScanCoord(lhs.Site, rhs.Site);
                }
            }
            return(cmp);
        }
示例#2
0
        // If we have collinear segments, then we may be able to just update the previous one
        // instead of growing the ScanSegmentTree.
        //  - For multiple collinear OpenVertexEvents, neighbors to the high side have not yet
        //    been seen, so a segment is created that spans the lowest and highest neighbors.
        //    A subsequent collinear OpenVertexEvent will be to the high side and will add a
        //    subsegment of that segment, so we subsume it into LastAddedSegment.
        //  - For multiple collinear CloseVertexEvents, closing neighbors to the high side are
        //    still open, so a segment is created from the lowest neighbor to the next-highest
        //    collinear obstacle to be closed.  When that next-highest CloseVertexEvent is
        //    encountered, it will extend LastAddedSegment.
        //  - For multiple collinear mixed Open and Close events, we'll do all Opens first,
        //    followed by all closes (per EventQueue opening), so we may add multiple discrete
        //    segments, which ScanSegmentTree will merge.
        internal static bool Subsume(ref ScanSegment seg, Point newStart, Point newEnd,
                                     double weight, PointAndCrossingsList gbcList,
                                     ScanDirection scanDir, ScanSegmentTree tree, out bool extendStart,
                                     out bool extendEnd)
        {
            // Initialize these to the non-subsumed state; the endpoints were extended (or on a
            // different line).
            extendStart = true;
            extendEnd   = true;
            if (null == seg)
            {
                return(false);
            }

            // If they don't overlap (including touching at an endpoint), we don't subsume.
            if (!StaticGraphUtility.IntervalsOverlap(seg.Start, seg.End, newStart, newEnd))
            {
                return(false);
            }

            // If the overlapped-ness isn't the same, we don't subsume.  ScanSegmentTree::MergeSegments
            // will mark that the low-to-high direction needs a VisibilityVertex to link the two segments.
            // These may differ by more than Curve.DistanceEpsilon in the case of reflection lookahead
            // segments collinear with vertex-derived segments, so have a looser tolerance here and we'll
            // adjust the segments in ScanSegmentTree.MergeSegments.
            if (seg.Weight != weight)
            {
                if ((seg.Start == newStart) && (seg.End == newEnd))
                {
                    // This is probably because of a rounding difference by one DistanceEpsilon reporting being
                    // inside an obstacle vs. the scanline intersection calculation side-ordering.
                    // Test is RectilinearFileTests.Overlap_Rounding_Vertex_Intersects_Side.
                    seg.Weight = Math.Min(seg.Weight, weight);
                    return(true);
                }

                // In the case of groups, we go through the group boundary; this may coincide with a
                // reflection segment. RectilinearFileTests.ReflectionSubsumedBySegmentExitingGroup.
                Debug.Assert((seg.Weight == OverlappedWeight) == (weight == OverlappedWeight) ||
                             ApproximateComparer.CloseIntersections(seg.End, newStart) ||
                             ApproximateComparer.CloseIntersections(seg.Start, newEnd)
                             , "non-equal overlap-mismatched ScanSegments overlap by more than just Start/End");
                return(false);
            }

            // Subsume the input segment.  Return whether the start/end points were extended (newStart
            // is before this.Start, or newEnd is after this.End), so the caller can generate reflections
            // and so we can merge group border crossings.
            extendStart = (-1 == scanDir.CompareScanCoord(newStart, seg.Start));
            extendEnd   = (1 == scanDir.CompareScanCoord(newEnd, seg.End));
            if (extendStart || extendEnd)
            {
                // We order by start and end so need to replace this in the tree regardless of which end changes.
                tree.Remove(seg);
                seg.startPoint = scanDir.Min(seg.Start, newStart);
                seg.endPoint   = scanDir.Max(seg.End, newEnd);
                seg            = tree.InsertUnique(seg).Item;
                seg.MergeGroupBoundaryCrossingList(gbcList);
            }
            return(true);
        }
示例#3
0
 /// <summary>
 /// For ordering Points in the lookahead list.  We just care about the coordinate that changes
 /// parallel to the scanline, so for vertical sweep (sweeping up from bottom, scanning
 /// horizontally) then order points by X only, else by Y only.
 /// </summary>
 /// <param name="lhs"></param>
 /// <param name="rhs"></param>
 /// <returns></returns>
 public int Compare(BasicReflectionEvent lhs, BasicReflectionEvent rhs)
 {
     ValidateArg.IsNotNull(lhs, "lhs");
     ValidateArg.IsNotNull(rhs, "rhs");
     return(scanDirection.CompareScanCoord(lhs.Site, rhs.Site));
 }
        // If we have collinear segments, then we may be able to just update the previous one
        // instead of growing the ScanSegmentTree.
        //  - For multiple collinear OpenVertexEvents, neighbors to the high side have not yet
        //    been seen, so a segment is created that spans the lowest and highest neighbors.
        //    A subsequent collinear OpenVertexEvent will be to the high side and will add a
        //    subsegment of that segment, so we subsume it into LastAddedSegment.
        //  - For multiple collinear CloseVertexEvents, closing neighbors to the high side are
        //    still open, so a segment is created from the lowest neighbor to the next-highest
        //    collinear obstacle to be closed.  When that next-highest CloseVertexEvent is
        //    encountered, it will extend LastAddedSegment.
        //  - For multiple collinear mixed Open and Close events, we'll do all Opens first,
        //    followed by all closes (per EventQueue opening), so we may add multiple discrete
        //    segments, which ScanSegmentTree will merge.
        internal static bool Subsume(ref ScanSegment seg, Point newStart, Point newEnd,
                double weight, PointAndCrossingsList gbcList,
                ScanDirection scanDir, ScanSegmentTree tree, out bool extendStart,
                out bool extendEnd) {
            // Initialize these to the non-subsumed state; the endpoints were extended (or on a
            // different line).
            extendStart = true;
            extendEnd = true;
            if (null == seg) {
                return false;
            }

            // If they don't overlap (including touching at an endpoint), we don't subsume.
            if (!StaticGraphUtility.IntervalsOverlap(seg.Start, seg.End, newStart, newEnd)) {
                return false;
            }

            // If the overlapped-ness isn't the same, we don't subsume.  ScanSegmentTree::MergeSegments
            // will mark that the low-to-high direction needs a VisibilityVertex to link the two segments.
            // These may differ by more than Curve.DistanceEpsilon in the case of reflection lookahead
            // segments collinear with vertex-derived segments, so have a looser tolerance here and we'll
            // adjust the segments in ScanSegmentTree.MergeSegments.
            if (seg.Weight != weight) {
                if ((seg.Start == newStart) && (seg.End == newEnd)) {
                    // This is probably because of a rounding difference by one DistanceEpsilon reporting being
                    // inside an obstacle vs. the scanline intersection calculation side-ordering.
                    // Test is RectilinearFileTests.Overlap_Rounding_Vertex_Intersects_Side.
                    seg.Weight = Math.Min(seg.Weight, weight);
                    return true;
                }
                
                // In the case of groups, we go through the group boundary; this may coincide with a
                // reflection segment. RectilinearFileTests.ReflectionSubsumedBySegmentExitingGroup.
                Debug.Assert((seg.Weight == OverlappedWeight) == (weight == OverlappedWeight) ||
                                ApproximateComparer.CloseIntersections(seg.End, newStart) ||
                                ApproximateComparer.CloseIntersections(seg.Start, newEnd)
                        , "non-equal overlap-mismatched ScanSegments overlap by more than just Start/End");
                return false;
            }

            // Subsume the input segment.  Return whether the start/end points were extended (newStart
            // is before this.Start, or newEnd is after this.End), so the caller can generate reflections
            // and so we can merge group border crossings.
            extendStart = (-1 == scanDir.CompareScanCoord(newStart, seg.Start));
            extendEnd = (1 == scanDir.CompareScanCoord(newEnd, seg.End));
            if (extendStart || extendEnd) {
                // We order by start and end so need to replace this in the tree regardless of which end changes.
                tree.Remove(seg);
                seg.startPoint = scanDir.Min(seg.Start, newStart);
                seg.endPoint = scanDir.Max(seg.End, newEnd);
                seg = tree.InsertUnique(seg).Item;
                seg.MergeGroupBoundaryCrossingList(gbcList);
            }
            return true;
        }