コード例 #1
0
        //------------------------------------------------------------------------------

        internal virtual void Reset()
        {
            m_CurrentLM = m_MinimaList;
            if (m_CurrentLM == null)
            {
                return;                      //ie nothing to process
            }
            //reset all edges ...
            m_Scanbeam = null;
            ClipperLocalMinima lm = m_MinimaList;

            while (lm != null)
            {
                InsertScanbeam(lm.Y);
                ClipperTEdge e = lm.LeftBound;
                if (e != null)
                {
                    e.Curr   = e.Bot;
                    e.OutIdx = Unassigned;
                }
                e = lm.RightBound;
                if (e != null)
                {
                    e.Curr   = e.Bot;
                    e.OutIdx = Unassigned;
                }
                lm = lm.Next;
            }
            m_ActiveEdges = null;
        }
コード例 #2
0
        //------------------------------------------------------------------------------

        private ClipperTEdge FindNextLocMin(ClipperTEdge E)
        {
            ClipperTEdge E2;

            for (; ;)
            {
                while (E.Bot != E.Prev.Bot || E.Curr == E.Top)
                {
                    E = E.Next;
                }
                if (E.Dx != Horizontal && E.Prev.Dx != Horizontal)
                {
                    break;
                }
                while (E.Prev.Dx == Horizontal)
                {
                    E = E.Prev;
                }
                E2 = E;
                while (E.Dx == Horizontal)
                {
                    E = E.Next;
                }
                if (E.Top.Y == E.Prev.Bot.Y)
                {
                    continue;                          //ie just an intermediate horz.
                }
                if (E2.Prev.Bot.X < E.Bot.X)
                {
                    E = E2;
                }
                break;
            }
            return(E);
        }
コード例 #3
0
        //------------------------------------------------------------------------------

        private void ReverseHorizontal(ClipperTEdge e)
        {
            //swap horizontal edges' top and bottom x's so they follow the natural
            //progression of the bounds - ie so their xbots will align with the
            //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
            Swap(ref e.Top.X, ref e.Bot.X);
        }
コード例 #4
0
        //------------------------------------------------------------------------------

        internal void UpdateEdgeIntoAEL(ref ClipperTEdge e)
        {
            if (e.NextInLML == null)
            {
                throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
            }
            ClipperTEdge AelPrev = e.PrevInAEL;
            ClipperTEdge AelNext = e.NextInAEL;

            e.NextInLML.OutIdx = e.OutIdx;
            if (AelPrev != null)
            {
                AelPrev.NextInAEL = e.NextInLML;
            }
            else
            {
                m_ActiveEdges = e.NextInLML;
            }
            if (AelNext != null)
            {
                AelNext.PrevInAEL = e.NextInLML;
            }
            e.NextInLML.Side      = e.Side;
            e.NextInLML.WindDelta = e.WindDelta;
            e.NextInLML.WindCnt   = e.WindCnt;
            e.NextInLML.WindCnt2  = e.WindCnt2;
            e           = e.NextInLML;
            e.Curr      = e.Bot;
            e.PrevInAEL = AelPrev;
            e.NextInAEL = AelNext;
            if (!IsHorizontal(e))
            {
                InsertScanbeam(e.Top.Y);
            }
        }
コード例 #5
0
        //------------------------------------------------------------------------------

        private void InitEdge(ClipperTEdge e, ClipperTEdge eNext,
                              ClipperTEdge ePrev, ClipperIntPoint pt)
        {
            e.Next   = eNext;
            e.Prev   = ePrev;
            e.Curr   = pt;
            e.OutIdx = Unassigned;
        }
コード例 #6
0
        //------------------------------------------------------------------------------

        ClipperTEdge RemoveEdge(ClipperTEdge e)
        {
            //removes e from double_linked_list (but without removing from memory)
            e.Prev.Next = e.Next;
            e.Next.Prev = e.Prev;
            ClipperTEdge result = e.Next;

            e.Prev = null; //flag as removed (see ClipperBase.Clear)
            return(result);
        }
コード例 #7
0
        //------------------------------------------------------------------------------

        private void SetDx(ClipperTEdge e)
        {
            e.Delta.X = (e.Top.X - e.Bot.X);
            e.Delta.Y = (e.Top.Y - e.Bot.Y);
            if (e.Delta.Y == 0)
            {
                e.Dx = Horizontal;
            }
            else
            {
                e.Dx = (double)(e.Delta.X) / (e.Delta.Y);
            }
        }
コード例 #8
0
        //------------------------------------------------------------------------------

        internal static bool SlopesEqual(ClipperTEdge e1, ClipperTEdge e2, bool UseFullRange)
        {
            if (UseFullRange)
            {
                return(ClipperInt128.Int128Mul(e1.Delta.Y, e2.Delta.X) ==
                       ClipperInt128.Int128Mul(e1.Delta.X, e2.Delta.Y));
            }
            else
            {
                return((long)(e1.Delta.Y) * (e2.Delta.X) ==
                       (long)(e1.Delta.X) * (e2.Delta.Y));
            }
        }
コード例 #9
0
        //------------------------------------------------------------------------------

        private void InitEdge2(ClipperTEdge e, ClipperPolyType polyType)
        {
            if (e.Curr.Y >= e.Next.Curr.Y)
            {
                e.Bot = e.Curr;
                e.Top = e.Next.Curr;
            }
            else
            {
                e.Top = e.Curr;
                e.Bot = e.Next.Curr;
            }
            SetDx(e);
            e.PolyTyp = polyType;
        }
コード例 #10
0
        //------------------------------------------------------------------------------

        internal void DeleteFromAEL(ClipperTEdge e)
        {
            ClipperTEdge AelPrev = e.PrevInAEL;
            ClipperTEdge AelNext = e.NextInAEL;

            if (AelPrev == null && AelNext == null && (e != m_ActiveEdges))
            {
                return; //already deleted
            }
            if (AelPrev != null)
            {
                AelPrev.NextInAEL = AelNext;
            }
            else
            {
                m_ActiveEdges = AelNext;
            }
            if (AelNext != null)
            {
                AelNext.PrevInAEL = AelPrev;
            }
            e.NextInAEL = null;
            e.PrevInAEL = null;
        }
コード例 #11
0
        //------------------------------------------------------------------------------

        public bool AddPath(List <ClipperIntPoint> pg, ClipperPolyType polyType, bool Closed)
        {
            if (!Closed && polyType == ClipperPolyType.Clip)
            {
                throw new ClipperException("AddPath: Open paths must be subject.");
            }

            int highI = (int)pg.Count - 1;

            if (Closed)
            {
                while (highI > 0 && (pg[highI] == pg[0]))
                {
                    --highI;
                }
            }
            while (highI > 0 && (pg[highI] == pg[highI - 1]))
            {
                --highI;
            }
            if ((Closed && highI < 2) || (!Closed && highI < 1))
            {
                return(false);
            }

            //create a new edge array ...
            List <ClipperTEdge> edges = new List <ClipperTEdge>(highI + 1);

            for (int i = 0; i <= highI; i++)
            {
                edges.Add(new ClipperTEdge());
            }

            bool IsFlat = true;

            //1. Basic (first) edge initialization ...
            edges[1].Curr = pg[1];
            RangeTest(pg[0], ref m_UseFullRange);
            RangeTest(pg[highI], ref m_UseFullRange);
            InitEdge(edges[0], edges[1], edges[highI], pg[0]);
            InitEdge(edges[highI], edges[0], edges[highI - 1], pg[highI]);
            for (int i = highI - 1; i >= 1; --i)
            {
                RangeTest(pg[i], ref m_UseFullRange);
                InitEdge(edges[i], edges[i + 1], edges[i - 1], pg[i]);
            }
            ClipperTEdge eStart = edges[0];

            //2. Remove duplicate vertices, and (when closed) collinear edges ...
            ClipperTEdge E = eStart, eLoopStop = eStart;

            for (; ;)
            {
                //nb: allows matching start and end points when not Closed ...
                if (E.Curr == E.Next.Curr && (Closed || E.Next != eStart))
                {
                    if (E == E.Next)
                    {
                        break;
                    }
                    if (E == eStart)
                    {
                        eStart = E.Next;
                    }
                    E         = RemoveEdge(E);
                    eLoopStop = E;
                    continue;
                }
                if (E.Prev == E.Next)
                {
                    break; //only two vertices
                }
                else if (Closed &&
                         SlopesEqual(E.Prev.Curr, E.Curr, E.Next.Curr, m_UseFullRange) &&
                         (!PreserveCollinear ||
                          !Pt2IsBetweenPt1AndPt3(E.Prev.Curr, E.Curr, E.Next.Curr)))
                {
                    //Collinear edges are allowed for open paths but in closed paths
                    //the default is to merge adjacent collinear edges into a single edge.
                    //However, if the PreserveCollinear property is enabled, only overlapping
                    //collinear edges (ie spikes) will be removed from closed paths.
                    if (E == eStart)
                    {
                        eStart = E.Next;
                    }
                    E         = RemoveEdge(E);
                    E         = E.Prev;
                    eLoopStop = E;
                    continue;
                }
                E = E.Next;
                if ((E == eLoopStop) || (!Closed && E.Next == eStart))
                {
                    break;
                }
            }

            if ((!Closed && (E == E.Next)) || (Closed && (E.Prev == E.Next)))
            {
                return(false);
            }

            if (!Closed)
            {
                m_HasOpenPaths     = true;
                eStart.Prev.OutIdx = Skip;
            }

            //3. Do second stage of edge initialization ...
            E = eStart;
            do
            {
                InitEdge2(E, polyType);
                E = E.Next;
                if (IsFlat && E.Curr.Y != eStart.Curr.Y)
                {
                    IsFlat = false;
                }
            }while (E != eStart);

            //4. Finally, add edge bounds to LocalMinima list ...

            //Totally flat paths must be handled differently when adding them
            //to LocalMinima list to avoid endless loops etc ...
            if (IsFlat)
            {
                if (Closed)
                {
                    return(false);
                }
                E.Prev.OutIdx = Skip;
                ClipperLocalMinima locMin = new ClipperLocalMinima
                {
                    Next       = null,
                    Y          = E.Bot.Y,
                    LeftBound  = null,
                    RightBound = E
                };
                locMin.RightBound.Side      = ClipperEdgeSide.Right;
                locMin.RightBound.WindDelta = 0;
                for (; ;)
                {
                    if (E.Bot.X != E.Prev.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    if (E.Next.OutIdx == Skip)
                    {
                        break;
                    }
                    E.NextInLML = E.Next;
                    E           = E.Next;
                }
                InsertLocalMinima(locMin);
                m_edges.Add(edges);
                return(true);
            }

            m_edges.Add(edges);
            bool         leftBoundIsForward;
            ClipperTEdge EMin = null;

            //workaround to avoid an endless loop in the while loop below when
            //open paths have matching start and end points ...
            if (E.Prev.Bot == E.Prev.Top)
            {
                E = E.Next;
            }

            for (; ;)
            {
                E = FindNextLocMin(E);
                if (E == EMin)
                {
                    break;
                }
                else if (EMin == null)
                {
                    EMin = E;
                }

                //E and E.Prev now share a local minima (left aligned if horizontal).
                //Compare their slopes to find which starts which bound ...
                ClipperLocalMinima locMin = new ClipperLocalMinima
                {
                    Next = null,
                    Y    = E.Bot.Y
                };
                if (E.Dx < E.Prev.Dx)
                {
                    locMin.LeftBound   = E.Prev;
                    locMin.RightBound  = E;
                    leftBoundIsForward = false; //Q.nextInLML = Q.prev
                }
                else
                {
                    locMin.LeftBound   = E;
                    locMin.RightBound  = E.Prev;
                    leftBoundIsForward = true; //Q.nextInLML = Q.next
                }
                locMin.LeftBound.Side  = ClipperEdgeSide.Left;
                locMin.RightBound.Side = ClipperEdgeSide.Right;

                if (!Closed)
                {
                    locMin.LeftBound.WindDelta = 0;
                }
                else if (locMin.LeftBound.Next == locMin.RightBound)
                {
                    locMin.LeftBound.WindDelta = -1;
                }
                else
                {
                    locMin.LeftBound.WindDelta = 1;
                }
                locMin.RightBound.WindDelta = -locMin.LeftBound.WindDelta;

                E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
                if (E.OutIdx == Skip)
                {
                    E = ProcessBound(E, leftBoundIsForward);
                }

                ClipperTEdge E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
                if (E2.OutIdx == Skip)
                {
                    E2 = ProcessBound(E2, !leftBoundIsForward);
                }

                if (locMin.LeftBound.OutIdx == Skip)
                {
                    locMin.LeftBound = null;
                }
                else if (locMin.RightBound.OutIdx == Skip)
                {
                    locMin.RightBound = null;
                }
                InsertLocalMinima(locMin);
                if (!leftBoundIsForward)
                {
                    E = E2;
                }
            }
            return(true);
        }
コード例 #12
0
        //------------------------------------------------------------------------------

        private ClipperTEdge ProcessBound(ClipperTEdge E, bool LeftBoundIsForward)
        {
            ClipperTEdge EStart, Result = E;
            ClipperTEdge Horz;

            if (Result.OutIdx == Skip)
            {
                //check if there are edges beyond the skip edge in the bound and if so
                //create another LocMin and calling ProcessBound once more ...
                E = Result;
                if (LeftBoundIsForward)
                {
                    while (E.Top.Y == E.Next.Bot.Y)
                    {
                        E = E.Next;
                    }
                    while (E != Result && E.Dx == Horizontal)
                    {
                        E = E.Prev;
                    }
                }
                else
                {
                    while (E.Top.Y == E.Prev.Bot.Y)
                    {
                        E = E.Prev;
                    }
                    while (E != Result && E.Dx == Horizontal)
                    {
                        E = E.Next;
                    }
                }
                if (E == Result)
                {
                    if (LeftBoundIsForward)
                    {
                        Result = E.Next;
                    }
                    else
                    {
                        Result = E.Prev;
                    }
                }
                else
                {
                    //there are more edges in the bound beyond result starting with E
                    if (LeftBoundIsForward)
                    {
                        E = Result.Next;
                    }
                    else
                    {
                        E = Result.Prev;
                    }
                    ClipperLocalMinima locMin = new ClipperLocalMinima
                    {
                        Next       = null,
                        Y          = E.Bot.Y,
                        LeftBound  = null,
                        RightBound = E
                    };
                    E.WindDelta = 0;
                    Result      = ProcessBound(E, LeftBoundIsForward);
                    InsertLocalMinima(locMin);
                }
                return(Result);
            }

            if (E.Dx == Horizontal)
            {
                //We need to be careful with open paths because this may not be a
                //true local minima (ie E may be following a skip edge).
                //Also, consecutive horz. edges may start heading left before going right.
                if (LeftBoundIsForward)
                {
                    EStart = E.Prev;
                }
                else
                {
                    EStart = E.Next;
                }
                if (EStart.Dx == Horizontal) //ie an adjoining horizontal skip edge
                {
                    if (EStart.Bot.X != E.Bot.X && EStart.Top.X != E.Bot.X)
                    {
                        ReverseHorizontal(E);
                    }
                }
                else if (EStart.Bot.X != E.Bot.X)
                {
                    ReverseHorizontal(E);
                }
            }

            EStart = E;
            if (LeftBoundIsForward)
            {
                while (Result.Top.Y == Result.Next.Bot.Y && Result.Next.OutIdx != Skip)
                {
                    Result = Result.Next;
                }
                if (Result.Dx == Horizontal && Result.Next.OutIdx != Skip)
                {
                    //nb: at the top of a bound, horizontals are added to the bound
                    //only when the preceding edge attaches to the horizontal's left vertex
                    //unless a Skip edge is encountered when that becomes the top divide
                    Horz = Result;
                    while (Horz.Prev.Dx == Horizontal)
                    {
                        Horz = Horz.Prev;
                    }
                    if (Horz.Prev.Top.X > Result.Next.Top.X)
                    {
                        Result = Horz.Prev;
                    }
                }
                while (E != Result)
                {
                    E.NextInLML = E.Next;
                    if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    E = E.Next;
                }
                if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
                {
                    ReverseHorizontal(E);
                }
                Result = Result.Next; //move to the edge just beyond current bound
            }
            else
            {
                while (Result.Top.Y == Result.Prev.Bot.Y && Result.Prev.OutIdx != Skip)
                {
                    Result = Result.Prev;
                }
                if (Result.Dx == Horizontal && Result.Prev.OutIdx != Skip)
                {
                    Horz = Result;
                    while (Horz.Next.Dx == Horizontal)
                    {
                        Horz = Horz.Next;
                    }
                    if (Horz.Next.Top.X == Result.Prev.Top.X ||
                        Horz.Next.Top.X > Result.Prev.Top.X)
                    {
                        Result = Horz.Next;
                    }
                }

                while (E != Result)
                {
                    E.NextInLML = E.Prev;
                    if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    E = E.Prev;
                }
                if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
                {
                    ReverseHorizontal(E);
                }
                Result = Result.Prev; //move to the edge just beyond current bound
            }
            return(Result);
        }
コード例 #13
0
        //------------------------------------------------------------------------------

        internal static bool IsHorizontal(ClipperTEdge e)
        {
            return(e.Delta.Y == 0);
        }
コード例 #14
0
        //------------------------------------------------------------------------------

        internal void SwapPositionsInAEL(ClipperTEdge edge1, ClipperTEdge edge2)
        {
            //check that one or other edge hasn't already been removed from AEL ...
            if (edge1.NextInAEL == edge1.PrevInAEL ||
                edge2.NextInAEL == edge2.PrevInAEL)
            {
                return;
            }

            if (edge1.NextInAEL == edge2)
            {
                ClipperTEdge next = edge2.NextInAEL;
                if (next != null)
                {
                    next.PrevInAEL = edge1;
                }
                ClipperTEdge prev = edge1.PrevInAEL;
                if (prev != null)
                {
                    prev.NextInAEL = edge2;
                }
                edge2.PrevInAEL = prev;
                edge2.NextInAEL = edge1;
                edge1.PrevInAEL = edge2;
                edge1.NextInAEL = next;
            }
            else if (edge2.NextInAEL == edge1)
            {
                ClipperTEdge next = edge1.NextInAEL;
                if (next != null)
                {
                    next.PrevInAEL = edge2;
                }
                ClipperTEdge prev = edge2.PrevInAEL;
                if (prev != null)
                {
                    prev.NextInAEL = edge1;
                }
                edge1.PrevInAEL = prev;
                edge1.NextInAEL = edge2;
                edge2.PrevInAEL = edge1;
                edge2.NextInAEL = next;
            }
            else
            {
                ClipperTEdge next = edge1.NextInAEL;
                ClipperTEdge prev = edge1.PrevInAEL;
                edge1.NextInAEL = edge2.NextInAEL;
                if (edge1.NextInAEL != null)
                {
                    edge1.NextInAEL.PrevInAEL = edge1;
                }
                edge1.PrevInAEL = edge2.PrevInAEL;
                if (edge1.PrevInAEL != null)
                {
                    edge1.PrevInAEL.NextInAEL = edge1;
                }
                edge2.NextInAEL = next;
                if (edge2.NextInAEL != null)
                {
                    edge2.NextInAEL.PrevInAEL = edge2;
                }
                edge2.PrevInAEL = prev;
                if (edge2.PrevInAEL != null)
                {
                    edge2.PrevInAEL.NextInAEL = edge2;
                }
            }

            if (edge1.PrevInAEL == null)
            {
                m_ActiveEdges = edge1;
            }
            else if (edge2.PrevInAEL == null)
            {
                m_ActiveEdges = edge2;
            }
        }