예제 #1
0
        //------------------------------------------------------------------------------

        internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange)
        {
            if (UseFullRange)
            {
                return(Int128.Int128Mul(e1.Delta.Y, e2.Delta.X) ==
                       Int128.Int128Mul(e1.Delta.X, e2.Delta.Y));
            }
            else
            {
                return((Int64)(e1.Delta.Y) * (e2.Delta.X) ==
                       (Int64)(e1.Delta.X) * (e2.Delta.Y));
            }
        }
예제 #2
0
        //------------------------------------------------------------------------------

        private void ReverseHorizontal(TEdge 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.]
            Int64 tmp = e.Top.X;

            e.Top.X = e.Bot.X;
            e.Bot.X = tmp;
#if use_xyz
            tmp     = e.Top.Z;
            e.Top.Z = e.Bot.Z;
            e.Bot.Z = tmp;
#endif
        }
 private void InitEdge2(TEdge e, PolyType 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;
 }
예제 #4
0
        //----------------------------------------------------------------------

        void AscendToMax(ref TEdge E, bool Appending, bool IsClosed)
        {
            if (E.OutIdx == Skip)
            {
                E = E.Next;
                if (!MoreAbove(E.Prev))
                {
                    return;
                }
            }

            if (IsHorizontal(E) && Appending &&
                (E.Bot != E.Prev.Bot))
            {
                ReverseHorizontal(E);
            }
            //now process the ascending bound ....
            TEdge EStart = E;

            for (;;)
            {
                if (E.Next.OutIdx == Skip ||
                    ((E.Next.Top.Y == E.Top.Y) && !IsHorizontal(E.Next)))
                {
                    break;
                }
                E.NextInLML = E.Next;
                E           = E.Next;
                if (IsHorizontal(E) && (E.Bot.X != E.Prev.Top.X))
                {
                    ReverseHorizontal(E);
                }
            }

            if (!Appending)
            {
                if (EStart.OutIdx == Skip)
                {
                    EStart = EStart.Next;
                }
                if (EStart != E.Next)
                {
                    DoMinimaLML(null, EStart, IsClosed);
                }
            }

            E = E.Next;
        }
예제 #5
0
        //------------------------------------------------------------------------------

        bool MoreAbove(TEdge Edge)
        {
            if (IsHorizontal(Edge))
            {
                Edge = GetLastHorz(Edge);
                return(Edge.Next.Top.Y < Edge.Top.Y);
            }
            else if (IsHorizontal(Edge.Next))
            {
                Edge = GetLastHorz(Edge.Next);
                return(Edge.Next.Top.Y < Edge.Top.Y);
            }
            else
            {
                return(Edge.Next.Top.Y < Edge.Top.Y);
            }
        }
        /// <summary>
        /// Reset all fields to default values in preparation for object recycling
        /// </summary>
        public void PrepareForRecycle()
        {
            PolyTyp = PolyType.Subject;
            Side    = EdgeSide.Left;

            Bot = Curr = Top = Delta = new IntPoint();

            Dx        = 0;
            WindDelta = 0;
            WindCnt   = 0;
            WindCnt2  = 0;
            OutIdx    = 0;

            Next      = Prev = null;
            PrevInAEL = PrevInSEL = null;
            NextInLML = NextInAEL = NextInSEL = null;
        }
예제 #7
0
        //------------------------------------------------------------------------------

        bool JustBeforeLocMin(TEdge Edge)
        {
            //Edge is Skip and was heading down.
            TEdge E = Edge;

            if (IsHorizontal(E))
            {
                while (IsHorizontal(E.Next))
                {
                    E = E.Next;
                }
                return(E.Next.Top.Y < E.Bot.Y);
            }
            else
            {
                return(SharedVertWithNextIsBot(E));
            }
        }
예제 #8
0
 //constructor
 public Clipper(int InitOptions = 0)
     : base()
 {
     m_Scanbeam = null;
     m_Maxima = null;
     m_ActiveEdges = null;
     m_SortedEdges = null;
     m_IntersectList = new List<IntersectNode>();
     m_IntersectNodeComparer = new MyIntersectNodeSort();
     m_ExecuteLocked = false;
     m_UsingPolyTree = false;
     m_PolyOuts = new List<OutRec>();
     m_Joins = new List<Join>();
     m_GhostJoins = new List<Join>();
     ReverseSolution = (ioReverseSolution & InitOptions) != 0;
     StrictlySimple = (ioStrictlySimple & InitOptions) != 0;
     PreserveCollinear = (ioPreserveCollinear & InitOptions) != 0;
     #if use_xyz
       ZFillFunction = null;
     #endif
 }
예제 #9
0
        //------------------------------------------------------------------------------

        bool AllHorizontal(TEdge Edge)
        {
            if (!IsHorizontal(Edge))
            {
                return(false);
            }
            TEdge E = Edge.Next;

            while (E != Edge)
            {
                if (!IsHorizontal(E))
                {
                    return(false);
                }
                else
                {
                    E = E.Next;
                }
            }
            return(true);
        }
예제 #10
0
        internal void DeleteFromAEL(TEdge e)
        {
            TEdge prevInAEL = e.PrevInAEL;
            TEdge nextInAEL = e.NextInAEL;

            if (prevInAEL != null || nextInAEL != null || e == m_ActiveEdges)
            {
                if (prevInAEL != null)
                {
                    prevInAEL.NextInAEL = nextInAEL;
                }
                else
                {
                    m_ActiveEdges = nextInAEL;
                }
                if (nextInAEL != null)
                {
                    nextInAEL.PrevInAEL = prevInAEL;
                }
                e.NextInAEL = null;
                e.PrevInAEL = null;
            }
        }
예제 #11
0
        internal void UpdateEdgeIntoAEL(ref TEdge e)
        {
            if (e.NextInLML == null)
            {
                throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
            }
            TEdge prevInAEL = e.PrevInAEL;
            TEdge nextInAEL = e.NextInAEL;

            e.NextInLML.OutIdx = e.OutIdx;
            if (prevInAEL != null)
            {
                prevInAEL.NextInAEL = e.NextInLML;
            }
            else
            {
                m_ActiveEdges = e.NextInLML;
            }
            if (nextInAEL != null)
            {
                nextInAEL.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;
            TEdge obj = e;

            obj.Curr    = obj.Bot;
            e.PrevInAEL = prevInAEL;
            e.NextInAEL = nextInAEL;
            if (!IsHorizontal(e))
            {
                InsertScanbeam(e.Top.Y);
            }
        }
 protected virtual void Reset()
 {
     m_CurrentLM = m_MinimaList;
     if (m_CurrentLM != null)
     {
         for (LocalMinima localMinima = m_MinimaList; localMinima != null; localMinima = localMinima.Next)
         {
             TEdge leftBound = localMinima.LeftBound;
             if (leftBound != null)
             {
                 leftBound.Curr   = leftBound.Bot;
                 leftBound.Side   = EdgeSide.esLeft;
                 leftBound.OutIdx = -1;
             }
             leftBound = localMinima.RightBound;
             if (leftBound != null)
             {
                 leftBound.Curr   = leftBound.Bot;
                 leftBound.Side   = EdgeSide.esRight;
                 leftBound.OutIdx = -1;
             }
         }
     }
 }
예제 #13
0
        //------------------------------------------------------------------------------

        internal void DeleteFromAEL(TEdge e)
        {
            TEdge AelPrev = e.PrevInAEL;
            TEdge 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;
        }
 //------------------------------------------------------------------------------
 protected override void Reset()
 {
     base.Reset();
       m_Scanbeam = null;
       m_ActiveEdges = null;
       m_SortedEdges = null;
       DisposeAllPolyPts();
       LocalMinima lm = m_MinimaList;
       while (lm != null)
       {
     InsertScanbeam(lm.Y);
     InsertScanbeam(lm.leftBound.ytop);
     lm = lm.next;
       }
 }
 //------------------------------------------------------------------------------
 private void SetDx(TEdge e)
 {
     if (e.ybot == e.ytop) e.dx = horizontal;
       else e.dx = (double)(e.xtop - e.xbot)/(e.ytop - e.ybot);
 }
        //---------------------------------------------------------------------------
        TEdge AddBoundsToLML(TEdge e)
        {
            //Starting at the top of one bound we progress to the bottom where there's
              //a local minima. We then go to the top of the next bound. These two bounds
              //form the left and right (or right and left) bounds of the local minima.
              e.nextInLML = null;
              e = e.next;
              for (;;)
              {
            if ( e.dx == horizontal )
            {
              //nb: proceed through horizontals when approaching from their right,
              //    but break on horizontal minima if approaching from their left.
              //    This ensures 'local minima' are always on the left of horizontals.
              if (e.next.ytop < e.ytop && e.next.xbot > e.prev.xbot) break;
              if (e.xtop != e.prev.xbot) SwapX(e);
              e.nextInLML = e.prev;
            }
            else if (e.ycurr == e.prev.ycurr) break;
            else e.nextInLML = e.prev;
            e = e.next;
              }

              //e and e.prev are now at a local minima ...
              LocalMinima newLm = new LocalMinima();
              newLm.next = null;
              newLm.Y = e.prev.ybot;

              if ( e.dx == horizontal ) //horizontal edges never start a left bound
              {
            if (e.xbot != e.prev.xbot) SwapX(e);
            newLm.leftBound = e.prev;
            newLm.rightBound = e;
              } else if (e.dx < e.prev.dx)
              {
            newLm.leftBound = e.prev;
            newLm.rightBound = e;
              } else
              {
            newLm.leftBound = e;
            newLm.rightBound = e.prev;
              }
              newLm.leftBound.side = EdgeSide.esLeft;
              newLm.rightBound.side = EdgeSide.esRight;
              InsertLocalMinima( newLm );

              for (;;)
              {
            if ( e.next.ytop == e.ytop && e.next.dx != horizontal ) break;
            e.nextInLML = e.next;
            e = e.next;
            if ( e.dx == horizontal && e.xbot != e.prev.xtop) SwapX(e);
              }
              return e.next;
        }
 //------------------------------------------------------------------------------
 private void UpdateEdgeIntoAEL(ref TEdge e)
 {
     if (e.nextInLML == null)
         throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
     TEdge AelPrev = e.prevInAEL;
     TEdge 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.prevInAEL = AelPrev;
     e.nextInAEL = AelNext;
     if (e.dx != horizontal) InsertScanbeam(e.ytop);
 }
예제 #18
0
        //------------------------------------------------------------------------------

        public IntRect GetBounds()
        {
            IntRect     result = new IntRect();
            LocalMinima lm     = m_MinimaList;

            if (lm == null)
            {
                return(result);
            }
            result.left   = lm.LeftBound.Bot.X;
            result.top    = lm.LeftBound.Bot.Y;
            result.right  = lm.LeftBound.Bot.X;
            result.bottom = lm.LeftBound.Bot.Y;
            while (lm != null)
            {
                if (lm.LeftBound.Bot.Y > result.bottom)
                {
                    result.bottom = lm.LeftBound.Bot.Y;
                }
                TEdge e = lm.LeftBound;
                for (; ;)
                {
                    TEdge bottomE = e;
                    while (e.NextInLML != null)
                    {
                        if (e.Bot.X < result.left)
                        {
                            result.left = e.Bot.X;
                        }
                        if (e.Bot.X > result.right)
                        {
                            result.right = e.Bot.X;
                        }
                        e = e.NextInLML;
                    }
                    if (e.Bot.X < result.left)
                    {
                        result.left = e.Bot.X;
                    }
                    if (e.Bot.X > result.right)
                    {
                        result.right = e.Bot.X;
                    }
                    if (e.Top.X < result.left)
                    {
                        result.left = e.Top.X;
                    }
                    if (e.Top.X > result.right)
                    {
                        result.right = e.Top.X;
                    }
                    if (e.Top.Y < result.top)
                    {
                        result.top = e.Top.Y;
                    }

                    if (bottomE == lm.LeftBound)
                    {
                        e = lm.RightBound;
                    }
                    else
                    {
                        break;
                    }
                }
                lm = lm.Next;
            }
            return(result);
        }
 //------------------------------------------------------------------------------
 private void AddOutPt(TEdge e, TEdge altE, IntPoint pt)
 {
     bool ToFront = (e.side == EdgeSide.esLeft);
       if(  e.outIdx < 0 )
       {
       OutRec outRec = CreateOutRec();
       m_PolyOuts.Add(outRec);
       outRec.idx = m_PolyOuts.Count -1;
       e.outIdx = outRec.idx;
       OutPt op = new OutPt();
       outRec.pts = op;
       outRec.bottomPt = op;
       outRec.bottomE1 = e;
       outRec.bottomE2 = altE;
       op.pt = pt;
       op.idx = outRec.idx;
       op.next = op;
       op.prev = op;
       SetHoleState(e, outRec);
       } else
       {
       OutRec outRec = m_PolyOuts[e.outIdx];
       OutPt op = outRec.pts;
       if (ToFront && PointsEqual(pt, op.pt) ||
           (!ToFront && PointsEqual(pt, op.prev.pt))) return;
       OutPt op2 = new OutPt();
       op2.pt = pt;
       op2.idx = outRec.idx;
       if (op2.pt.Y == outRec.bottomPt.pt.Y &&
         op2.pt.X < outRec.bottomPt.pt.X)
       {
           outRec.bottomPt = op2;
           outRec.bottomE1 = e;
           outRec.bottomE2 = altE;
       }
       op2.next = op;
       op2.prev = op.prev;
       op2.prev.next = op2;
       op.prev = op2;
       if (ToFront) outRec.pts = op2;
       }
 }
 //------------------------------------------------------------------------------
 private void AddIntersectNode(TEdge e1, TEdge e2, IntPoint pt)
 {
     IntersectNode newNode = new IntersectNode();
       newNode.edge1 = e1;
       newNode.edge2 = e2;
       newNode.pt = pt;
       newNode.next = null;
       if (m_IntersectNodes == null) m_IntersectNodes = newNode;
       else if( Process1Before2(newNode, m_IntersectNodes) )
       {
     newNode.next = m_IntersectNodes;
     m_IntersectNodes = newNode;
       }
       else
       {
     IntersectNode iNode = m_IntersectNodes;
     while( iNode.next != null  && Process1Before2(iNode.next, newNode) )
         iNode = iNode.next;
     newNode.next = iNode.next;
     iNode.next = newNode;
       }
 }
예제 #21
0
        //------------------------------------------------------------------------------

        internal void SwapPositionsInAEL(TEdge edge1, TEdge 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)
            {
                TEdge next = edge2.NextInAEL;
                if (next != null)
                {
                    next.PrevInAEL = edge1;
                }
                TEdge 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)
            {
                TEdge next = edge1.NextInAEL;
                if (next != null)
                {
                    next.PrevInAEL = edge2;
                }
                TEdge prev = edge2.PrevInAEL;
                if (prev != null)
                {
                    prev.NextInAEL = edge1;
                }
                edge1.PrevInAEL = prev;
                edge1.NextInAEL = edge2;
                edge2.PrevInAEL = edge1;
                edge2.NextInAEL = next;
            }
            else
            {
                TEdge next = edge1.NextInAEL;
                TEdge 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;
            }
        }
예제 #22
0
        //----------------------------------------------------------------------

        TEdge DescendToMin(ref TEdge E)
        {
            //PRECONDITION: STARTING EDGE IS A VALID DESCENDING EDGE.
            //Starting at the top of one bound we progress to the bottom where there's
            //A local minima. We  go to the top of the Next bound. These two bounds
            //form the left and right (or right and left) bounds of the local minima.
            TEdge EHorz;

            E.NextInLML = null;
            if (IsHorizontal(E))
            {
                EHorz = E;
                while (IsHorizontal(EHorz.Next))
                {
                    EHorz = EHorz.Next;
                }
                if (EHorz.Bot != EHorz.Next.Top)
                {
                    ReverseHorizontal(E);
                }
            }
            for (; ;)
            {
                E = E.Next;
                if (E.OutIdx == Skip)
                {
                    break;
                }
                else if (IsHorizontal(E))
                {
                    //nb: proceed through horizontals when approaching from their right,
                    //    but break on horizontal minima if approaching from their left.
                    //    This ensures 'local minima' are always on the left of horizontals.

                    //look ahead is required in case of multiple consec. horizontals
                    EHorz = GetLastHorz(E);
                    if (EHorz == E.Prev ||                  //horizontal line
                        (EHorz.Next.Top.Y < E.Top.Y &&      //bottom horizontal
                         EHorz.Next.Bot.X > E.Prev.Bot.X))  //approaching from the left
                    {
                        break;
                    }
                    if (E.Top.X != E.Prev.Bot.X)
                    {
                        ReverseHorizontal(E);
                    }
                    if (EHorz.OutIdx == Skip)
                    {
                        EHorz = EHorz.Prev;
                    }
                    while (E != EHorz)
                    {
                        E.NextInLML = E.Prev;
                        E           = E.Next;
                        if (E.Top.X != E.Prev.Bot.X)
                        {
                            ReverseHorizontal(E);
                        }
                    }
                }
                else if (E.Bot.Y == E.Prev.Bot.Y)
                {
                    break;
                }
                E.NextInLML = E.Prev;
            }
            return(E.Prev);
        }
예제 #23
0
        //----------------------------------------------------------------------

        TEdge AddBoundsToLML(TEdge E, bool Closed)
        {
            //Starting at the top of one bound we progress to the bottom where there's
            //A local minima. We then go to the top of the Next bound. These two bounds
            //form the left and right (or right and left) bounds of the local minima.

            TEdge B;
            bool  AppendMaxima;

            //do minima ...
            if (E.OutIdx == Skip)
            {
                if (MoreBelow(E))
                {
                    E = E.Next;
                    B = DescendToMin(ref E);
                }
                else
                {
                    B = null;
                }
            }
            else
            {
                B = DescendToMin(ref E);
            }

            if (E.OutIdx == Skip)    //nb: may be BEFORE, AT or just THRU LM
            {
                //do minima before Skip...
                DoMinimaLML(null, B, Closed);      //store what we've got so far (if anything)
                AppendMaxima = false;
                //finish off any minima ...
                if (E.Bot != E.Prev.Bot && MoreBelow(E))
                {
                    E = E.Next;
                    B = DescendToMin(ref E);
                    DoMinimaLML(B, E, Closed);
                    AppendMaxima = true;
                }
                else if (JustBeforeLocMin(E))
                {
                    E = E.Next;
                }
            }
            else
            {
                DoMinimaLML(B, E, Closed);
                AppendMaxima = true;
            }

            //now do maxima ...
            AscendToMax(ref E, AppendMaxima, Closed);

            if (E.OutIdx == Skip && (E.Top != E.Prev.Top)) //may be BEFORE, AT or just AFTER maxima
            {
                //finish off any maxima ...
                if (MoreAbove(E))
                {
                    E = E.Next;
                    AscendToMax(ref E, false, Closed);
                }
                else if (E.Top == E.Next.Top || (IsHorizontal(E.Next) && (E.Top == E.Next.Bot)))
                {
                    E = E.Next; //ie just before Maxima
                }
            }
            return(E);
        }
예제 #24
0
        //---------------------------------------------------------------------------

        void DoMinimaLML(TEdge E1, TEdge E2, bool IsClosed)
        {
            if (E1 == null)
            {
                if (E2 == null)
                {
                    return;
                }
                LocalMinima NewLm = new LocalMinima();
                NewLm.Next       = null;
                NewLm.Y          = E2.Bot.Y;
                NewLm.LeftBound  = null;
                E2.WindDelta     = 0;
                NewLm.RightBound = E2;
                InsertLocalMinima(NewLm);
            }
            else
            {
                //E and E.Prev are now at a local minima ...
                LocalMinima NewLm = new LocalMinima();
                NewLm.Y    = E1.Bot.Y;
                NewLm.Next = null;
                if (IsHorizontal(E2)) //Horz. edges never start a Left bound
                {
                    if (E2.Bot.X != E1.Bot.X)
                    {
                        ReverseHorizontal(E2);
                    }
                    NewLm.LeftBound  = E1;
                    NewLm.RightBound = E2;
                }
                else if (E2.Dx < E1.Dx)
                {
                    NewLm.LeftBound  = E1;
                    NewLm.RightBound = E2;
                }
                else
                {
                    NewLm.LeftBound  = E2;
                    NewLm.RightBound = E1;
                }
                NewLm.LeftBound.Side  = EdgeSide.esLeft;
                NewLm.RightBound.Side = EdgeSide.esRight;
                //set the winding state of the first edge in each bound
                //(it'll be copied to subsequent edges in the bound) ...
                if (!IsClosed)
                {
                    NewLm.LeftBound.WindDelta = 0;
                }
                else if (NewLm.LeftBound.Next == NewLm.RightBound)
                {
                    NewLm.LeftBound.WindDelta = -1;
                }
                else
                {
                    NewLm.LeftBound.WindDelta = 1;
                }
                NewLm.RightBound.WindDelta = -NewLm.LeftBound.WindDelta;
                InsertLocalMinima(NewLm);
            }
        }
예제 #25
0
        private TEdge ProcessBound(TEdge E, bool IsClockwise)
        {
            TEdge tEdge  = E;
            TEdge tEdge2 = E;

            if (E.Dx == -3.4E+38)
            {
                long num = (!IsClockwise) ? E.Next.Bot.X : E.Prev.Bot.X;
                if (E.Bot.X != num)
                {
                    ReverseHorizontal(E);
                }
            }
            if (tEdge2.OutIdx != -2)
            {
                if (IsClockwise)
                {
                    while (tEdge2.Top.Y == tEdge2.Next.Bot.Y && tEdge2.Next.OutIdx != -2)
                    {
                        tEdge2 = tEdge2.Next;
                    }
                    if (tEdge2.Dx == -3.4E+38 && tEdge2.Next.OutIdx != -2)
                    {
                        TEdge tEdge3 = tEdge2;
                        while (tEdge3.Prev.Dx == -3.4E+38)
                        {
                            tEdge3 = tEdge3.Prev;
                        }
                        if (tEdge3.Prev.Top.X == tEdge2.Next.Top.X)
                        {
                            if (!IsClockwise)
                            {
                                tEdge2 = tEdge3.Prev;
                            }
                        }
                        else if (tEdge3.Prev.Top.X > tEdge2.Next.Top.X)
                        {
                            tEdge2 = tEdge3.Prev;
                        }
                    }
                    while (E != tEdge2)
                    {
                        E.NextInLML = E.Next;
                        if (E.Dx == -3.4E+38 && E != tEdge && E.Bot.X != E.Prev.Top.X)
                        {
                            ReverseHorizontal(E);
                        }
                        E = E.Next;
                    }
                    if (E.Dx == -3.4E+38 && E != tEdge && E.Bot.X != E.Prev.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    tEdge2 = tEdge2.Next;
                }
                else
                {
                    while (tEdge2.Top.Y == tEdge2.Prev.Bot.Y && tEdge2.Prev.OutIdx != -2)
                    {
                        tEdge2 = tEdge2.Prev;
                    }
                    if (tEdge2.Dx == -3.4E+38 && tEdge2.Prev.OutIdx != -2)
                    {
                        TEdge tEdge3 = tEdge2;
                        while (tEdge3.Next.Dx == -3.4E+38)
                        {
                            tEdge3 = tEdge3.Next;
                        }
                        if (tEdge3.Next.Top.X == tEdge2.Prev.Top.X)
                        {
                            if (!IsClockwise)
                            {
                                tEdge2 = tEdge3.Next;
                            }
                        }
                        else if (tEdge3.Next.Top.X > tEdge2.Prev.Top.X)
                        {
                            tEdge2 = tEdge3.Next;
                        }
                    }
                    while (E != tEdge2)
                    {
                        E.NextInLML = E.Prev;
                        if (E.Dx == -3.4E+38 && E != tEdge && E.Bot.X != E.Next.Top.X)
                        {
                            ReverseHorizontal(E);
                        }
                        E = E.Prev;
                    }
                    if (E.Dx == -3.4E+38 && E != tEdge && E.Bot.X != E.Next.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    tEdge2 = tEdge2.Prev;
                }
            }
            if (tEdge2.OutIdx == -2)
            {
                E = tEdge2;
                if (IsClockwise)
                {
                    while (E.Top.Y == E.Next.Bot.Y)
                    {
                        E = E.Next;
                    }
                    while (E != tEdge2 && E.Dx == -3.4E+38)
                    {
                        E = E.Prev;
                    }
                }
                else
                {
                    while (E.Top.Y == E.Prev.Bot.Y)
                    {
                        E = E.Prev;
                    }
                    while (E != tEdge2 && E.Dx == -3.4E+38)
                    {
                        E = E.Next;
                    }
                }
                if (E == tEdge2)
                {
                    tEdge2 = ((!IsClockwise) ? E.Prev : E.Next);
                }
                else
                {
                    E = ((!IsClockwise) ? tEdge2.Prev : tEdge2.Next);
                    LocalMinima localMinima = new LocalMinima();
                    localMinima.Next                 = null;
                    localMinima.Y                    = E.Bot.Y;
                    localMinima.LeftBound            = null;
                    localMinima.RightBound           = E;
                    localMinima.RightBound.WindDelta = 0;
                    tEdge2 = ProcessBound(localMinima.RightBound, IsClockwise);
                    InsertLocalMinima(localMinima);
                }
            }
            return(tEdge2);
        }
예제 #26
0
 internal void SwapPositionsInAEL(TEdge edge1, TEdge edge2)
 {
     if (edge1.NextInAEL != edge1.PrevInAEL && edge2.NextInAEL != edge2.PrevInAEL)
     {
         if (edge1.NextInAEL == edge2)
         {
             TEdge nextInAEL = edge2.NextInAEL;
             if (nextInAEL != null)
             {
                 nextInAEL.PrevInAEL = edge1;
             }
             TEdge prevInAEL = edge1.PrevInAEL;
             if (prevInAEL != null)
             {
                 prevInAEL.NextInAEL = edge2;
             }
             edge2.PrevInAEL = prevInAEL;
             edge2.NextInAEL = edge1;
             edge1.PrevInAEL = edge2;
             edge1.NextInAEL = nextInAEL;
         }
         else if (edge2.NextInAEL == edge1)
         {
             TEdge nextInAEL2 = edge1.NextInAEL;
             if (nextInAEL2 != null)
             {
                 nextInAEL2.PrevInAEL = edge2;
             }
             TEdge prevInAEL2 = edge2.PrevInAEL;
             if (prevInAEL2 != null)
             {
                 prevInAEL2.NextInAEL = edge1;
             }
             edge1.PrevInAEL = prevInAEL2;
             edge1.NextInAEL = edge2;
             edge2.PrevInAEL = edge1;
             edge2.NextInAEL = nextInAEL2;
         }
         else
         {
             TEdge nextInAEL3 = edge1.NextInAEL;
             TEdge prevInAEL3 = 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 = nextInAEL3;
             if (edge2.NextInAEL != null)
             {
                 edge2.NextInAEL.PrevInAEL = edge2;
             }
             edge2.PrevInAEL = prevInAEL3;
             if (edge2.PrevInAEL != null)
             {
                 edge2.PrevInAEL.NextInAEL = edge2;
             }
         }
         if (edge1.PrevInAEL == null)
         {
             m_ActiveEdges = edge1;
         }
         else if (edge2.PrevInAEL == null)
         {
             m_ActiveEdges = edge2;
         }
     }
 }
 //------------------------------------------------------------------------------
 private static void SwapSides(TEdge edge1, TEdge edge2)
 {
     EdgeSide side = edge1.side;
     edge1.side = edge2.side;
     edge2.side = side;
 }
예제 #28
0
        //------------------------------------------------------------------------------

        private TEdge ProcessBound(TEdge E, bool LeftBoundIsForward)
        {
            TEdge EStart, Result = E;
            TEdge 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;
                    }
                    LocalMinima locMin = new LocalMinima();
                    locMin.Next       = null;
                    locMin.Y          = E.Bot.Y;
                    locMin.LeftBound  = null;
                    locMin.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);
        }
 //------------------------------------------------------------------------------
 private void AddEdgeToSEL(TEdge edge)
 {
     //SEL pointers in PEdge are reused to build a list of horizontal edges.
     //However, we don't need to worry about order with horizontal edge processing.
     if (m_SortedEdges == null)
     {
         m_SortedEdges = edge;
         edge.prevInSEL = null;
         edge.nextInSEL = null;
     }
     else
     {
         edge.nextInSEL = m_SortedEdges;
         edge.prevInSEL = null;
         m_SortedEdges.prevInSEL = edge;
         m_SortedEdges = edge;
     }
 }
예제 #30
0
        //------------------------------------------------------------------------------


        public bool AddPath(List <IntPoint> pg, PolyType polyType, bool Closed)
        {
#if use_lines
            if (!Closed && polyType == PolyType.ptClip)
            {
                throw new ClipperException("AddPath: Open paths must be subject.");
            }
#else
            if (!Closed)
            {
                throw new ClipperException("AddPath: Open paths have been disabled.");
            }
#endif

            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 <TEdge> edges = new List <TEdge>(highI + 1);
            for (int i = 0; i <= highI; i++)
            {
                edges.Add(new TEdge());
            }

            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]);
            }
            TEdge eStart = edges[0];

            //2. Remove duplicate vertices, and (when closed) collinear edges ...
            TEdge 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;
                LocalMinima locMin = new LocalMinima();
                locMin.Next                 = null;
                locMin.Y                    = E.Bot.Y;
                locMin.LeftBound            = null;
                locMin.RightBound           = E;
                locMin.RightBound.Side      = EdgeSide.esRight;
                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;
            TEdge 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 ...
                LocalMinima locMin = new LocalMinima();
                locMin.Next = null;
                locMin.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  = EdgeSide.esLeft;
                locMin.RightBound.Side = EdgeSide.esRight;

                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);
                }

                TEdge 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);
        }
 //------------------------------------------------------------------------------
 private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt)
 {
     AddOutPt(e1, null, pt);
     if (e1.outIdx == e2.outIdx)
     {
         e1.outIdx = -1;
         e2.outIdx = -1;
     }
     else AppendPolygon(e1, e2);
 }
 /// <summary>
 /// Reset all fields to default values in preparation for object recycling
 /// </summary>
 public void PrepareForRecycle()
 {
     Edge1 = null;
     Edge2 = null;
     Pt    = new IntPoint();
 }
        //------------------------------------------------------------------------------
        private void BuildIntersectList(Int64 botY, Int64 topY)
        {
            if ( m_ActiveEdges == null ) return;

              //prepare for sorting ...
              TEdge e = m_ActiveEdges;
              e.tmpX = TopX( e, topY );
              m_SortedEdges = e;
              m_SortedEdges.prevInSEL = null;
              e = e.nextInAEL;
              while( e != null )
              {
            e.prevInSEL = e.prevInAEL;
            e.prevInSEL.nextInSEL = e;
            e.nextInSEL = null;
            e.tmpX = TopX( e, topY );
            e = e.nextInAEL;
              }

              //bubblesort ...
              bool isModified = true;
              while( isModified && m_SortedEdges != null )
              {
            isModified = false;
            e = m_SortedEdges;
            while( e.nextInSEL != null )
            {
              TEdge eNext = e.nextInSEL;
              IntPoint pt = new IntPoint();
              if(e.tmpX > eNext.tmpX && IntersectPoint(e, eNext, ref pt))
              {
                  if (pt.Y > botY)
                  {
                      pt.Y = botY;
                      pt.X = TopX(e, pt.Y);
                  }
                  AddIntersectNode(e, eNext, pt);
                  SwapPositionsInSEL(e, eNext);
                  isModified = true;
              }
              else
                e = eNext;
            }
            if( e.prevInSEL != null ) e.prevInSEL.nextInSEL = null;
            else break;
              }
              m_SortedEdges = null;
        }
        private TEdge ProcessBound(TEdge E, bool LeftBoundIsForward)
        {
            TEdge tEdge = E;

            if (tEdge.OutIdx == -2)
            {
                E = tEdge;
                if (!LeftBoundIsForward)
                {
                    while (E.Top.Y == E.Prev.Bot.Y)
                    {
                        E = E.Prev;
                    }
                    while (E != tEdge && E.Dx == -3.4E+38)
                    {
                        E = E.Next;
                    }
                }
                else
                {
                    while (E.Top.Y == E.Next.Bot.Y)
                    {
                        E = E.Next;
                    }
                    while (E != tEdge && E.Dx == -3.4E+38)
                    {
                        E = E.Prev;
                    }
                }
                if (E == tEdge)
                {
                    tEdge = ((!LeftBoundIsForward) ? E.Prev : E.Next);
                }
                else
                {
                    E = ((!LeftBoundIsForward) ? tEdge.Prev : tEdge.Next);
                    LocalMinima localMinima = new LocalMinima();
                    localMinima.Next       = null;
                    localMinima.Y          = E.Bot.Y;
                    localMinima.LeftBound  = null;
                    localMinima.RightBound = E;
                    E.WindDelta            = 0;
                    tEdge = ProcessBound(E, LeftBoundIsForward);
                    InsertLocalMinima(localMinima);
                }
                return(tEdge);
            }
            TEdge tEdge2;

            if (E.Dx == -3.4E+38)
            {
                tEdge2 = ((!LeftBoundIsForward) ? E.Next : E.Prev);
                if (tEdge2.OutIdx != -2)
                {
                    if (tEdge2.Dx == -3.4E+38)
                    {
                        if (tEdge2.Bot.X != E.Bot.X && tEdge2.Top.X != E.Bot.X)
                        {
                            ReverseHorizontal(E);
                        }
                    }
                    else if (tEdge2.Bot.X != E.Bot.X)
                    {
                        ReverseHorizontal(E);
                    }
                }
            }
            tEdge2 = E;
            if (!LeftBoundIsForward)
            {
                while (tEdge.Top.Y == tEdge.Prev.Bot.Y && tEdge.Prev.OutIdx != -2)
                {
                    tEdge = tEdge.Prev;
                }
                if (tEdge.Dx == -3.4E+38 && tEdge.Prev.OutIdx != -2)
                {
                    TEdge tEdge3 = tEdge;
                    while (tEdge3.Next.Dx == -3.4E+38)
                    {
                        tEdge3 = tEdge3.Next;
                    }
                    if (tEdge3.Next.Top.X == tEdge.Prev.Top.X)
                    {
                        if (!LeftBoundIsForward)
                        {
                            tEdge = tEdge3.Next;
                        }
                    }
                    else if (tEdge3.Next.Top.X > tEdge.Prev.Top.X)
                    {
                        tEdge = tEdge3.Next;
                    }
                }
                while (E != tEdge)
                {
                    E.NextInLML = E.Prev;
                    if (E.Dx == -3.4E+38 && E != tEdge2 && E.Bot.X != E.Next.Top.X)
                    {
                        ReverseHorizontal(E);
                    }
                    E = E.Prev;
                }
                if (E.Dx == -3.4E+38 && E != tEdge2 && E.Bot.X != E.Next.Top.X)
                {
                    ReverseHorizontal(E);
                }
                return(tEdge.Prev);
            }
            while (tEdge.Top.Y == tEdge.Next.Bot.Y && tEdge.Next.OutIdx != -2)
            {
                tEdge = tEdge.Next;
            }
            if (tEdge.Dx == -3.4E+38 && tEdge.Next.OutIdx != -2)
            {
                TEdge tEdge3 = tEdge;
                while (tEdge3.Prev.Dx == -3.4E+38)
                {
                    tEdge3 = tEdge3.Prev;
                }
                if (tEdge3.Prev.Top.X == tEdge.Next.Top.X)
                {
                    if (!LeftBoundIsForward)
                    {
                        tEdge = tEdge3.Prev;
                    }
                }
                else if (tEdge3.Prev.Top.X > tEdge.Next.Top.X)
                {
                    tEdge = tEdge3.Prev;
                }
            }
            while (E != tEdge)
            {
                E.NextInLML = E.Next;
                if (E.Dx == -3.4E+38 && E != tEdge2 && E.Bot.X != E.Prev.Top.X)
                {
                    ReverseHorizontal(E);
                }
                E = E.Next;
            }
            if (E.Dx == -3.4E+38 && E != tEdge2 && E.Bot.X != E.Prev.Top.X)
            {
                ReverseHorizontal(E);
            }
            return(tEdge.Next);
        }
        //------------------------------------------------------------------------------
        private void SwapPositionsInSEL(TEdge edge1, TEdge edge2)
        {
            if (edge1.nextInSEL == null && edge1.prevInSEL == null)
                return;
            if (edge2.nextInSEL == null && edge2.prevInSEL == null)
                return;

            if (edge1.nextInSEL == edge2)
            {
                TEdge next = edge2.nextInSEL;
                if (next != null)
                    next.prevInSEL = edge1;
                TEdge prev = edge1.prevInSEL;
                if (prev != null)
                    prev.nextInSEL = edge2;
                edge2.prevInSEL = prev;
                edge2.nextInSEL = edge1;
                edge1.prevInSEL = edge2;
                edge1.nextInSEL = next;
            }
            else if (edge2.nextInSEL == edge1)
            {
                TEdge next = edge1.nextInSEL;
                if (next != null)
                    next.prevInSEL = edge2;
                TEdge prev = edge2.prevInSEL;
                if (prev != null)
                    prev.nextInSEL = edge1;
                edge1.prevInSEL = prev;
                edge1.nextInSEL = edge2;
                edge2.prevInSEL = edge1;
                edge2.nextInSEL = next;
            }
            else
            {
                TEdge next = edge1.nextInSEL;
                TEdge prev = edge1.prevInSEL;
                edge1.nextInSEL = edge2.nextInSEL;
                if (edge1.nextInSEL != null)
                    edge1.nextInSEL.prevInSEL = edge1;
                edge1.prevInSEL = edge2.prevInSEL;
                if (edge1.prevInSEL != null)
                    edge1.prevInSEL.nextInSEL = edge1;
                edge2.nextInSEL = next;
                if (edge2.nextInSEL != null)
                    edge2.nextInSEL.prevInSEL = edge2;
                edge2.prevInSEL = prev;
                if (edge2.prevInSEL != null)
                    edge2.prevInSEL.nextInSEL = edge2;
            }

            if (edge1.prevInSEL == null)
                m_SortedEdges = edge1;
            else if (edge2.prevInSEL == null)
                m_SortedEdges = edge2;
        }
        public bool AddPath(List <IntPoint> pg, PolyType polyType, bool Closed)
        {
            if (!Closed)
            {
                throw new ClipperException("AddPath: Open paths have been disabled.");
            }
            int num = pg.Count - 1;

            if (Closed)
            {
                while (num > 0 && pg[num] == pg[0])
                {
                    num--;
                }
            }
            while (num > 0 && pg[num] == pg[num - 1])
            {
                num--;
            }
            if ((Closed && num < 2) || (!Closed && num < 1))
            {
                return(false);
            }
            List <TEdge> list = new List <TEdge>(num + 1);

            for (int i = 0; i <= num; i++)
            {
                list.Add(new TEdge());
            }
            bool flag = true;

            list[1].Curr = pg[1];
            RangeTest(pg[0], ref m_UseFullRange);
            RangeTest(pg[num], ref m_UseFullRange);
            InitEdge(list[0], list[1], list[num], pg[0]);
            InitEdge(list[num], list[0], list[num - 1], pg[num]);
            for (int num2 = num - 1; num2 >= 1; num2--)
            {
                RangeTest(pg[num2], ref m_UseFullRange);
                InitEdge(list[num2], list[num2 + 1], list[num2 - 1], pg[num2]);
            }
            TEdge tEdge  = list[0];
            TEdge tEdge2 = tEdge;
            TEdge tEdge3 = tEdge;

            while (true)
            {
                if (tEdge2.Curr == tEdge2.Next.Curr && (Closed || tEdge2.Next != tEdge))
                {
                    if (tEdge2 == tEdge2.Next)
                    {
                        break;
                    }
                    if (tEdge2 == tEdge)
                    {
                        tEdge = tEdge2.Next;
                    }
                    tEdge2 = RemoveEdge(tEdge2);
                    tEdge3 = tEdge2;
                }
                else
                {
                    if (tEdge2.Prev == tEdge2.Next)
                    {
                        break;
                    }
                    if (Closed && SlopesEqual(tEdge2.Prev.Curr, tEdge2.Curr, tEdge2.Next.Curr, m_UseFullRange) && (!PreserveCollinear || !Pt2IsBetweenPt1AndPt3(tEdge2.Prev.Curr, tEdge2.Curr, tEdge2.Next.Curr)))
                    {
                        if (tEdge2 == tEdge)
                        {
                            tEdge = tEdge2.Next;
                        }
                        tEdge2 = RemoveEdge(tEdge2);
                        tEdge2 = tEdge2.Prev;
                        tEdge3 = tEdge2;
                    }
                    else
                    {
                        tEdge2 = tEdge2.Next;
                        if (tEdge2 == tEdge3 || (!Closed && tEdge2.Next == tEdge))
                        {
                            break;
                        }
                    }
                }
            }
            if ((!Closed && tEdge2 == tEdge2.Next) || (Closed && tEdge2.Prev == tEdge2.Next))
            {
                return(false);
            }
            if (!Closed)
            {
                m_HasOpenPaths    = true;
                tEdge.Prev.OutIdx = -2;
            }
            tEdge2 = tEdge;
            do
            {
                InitEdge2(tEdge2, polyType);
                tEdge2 = tEdge2.Next;
                if (flag && tEdge2.Curr.Y != tEdge.Curr.Y)
                {
                    flag = false;
                }
            }while (tEdge2 != tEdge);
            if (flag)
            {
                if (Closed)
                {
                    return(false);
                }
                tEdge2.Prev.OutIdx = -2;
                if (tEdge2.Prev.Bot.X < tEdge2.Prev.Top.X)
                {
                    ReverseHorizontal(tEdge2.Prev);
                }
                LocalMinima localMinima = new LocalMinima();
                localMinima.Next                 = null;
                localMinima.Y                    = tEdge2.Bot.Y;
                localMinima.LeftBound            = null;
                localMinima.RightBound           = tEdge2;
                localMinima.RightBound.Side      = EdgeSide.esRight;
                localMinima.RightBound.WindDelta = 0;
                while (tEdge2.Next.OutIdx != -2)
                {
                    tEdge2.NextInLML = tEdge2.Next;
                    if (tEdge2.Bot.X != tEdge2.Prev.Top.X)
                    {
                        ReverseHorizontal(tEdge2);
                    }
                    tEdge2 = tEdge2.Next;
                }
                InsertLocalMinima(localMinima);
                m_edges.Add(list);
                return(true);
            }
            m_edges.Add(list);
            TEdge tEdge4 = null;

            if (tEdge2.Prev.Bot == tEdge2.Prev.Top)
            {
                tEdge2 = tEdge2.Next;
            }
            while (true)
            {
                tEdge2 = FindNextLocMin(tEdge2);
                if (tEdge2 == tEdge4)
                {
                    break;
                }
                if (tEdge4 == null)
                {
                    tEdge4 = tEdge2;
                }
                LocalMinima localMinima2 = new LocalMinima();
                localMinima2.Next = null;
                localMinima2.Y    = tEdge2.Bot.Y;
                bool flag2;
                if (tEdge2.Dx < tEdge2.Prev.Dx)
                {
                    localMinima2.LeftBound  = tEdge2.Prev;
                    localMinima2.RightBound = tEdge2;
                    flag2 = false;
                }
                else
                {
                    localMinima2.LeftBound  = tEdge2;
                    localMinima2.RightBound = tEdge2.Prev;
                    flag2 = true;
                }
                localMinima2.LeftBound.Side  = EdgeSide.esLeft;
                localMinima2.RightBound.Side = EdgeSide.esRight;
                if (!Closed)
                {
                    localMinima2.LeftBound.WindDelta = 0;
                }
                else if (localMinima2.LeftBound.Next == localMinima2.RightBound)
                {
                    localMinima2.LeftBound.WindDelta = -1;
                }
                else
                {
                    localMinima2.LeftBound.WindDelta = 1;
                }
                localMinima2.RightBound.WindDelta = -localMinima2.LeftBound.WindDelta;
                tEdge2 = ProcessBound(localMinima2.LeftBound, flag2);
                if (tEdge2.OutIdx == -2)
                {
                    tEdge2 = ProcessBound(tEdge2, flag2);
                }
                TEdge tEdge5 = ProcessBound(localMinima2.RightBound, !flag2);
                if (tEdge5.OutIdx == -2)
                {
                    tEdge5 = ProcessBound(tEdge5, !flag2);
                }
                if (localMinima2.LeftBound.OutIdx == -2)
                {
                    localMinima2.LeftBound = null;
                }
                else if (localMinima2.RightBound.OutIdx == -2)
                {
                    localMinima2.RightBound = null;
                }
                InsertLocalMinima(localMinima2);
                if (!flag2)
                {
                    tEdge2 = tEdge5;
                }
            }
            return(true);
        }
 //------------------------------------------------------------------------------
 internal bool SlopesEqual(TEdge e1, TEdge e2, bool UseFulllongRange)
 {
     if (e1.ybot == e1.ytop) return (e2.ybot == e2.ytop);
     else if (e1.xbot == e1.xtop) return (e2.xbot == e2.xtop);
     else if (UseFulllongRange)
       return Int128.Int128Mul(e1.ytop - e1.ybot, e2.xtop - e2.xbot) ==
           Int128.Int128Mul(e1.xtop - e1.xbot, e2.ytop - e2.ybot);
     else return (Int64)(e1.ytop - e1.ybot) * (e2.xtop - e2.xbot) -
       (Int64)(e1.xtop - e1.xbot)*(e2.ytop - e2.ybot) == 0;
 }
 internal static bool IsHorizontal(TEdge e)
 {
     return(e.Delta.Y == 0);
 }
 //------------------------------------------------------------------------------
 private void InitEdge(TEdge e, TEdge eNext,
   TEdge ePrev, IntPoint pt, PolyType polyType)
 {
     e.next = eNext;
       e.prev = ePrev;
       e.xcurr = pt.X;
       e.ycurr = pt.Y;
       if (e.ycurr >= e.next.ycurr)
       {
     e.xbot = e.xcurr;
     e.ybot = e.ycurr;
     e.xtop = e.next.xcurr;
     e.ytop = e.next.ycurr;
     e.windDelta = 1;
       } else
       {
     e.xtop = e.xcurr;
     e.ytop = e.ycurr;
     e.xbot = e.next.xcurr;
     e.ybot = e.next.ycurr;
     e.windDelta = -1;
       }
       SetDx(e);
       e.polyType = polyType;
       e.outIdx = -1;
 }
 private void ReverseHorizontal(TEdge e)
 {
     Swap(ref e.Top.X, ref e.Bot.X);
 }
 //------------------------------------------------------------------------------
 private void SwapX(TEdge 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.]
       e.xcurr = e.xtop;
       e.xtop = e.xbot;
       e.xbot = e.xcurr;
 }
 //------------------------------------------------------------------------------
 private void DeleteFromAEL(TEdge e)
 {
     TEdge AelPrev = e.prevInAEL;
     TEdge 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;
 }
 //------------------------------------------------------------------------------
 private static void SwapPolyIndexes(TEdge edge1, TEdge edge2)
 {
     int outIdx = edge1.outIdx;
     edge1.outIdx = edge2.outIdx;
     edge2.outIdx = outIdx;
 }
 /// <summary>
 /// Reset all fields to default values in preparation for object recycling
 /// </summary>
 public void PrepareForRecycle()
 {
     Y         = new cInt();
     LeftBound = RightBound = null;
     Next      = null;
 }
 //------------------------------------------------------------------------------
 private static Int64 TopX(TEdge edge, Int64 currentY)
 {
     if (currentY == edge.ytop)
         return edge.xtop;
     return edge.xbot + Round(edge.dx *(currentY - edge.ybot));
 }
 //------------------------------------------------------------------------------
 private bool IsTopHorz(TEdge horzEdge, double XPos)
 {
     TEdge e = m_SortedEdges;
     while (e != null)
     {
         if ((XPos >= Math.Min(e.xcurr, e.xtop)) && (XPos <= Math.Max(e.xcurr, e.xtop)))
             return false;
         e = e.nextInSEL;
     }
     return true;
 }
 //------------------------------------------------------------------------------
 private void AddHorzJoin(TEdge e, int idx)
 {
     HorzJoinRec hj = new HorzJoinRec();
     hj.edge = e;
     hj.savedIdx = idx;
     m_HorizJoins.Add(hj);
 }
        //------------------------------------------------------------------------------
        private void ProcessHorizontal(TEdge horzEdge)
        {
            Direction Direction;
            Int64 horzLeft, horzRight;

            if (horzEdge.xcurr < horzEdge.xtop)
            {
                horzLeft = horzEdge.xcurr;
                horzRight = horzEdge.xtop;
                Direction = Direction.dLeftToRight;
            }
            else
            {
                horzLeft = horzEdge.xtop;
                horzRight = horzEdge.xcurr;
                Direction = Direction.dRightToLeft;
            }

            TEdge eMaxPair;
            if (horzEdge.nextInLML != null)
                eMaxPair = null;
            else
                eMaxPair = GetMaximaPair(horzEdge);

            TEdge e = GetNextInAEL(horzEdge, Direction);
            while (e != null)
            {
                TEdge eNext = GetNextInAEL(e, Direction);
                if (eMaxPair != null ||
                  ((Direction == Direction.dLeftToRight) && (e.xcurr <= horzRight)) ||
                  ((Direction == Direction.dRightToLeft) && (e.xcurr >= horzLeft)))
                {
                    //ok, so far it looks like we're still in range of the horizontal edge
                    if (e.xcurr == horzEdge.xtop && eMaxPair == null)
                    {
                        if (SlopesEqual(e, horzEdge.nextInLML, m_UseFullRange))
                        {
                            //if output polygons share an edge, they'll need joining later ...
                            if (horzEdge.outIdx >= 0 && e.outIdx >= 0)
                                AddJoin(horzEdge.nextInLML, e, horzEdge.outIdx, -1);
                            break; //we've reached the end of the horizontal line
                        }
                        else if (e.dx < horzEdge.nextInLML.dx)
                            //we really have got to the end of the intermediate horz edge so quit.
                            //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal.
                            break;
                    }

                    if (e == eMaxPair)
                    {
                        //horzEdge is evidently a maxima horizontal and we've arrived at its end.
                        if (Direction == Direction.dLeftToRight)
                            IntersectEdges(horzEdge, e, new IntPoint(e.xcurr, horzEdge.ycurr), 0);
                        else
                            IntersectEdges(e, horzEdge, new IntPoint(e.xcurr, horzEdge.ycurr), 0);
                        if (eMaxPair.outIdx >= 0) throw new ClipperException("ProcessHorizontal error");
                        return;
                    }
                    else if (e.dx == horizontal && !IsMinima(e) && !(e.xcurr > e.xtop))
                    {
                        if (Direction == Direction.dLeftToRight)
                            IntersectEdges(horzEdge, e, new IntPoint(e.xcurr, horzEdge.ycurr),
                              (IsTopHorz(horzEdge, e.xcurr)) ? Protects.ipLeft : Protects.ipBoth);
                        else
                            IntersectEdges(e, horzEdge, new IntPoint(e.xcurr, horzEdge.ycurr),
                              (IsTopHorz(horzEdge, e.xcurr)) ? Protects.ipRight : Protects.ipBoth);
                    }
                    else if (Direction == Direction.dLeftToRight)
                    {
                        IntersectEdges(horzEdge, e, new IntPoint(e.xcurr, horzEdge.ycurr),
                          (IsTopHorz(horzEdge, e.xcurr)) ? Protects.ipLeft : Protects.ipBoth);
                    }
                    else
                    {
                        IntersectEdges(e, horzEdge, new IntPoint(e.xcurr, horzEdge.ycurr),
                          (IsTopHorz(horzEdge, e.xcurr)) ? Protects.ipRight : Protects.ipBoth);
                    }
                    SwapPositionsInAEL(horzEdge, e);
                }
                else if ( (Direction == Direction.dLeftToRight &&
                    e.xcurr > horzRight && horzEdge.nextInSEL == null) ||
                    (Direction == Direction.dRightToLeft &&
                    e.xcurr < horzLeft && horzEdge.nextInSEL == null) ) break;
                e = eNext;
            } //end while ( e )

            if (horzEdge.nextInLML != null)
            {
                if (horzEdge.outIdx >= 0)
                    AddOutPt(horzEdge, null, new IntPoint(horzEdge.xtop, horzEdge.ytop));
                UpdateEdgeIntoAEL(ref horzEdge);
            }
            else
            {
                if (horzEdge.outIdx >= 0)
                    IntersectEdges(horzEdge, eMaxPair,
                        new IntPoint(horzEdge.xtop, horzEdge.ycurr), Protects.ipBoth);
                DeleteFromAEL(eMaxPair);
                DeleteFromAEL(horzEdge);
            }
        }
 //------------------------------------------------------------------------------
 private void AddJoin(TEdge e1, TEdge e2, int e1OutIdx, int e2OutIdx)
 {
     JoinRec jr = new JoinRec();
     if (e1OutIdx >= 0)
         jr.poly1Idx = e1OutIdx; else
     jr.poly1Idx = e1.outIdx;
     jr.pt1a = new IntPoint(e1.xcurr, e1.ycurr);
     jr.pt1b = new IntPoint(e1.xtop, e1.ytop);
     if (e2OutIdx >= 0)
         jr.poly2Idx = e2OutIdx; else
         jr.poly2Idx = e2.outIdx;
     jr.pt2a = new IntPoint(e2.xcurr, e2.ycurr);
     jr.pt2b = new IntPoint(e2.xtop, e2.ytop);
     m_Joins.Add(jr);
 }
 //------------------------------------------------------------------------------
 private bool ProcessIntersections(Int64 botY, Int64 topY)
 {
     if( m_ActiveEdges == null ) return true;
       try {
     BuildIntersectList(botY, topY);
     if ( m_IntersectNodes == null) return true;
     if ( FixupIntersections() ) ProcessIntersectList();
     else return false;
       }
       catch {
     m_SortedEdges = null;
     DisposeIntersectNodes();
     throw new ClipperException("ProcessIntersections error");
       }
       return true;
 }
 //------------------------------------------------------------------------------
 private void AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt)
 {
     if (e2.dx == horizontal || (e1.dx > e2.dx))
     {
         AddOutPt(e1, e2, pt);
         e2.outIdx = e1.outIdx;
         e1.side = EdgeSide.esLeft;
         e2.side = EdgeSide.esRight;
     }
     else
     {
         AddOutPt(e2, e1, pt);
         e1.outIdx = e2.outIdx;
         e1.side = EdgeSide.esRight;
         e2.side = EdgeSide.esLeft;
     }
 }
 //------------------------------------------------------------------------------
 private void SetHoleState(TEdge e, OutRec outRec)
 {
     bool isHole = false;
     TEdge e2 = e.prevInAEL;
     while (e2 != null)
     {
         if (e2.outIdx >= 0)
         {
             isHole = !isHole;
             if (outRec.FirstLeft == null)
                 outRec.FirstLeft = m_PolyOuts[e2.outIdx];
         }
         e2 = e2.prevInAEL;
     }
     if (isHole) outRec.isHole = true;
 }
        //------------------------------------------------------------------------------
        private void AppendPolygon(TEdge e1, TEdge e2)
        {
            //get the start and ends of both output polygons ...
              OutRec outRec1 = m_PolyOuts[e1.outIdx];
              OutRec outRec2 = m_PolyOuts[e2.outIdx];

              //work out which polygon fragment has the correct hole state ...
              OutRec holeStateRec = GetLowermostRec(outRec1, outRec2);

              //fixup hole status ...
              if (holeStateRec == outRec2)
            outRec1.isHole = outRec2.isHole;
              else
            outRec2.isHole = outRec1.isHole;

              OutPt p1_lft = outRec1.pts;
              OutPt p1_rt = p1_lft.prev;
              OutPt p2_lft = outRec2.pts;
              OutPt p2_rt = p2_lft.prev;

            EdgeSide side;
              //join e2 poly onto e1 poly and delete pointers to e2 ...
              if(  e1.side == EdgeSide.esLeft )
              {
            if (e2.side == EdgeSide.esLeft)
            {
              //z y x a b c
              ReversePolyPtLinks(p2_lft);
              p2_lft.next = p1_lft;
              p1_lft.prev = p2_lft;
              p1_rt.next = p2_rt;
              p2_rt.prev = p1_rt;
              outRec1.pts = p2_rt;
            } else
            {
              //x y z a b c
              p2_rt.next = p1_lft;
              p1_lft.prev = p2_rt;
              p2_lft.prev = p1_rt;
              p1_rt.next = p2_lft;
              outRec1.pts = p2_lft;
            }
            side = EdgeSide.esLeft;
              } else
              {
            if (e2.side == EdgeSide.esRight)
            {
              //a b c z y x
              ReversePolyPtLinks( p2_lft );
              p1_rt.next = p2_rt;
              p2_rt.prev = p1_rt;
              p2_lft.next = p1_lft;
              p1_lft.prev = p2_lft;
            } else
            {
              //a b c x y z
              p1_rt.next = p2_lft;
              p2_lft.prev = p1_rt;
              p1_lft.prev = p2_rt;
              p2_rt.next = p1_lft;
            }
            side = EdgeSide.esRight;
              }

              if (holeStateRec == outRec2)
              {
              outRec1.bottomPt = outRec2.bottomPt;
              outRec1.bottomPt.idx = outRec1.idx;
              outRec1.bottomE1 = outRec2.bottomE1;
              outRec1.bottomE2 = outRec2.bottomE2;
              if (outRec2.FirstLeft != outRec1)
                  outRec1.FirstLeft = outRec2.FirstLeft;
              }
              outRec2.pts = null;
              outRec2.bottomPt = null;
              outRec2.AppendLink = outRec1;
              int OKIdx = e1.outIdx;
              int ObsoleteIdx = e2.outIdx;

              e1.outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly
              e2.outIdx = -1;

              TEdge e = m_ActiveEdges;
              while( e != null )
              {
            if( e.outIdx == ObsoleteIdx )
            {
              e.outIdx = OKIdx;
              e.side = side;
              break;
            }
            e = e.nextInAEL;
              }

              for (int i = 0; i < m_Joins.Count; ++i)
              {
              if (m_Joins[i].poly1Idx == ObsoleteIdx) m_Joins[i].poly1Idx = OKIdx;
              if (m_Joins[i].poly2Idx == ObsoleteIdx) m_Joins[i].poly2Idx = OKIdx;
              }

              for (int i = 0; i < m_HorizJoins.Count; ++i)
              {
              if (m_HorizJoins[i].savedIdx == ObsoleteIdx)
                m_HorizJoins[i].savedIdx = OKIdx;
              }
        }
        //------------------------------------------------------------------------------
        private void SetWindingCount(TEdge edge)
        {
            TEdge e = edge.prevInAEL;
            //find the edge of the same polytype that immediately preceeds 'edge' in AEL
            while (e != null && e.polyType != edge.polyType)
                e = e.prevInAEL;
            if (e == null)
            {
                edge.windCnt = edge.windDelta;
                edge.windCnt2 = 0;
                e = m_ActiveEdges; //ie get ready to calc windCnt2
            }
            else if (IsEvenOddFillType(edge))
            {
                //even-odd filling ...
                edge.windCnt = 1;
                edge.windCnt2 = e.windCnt2;
                e = e.nextInAEL; //ie get ready to calc windCnt2
            }
            else
            {
                //nonZero filling ...
                if (e.windCnt * e.windDelta < 0)
                {
                    if (Math.Abs(e.windCnt) > 1)
                    {
                        if (e.windDelta * edge.windDelta < 0)
                            edge.windCnt = e.windCnt;
                        else
                            edge.windCnt = e.windCnt + edge.windDelta;
                    }
                    else
                        edge.windCnt = e.windCnt + e.windDelta + edge.windDelta;
                }
                else
                {
                    if (Math.Abs(e.windCnt) > 1 && e.windDelta * edge.windDelta < 0)
                        edge.windCnt = e.windCnt;
                    else if (e.windCnt + edge.windDelta == 0)
                        edge.windCnt = e.windCnt;
                    else
                        edge.windCnt = e.windCnt + edge.windDelta;
                }
                edge.windCnt2 = e.windCnt2;
                e = e.nextInAEL; //ie get ready to calc windCnt2
            }

            //update windCnt2 ...
            if (IsEvenOddAltFillType(edge))
            {
                //even-odd filling ...
                while (e != edge)
                {
                    edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
                    e = e.nextInAEL;
                }
            }
            else
            {
                //nonZero filling ...
                while (e != edge)
                {
                    edge.windCnt2 += e.windDelta;
                    e = e.nextInAEL;
                }
            }
        }
 //------------------------------------------------------------------------------
 private void CopyAELToSEL()
 {
     TEdge e = m_ActiveEdges;
     m_SortedEdges = e;
     if (m_ActiveEdges == null)
         return;
     m_SortedEdges.prevInSEL = null;
     e = e.nextInAEL;
     while (e != null)
     {
         e.prevInSEL = e.prevInAEL;
         e.prevInSEL.nextInSEL = e;
         e.nextInSEL = null;
         e = e.nextInAEL;
     }
 }
예제 #56
0
        //------------------------------------------------------------------------------

        public bool AddPath(List <IntPoint> pg, PolyType polyType, bool Closed)
        {
#if use_lines
            if (!Closed && polyType == PolyType.ptClip)
            {
                throw new ClipperException("AddPath: Open paths must be subject.");
            }
#else
            if (!Closed)
            {
                throw new ClipperException("AddPath: Open paths have been disabled.");
            }
#endif

            int  highI = (int)pg.Count - 1;
            bool ClosedOrSemiClosed = (highI > 0) && (Closed || (pg[0] == pg[highI]));
            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 <TEdge> edges = new List <TEdge>(highI + 1);
            for (int i = 0; i <= highI; i++)
            {
                edges.Add(new TEdge());
            }

            //1. Basic initialization of Edges ...
            try
            {
                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]);
                }
            }
            catch
            {
                return(false); //almost certainly a vertex has exceeded range
            };

            TEdge eStart = edges[0];
            if (!ClosedOrSemiClosed)
            {
                eStart.Prev.OutIdx = Skip;
            }

            //2. Remove duplicate vertices, and collinear edges (when closed) ...
            TEdge E = eStart, eLoopStop = eStart;
            for (; ;)
            {
                if (E.Curr == E.Next.Curr)
                {
                    //nb if E.OutIdx == Skip, it would have been semiOpen
                    if (E == eStart)
                    {
                        eStart = E.Next;
                    }
                    E         = RemoveEdge(E);
                    eLoopStop = E;
                    continue;
                }
                if (E.Prev == E.Next)
                {
                    break; //only two vertices
                }
                else if ((ClosedOrSemiClosed ||
                          (E.Prev.OutIdx != Skip && E.OutIdx != Skip &&
                           E.Next.OutIdx != Skip)) &&
                         SlopesEqual(E.Prev.Curr, E.Curr, E.Next.Curr, m_UseFullRange))
                {
                    //All collinear edges are allowed for open paths but in closed paths
                    //inner vertices of adjacent collinear edges are removed. However if the
                    //PreserveCollinear property has been enabled, only overlapping collinear
                    //edges (ie spikes) are removed from closed paths.
                    if (Closed && (!PreserveCollinear ||
                                   !Pt2IsBetweenPt1AndPt3(E.Prev.Curr, E.Curr, E.Next.Curr)))
                    {
                        if (E == eStart)
                        {
                            eStart = E.Next;
                        }
                        E         = RemoveEdge(E);
                        E         = E.Prev;
                        eLoopStop = E;
                        continue;
                    }
                }
                E = E.Next;
                if (E == eLoopStop)
                {
                    break;
                }
            }

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

            if (!Closed)
            {
                m_HasOpenPaths = true;
            }

            //3. Do final Init and also find the 'highest' Edge. (nb: since I'm much
            //more familiar with positive downwards Y axes, 'highest' here will be
            //the Edge with the *smallest* Top.Y.)
            TEdge eHighest = eStart;
            E = eStart;
            do
            {
                InitEdge2(E, polyType);
                if (E.Top.Y < eHighest.Top.Y)
                {
                    eHighest = E;
                }
                E = E.Next;
            }while (E != eStart);

            //4. build the local minima list ...
            if (AllHorizontal(E))
            {
                if (ClosedOrSemiClosed)
                {
                    E.Prev.OutIdx = Skip;
                }
                AscendToMax(ref E, false, false);
                return(true);
            }

            //if eHighest is also the Skip then it's a natural break, otherwise
            //make sure eHighest is positioned so we're either at a top horizontal or
            //just starting to head down one edge of the polygon
            E = eStart.Prev; //EStart.Prev == Skip edge
            if (E.Prev == E.Next)
            {
                eHighest = E.Next;
            }
            else if (!ClosedOrSemiClosed && E.Top.Y == eHighest.Top.Y)
            {
                if ((IsHorizontal(E) || IsHorizontal(E.Next)) &&
                    E.Next.Bot.Y == eHighest.Top.Y)
                {
                    eHighest = E.Next;
                }
                else if (SharedVertWithPrevAtTop(E))
                {
                    eHighest = E;
                }
                else if (E.Top == E.Prev.Top)
                {
                    eHighest = E.Prev;
                }
                else
                {
                    eHighest = E.Next;
                }
            }
            else
            {
                E = eHighest;
                while (IsHorizontal(eHighest) ||
                       (eHighest.Top == eHighest.Next.Top) ||
                       (eHighest.Top == eHighest.Next.Bot)) //next is high horizontal
                {
                    eHighest = eHighest.Next;
                    if (eHighest == E)
                    {
                        while (IsHorizontal(eHighest) || !SharedVertWithPrevAtTop(eHighest))
                        {
                            eHighest = eHighest.Next;
                        }
                        break; //avoids potential endless loop
                    }
                }
            }
            E = eHighest;
            do
            {
                E = AddBoundsToLML(E, Closed);
            }while (E != eHighest);
            return(true);
        }
 //------------------------------------------------------------------------------
 private void DeleteFromSEL(TEdge e)
 {
     TEdge SelPrev = e.prevInSEL;
     TEdge SelNext = e.nextInSEL;
     if (SelPrev == null && SelNext == null && (e != m_SortedEdges))
         return; //already deleted
     if (SelPrev != null)
         SelPrev.nextInSEL = SelNext;
     else m_SortedEdges = SelNext;
     if (SelNext != null)
         SelNext.prevInSEL = SelPrev;
     e.nextInSEL = null;
     e.prevInSEL = null;
 }
 //------------------------------------------------------------------------------
 private bool IsMinima(TEdge e)
 {
     return e != null && (e.prev.nextInLML != e) && (e.next.nextInLML != e);
 }