Esempio n. 1
0
        /// <summary>
        /// Creates the events for a segment.
        /// </summary>
        /// <param name="segment">A list consisting of two points defining an edge</param>
        /// <param name="polygonType"></param>
        /// <param name="list">The list to add the events to</param>
        private void CreateEvents(IList <Vector2D> segment, PolygonType polygonType,
                                  ICollection <SweepEvent> list)
        {
            var point1 = segment[0];
            var point2 = segment[1];

            var event1 = new SweepEvent(point1, false, null, polygonType);
            var event2 = new SweepEvent(point2, false, event1, polygonType);

            event1.OtherEvent = event2;

            if (point1.Equals(point2))
            {
                // 0-length segments are irrelevant for us since they will never result in intersections
                return;
            }

            // The segment could be ordered the wrong way around, so we need to set the IsStart field properly
            if (SweepEvent.CompareTo(event1, event2) > 0)
            {
                event2.IsStart = true;
            }
            else
            {
                event1.IsStart = true;
            }

            list.Add(event1);
            list.Add(event2);
        }
Esempio n. 2
0
        private void DivideSegment(SweepEvent ev, Vector2D pos, IBST <SweepEvent> events)
        {
            // "Right event" of the "left line segment" resulting from dividing ev.Segment
            var r = new SweepEvent(pos, false, ev, ev.PolygonType);
            // "Left event" of the "right line segment" resulting from dividing ev.Segment
            var l = new SweepEvent(pos, true, ev.OtherEvent, ev.PolygonType);

            if (SweepEvent.CompareTo(l, ev.OtherEvent) > 0
                ) // Avoid a rounding error. The left event would be processed after the right event
            {
                ev.OtherEvent.IsStart = true;
                l.IsStart             = false;
            }

            ev.OtherEvent.OtherEvent = l;
            ev.OtherEvent            = r;
            events.Insert(l);
            events.Insert(r);
        }
Esempio n. 3
0
        private ContourPolygon ConnectEdges()
        {
            var result = new ContourPolygon();

            var resultEvents = ResultEvents
                               .Where(it => (it.IsStart && it.InResult) || (!it.IsStart && it.OtherEvent.InResult)).ToList();

            // Due to overlapping edges the resultEvents list can be not wholly sorted
            var sorted = false;

            while (!sorted)
            {
                sorted = true;
                for (int i = 0; i < resultEvents.Count; i++)
                {
                    if (i + 1 < resultEvents.Count && SweepEvent.CompareTo(resultEvents[i], resultEvents[i + 1]) == 1)
                    {
                        var tmp = resultEvents[i];
                        resultEvents[i]     = resultEvents[i + 1];
                        resultEvents[i + 1] = tmp;
                        sorted = false;
                    }
                }
            }

            // We cannot do a foreach because we need to set PositionInResult
            for (int i = 0; i < resultEvents.Count; i++)
            {
                var resultEvent = resultEvents[i];
                resultEvent.PositionInResult = i;
            }

            foreach (var resultEvent in resultEvents)
            {
                if (!resultEvent.IsStart)
                {
                    var tmp = resultEvent.PositionInResult;
                    resultEvent.PositionInResult            = resultEvent.OtherEvent.PositionInResult;
                    resultEvent.OtherEvent.PositionInResult = tmp;
                }
            }

            var processed = new BitArray(resultEvents.Count);
            var depth     = new List <int>();
            var holeOf    = new List <int>();

            for (int i = 0; i < resultEvents.Count; i++)
            {
                if (processed[i])
                {
                    continue;
                }

                var contour = new Contour();
                result.Add(contour);
                var contourId = result.NumberOfContours - 1;
                depth.Add(0);
                holeOf.Add(-1);
                if (resultEvents[i].PreviousInResult != null)
                {
                    var lowerContourId = resultEvents[i].PreviousInResult.ContourId;
                    if (!resultEvents[i].PreviousInResult.ResultInOut)
                    {
                        result[lowerContourId].AddHole(contourId);
                        holeOf[contourId] = lowerContourId;
                        depth[contourId]  = depth[lowerContourId] + 1;
                        contour.External  = false;
                    }
                    else if (!result[lowerContourId].External)
                    {
                        result[holeOf[lowerContourId]].AddHole(contourId);
                        holeOf[contourId] = holeOf[lowerContourId];
                        depth[contourId]  = depth[lowerContourId];
                        contour.External  = false;
                    }
                }

                var pos     = i;
                var initial = resultEvents[i].Point;
                contour.AddVertex(initial);
                while (pos >= i)
                {
                    processed[pos] = true;
                    if (resultEvents[pos].IsStart)
                    {
                        resultEvents[pos].ResultInOut = false;
                        resultEvents[pos].ContourId   = contourId;
                    }
                    else
                    {
                        resultEvents[pos].OtherEvent.ResultInOut = true;
                        resultEvents[pos].OtherEvent.ContourId   = contourId;
                    }

                    pos            = resultEvents[pos].PositionInResult;
                    processed[pos] = true;
                    contour.AddVertex(resultEvents[pos].Point);
                    pos = NextPos(pos, resultEvents, processed, i);
                }

                pos = pos == -1 ? i : pos;

                processed[pos] = processed[resultEvents[pos].PositionInResult] = true;
                resultEvents[pos].OtherEvent.ResultInOut = true;
                resultEvents[pos].OtherEvent.ContourId   = contourId;
                if ((depth[contourId] & 1) != 0)
                {
                    contour.ChangeOrientation();
                }
            }

            return(result);
        }
Esempio n. 4
0
        private int PossibleIntersection(SweepEvent ev1, SweepEvent ev2, IBST <SweepEvent> events)
        {
            Vector2D intersectionPoint;
            var      nIntersections = FindIntersections(ev1.Point, ev1.OtherEvent.Point, ev2.Point, ev2.OtherEvent.Point,
                                                        out intersectionPoint);

            if (nIntersections == 0)
            {
                return(0); // no intersection
            }

            // If the intersection is between two endpoints
            if (nIntersections == 1 && (ev1.Point.Equals(ev2.Point) ||
                                        ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point)))
            {
                return(0); // the line segments intersect at an endpoint of both line segments
            }

            if (nIntersections == 2 && ev1.PolygonType == ev2.PolygonType)
            {
                // The line segments overlap, but they belong to the same polygon
                throw new ArgumentException(string.Format("Sorry, edges of the same polygon overlap ({0} and {1})", ev1,
                                                          ev2));
            }

            // The line segments associated to ev1 and ev2 intersect
            if (nIntersections == 1)
            {
                if (!ev1.Point.Equals(intersectionPoint) && !ev1.OtherEvent.Point.Equals(intersectionPoint)
                    ) // If the intersection point is not an endpoint of ev1.Segment
                {
                    DivideSegment(ev1, intersectionPoint, events);
                }

                if (!ev2.Point.Equals(intersectionPoint) && !ev2.OtherEvent.Point.Equals(intersectionPoint)
                    ) // If the intersection point is not an endpoint of ev2.Segment
                {
                    DivideSegment(ev2, intersectionPoint, events);
                }

                return(1);
            }

            // The line segments associated to ev1 and ev2 overlap
            var sortedEvents = new List <SweepEvent>();
            var leftEqual    = false;
            var rightEqual   = false;

            if (ev1.Point.Equals(ev2.Point))
            {
                leftEqual = true;
            }
            else if (SweepEvent.CompareTo(ev1, ev2) == 1)
            {
                sortedEvents.Add(ev2);
                sortedEvents.Add(ev1);
            }
            else
            {
                sortedEvents.Add(ev1);
                sortedEvents.Add(ev2);
            }

            if (ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point))
            {
                rightEqual = true;
            }
            else if (SweepEvent.CompareTo(ev1.OtherEvent, ev2.OtherEvent) == 1)
            {
                sortedEvents.Add(ev2.OtherEvent);
                sortedEvents.Add(ev1.OtherEvent);
            }
            else
            {
                sortedEvents.Add(ev1.OtherEvent);
                sortedEvents.Add(ev2.OtherEvent);
            }

            if (leftEqual)
            {
                // Both line segments are equal or share the left endpoint
                ev2.EdgeType = EdgeType.NonContributing;
                ev1.EdgeType = (ev2.InOut == ev1.InOut) ? EdgeType.SameTransition : EdgeType.DifferentTransition;
                if (!rightEqual)
                {
                    DivideSegment(sortedEvents[1].OtherEvent, sortedEvents[0].Point, events);
                }

                return(2);
            }

            if (rightEqual)
            {
                // The line segments share the right endpoint
                DivideSegment(sortedEvents[0], sortedEvents[1].Point, events);
                return(3);
            }

            if (sortedEvents[0] != sortedEvents[3].OtherEvent)
            {
                // No line segment includes totally the other one
                DivideSegment(sortedEvents[0], sortedEvents[1].Point, events);
                DivideSegment(sortedEvents[1], sortedEvents[2].Point, events);
                return(3);
            }

            // One line segment includes the other one
            DivideSegment(sortedEvents[0], sortedEvents[1].Point, events);
            DivideSegment(sortedEvents[3].OtherEvent, sortedEvents[2].Point, events);
            return(3);
        }