Example #1
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);
        }
Example #2
0
        private void HandleEvent(IBST <SweepEvent> events, IBST <StatusItem> status, SweepEvent ev)
        {
            ResultEvents.Add(ev);

            // Optimization 2
            if ((Operation == OperationType.Intersection && ev.Point.x > RightBound) ||
                (Operation == OperationType.Difference && ev.Point.x > SubjectBoundingBox.xMax))
            {
                // We need to connect edges now, so just clear all events. This will result in us immediately
                // going to ConnectEdges() since there are no more events to handle.
                InitializeEvents(new List <SweepEvent>());
                return;
            }

            if (ev.IsStart) // The line segment must be inserted into status
            {
                ev.StatusItem = new StatusItem(ev);
                if (!status.Insert(ev.StatusItem))
                {
                    throw new ArgumentException("Failed to insert into state");
                }

                StatusItem prev;
                var        prevFound = status.FindNextSmallest(ev.StatusItem, out prev);

                ComputeFields(ev, prev, prevFound);

                StatusItem next;
                if (status.FindNextBiggest(ev.StatusItem, out next))
                {
                    // Process a possible intersection between "ev" and its next neighbor in status
                    if (PossibleIntersection(ev, next.SweepEvent, events) == 2)
                    {
                        ComputeFields(ev, prev, prevFound);
                        ComputeFields(next.SweepEvent, ev.StatusItem, true);
                    }
                }

                // Process a possible intersection between "ev" and its previous neighbor in status
                if (prevFound)
                {
                    if (PossibleIntersection(prev.SweepEvent, ev, events) == 2)
                    {
                        StatusItem prevprev;
                        var        prevprevFound = status.FindNextSmallest(prev, out prevprev);

                        ComputeFields(prev.SweepEvent, prevprev, prevprevFound);
                        ComputeFields(ev, prev, prevFound);
                    }
                }
            }
            else
            {
                // The line segment must be removed from status
                ev = ev.OtherEvent; // We work with the left event

                StatusItem prev, next;
                var        prevFound = status.FindNextSmallest(ev.StatusItem, out prev);
                var        nextFound = status.FindNextBiggest(ev.StatusItem, out next);

                // Delete line segment associated to "ev" from status and check for intersection between the neighbors of "ev" in status
                status.Delete(ev.StatusItem);

                if (nextFound && prevFound)
                {
                    PossibleIntersection(prev.SweepEvent, next.SweepEvent, events);
                }
            }
        }