예제 #1
0
 // Scan segments with no visibility will usually be internal to an overlap clump,
 // but may be in an external "corner" of intersecting sides for a small enough span
 // that no other segment crosses them.  In that case we don't need them and they
 // would require extra handling later.
 internal void RemoveSegmentsWithNoVisibility(ScanSegmentTree horizontalScanSegments,
                                              ScanSegmentTree verticalScanSegments)
 {
     foreach (ScanSegment seg in segmentsWithoutVisibility)
     {
         (seg.IsVertical ? verticalScanSegments : horizontalScanSegments).Remove(seg);
     }
 }
예제 #2
0
        static internal void Test_DumpScanSegments(ObstacleTree obstacleTree, ScanSegmentTree hSegs, ScanSegmentTree vSegs)
        {
            var debugCurves = Test_GetObstacleDebugCurves(obstacleTree);

            debugCurves.AddRange(Test_GetScanSegmentCurves(hSegs));
            debugCurves.AddRange(Test_GetScanSegmentCurves(vSegs));
            DebugCurveCollection.WriteToFile(debugCurves, GetDumpFileName("ScanSegments"));
        }
        static internal void Test_ShowScanSegments(ObstacleTree obstacleTree, ScanSegmentTree hSegs, ScanSegmentTree vSegs)
        {
#if TEST_MSAGL
            var debugCurves = Test_GetObstacleDebugCurves(obstacleTree);
            debugCurves.AddRange(Test_GetScanSegmentCurves(hSegs));
            debugCurves.AddRange(Test_GetScanSegmentCurves(vSegs));
            LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(debugCurves);
#endif // TEST
        }
예제 #4
0
 private static void CreateScanSegmentTree(ScanSegmentVector segmentVector, ScanSegmentTree segmentTree)
 {
     foreach (var item in segmentVector.Items)
     {
         for (var segment = item.FirstSegment; segment != null; segment = segment.NextSegment)
         {
             if (segment.HasVisibility())
             {
                 segmentTree.InsertUnique(segment);
             }
         }
     }
 }
예제 #5
0
 static internal List <DebugCurve> Test_GetScanSegmentCurves(ScanSegmentTree segTree)
 {
     return(segTree.Segments.Select(seg => new DebugCurve(0.2,
                                                          seg.IsOverlapped ? "Aqua" : (seg.IsReflection ? "LightGreen" : "DarkGreen"),
                                                          new LineSegment(seg.Start, seg.End))).ToList());
 }
예제 #6
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);
        }