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