Beispiel #1
0
        internal static TinyQueue divideSegment(SweepEvent se, Point p, TinyQueue queue)
        {
            var r = new SweepEvent(p, false, se, se.isSubject);
            var l = new SweepEvent(p, true, se.otherEvent, se.isSubject);

            if (equals(se.point, se.otherEvent.point))
            {
                MessageBox.Show("what is that?" + se.ToString());
            }

            r.contourId = l.contourId = se.contourId;

            // avoid a rounding error. The left _event would be processed after the right _event
            if (compareEvents(l, se.otherEvent) > 0)
            {
                se.otherEvent.left = true;
                l.left             = false;
            }

            // avoid a rounding error. The left _event would be processed after the right _event
            // if (compareEvents(se, r) > 0) {}

            se.otherEvent.otherEvent = l;
            se.otherEvent            = r;

            queue.push(l);
            queue.push(r);

            return(queue);
        }
Beispiel #2
0
        internal static TinyQueue fillQueue(Point[][][] subject, Point[][][] clipping, double[] sbbox, double[] cbbox)
        {
            TinyQueue eventQueue = new TinyQueue(null, compareEvents);

            Point[][] polygonSet;
            bool      isExteriorRing;

            int len = subject.GetLength(0);

            for (int i = 0; i < len; i++)
            {
                polygonSet = subject[i];
                int jj = polygonSet.GetLength(0);
                for (int j = 0; j < jj; j++)
                {
                    isExteriorRing = (j == 0);
                    if (isExteriorRing)
                    {
                        contourId++;
                    }

                    processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
                }
            }

            for (int i = 0, ii = clipping.GetLength(0); i < ii; i++)
            {
                polygonSet = clipping[i];
                int jj = polygonSet.GetLength(0);
                for (int j = 0; j < jj; j++)
                {
                    isExteriorRing = (j == 0);
                    if (isExteriorRing)
                    {
                        contourId++;
                    }
                    processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
                }
            }

            return(eventQueue);
        }
Beispiel #3
0
        internal static void processPolygon(Point[] contourOrHole, bool isSubject, int depth, TinyQueue queue, double[] bbox, bool isExteriorRing)
        {
            int len = contourOrHole.GetLength(0) - 1;

            for (int i = 0; i < len; i++)
            {
                processSegment(contourOrHole[i], contourOrHole[i + 1], isSubject, depth + 1, queue, bbox, isExteriorRing);
            }
        }
Beispiel #4
0
        ///* eslint-disable no-unused-vars, no-debugger, no-undef */
        //function iteratorEquals(it1, it2) {
        //  return it1._cursor === it2._cursor;
        //}


        //function _renderSweepLine(sweepLine, pos, _event)
        //{
        //var map = window.map;
        //if (!map) return;
        //if (window.sws) window.sws.forEach(function (p) {
        //map.removeLayer(p);
        //});
        //window.sws = [];
        //sweepLine.forEach(function (e) {
        //var poly = L.polyline([
        //    e.point.slice().reverse(),
        //    e.otherEvent.point.slice().reverse()
        //], {color: 'green'}).addTo(map);
        //window.sws.push(poly);
        //});

        //if (window.vt) map.removeLayer(window.vt);
        //var v = pos.slice();
        //var b = map.getBounds();
        //window.vt = L.polyline([
        //[b.getNorth(), v[0]],
        //[b.getSouth(), v[0]]
        //], {color: 'green', weight: 1}).addTo(map);

        //if (window.ps) map.removeLayer(window.ps);
        //window.ps = L.polyline([
        //_event.point.slice().reverse(),
        //_event.otherEvent.point.slice().reverse()
        //], {color: 'black', weight: 9, opacity: 0.4}).addTo(map);
        //debugger;
        //}
        ///* eslint-enable no-unused-vars, no-debugger, no-undef */


        internal static List <SweepEvent> subdivideSegments(TinyQueue eventQueue, Point[][][] subject, Point[][][] clipping, double[] sbbox, double[] cbbox, Operation operation)
        {
            RedBlackTree      sweepLine    = new RedBlackTree(_comp_Segm);
            List <SweepEvent> sortedEvents = new List <SweepEvent>();

            double rightbound = Math.Min(sbbox[2], cbbox[2]);

            RedBlackTreeIterator prev, next;

            SweepEvent prevEvent, prevprevEvent;

            while (eventQueue.length > 0)
            {
                SweepEvent _event = eventQueue.pop();
                sortedEvents.Add(_event);

                // optimization by bboxes for intersection and difference goes here  - коммент оригинала
                if ((operation == Operation.INTERSECTION && _event.point.X > rightbound) || (operation == Operation.DIFFERENCE && _event.point.X > sbbox[2]))
                {
                    break;
                }

                if (_event.left)
                {
                    sweepLine = sweepLine.insert(_event, _event);
                    //_renderSweepLine(sweepLine, _event.point, _event);  - коммент оригинала

                    next            = sweepLine.find(_event);
                    prev            = sweepLine.find(_event);
                    _event.iterator = sweepLine.find(_event);

                    if (!prev.node.Equals(sweepLine.begin.node))                                             // ??? (prev.node !== sweepLine.begin)
                    {
                        prev.prev();
                    }
                    else
                    {
                        prev = sweepLine.begin;
                        prev.prev();
                        prev.next();
                    }
                    next.next();

                    //---  prevEvent = (prev.key || null), prevprevEvent;
                    prevEvent = (SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent));
                    computeFields(_event, prevEvent, operation);
                    if (next.node != null)
                    {
                        if (possibleIntersection(_event, (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), eventQueue) == 2)
                        {
                            computeFields(_event, prevEvent, operation);
                            computeFields(_event, (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), operation);
                        }
                    }

                    if (prev.node != null)
                    {
                        if (possibleIntersection((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)), _event, eventQueue) == 2)
                        {
                            RedBlackTreeIterator prevprev = sweepLine.find((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)));
                            if (!prevprev.node.Equals(sweepLine.begin.node))                            //prevprev.node != sweepLine.begin
                            {
                                prevprev.prev();
                            }
                            else
                            {
                                prevprev = sweepLine.find((SweepEvent)Convert.ChangeType(sweepLine.end.key, typeof(SweepEvent)));
                                prevprev.next();
                            }
                            prevprevEvent = (SweepEvent)Convert.ChangeType(prevprev.key, typeof(SweepEvent));
                            computeFields(prevEvent, prevprevEvent, operation);
                            computeFields(_event, prevEvent, operation);
                        }
                    }
                }
                else
                {
                    _event = _event.otherEvent;
                    next   = sweepLine.find(_event);
                    prev   = sweepLine.find(_event);

                    // _renderSweepLine(sweepLine, _event.otherEvent.point, _event);  - коммент оригинала

                    if (!(prev != null && next != null))
                    {
                        continue;
                    }

                    if (!prev.node.Equals(sweepLine.begin.node))                                        // prev.node !=  sweepLine.begin
                    {
                        prev.prev();
                    }
                    else
                    {
                        prev = sweepLine.begin;
                        prev.prev();
                        prev.next();
                    }
                    next.next();
                    sweepLine = sweepLine.remove(_event);

                    // _renderSweepLine(sweepLine, _event.otherEvent.point, _event);  - коммент оригинала

                    if (next.node != null && prev.node != null)
                    {
                        if (prev.node.value != null && next.node.value != null)    //-- if (typeof prev.node.value != 'undefined' && typeof next.node.value != 'undefined')
                        {
                            possibleIntersection((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)), (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), eventQueue);
                        }
                    }
                }
            }
            return(sortedEvents);
        }
Beispiel #5
0
        //var max = Math.max;
        //var min = Math.min;

        /**
         * @param  {Array<Number>} s1
         * @param  {Array<Number>} s2
         * @param  {Boolean}         isSubject
         * @param  {Queue}           eventQueue
         * @param  {Array<Number>}  bbox
         */
        internal static void processSegment(Point s1, Point s2, bool isSubject, int depth, TinyQueue eventQueue, double[] bbox, bool isExteriorRing)
        {
            // Possible degenerate condition.
            // if (equals(s1, s2)) return;
            var e1 = new SweepEvent(s1, false, null, isSubject);
            var e2 = new SweepEvent(s2, false, e1, isSubject);

            e1.otherEvent = e2;

            e1.contourId = e2.contourId = depth;
            if (!isExteriorRing)
            {
                e1.isExteriorRing = false;
                e2.isExteriorRing = false;
            }

            if (compareEvents(e1, e2) > 0)
            {
                e2.left = true;
            }
            else
            {
                e1.left = true;
            }

            bbox[0] = Math.Min(bbox[0], s1.X);
            bbox[1] = Math.Min(bbox[1], s1.Y);
            bbox[2] = Math.Max(bbox[2], s1.X);
            bbox[3] = Math.Max(bbox[3], s1.Y);

            // Pushing it so the queue is sorted from left to right, with object on the left having the highest priority.
            eventQueue.push(e1);
            eventQueue.push(e2);
        }
Beispiel #6
0
        internal static int possibleIntersection(SweepEvent se1, SweepEvent se2, TinyQueue queue)
        {
            // that disallows self-intersecting polygons,
            // did cost us half a day, so I'll leave it
            // out of respect
            // if (se1.isSubject === se2.isSubject) return;
            var inter = SegmentIntersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);

            var nintersections = inter != null ? inter.Length : 0;

            if (nintersections == 0)
            {
                return(0); // no intersection
            }
            // the line segments intersect at an endpoint of both line segments
            if ((nintersections == 1) && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point)))
            {
                return(0);
            }

            if (nintersections == 2 && se1.isSubject == se2.isSubject)
            {
                // if(se1.contourId === se2.contourId){
                // console.warn('Edges of the same polygon overlap',
                //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
                // }
                //throw new Error('Edges of the same polygon overlap');
                return(0);
            }

            // The line segments associated to se1 and se2 intersect
            if (nintersections == 1)
            {
                // if the intersection point is not an endpoint of se1
                if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0]))
                {
                    divideSegment(se1, inter[0], queue);
                }

                // if the intersection point is not an endpoint of se2
                if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0]))
                {
                    divideSegment(se2, inter[0], queue);
                }

                return(1);
            }

            // The line segments associated to se1 and se2 overlap
            var events        = new List <SweepEvent>();
            var leftCoincide  = false;
            var rightCoincide = false;

            if (equals(se1.point, se2.point))
            {
                leftCoincide = true; // linked
            }
            else if (compareEvents(se1, se2) == 1)
            {
                events.Add(se2);
                events.Add(se1);
            }
            else
            {
                events.Add(se1);
                events.Add(se2);
            }

            if (equals(se1.otherEvent.point, se2.otherEvent.point))
            {
                rightCoincide = true;
            }
            else if (compareEvents(se1.otherEvent, se2.otherEvent) == 1)
            {
                events.Add(se2.otherEvent);
                events.Add(se1.otherEvent);
            }
            else
            {
                events.Add(se1.otherEvent);
                events.Add(se2.otherEvent);
            }

            if ((leftCoincide && rightCoincide) || leftCoincide)                    // both line segments are equal or share the left endpoint
            {
                se1.type = EdgeType.NON_CONTRIBUTING;
                se2.type = (se1.inOut == se2.inOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION;

                if (leftCoincide && !rightCoincide)
                {
                    // honestly no idea, but changing events selection from [2, 1] to [0, 1] fixes the overlapping self-intersecting polygons issue
                    divideSegment(events[1].otherEvent, events[0].point, queue);
                }

                return(2);
            }

            if (rightCoincide)                                                      // the line segments share the right endpoint
            {
                divideSegment(events[0], events[1].point, queue);
                return(3);
            }

            if (events[0] != events[3].otherEvent)              // no line segment includes totally the other one
            {
                divideSegment(events[0], events[1].point, queue);
                divideSegment(events[1], events[2].point, queue);
                return(3);
            }

            // one line segment includes the other one
            divideSegment(events[0], events[1].point, queue);
            divideSegment(events[3].otherEvent, events[2].point, queue);

            return(3);
        }