//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 }
//------------------------------------------------------------------------------ private void ProcessEdgesAtTopOfScanbeam(int topY) { TEdge e = m_ActiveEdges; while (e != null) { //1. process maxima, treating them as if they're 'bent' horizontal edges, // but exclude maxima with horizontal edges. nb: e can't be a horizontal. bool IsMaximaEdge = IsMaxima(e, topY); if (IsMaximaEdge) { TEdge eMaxPair = GetMaximaPairEx(e); IsMaximaEdge = (eMaxPair == null || !IsHorizontal(eMaxPair)); } if (IsMaximaEdge) { if (StrictlySimple) InsertMaxima(e.Top.X); TEdge ePrev = e.PrevInAEL; DoMaxima(e); if (ePrev == null) e = m_ActiveEdges; else e = ePrev.NextInAEL; } else { //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... if (IsIntermediate(e, topY) && IsHorizontal(e.NextInLML)) { UpdateEdgeIntoAEL(ref e); if (e.OutIdx >= 0) AddOutPt(e, e.Bot); AddEdgeToSEL(e); } else { e.Curr.X = TopX(e, topY); e.Curr.Y = topY; } //When StrictlySimple and 'e' is being touched by another edge, then //make sure both edges have a vertex here ... if (StrictlySimple) { TEdge ePrev = e.PrevInAEL; if ((e.OutIdx >= 0) && (e.WindDelta != 0) && ePrev != null && (ePrev.OutIdx >= 0) && (ePrev.Curr.X == e.Curr.X) && (ePrev.WindDelta != 0)) { IntPoint ip = new IntPoint(e.Curr); #if use_xyz SetZ(ref ip, ePrev, e); #endif OutPt op = AddOutPt(ePrev, ip); OutPt op2 = AddOutPt(e, ip); AddJoin(op, op2, ip); //StrictlySimple (type-3) join } } e = e.NextInAEL; } } //3. Process horizontals at the Top of the scanbeam ... ProcessHorizontals(); m_Maxima = null; //4. Promote intermediate vertices ... e = m_ActiveEdges; while (e != null) { if (IsIntermediate(e, topY)) { OutPt op = null; if (e.OutIdx >= 0) op = AddOutPt(e, e.Top); UpdateEdgeIntoAEL(ref e); //if output polygons share an edge, they'll need joining later ... TEdge ePrev = e.PrevInAEL; TEdge eNext = e.NextInAEL; if (ePrev != null && ePrev.Curr.X == e.Bot.X && ePrev.Curr.Y == e.Bot.Y && op != null && ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y && SlopesEqual(e.Curr, e.Top, ePrev.Curr, ePrev.Top, m_UseFullRange) && (e.WindDelta != 0) && (ePrev.WindDelta != 0)) { OutPt op2 = AddOutPt(ePrev, e.Bot); AddJoin(op, op2, e.Top); } else if (eNext != null && eNext.Curr.X == e.Bot.X && eNext.Curr.Y == e.Bot.Y && op != null && eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y && SlopesEqual(e.Curr, e.Top, eNext.Curr, eNext.Top, m_UseFullRange) && (e.WindDelta != 0) && (eNext.WindDelta != 0)) { OutPt op2 = AddOutPt(eNext, e.Bot); AddJoin(op, op2, e.Top); } } e = e.NextInAEL; } }
//------------------------------------------------------------------------------ private bool ExecuteInternal() { try { Reset(); m_SortedEdges = null; m_Maxima = null; int botY, topY; if (!PopScanbeam(out botY)) return false; InsertLocalMinimaIntoAEL(botY); while (PopScanbeam(out topY) || LocalMinimaPending()) { ProcessHorizontals(); m_GhostJoins.Clear(); if (!ProcessIntersections(topY)) return false; ProcessEdgesAtTopOfScanbeam(topY); botY = topY; InsertLocalMinimaIntoAEL(botY); } //fix orientations ... foreach (OutRec outRec in m_PolyOuts) { if (outRec.Pts == null || outRec.IsOpen) continue; if ((outRec.IsHole ^ ReverseSolution) == (Area(outRec) > 0)) ReversePolyPtLinks(outRec.Pts); } JoinCommonEdges(); foreach (OutRec outRec in m_PolyOuts) { if (outRec.Pts == null) continue; else if (outRec.IsOpen) FixupOutPolyline(outRec); else FixupOutPolygon(outRec); } if (StrictlySimple) DoSimplePolygons(); return true; } //catch { return false; } finally { m_Joins.Clear(); m_GhostJoins.Clear(); } }
//------------------------------------------------------------------------------ private void InsertMaxima(int X) { //double-linked list: sorted ascending, ignoring dups. Maxima newMax = new Maxima(); newMax.X = X; if (m_Maxima == null) { m_Maxima = newMax; m_Maxima.Next = null; m_Maxima.Prev = null; } else if (X < m_Maxima.X) { newMax.Next = m_Maxima; newMax.Prev = null; m_Maxima = newMax; } else { Maxima m = m_Maxima; while (m.Next != null && (X >= m.Next.X)) m = m.Next; if (X == m.X) return; //ie ignores duplicates (& CG to clean up newMax) //insert newMax between m and m.Next ... newMax.Next = m.Next; newMax.Prev = m; if (m.Next != null) m.Next.Prev = newMax; m.Next = newMax; } }
/// <summary> /// Reset all fields to default values in preparation for object recycling /// </summary> public void PrepareForRecycle() { X = new cInt(); Next = Prev = null; }