//constructor (nb: no external instantiation) //------------------------------------------------------------------------------ internal ClipperBase() { m_MinimaList = null; m_CurrentLM = null; m_UseFullRange = false; m_HasOpenPaths = false; }
protected virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM == null) { return; } 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 ClipperBase() //constructor (nb: no external instantiation) { m_MinimaList = null; m_CurrentLM = null; m_UseFullRange = false; m_HasOpenPaths = false; }
protected void PopLocalMinima() { if (m_CurrentLM != null) { m_CurrentLM = m_CurrentLM.Next; } }
internal ClipperBase() { m_MinimaList = null; m_CurrentLM = null; m_UseFullRange = false; m_HasOpenPaths = false; }
//------------------------------------------------------------------------------ internal virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM == null) { return; //ie nothing to process } //reset all edges ... m_Scanbeam = null; LocalMinima lm = m_MinimaList; while (lm != null) { InsertScanbeam(lm.Y); TEdge e = lm.LeftBound; if (e != null) { e.Curr = e.Bot; e.OutIdx = Unassigned; } e = lm.RightBound; if (e != null) { e.Curr = e.Bot; e.OutIdx = Unassigned; } lm = lm.Next; } m_ActiveEdges = null; }
internal virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM != null) { m_Scanbeam = null; for (LocalMinima localMinima = m_MinimaList; localMinima != null; localMinima = localMinima.Next) { InsertScanbeam(localMinima.Y); TEdge leftBound = localMinima.LeftBound; if (leftBound != null) { TEdge tEdge = leftBound; tEdge.Curr = tEdge.Bot; leftBound.OutIdx = -1; } leftBound = localMinima.RightBound; if (leftBound != null) { TEdge tEdge2 = leftBound; tEdge2.Curr = tEdge2.Bot; leftBound.OutIdx = -1; } } m_ActiveEdges = null; } }
//------------------------------------------------------------------------------ protected virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM == null) { return; //ie nothing to process } //reset all edges ... LocalMinima lm = m_MinimaList; while (lm != null) { TEdge e = lm.LeftBound; if (e != null) { e.Curr = e.Bot; e.Side = EdgeSide.esLeft; if (e.OutIdx != Skip) { e.OutIdx = Unassigned; } } e = lm.RightBound; e.Curr = e.Bot; e.Side = EdgeSide.esRight; if (e.OutIdx != Skip) { e.OutIdx = Unassigned; } lm = lm.Next; } }
//------------------------------------------------------------------------------ protected void PopLocalMinima() { if (m_CurrentLM == null) { return; } m_CurrentLM = m_CurrentLM.Next; }
//------------------------------------------------------------------------------ internal Boolean PopLocalMinima(int Y, out LocalMinima current) { current = m_CurrentLM; if (m_CurrentLM != null && m_CurrentLM.Y == Y) { m_CurrentLM = m_CurrentLM.Next; return(true); } return(false); }
private void DisposeLocalMinimaList() { while (m_MinimaList != null) { LocalMinima next = m_MinimaList.Next; m_MinimaList = null; m_MinimaList = next; } m_CurrentLM = null; }
private void InsertLocalMinima(LocalMinima newLm) { if (m_MinimaList == null) { m_MinimaList = newLm; } else if (newLm.Y >= m_MinimaList.Y) { newLm.Next = m_MinimaList; m_MinimaList = newLm; } else { LocalMinima localMinima = m_MinimaList; while (localMinima.Next != null && newLm.Y < localMinima.Next.Y) { localMinima = localMinima.Next; } newLm.Next = localMinima.Next; localMinima.Next = newLm; } }
//--------------------------------------------------------------------------- private void InsertLocalMinima(LocalMinima newLm) { if (m_MinimaList == null) { m_MinimaList = newLm; } else if (newLm.Y >= m_MinimaList.Y) { newLm.Next = m_MinimaList; m_MinimaList = newLm; } else { LocalMinima tmpLm = m_MinimaList; while (tmpLm.Next != null && (newLm.Y < tmpLm.Next.Y)) { tmpLm = tmpLm.Next; } newLm.Next = tmpLm.Next; tmpLm.Next = 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 virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM == null) return; //ie nothing to process //reset all edges ... m_Scanbeam = null; LocalMinima lm = m_MinimaList; while (lm != null) { InsertScanbeam(lm.Y); TEdge e = lm.LeftBound; if (e != null) { e.Curr = e.Bot; e.OutIdx = Unassigned; } e = lm.RightBound; if (e != null) { e.Curr = e.Bot; e.OutIdx = Unassigned; } lm = lm.Next; } m_ActiveEdges = null; }
//------------------------------------------------------------------------------ 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); }
//------------------------------------------------------------------------------ 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 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; }
//--------------------------------------------------------------------------- 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); } }
//------------------------------------------------------------------------------ protected virtual void Reset() { m_CurrentLM = m_MinimaList; if (m_CurrentLM == null) return; //ie nothing to process //reset all edges ... LocalMinima lm = m_MinimaList; while (lm != null) { TEdge e = lm.LeftBound; if (e != null) { e.Curr = e.Bot; e.Side = EdgeSide.esLeft; if (e.OutIdx != Skip) e.OutIdx = Unassigned; } e = lm.RightBound; e.Curr = e.Bot; e.Side = EdgeSide.esRight; if (e.OutIdx != Skip) e.OutIdx = Unassigned; lm = lm.Next; } }
//--------------------------------------------------------------------------- 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 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); }
//------------------------------------------------------------------------------ internal ClipperBase() //constructor (nb: no external instantiation) { m_MinimaList = null; m_CurrentLM = null; m_UseFullRange = false; }
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); }
//------------------------------------------------------------------------------ protected virtual void Reset() { m_CurrentLM = m_MinimaList; //reset all edges ... LocalMinima lm = m_MinimaList; while (lm != null) { TEdge e = lm.leftBound; while (e != null) { e.xcurr = e.xbot; e.ycurr = e.ybot; e.side = EdgeSide.esLeft; e.outIdx = -1; e = e.nextInLML; } e = lm.rightBound; while (e != null) { e.xcurr = e.xbot; e.ycurr = e.ybot; e.side = EdgeSide.esRight; e.outIdx = -1; e = e.nextInLML; } lm = lm.next; } return; }
//------------------------------------------------------------------------------ private void DisposeLocalMinimaList() { while( m_MinimaList != null ) { LocalMinima tmpLm = m_MinimaList.next; m_MinimaList = null; m_MinimaList = tmpLm; } m_CurrentLM = null; }
//------------------------------------------------------------------------------ internal Boolean PopLocalMinima(int Y, out LocalMinima current) { current = m_CurrentLM; if (m_CurrentLM != null && m_CurrentLM.Y == Y) { m_CurrentLM = m_CurrentLM.Next; return true; } return false; }
//------------------------------------------------------------------------------ protected void PopLocalMinima() { if (m_CurrentLM == null) return; m_CurrentLM = m_CurrentLM.next; }
//------------------------------------------------------------------------------ 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); }
//--------------------------------------------------------------------------- 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; }
//------------------------------------------------------------------------------ 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 InsertLocalMinima(LocalMinima newLm) { if( m_MinimaList == null ) { m_MinimaList = newLm; } else if( newLm.Y >= m_MinimaList.Y ) { newLm.next = m_MinimaList; m_MinimaList = newLm; } else { LocalMinima tmpLm = m_MinimaList; while( tmpLm.next != null && ( newLm.Y < tmpLm.next.Y ) ) tmpLm = tmpLm.next; newLm.next = tmpLm.next; tmpLm.next = newLm; } }
/// <summary> /// Reset all fields to default values in preparation for object recycling /// </summary> public void PrepareForRecycle() { Y = new cInt(); LeftBound = RightBound = null; Next = null; }