Esempio n. 1
0
        private int eventCompare(bool p1_isStart, ref Vector2 p1_1, ref Vector2 p1_2, bool p2_isStart, ref Vector2 p2_1, ref Vector2 p2_2)
        {
            // compare the selected points first
            var comp = Epsilon.pointsCompare(p1_1, p2_1);

            if (comp != 0)
            {
                return(comp);
            }

            // the selected points are the same

            if (Epsilon.pointsSame(p1_2, p2_2)) // if the non-selected points are the same too...
            {
                return(0);                      // then the segments are equal
            }
            if (p1_isStart != p2_isStart)       // if one is a start and the other isn't...
            {
                return(p1_isStart ? 1 : -1);    // favor the one that isn't the start
            }
            // otherwise, we'll have to calculate which one is below the other manually
            return(Epsilon.pointAboveOrOnLine(
                       p1_2,
                       p2_isStart ? p2_1 : p2_2,          // order matters
                       p2_isStart ? p2_2 : p2_1
                       ) ? 1 : -1);
        }
Esempio n. 2
0
        private int statusCompare(EventNode ev1, EventNode ev2)
        {
            var a1 = ev1.seg.start;
            var a2 = ev1.seg.end;
            var b1 = ev2.seg.start;
            var b2 = ev2.seg.end;

            if (Epsilon.pointsCollinear(a1, b1, b2))
            {
                if (Epsilon.pointsCollinear(a2, b1, b2))
                {
                    return(1);                   //eventCompare(true, a1, a2, true, b1, b2);
                }
                return(Epsilon.pointAboveOrOnLine(a2, b1, b2) ? 1 : -1);
            }

            return(Epsilon.pointAboveOrOnLine(a1, b1, b2) ? 1 : -1);
        }
Esempio n. 3
0
        private void appendChain(int index1, int index2)
        {
            // index1 gets index2 appended to it, and index2 is removed
            var chain1 = chains[index1];
            var chain2 = chains[index2];
            var tail   = chain1[chain1.Count - 1];
            var tail2  = chain1[chain1.Count - 2];
            var head   = chain2[0];
            var head2  = chain2[1];

            if (Epsilon.pointsCollinear(tail2, tail, head))
            {
                // tail isn't needed because it's directly between tail2 and head
                // tail2 ---tail---> head
                if (buildLog != null)
                {
                    buildLog.chainRemoveTail(index1, tail);
                }

                chain1.RemoveAt(chain1.Count - 1);
                tail = tail2;                 // old tail is gone... new tail is what tail2 was
            }

            if (Epsilon.pointsCollinear(tail, head, head2))
            {
                // head isn't needed because it's directly between tail and head2
                // tail ---head---> head2
                if (buildLog != null)
                {
                    buildLog.chainRemoveHead(index2, head);
                }

                chain2.RemoveAt(0);
            }

            if (buildLog != null)
            {
                buildLog.chainJoin(index1, index2);
            }

            chain1.AddRange(chain2);
            chains.RemoveAt(index2);
        }
Esempio n. 4
0
        public void addRegion(PointList region)
        {
            if (!selfIntersection)
            {
                throw new Exception("The addRegion() function is only intended for use when selfIntersection = false");
            }

            // Ensure that the polygon is fully closed (the start point and end point are exactly the same)
            if (!Epsilon.pointsSame(region[region.Count - 1], region[0]))
            {
                region.Add(region[0]);
            }

            // regions are a list of points:
            //  [ [0, 0], [100, 0], [50, 100] ]
            // you can add multiple regions before running calculate
            var pt1 = new Point();
            var pt2 = region[region.Count - 1];

            for (var i = 0; i < region.Count; i++)
            {
                pt1 = pt2;
                pt2 = region[i];

                var forward = Epsilon.pointsCompare(pt1, pt2);
                if (forward == 0)                 // points are equal, so we have a zero-length segment
                {
                    continue;                     // just skip it
                }
                eventAddSegment(
                    segmentNew(
                        forward < 0 ? pt1 : pt2,
                        forward < 0 ? pt2 : pt1
                        ),
                    true
                    );
            }
        }
Esempio n. 5
0
        public List <List <Vector2> > chain(SegmentList segments, BuildLog buildLog = null)
        {
            this.buildLog = buildLog;
            this.chains   = new List <List <Vector2> >();
            this.regions  = new List <List <Vector2> >();

            foreach (var seg in segments)
            {
                var pt1 = seg.start;
                var pt2 = seg.end;

                if (Epsilon.pointsSame(pt1, pt2))
                {
                    Console.WriteLine("PolyBool: Warning: Zero-length segment detected; your epsilon is probably too small or too large");
                    continue;
                }

                if (buildLog != null)
                {
                    buildLog.chainStart(seg);
                }

                first_match = new Match()
                {
                    index        = 0,
                    matches_head = false,
                    matches_pt1  = false
                };

                second_match = new Match()
                {
                    index        = 0,
                    matches_head = false,
                    matches_pt1  = false
                };

                next_match = first_match;

                for (var i = 0; i < chains.Count; i++)
                {
                    var chain = chains[i];
                    var head  = chain[0];
                    var head2 = chain[1];
                    var tail  = chain[chain.Count - 1];
                    var tail2 = chain[chain.Count - 2];

                    if (Epsilon.pointsSame(head, pt1))
                    {
                        if (setMatch(i, true, true))
                        {
                            break;
                        }
                    }
                    else if (Epsilon.pointsSame(head, pt2))
                    {
                        if (setMatch(i, true, false))
                        {
                            break;
                        }
                    }
                    else if (Epsilon.pointsSame(tail, pt1))
                    {
                        if (setMatch(i, false, true))
                        {
                            break;
                        }
                    }
                    else if (Epsilon.pointsSame(tail, pt2))
                    {
                        if (setMatch(i, false, false))
                        {
                            break;
                        }
                    }
                }

                if (next_match == first_match)
                {
                    // we didn't match anything, so create a new chain
                    chains.Add(new List <Vector2>()
                    {
                        pt1, pt2
                    });

                    if (buildLog != null)
                    {
                        buildLog.chainNew(pt1, pt2);
                    }

                    continue;
                }

                if (next_match == second_match)
                {
                    // we matched a single chain

                    if (buildLog != null)
                    {
                        buildLog.chainMatch(first_match.index);
                    }

                    // add the other point to the apporpriate end, and check to see if we've closed the
                    // chain into a loop

                    var index     = first_match.index;
                    var pt        = first_match.matches_pt1 ? pt2 : pt1;          // if we matched pt1, then we add pt2, etc
                    var addToHead = first_match.matches_head;                     // if we matched at head, then add to the head

                    var chain = chains[index];
                    var grow  = addToHead ? chain[0] : chain[chain.Count - 1];
                    var grow2 = addToHead ? chain[1] : chain[chain.Count - 2];
                    var oppo  = addToHead ? chain[chain.Count - 1] : chain[0];
                    var oppo2 = addToHead ? chain[chain.Count - 2] : chain[1];

                    if (Epsilon.pointsCollinear(grow2, grow, pt))
                    {
                        // grow isn't needed because it's directly between grow2 and pt:
                        // grow2 ---grow---> pt
                        if (addToHead)
                        {
                            if (buildLog != null)
                            {
                                buildLog.chainRemoveHead(first_match.index, pt);
                            }

                            chain.RemoveAt(0);
                        }
                        else
                        {
                            if (buildLog != null)
                            {
                                buildLog.chainRemoveTail(first_match.index, pt);
                            }

                            chain.RemoveAt(chain.Count - 1);
                        }
                        grow = grow2;                         // old grow is gone... new grow is what grow2 was
                    }

                    if (Epsilon.pointsSame(oppo, pt))
                    {
                        // we're closing the loop, so remove chain from chains
                        chains.RemoveAt(index);

                        if (Epsilon.pointsCollinear(oppo2, oppo, grow))
                        {
                            // oppo isn't needed because it's directly between oppo2 and grow:
                            // oppo2 ---oppo--->grow
                            if (addToHead)
                            {
                                if (buildLog != null)
                                {
                                    buildLog.chainRemoveTail(first_match.index, grow);
                                }

                                chain.RemoveAt(chain.Count - 1);
                            }
                            else
                            {
                                if (buildLog != null)
                                {
                                    buildLog.chainRemoveHead(first_match.index, grow);
                                }

                                chain.RemoveAt(0);
                            }
                        }

                        if (buildLog != null)
                        {
                            buildLog.chainClose(first_match.index);
                        }

                        // we have a closed chain!
                        regions.Add(chain);
                        continue;
                    }

                    // not closing a loop, so just add it to the apporpriate side
                    if (addToHead)
                    {
                        if (buildLog != null)
                        {
                            buildLog.chainAddHead(first_match.index, pt);
                        }

                        chain.Insert(0, pt);
                    }
                    else
                    {
                        if (buildLog != null)
                        {
                            buildLog.chainAddTail(first_match.index, pt);
                        }

                        chain.Add(pt);
                    }

                    continue;
                }

                // otherwise, we matched two chains, so we need to combine those chains together

                var F = first_match.index;
                var S = second_match.index;

                if (buildLog != null)
                {
                    buildLog.chainConnect(F, S);
                }

                var reverseF = chains[F].Count < chains[S].Count;                     // reverse the shorter chain, if needed
                if (first_match.matches_head)
                {
                    if (second_match.matches_head)
                    {
                        if (reverseF)
                        {
                            // <<<< F <<<< --- >>>> S >>>>
                            reverseChain(F);
                            // >>>> F >>>> --- >>>> S >>>>
                            appendChain(F, S);
                        }
                        else
                        {
                            // <<<< F <<<< --- >>>> S >>>>
                            reverseChain(S);
                            // <<<< F <<<< --- <<<< S <<<<   logically same as:
                            // >>>> S >>>> --- >>>> F >>>>
                            appendChain(S, F);
                        }
                    }
                    else
                    {
                        // <<<< F <<<< --- <<<< S <<<<   logically same as:
                        // >>>> S >>>> --- >>>> F >>>>
                        appendChain(S, F);
                    }
                }
                else
                {
                    if (second_match.matches_head)
                    {
                        // >>>> F >>>> --- >>>> S >>>>
                        appendChain(F, S);
                    }
                    else
                    {
                        if (reverseF)
                        {
                            // >>>> F >>>> --- <<<< S <<<<
                            reverseChain(F);
                            // <<<< F <<<< --- <<<< S <<<<   logically same as:
                            // >>>> S >>>> --- >>>> F >>>>
                            appendChain(S, F);
                        }
                        else
                        {
                            // >>>> F >>>> --- <<<< S <<<<
                            reverseChain(S);
                            // >>>> F >>>> --- >>>> S >>>>
                            appendChain(F, S);
                        }
                    }
                }
            }

            return(regions);
        }
Esempio n. 6
0
        private EventNode checkIntersection(EventNode ev1, EventNode ev2)
        {
            // returns the segment equal to ev1, or false if nothing equal

            var seg1 = ev1.seg;
            var seg2 = ev2.seg;
            var a1   = seg1.start;
            var a2   = seg1.end;
            var b1   = seg2.start;
            var b2   = seg2.end;

            if (buildLog != null)
            {
                buildLog.checkIntersection(seg1, seg2);
            }

            Intersection intersect;

            if (!Epsilon.linesIntersect(a1, a2, b1, b2, out intersect))
            {
                // segments are parallel or coincident

                // if points aren't collinear, then the segments are parallel, so no intersections
                if (!Epsilon.pointsCollinear(a1, a2, b1))
                {
                    return(null);
                }

                // otherwise, segments are on top of each other somehow (aka coincident)

                if (Epsilon.pointsSame(a1, b2) || Epsilon.pointsSame(a2, b1))
                {
                    return(null);                    // segments touch at endpoints... no intersection
                }
                var a1_equ_b1 = Epsilon.pointsSame(a1, b1);
                var a2_equ_b2 = Epsilon.pointsSame(a2, b2);

                if (a1_equ_b1 && a2_equ_b2)
                {
                    return(ev2);                    // segments are exactly equal
                }
                var a1_between = !a1_equ_b1 && Epsilon.pointBetween(a1, b1, b2);
                var a2_between = !a2_equ_b2 && Epsilon.pointBetween(a2, b1, b2);

                // handy for debugging:
                // buildLog.log({
                //	a1_equ_b1: a1_equ_b1,
                //	a2_equ_b2: a2_equ_b2,
                //	a1_between: a1_between,
                //	a2_between: a2_between
                // });

                if (a1_equ_b1)
                {
                    if (a2_between)
                    {
                        //  (a1)---(a2)
                        //  (b1)----------(b2)
                        eventDivide(ev2, a2);
                    }
                    else
                    {
                        //  (a1)----------(a2)
                        //  (b1)---(b2)
                        eventDivide(ev1, b2);
                    }

                    return(ev2);
                }
                else if (a1_between)
                {
                    if (!a2_equ_b2)
                    {
                        // make a2 equal to b2
                        if (a2_between)
                        {
                            //         (a1)---(a2)
                            //  (b1)-----------------(b2)
                            eventDivide(ev2, a2);
                        }
                        else
                        {
                            //         (a1)----------(a2)
                            //  (b1)----------(b2)
                            eventDivide(ev1, b2);
                        }
                    }

                    //         (a1)---(a2)
                    //  (b1)----------(b2)
                    eventDivide(ev2, a1);
                }
            }
            else
            {
                // otherwise, lines intersect at i.pt, which may or may not be between the endpoints

                // is A divided between its endpoints? (exclusive)
                if (intersect.alongA == 0)
                {
                    if (intersect.alongB == -1)                      // yes, at exactly b1
                    {
                        eventDivide(ev1, b1);
                    }
                    else if (intersect.alongB == 0)                      // yes, somewhere between B's endpoints
                    {
                        eventDivide(ev1, intersect.pt);
                    }
                    else if (intersect.alongB == 1)                      // yes, at exactly b2
                    {
                        eventDivide(ev1, b2);
                    }
                }

                // is B divided between its endpoints? (exclusive)
                if (intersect.alongB == 0)
                {
                    if (intersect.alongA == -1)                      // yes, at exactly a1
                    {
                        eventDivide(ev2, a1);
                    }
                    else if (intersect.alongA == 0)                      // yes, somewhere between A's endpoints (exclusive)
                    {
                        eventDivide(ev2, intersect.pt);
                    }
                    else if (intersect.alongA == 1)                      // yes, at exactly a2
                    {
                        eventDivide(ev2, a2);
                    }
                }
            }

            return(null);
        }