private bool JustBeforeLocMin(TEdge Edge) { TEdge e = Edge; if (!IsHorizontal(e)) { return(this.SharedVertWithNextIsBot(e)); } while (IsHorizontal(e.Next)) { e = e.Next; } return(e.Next.Top.Y < e.Bot.Y); }
private bool JustBeforeLocMin(TEdge Edge) { TEdge tEdge = Edge; if (ClipperBase.IsHorizontal(tEdge)) { while (ClipperBase.IsHorizontal(tEdge.Next)) { tEdge = tEdge.Next; } return(tEdge.Next.Top.Y < tEdge.Bot.Y); } return(this.SharedVertWithNextIsBot(tEdge)); }
private bool MoreAbove(TEdge Edge) { if (IsHorizontal(Edge)) { Edge = this.GetLastHorz(Edge); return(Edge.Next.Top.Y < Edge.Top.Y); } if (IsHorizontal(Edge.Next)) { Edge = this.GetLastHorz(Edge.Next); return(Edge.Next.Top.Y < Edge.Top.Y); } return(Edge.Next.Top.Y < Edge.Top.Y); }
private bool AllHorizontal(TEdge Edge) { if (!ClipperBase.IsHorizontal(Edge)) { return(false); } for (TEdge next = Edge.Next; next != Edge; next = next.Next) { if (!ClipperBase.IsHorizontal(next)) { return(false); } } return(true); }
private bool AllHorizontal(TEdge Edge) { if (!IsHorizontal(Edge)) { return(false); } for (TEdge edge = Edge.Next; edge != Edge; edge = edge.Next) { if (!IsHorizontal(edge)) { return(false); } } return(true); }
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; } this.SetDx(e); e.PolyTyp = polyType; }
private bool MoreBelow(TEdge Edge) { TEdge e = Edge; if (IsHorizontal(e)) { while (IsHorizontal(e.Next)) { e = e.Next; } return(e.Next.Bot.Y > e.Bot.Y); } if (!IsHorizontal(e.Next)) { return(e.Bot == e.Next.Top); } while (IsHorizontal(e.Next)) { e = e.Next; } return(e.Next.Bot.Y > e.Bot.Y); }
private bool MoreBelow(TEdge Edge) { TEdge tEdge = Edge; if (ClipperBase.IsHorizontal(tEdge)) { while (ClipperBase.IsHorizontal(tEdge.Next)) { tEdge = tEdge.Next; } return(tEdge.Next.Bot.Y > tEdge.Bot.Y); } if (ClipperBase.IsHorizontal(tEdge.Next)) { while (ClipperBase.IsHorizontal(tEdge.Next)) { tEdge = tEdge.Next; } return(tEdge.Next.Bot.Y > tEdge.Bot.Y); } return(tEdge.Bot == tEdge.Next.Top); }
private void AscendToMax(ref TEdge E, bool Appending, bool IsClosed) { if (E.OutIdx == -2) { E = E.Next; if (!this.MoreAbove(E.Prev)) { return; } } if ((IsHorizontal(E) && Appending) && (E.Bot != E.Prev.Bot)) { this.ReverseHorizontal(E); } TEdge next = E; while ((E.Next.OutIdx != -2) && ((E.Next.Top.Y != E.Top.Y) || IsHorizontal(E.Next))) { E.NextInLML = E.Next; E = E.Next; if (IsHorizontal(E) && (E.Bot.X != E.Prev.Top.X)) { this.ReverseHorizontal(E); } } if (!Appending) { if (next.OutIdx == -2) { next = next.Next; } if (next != E.Next) { this.DoMinimaLML(null, next, IsClosed); } } E = E.Next; }
private void AscendToMax(ref TEdge E, bool Appending, bool IsClosed) { if (E.OutIdx == -2) { E = E.Next; if (!this.MoreAbove(E.Prev)) { return; } } if (ClipperBase.IsHorizontal(E) && Appending && E.Bot != E.Prev.Bot) { this.ReverseHorizontal(E); } TEdge tEdge = E; while (E.Next.OutIdx != -2 && (E.Next.Top.Y != E.Top.Y || ClipperBase.IsHorizontal(E.Next))) { E.NextInLML = E.Next; E = E.Next; if (ClipperBase.IsHorizontal(E) && E.Bot.X != E.Prev.Top.X) { this.ReverseHorizontal(E); } } if (!Appending) { if (tEdge.OutIdx == -2) { tEdge = tEdge.Next; } if (tEdge != E.Next) { this.DoMinimaLML(null, tEdge, IsClosed); } } E = 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.Curr = e.Bot; e.PrevInAEL = AelPrev; e.NextInAEL = AelNext; if (!IsHorizontal(e)) InsertScanbeam(e.Top.Y); }
//------------------------------------------------------------------------------ private OutPt AddOutPt(TEdge e, IntPoint pt) { bool ToFront = (e.Side == EdgeSide.esLeft); if( e.OutIdx < 0 ) { OutRec outRec = CreateOutRec(); outRec.IsOpen = (e.WindDelta == 0); OutPt newOp = new OutPt(); outRec.Pts = newOp; newOp.Idx = outRec.Idx; newOp.Pt = pt; newOp.Next = newOp; newOp.Prev = newOp; if (!outRec.IsOpen) SetHoleState(e, outRec); #if use_xyz if (pt == e.Bot) newOp.Pt = e.Bot; else if (pt == e.Top) newOp.Pt = e.Top; else SetZ(ref newOp.Pt, e); #endif e.OutIdx = outRec.Idx; //nb: do this after SetZ ! return newOp; } else { OutRec outRec = m_PolyOuts[e.OutIdx]; //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' OutPt op = outRec.Pts; if (ToFront && pt == op.Pt) return op; else if (!ToFront && pt == op.Prev.Pt) return op.Prev; OutPt newOp = new OutPt(); newOp.Idx = outRec.Idx; newOp.Pt = pt; newOp.Next = op; newOp.Prev = op.Prev; newOp.Prev.Next = newOp; op.Prev = newOp; if (ToFront) outRec.Pts = newOp; #if use_xyz if (pt == e.Bot) newOp.Pt = e.Bot; else if (pt == e.Top) newOp.Pt = e.Top; else SetZ(ref newOp.Pt, e); #endif return newOp; } }
//------------------------------------------------------------------------------ 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]; OutRec holeStateRec; if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; else holeStateRec = GetLowermostRec(outRec1, outRec2); 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; } outRec1.BottomPt = null; if (holeStateRec == outRec2) { if (outRec2.FirstLeft != outRec1) outRec1.FirstLeft = outRec2.FirstLeft; outRec1.IsHole = outRec2.IsHole; } outRec2.Pts = null; outRec2.BottomPt = null; outRec2.FirstLeft = outRec1; int OKIdx = e1.OutIdx; int ObsoleteIdx = e2.OutIdx; e1.OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly e2.OutIdx = Unassigned; TEdge e = m_ActiveEdges; while( e != null ) { if( e.OutIdx == ObsoleteIdx ) { e.OutIdx = OKIdx; e.Side = side; break; } e = e.NextInAEL; } outRec2.Idx = outRec1.Idx; }
//------------------------------------------------------------------------------ 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; }
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; bool flag = num > 0 && (Closed || pg[0] == pg[num]); 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()); } try { list[1].Curr = pg[1]; this.RangeTest(pg[0], ref this.m_UseFullRange); this.RangeTest(pg[num], ref this.m_UseFullRange); this.InitEdge(list[0], list[1], list[num], pg[0]); this.InitEdge(list[num], list[0], list[num - 1], pg[num]); for (int j = num - 1; j >= 1; j--) { this.RangeTest(pg[j], ref this.m_UseFullRange); this.InitEdge(list[j], list[j + 1], list[j - 1], pg[j]); } } catch { bool result = false; return(result); } TEdge tEdge = list[0]; if (!flag) { tEdge.Prev.OutIdx = -2; } TEdge tEdge2 = tEdge; TEdge tEdge3 = tEdge; while (true) { if (tEdge2.Curr == tEdge2.Next.Curr) { if (tEdge2 == tEdge2.Next) { break; } if (tEdge2 == tEdge) { tEdge = tEdge2.Next; } tEdge2 = this.RemoveEdge(tEdge2); tEdge3 = tEdge2; } else { if (tEdge2.Prev == tEdge2.Next) { break; } if ((flag || (tEdge2.Prev.OutIdx != -2 && tEdge2.OutIdx != -2 && tEdge2.Next.OutIdx != -2)) && ClipperBase.SlopesEqual(tEdge2.Prev.Curr, tEdge2.Curr, tEdge2.Next.Curr, this.m_UseFullRange) && Closed && (!this.PreserveCollinear || !this.Pt2IsBetweenPt1AndPt3(tEdge2.Prev.Curr, tEdge2.Curr, tEdge2.Next.Curr))) { if (tEdge2 == tEdge) { tEdge = tEdge2.Next; } tEdge2 = this.RemoveEdge(tEdge2); tEdge2 = tEdge2.Prev; tEdge3 = tEdge2; } else { tEdge2 = tEdge2.Next; if (tEdge2 == tEdge3) { break; } } } } if ((!Closed && tEdge2 == tEdge2.Next) || (Closed && tEdge2.Prev == tEdge2.Next)) { return(false); } this.m_edges.Add(list); if (!Closed) { this.m_HasOpenPaths = true; } TEdge tEdge4 = tEdge; tEdge2 = tEdge; do { this.InitEdge2(tEdge2, polyType); if (tEdge2.Top.Y < tEdge4.Top.Y) { tEdge4 = tEdge2; } tEdge2 = tEdge2.Next; }while (tEdge2 != tEdge); if (this.AllHorizontal(tEdge2)) { if (flag) { tEdge2.Prev.OutIdx = -2; } this.AscendToMax(ref tEdge2, false, false); return(true); } tEdge2 = tEdge.Prev; if (tEdge2.Prev == tEdge2.Next) { tEdge4 = tEdge2.Next; } else if (!flag && tEdge2.Top.Y == tEdge4.Top.Y) { if ((ClipperBase.IsHorizontal(tEdge2) || ClipperBase.IsHorizontal(tEdge2.Next)) && tEdge2.Next.Bot.Y == tEdge4.Top.Y) { tEdge4 = tEdge2.Next; } else if (this.SharedVertWithPrevAtTop(tEdge2)) { tEdge4 = tEdge2; } else if (tEdge2.Top == tEdge2.Prev.Top) { tEdge4 = tEdge2.Prev; } else { tEdge4 = tEdge2.Next; } } else { tEdge2 = tEdge4; while (ClipperBase.IsHorizontal(tEdge4) || tEdge4.Top == tEdge4.Next.Top || tEdge4.Top == tEdge4.Next.Bot) { tEdge4 = tEdge4.Next; if (tEdge4 == tEdge2) { while (ClipperBase.IsHorizontal(tEdge4) || !this.SharedVertWithPrevAtTop(tEdge4)) { tEdge4 = tEdge4.Next; } break; } } } tEdge2 = tEdge4; do { tEdge2 = this.AddBoundsToLML(tEdge2, Closed); }while (tEdge2 != tEdge4); return(true); }
//------------------------------------------------------------------------------ private bool IsMaxima(TEdge e, double Y) { return (e != null && e.Top.Y == Y && e.NextInLML == null); }
//------------------------------------------------------------------------------ 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 (cInt)(e1.Delta.Y) * (e2.Delta.X) == (cInt)(e1.Delta.X) * (e2.Delta.Y); }
//------------------------------------------------------------------------------ private TEdge GetNextInAEL(TEdge e, Direction Direction) { return Direction == Direction.dLeftToRight ? e.NextInAEL: e.PrevInAEL; }
//------------------------------------------------------------------------------ private bool IsMinima(TEdge e) { return e != null && (e.Prev.NextInLML != e) && (e.Next.NextInLML != e); }
//------------------------------------------------------------------------------ private void ProcessHorizontal(TEdge horzEdge, bool isTopOfScanbeam) { Direction dir; cInt horzLeft, horzRight; GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); TEdge eLastHorz = horzEdge, eMaxPair = null; while (eLastHorz.NextInLML != null && IsHorizontal(eLastHorz.NextInLML)) eLastHorz = eLastHorz.NextInLML; if (eLastHorz.NextInLML == null) eMaxPair = GetMaximaPair(eLastHorz); for (;;) { bool IsLastHorz = (horzEdge == eLastHorz); TEdge e = GetNextInAEL(horzEdge, dir); while(e != null) { //Break if we've got to the end of an intermediate horizontal edge ... //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. if (e.Curr.X == horzEdge.Top.X && horzEdge.NextInLML != null && e.Dx < horzEdge.NextInLML.Dx) break; TEdge eNext = GetNextInAEL(e, dir); //saves eNext for later if ((dir == Direction.dLeftToRight && e.Curr.X <= horzRight) || (dir == Direction.dRightToLeft && e.Curr.X >= horzLeft)) { //so far we're still in range of the horizontal Edge but make sure //we're at the last of consec. horizontals when matching with eMaxPair if(e == eMaxPair && IsLastHorz) { if (horzEdge.OutIdx >= 0 && horzEdge.WindDelta != 0) PrepareHorzJoins(horzEdge, isTopOfScanbeam); if (dir == Direction.dLeftToRight) IntersectEdges(horzEdge, e, e.Top); else IntersectEdges(e, horzEdge, e.Top); if (eMaxPair.OutIdx >= 0) throw new ClipperException("ProcessHorizontal error"); return; } else if(dir == Direction.dLeftToRight) { IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y); IntersectEdges(horzEdge, e, Pt, true); } else { IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y); IntersectEdges(e, horzEdge, Pt, true); } SwapPositionsInAEL(horzEdge, e); } else if ((dir == Direction.dLeftToRight && e.Curr.X >= horzRight) || (dir == Direction.dRightToLeft && e.Curr.X <= horzLeft)) break; e = eNext; } //end while if (horzEdge.OutIdx >= 0 && horzEdge.WindDelta != 0) PrepareHorzJoins(horzEdge, isTopOfScanbeam); if (horzEdge.NextInLML != null && IsHorizontal(horzEdge.NextInLML)) { UpdateEdgeIntoAEL(ref horzEdge); if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Bot); GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight); } else break; } //end for (;;) if(horzEdge.NextInLML != null) { if(horzEdge.OutIdx >= 0) { OutPt op1 = AddOutPt( horzEdge, horzEdge.Top); UpdateEdgeIntoAEL(ref horzEdge); if (horzEdge.WindDelta == 0) return; //nb: HorzEdge is no longer horizontal here TEdge ePrev = horzEdge.PrevInAEL; TEdge eNext = horzEdge.NextInAEL; if (ePrev != null && ePrev.Curr.X == horzEdge.Bot.X && ePrev.Curr.Y == horzEdge.Bot.Y && ePrev.WindDelta != 0 && (ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && SlopesEqual(horzEdge, ePrev, m_UseFullRange))) { OutPt op2 = AddOutPt(ePrev, horzEdge.Bot); AddJoin(op1, op2, horzEdge.Top); } else if (eNext != null && eNext.Curr.X == horzEdge.Bot.X && eNext.Curr.Y == horzEdge.Bot.Y && eNext.WindDelta != 0 && eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && SlopesEqual(horzEdge, eNext, m_UseFullRange)) { OutPt op2 = AddOutPt(eNext, horzEdge.Bot); AddJoin(op1, op2, horzEdge.Top); } } else UpdateEdgeIntoAEL(ref horzEdge); } else if (eMaxPair != null) { if (eMaxPair.OutIdx >= 0) { if (dir == Direction.dLeftToRight) IntersectEdges(horzEdge, eMaxPair, horzEdge.Top); else IntersectEdges(eMaxPair, horzEdge, horzEdge.Top); if (eMaxPair.OutIdx >= 0) throw new ClipperException("ProcessHorizontal error"); } else { DeleteFromAEL(horzEdge); DeleteFromAEL(eMaxPair); } } else { if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Top); DeleteFromAEL(horzEdge); } }
//------------------------------------------------------------------------ void PrepareHorzJoins(TEdge horzEdge, bool isTopOfScanbeam) { //get the last Op for this horizontal edge //the point may be anywhere along the horizontal ... OutPt outPt = m_PolyOuts[horzEdge.OutIdx].Pts; if (horzEdge.Side != EdgeSide.esLeft) outPt = outPt.Prev; //First, match up overlapping horizontal edges (eg when one polygon's //intermediate horz edge overlaps an intermediate horz edge of another, or //when one polygon sits on top of another) ... for (int i = 0; i < m_GhostJoins.Count; ++i) { Join j = m_GhostJoins[i]; if (HorzSegmentsOverlap(j.OutPt1.Pt, j.OffPt, horzEdge.Bot, horzEdge.Top)) AddJoin(j.OutPt1, outPt, j.OffPt); } //Also, since horizontal edges at the top of one SB are often removed from //the AEL before we process the horizontal edges at the bottom of the next, //we need to create 'ghost' Join records of 'contrubuting' horizontals that //we can compare with horizontals at the bottom of the next SB. if (isTopOfScanbeam) if (outPt.Pt == horzEdge.Top) AddGhostJoin(outPt, horzEdge.Bot); else AddGhostJoin(outPt, horzEdge.Top); }
//------------------------------------------------------------------------------ void GetHorzDirection(TEdge HorzEdge, out Direction Dir, out cInt Left, out cInt Right) { if (HorzEdge.Bot.X < HorzEdge.Top.X) { Left = HorzEdge.Bot.X; Right = HorzEdge.Top.X; Dir = Direction.dLeftToRight; } else { Left = HorzEdge.Top.X; Right = HorzEdge.Bot.X; Dir = Direction.dRightToLeft; } }
//------------------------------------------------------------------------------ private void DoMaxima(TEdge e) { TEdge eMaxPair = GetMaximaPair(e); if (eMaxPair == null) { if (e.OutIdx >= 0) AddOutPt(e, e.Top); DeleteFromAEL(e); return; } TEdge eNext = e.NextInAEL; while(eNext != null && eNext != eMaxPair) { IntersectEdges(e, eNext, e.Top, true); SwapPositionsInAEL(e, eNext); eNext = e.NextInAEL; } if(e.OutIdx == Unassigned && eMaxPair.OutIdx == Unassigned) { DeleteFromAEL(e); DeleteFromAEL(eMaxPair); } else if( e.OutIdx >= 0 && eMaxPair.OutIdx >= 0 ) { IntersectEdges( e, eMaxPair, e.Top); } #if use_lines else if (e.WindDelta == 0) { if (e.OutIdx >= 0) { AddOutPt(e, e.Top); e.OutIdx = Unassigned; } DeleteFromAEL(e); if (eMaxPair.OutIdx >= 0) { AddOutPt(eMaxPair, e.Top); eMaxPair.OutIdx = Unassigned; } DeleteFromAEL(eMaxPair); } #endif else throw new ClipperException("DoMaxima error"); }
//------------------------------------------------------------------------------ private bool IsIntermediate(TEdge e, double Y) { return (e.Top.Y == Y && e.NextInLML != null); }
//------------------------------------------------------------------------------ internal static bool IsHorizontal(TEdge e) { return e.Delta.Y == 0; }
//------------------------------------------------------------------------------ private TEdge GetMaximaPair(TEdge e) { TEdge result = null; if ((e.Next.Top == e.Top) && e.Next.NextInLML == null) result = e.Next; else if ((e.Prev.Top == e.Top) && e.Prev.NextInLML == null) result = e.Prev; if (result != null && (result.OutIdx == Skip || (result.NextInAEL == result.PrevInAEL && !IsHorizontal(result)))) return null; return result; }
//------------------------------------------------------------------------------ private void InitEdge(TEdge e, TEdge eNext, TEdge ePrev, IntPoint pt) { e.Next = eNext; e.Prev = ePrev; e.Curr = pt; e.OutIdx = Unassigned; }
//------------------------------------------------------------------------------ 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; }
//------------------------------------------------------------------------------ TEdge RemoveEdge(TEdge e) { //removes e from double_linked_list (but without removing from memory) e.Prev.Next = e.Next; e.Next.Prev = e.Prev; TEdge result = e.Next; e.Prev = null; //flag as removed (see ClipperBase.Clear) return result; }
//------------------------------------------------------------------------------ private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, bool protect = false) { //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before //e2 in AEL except when e1 is being inserted at the intersection point ... bool e1stops = !protect && e1.NextInLML == null && e1.Top.X == pt.X && e1.Top.Y == pt.Y; bool e2stops = !protect && e2.NextInLML == null && e2.Top.X == pt.X && e2.Top.Y == pt.Y; bool e1Contributing = (e1.OutIdx >= 0); bool e2Contributing = (e2.OutIdx >= 0); #if use_lines //if either edge is on an OPEN path ... if (e1.WindDelta == 0 || e2.WindDelta == 0) { //ignore subject-subject open path intersections UNLESS they //are both open paths, AND they are both 'contributing maximas' ... if (e1.WindDelta == 0 && e2.WindDelta == 0) { if ((e1stops || e2stops) && e1Contributing && e2Contributing) AddLocalMaxPoly(e1, e2, pt); } //if intersecting a subj line with a subj poly ... else if (e1.PolyTyp == e2.PolyTyp && e1.WindDelta != e2.WindDelta && m_ClipType == ClipType.ctUnion) { if (e1.WindDelta == 0) { if (e2Contributing) { AddOutPt(e1, pt); if (e1Contributing) e1.OutIdx = Unassigned; } } else { if (e1Contributing) { AddOutPt(e2, pt); if (e2Contributing) e2.OutIdx = Unassigned; } } } else if (e1.PolyTyp != e2.PolyTyp) { if ((e1.WindDelta == 0) && Math.Abs(e2.WindCnt) == 1 && (m_ClipType != ClipType.ctUnion || e2.WindCnt2 == 0)) { AddOutPt(e1, pt); if (e1Contributing) e1.OutIdx = Unassigned; } else if ((e2.WindDelta == 0) && (Math.Abs(e1.WindCnt) == 1) && (m_ClipType != ClipType.ctUnion || e1.WindCnt2 == 0)) { AddOutPt(e2, pt); if (e2Contributing) e2.OutIdx = Unassigned; } } if (e1stops) if (e1.OutIdx < 0) DeleteFromAEL(e1); else throw new ClipperException("Error intersecting polylines"); if (e2stops) if (e2.OutIdx < 0) DeleteFromAEL(e2); else throw new ClipperException("Error intersecting polylines"); return; } #endif //update winding counts... //assumes that e1 will be to the Right of e2 ABOVE the intersection if (e1.PolyTyp == e2.PolyTyp) { if (IsEvenOddFillType(e1)) { int oldE1WindCnt = e1.WindCnt; e1.WindCnt = e2.WindCnt; e2.WindCnt = oldE1WindCnt; } else { if (e1.WindCnt + e2.WindDelta == 0) e1.WindCnt = -e1.WindCnt; else e1.WindCnt += e2.WindDelta; if (e2.WindCnt - e1.WindDelta == 0) e2.WindCnt = -e2.WindCnt; else e2.WindCnt -= e1.WindDelta; } } else { if (!IsEvenOddFillType(e2)) e1.WindCnt2 += e2.WindDelta; else e1.WindCnt2 = (e1.WindCnt2 == 0) ? 1 : 0; if (!IsEvenOddFillType(e1)) e2.WindCnt2 -= e1.WindDelta; else e2.WindCnt2 = (e2.WindCnt2 == 0) ? 1 : 0; } PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; if (e1.PolyTyp == PolyType.ptSubject) { e1FillType = m_SubjFillType; e1FillType2 = m_ClipFillType; } else { e1FillType = m_ClipFillType; e1FillType2 = m_SubjFillType; } if (e2.PolyTyp == PolyType.ptSubject) { e2FillType = m_SubjFillType; e2FillType2 = m_ClipFillType; } else { e2FillType = m_ClipFillType; e2FillType2 = m_SubjFillType; } int e1Wc, e2Wc; switch (e1FillType) { case PolyFillType.pftPositive: e1Wc = e1.WindCnt; break; case PolyFillType.pftNegative: e1Wc = -e1.WindCnt; break; default: e1Wc = Math.Abs(e1.WindCnt); break; } switch (e2FillType) { case PolyFillType.pftPositive: e2Wc = e2.WindCnt; break; case PolyFillType.pftNegative: e2Wc = -e2.WindCnt; break; default: e2Wc = Math.Abs(e2.WindCnt); break; } if (e1Contributing && e2Contributing) { if ( e1stops || e2stops || (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || (e1.PolyTyp != e2.PolyTyp && m_ClipType != ClipType.ctXor)) AddLocalMaxPoly(e1, e2, pt); else { AddOutPt(e1, pt); AddOutPt(e2, pt); SwapSides(e1, e2); SwapPolyIndexes(e1, e2); } } else if (e1Contributing) { if (e2Wc == 0 || e2Wc == 1) { AddOutPt(e1, pt); SwapSides(e1, e2); SwapPolyIndexes(e1, e2); } } else if (e2Contributing) { if (e1Wc == 0 || e1Wc == 1) { AddOutPt(e2, pt); SwapSides(e1, e2); SwapPolyIndexes(e1, e2); } } else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) { //neither edge is currently contributing ... cInt e1Wc2, e2Wc2; switch (e1FillType2) { case PolyFillType.pftPositive: e1Wc2 = e1.WindCnt2; break; case PolyFillType.pftNegative: e1Wc2 = -e1.WindCnt2; break; default: e1Wc2 = Math.Abs(e1.WindCnt2); break; } switch (e2FillType2) { case PolyFillType.pftPositive: e2Wc2 = e2.WindCnt2; break; case PolyFillType.pftNegative: e2Wc2 = -e2.WindCnt2; break; default: e2Wc2 = Math.Abs(e2.WindCnt2); break; } if (e1.PolyTyp != e2.PolyTyp) AddLocalMinPoly(e1, e2, pt); else if (e1Wc == 1 && e2Wc == 1) switch (m_ClipType) { case ClipType.ctIntersection: if (e1Wc2 > 0 && e2Wc2 > 0) AddLocalMinPoly(e1, e2, pt); break; case ClipType.ctUnion: if (e1Wc2 <= 0 && e2Wc2 <= 0) AddLocalMinPoly(e1, e2, pt); break; case ClipType.ctDifference: if (((e1.PolyTyp == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1.PolyTyp == PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) AddLocalMinPoly(e1, e2, pt); break; case ClipType.ctXor: AddLocalMinPoly(e1, e2, pt); break; } else SwapSides(e1, e2); } if ((e1stops != e2stops) && ((e1stops && (e1.OutIdx >= 0)) || (e2stops && (e2.OutIdx >= 0)))) { SwapSides(e1, e2); SwapPolyIndexes(e1, e2); } //finally, delete any non-contributing maxima edges ... if (e1stops) DeleteFromAEL(e1); if (e2stops) DeleteFromAEL(e2); }
//------------------------------------------------------------------------------ private static void SwapSides(TEdge edge1, TEdge edge2) { EdgeSide side = edge1.Side; edge1.Side = edge2.Side; edge2.Side = side; }
//------------------------------------------------------------------------------ private static void SwapPolyIndexes(TEdge edge1, TEdge edge2) { int outIdx = edge1.OutIdx; edge1.OutIdx = edge2.OutIdx; edge2.OutIdx = outIdx; }
//------------------------------------------------------------------------------ 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 OutPt AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt) { OutPt result; TEdge e, prevE; if (IsHorizontal(e2) || (e1.Dx > e2.Dx)) { result = AddOutPt(e1, pt); e2.OutIdx = e1.OutIdx; e1.Side = EdgeSide.esLeft; e2.Side = EdgeSide.esRight; e = e1; if (e.PrevInAEL == e2) prevE = e2.PrevInAEL; else prevE = e.PrevInAEL; } else { result = AddOutPt(e2, pt); e1.OutIdx = e2.OutIdx; e1.Side = EdgeSide.esRight; e2.Side = EdgeSide.esLeft; e = e2; if (e.PrevInAEL == e1) prevE = e1.PrevInAEL; else prevE = e.PrevInAEL; } if (prevE != null && prevE.OutIdx >= 0 && (TopX(prevE, pt.Y) == TopX(e, pt.Y)) && SlopesEqual(e, prevE, m_UseFullRange) && (e.WindDelta != 0) && (prevE.WindDelta != 0)) { OutPt outPt = AddOutPt(prevE, pt); AddJoin(result, outPt, e.Top); } return result; }
public IntRect GetBounds() { IntRect result = default(IntRect); LocalMinima localMinima = this.m_MinimaList; if (localMinima == null) { return(result); } result.left = localMinima.LeftBound.Bot.X; result.top = localMinima.LeftBound.Bot.Y; result.right = localMinima.LeftBound.Bot.X; result.bottom = localMinima.LeftBound.Bot.Y; while (localMinima != null) { if (localMinima.LeftBound.Bot.Y > result.bottom) { result.bottom = localMinima.LeftBound.Bot.Y; } TEdge tEdge = localMinima.LeftBound; while (true) { TEdge tEdge2 = tEdge; while (tEdge.NextInLML != null) { if (tEdge.Bot.X < result.left) { result.left = tEdge.Bot.X; } if (tEdge.Bot.X > result.right) { result.right = tEdge.Bot.X; } tEdge = tEdge.NextInLML; } if (tEdge.Bot.X < result.left) { result.left = tEdge.Bot.X; } if (tEdge.Bot.X > result.right) { result.right = tEdge.Bot.X; } if (tEdge.Top.X < result.left) { result.left = tEdge.Top.X; } if (tEdge.Top.X > result.right) { result.right = tEdge.Top.X; } if (tEdge.Top.Y < result.top) { result.top = tEdge.Top.Y; } if (tEdge2 != localMinima.LeftBound) { break; } tEdge = localMinima.RightBound; } localMinima = localMinima.Next; } return(result); }
//------------------------------------------------------------------------------ private bool IntersectPoint(TEdge edge1, TEdge edge2, out IntPoint ip) { ip = new IntPoint(); double b1, b2; //nb: with very large coordinate values, it's possible for SlopesEqual() to //return false but for the edge.Dx value be equal due to double precision rounding. if (SlopesEqual(edge1, edge2, m_UseFullRange) || edge1.Dx == edge2.Dx) { if (edge2.Bot.Y > edge1.Bot.Y) ip.Y = edge2.Bot.Y; else ip.Y = edge1.Bot.Y; return false; } else if (edge1.Delta.X == 0) { ip.X = edge1.Bot.X; if (IsHorizontal(edge2)) { ip.Y = edge2.Bot.Y; } else { b2 = edge2.Bot.Y - (edge2.Bot.X / edge2.Dx); ip.Y = Round(ip.X / edge2.Dx + b2); } } else if (edge2.Delta.X == 0) { ip.X = edge2.Bot.X; if (IsHorizontal(edge1)) { ip.Y = edge1.Bot.Y; } else { b1 = edge1.Bot.Y - (edge1.Bot.X / edge1.Dx); ip.Y = Round(ip.X / edge1.Dx + b1); } } else { b1 = edge1.Bot.X - edge1.Bot.Y * edge1.Dx; b2 = edge2.Bot.X - edge2.Bot.Y * edge2.Dx; double q = (b2 - b1) / (edge1.Dx - edge2.Dx); ip.Y = Round(q); if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx)) ip.X = Round(edge1.Dx * q + b1); else ip.X = Round(edge2.Dx * q + b2); } if (ip.Y < edge1.Top.Y || ip.Y < edge2.Top.Y) { if (edge1.Top.Y > edge2.Top.Y) { ip.Y = edge1.Top.Y; ip.X = TopX(edge2, edge1.Top.Y); return ip.X < edge1.Top.X; } else { ip.Y = edge2.Top.Y; ip.X = TopX(edge1, edge2.Top.Y); return ip.X > edge2.Top.X; } } else return true; }
//------------------------------------------------------------------------------ private bool ProcessIntersections(cInt botY, cInt topY) { if( m_ActiveEdges == null ) return true; try { BuildIntersectList(botY, topY); if ( m_IntersectNodes == null) return true; if (m_IntersectNodes.Next == null || FixupIntersectionOrder()) ProcessIntersectList(); else return false; } catch { m_SortedEdges = null; DisposeIntersectNodes(); throw new ClipperException("ProcessIntersections error"); } m_SortedEdges = null; 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; }
internal static bool IsHorizontal(TEdge e) { return(e.Delta.Y == 0L); }
//------------------------------------------------------------------------------ private void BuildIntersectList(cInt botY, cInt topY) { if ( m_ActiveEdges == null ) return; //prepare for sorting ... TEdge e = m_ActiveEdges; m_SortedEdges = e; while( e != null ) { e.PrevInSEL = e.PrevInAEL; e.NextInSEL = e.NextInAEL; e.Curr.X = 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; if (e.Curr.X > eNext.Curr.X) { if (!IntersectPoint(e, eNext, out pt) && e.Curr.X > eNext.Curr.X +1) throw new ClipperException("Intersection error"); if (pt.Y > botY) { pt.Y = botY; if (Math.Abs(e.Dx) > Math.Abs(eNext.Dx)) pt.X = TopX(eNext, botY); else pt.X = TopX(e, botY); } InsertIntersectNode(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 static cInt TopX(TEdge edge, cInt currentY) { if (currentY == edge.Top.Y) return edge.Top.X; return edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); }
//------------------------------------------------------------------------------ private void InsertIntersectNode(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 (newNode.Pt.Y > m_IntersectNodes.Pt.Y) { newNode.Next = m_IntersectNodes; m_IntersectNodes = newNode; } else { IntersectNode iNode = m_IntersectNodes; while (iNode.Next != null && newNode.Pt.Y < iNode.Next.Pt.Y) iNode = iNode.Next; newNode.Next = iNode.Next; iNode.Next = newNode; } }
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; bool flag = (num > 0) && (Closed || (pg[0] == pg[num])); 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> item = new List <TEdge>(num + 1); for (int i = 0; i <= num; i++) { item.Add(new TEdge()); } try { item[1].Curr = pg[1]; this.RangeTest(pg[0], ref this.m_UseFullRange); this.RangeTest(pg[num], ref this.m_UseFullRange); this.InitEdge(item[0], item[1], item[num], pg[0]); this.InitEdge(item[num], item[0], item[num - 1], pg[num]); for (int j = num - 1; j >= 1; j--) { this.RangeTest(pg[j], ref this.m_UseFullRange); this.InitEdge(item[j], item[j + 1], item[j - 1], pg[j]); } } catch { return(false); } TEdge next = item[0]; if (!flag) { next.Prev.OutIdx = -2; } TEdge e = next; TEdge edge3 = next; Label_01E7: while (e.Curr == e.Next.Curr) { if (e == e.Next) { goto Label_0342; } if (e == next) { next = e.Next; } e = this.RemoveEdge(e); edge3 = e; } if (e.Prev != e.Next) { if ((flag || (((e.Prev.OutIdx != -2) && (e.OutIdx != -2)) && (e.Next.OutIdx != -2))) && ((SlopesEqual(e.Prev.Curr, e.Curr, e.Next.Curr, this.m_UseFullRange) && Closed) && (!this.PreserveCollinear || !this.Pt2IsBetweenPt1AndPt3(e.Prev.Curr, e.Curr, e.Next.Curr)))) { if (e == next) { next = e.Next; } e = this.RemoveEdge(e).Prev; edge3 = e; goto Label_01E7; } e = e.Next; if (e != edge3) { goto Label_01E7; } } Label_0342: if ((!Closed && (e == e.Next)) || (Closed && (e.Prev == e.Next))) { return(false); } this.m_edges.Add(item); if (!Closed) { this.m_HasOpenPaths = true; } TEdge prev = next; e = next; do { this.InitEdge2(e, polyType); if (e.Top.Y < prev.Top.Y) { prev = e; } e = e.Next; }while (e != next); if (this.AllHorizontal(e)) { if (flag) { e.Prev.OutIdx = -2; } this.AscendToMax(ref e, false, false); return(true); } e = next.Prev; if (e.Prev == e.Next) { prev = e.Next; } else if (!flag && (e.Top.Y == prev.Top.Y)) { if ((IsHorizontal(e) || IsHorizontal(e.Next)) && (e.Next.Bot.Y == prev.Top.Y)) { prev = e.Next; } else if (this.SharedVertWithPrevAtTop(e)) { prev = e; } else if (e.Top == e.Prev.Top) { prev = e.Prev; } else { prev = e.Next; } } else { e = prev; while ((IsHorizontal(prev) || (prev.Top == prev.Next.Top)) || (prev.Top == prev.Next.Bot)) { prev = prev.Next; if (prev == e) { while (IsHorizontal(prev) || !this.SharedVertWithPrevAtTop(prev)) { prev = prev.Next; } break; } } } e = prev; do { e = this.AddBoundsToLML(e, Closed); }while (e != prev); return(true); }
//------------------------------------------------------------------------------ private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt) { AddOutPt(e1, pt); if (e1.OutIdx == e2.OutIdx) { e1.OutIdx = Unassigned; e2.OutIdx = Unassigned; } else if (e1.OutIdx < e2.OutIdx) AppendPolygon(e1, e2); else AppendPolygon(e2, e1); }