//------------------------------------------------------------------------------ private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt) { AddOutPt(e1, pt); if (e1.outIdx == e2.outIdx) { e1.outIdx = -1; e2.outIdx = -1; } else if (e1.outIdx < e2.outIdx) AppendPolygon(e1, e2); else AppendPolygon(e2, e1); }
//------------------------------------------------------------------------------ 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; }
//--------------------------------------------------------------------------- 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 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; } }
//------------------------------------------------------------------------------ private void DoMaxima(TEdge e, Int64 topY) { TEdge eMaxPair = GetMaximaPair(e); Int64 X = e.xtop; TEdge eNext = e.nextInAEL; while (eNext != eMaxPair) { if (eNext == null) throw new ClipperException("DoMaxima error"); IntersectEdges(e, eNext, new IntPoint(X, topY), Protects.ipBoth); SwapPositionsInAEL(e, eNext); eNext = e.nextInAEL; } if (e.outIdx < 0 && eMaxPair.outIdx < 0) { DeleteFromAEL(e); DeleteFromAEL(eMaxPair); } else if (e.outIdx >= 0 && eMaxPair.outIdx >= 0) { IntersectEdges(e, eMaxPair, new IntPoint(X, topY), Protects.ipNone); } else throw new ClipperException("DoMaxima error"); }
//------------------------------------------------------------------------------ private TEdge GetMaximaPair(TEdge e) { if (!IsMaxima(e.next, e.ytop) || (e.next.xtop != e.xtop)) return e.prev; else return e.next; }
//------------------------------------------------------------------------------ private void BuildIntersectList(Int64 botY, Int64 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.xcurr = 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.xcurr > eNext.xcurr) { if (!IntersectPoint(e, eNext, ref pt) && e.xcurr > eNext.xcurr + 1) throw new ClipperException("Intersection error"); if (pt.Y > botY) { pt.Y = botY; pt.X = TopX(e, pt.Y); } 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 void SwapPolyIndexes(TEdge edge1, TEdge edge2) { int outIdx = edge1.outIdx; edge1.outIdx = edge2.outIdx; edge2.outIdx = outIdx; }
//------------------------------------------------------------------------------ private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, Protects protects) { //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 = (Protects.ipLeft & protects) == 0 && e1.nextInLML == null && e1.xtop == pt.X && e1.ytop == pt.Y; bool e2stops = (Protects.ipRight & protects) == 0 && e2.nextInLML == null && e2.xtop == pt.X && e2.ytop == pt.Y; bool e1Contributing = (e1.outIdx >= 0); bool e2contributing = (e2.outIdx >= 0); //update winding counts... //assumes that e1 will be to the right of e2 ABOVE the intersection if (e1.polyType == e2.polyType) { 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.polyType == PolyType.ptSubject) { e1FillType = m_SubjFillType; e1FillType2 = m_ClipFillType; } else { e1FillType = m_ClipFillType; e1FillType2 = m_SubjFillType; } if (e2.polyType == 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.polyType != e2.polyType && 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 ... Int64 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.polyType != e2.polyType) 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.polyType == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1.polyType == 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 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 = -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; } outRec2.idx = outRec1.idx; }
//------------------------------------------------------------------------------ private static void SwapSides(TEdge edge1, TEdge edge2) { EdgeSide side = edge1.side; edge1.side = edge2.side; edge2.side = side; }
//------------------------------------------------------------------------------ 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 AddOutPt(TEdge e, IntPoint pt) { bool ToFront = (e.side == EdgeSide.esLeft); if (e.outIdx < 0) { OutRec outRec = CreateOutRec(); e.outIdx = outRec.idx; OutPt op = new OutPt(); outRec.pts = op; 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, op2; if (ToFront && PointsEqual(pt, op.pt) || (!ToFront && PointsEqual(pt, op.prev.pt))) return; op2 = new OutPt(); op2.pt = pt; op2.idx = outRec.idx; op2.next = op; op2.prev = op.prev; op2.prev.next = op2; op.prev = op2; if (ToFront) outRec.pts = op2; } }
//------------------------------------------------------------------------------ private void AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt) { TEdge e, prevE; if (e2.dx == horizontal || (e1.dx > e2.dx)) { 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 { 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)) AddJoin(e, prevE, -1, -1); }
//------------------------------------------------------------------------------ private bool IsMaxima(TEdge e, double Y) { return (e != null && e.ytop == Y && e.nextInLML == null); }
//------------------------------------------------------------------------------ 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 bool IsIntermediate(TEdge e, double Y) { return (e.ytop == Y && e.nextInLML != null); }
//------------------------------------------------------------------------------ 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 ProcessIntersections(Int64 botY, Int64 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 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); }
//------------------------------------------------------------------------------ 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 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) { 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; } TEdge eNext = GetNextInAEL(e, Direction); if (eMaxPair != null || ((Direction == Direction.dLeftToRight) && (e.xcurr < horzRight)) || ((Direction == Direction.dRightToLeft) && (e.xcurr > horzLeft))) { //so far we're still in range of the horizontal edge 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) || (Direction == Direction.dRightToLeft && e.xcurr <= horzLeft)) break; e = eNext; } //end while ( e ) if (horzEdge.nextInLML != null) { if (horzEdge.outIdx >= 0) AddOutPt(horzEdge, 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 bool IntersectPoint(TEdge edge1, TEdge edge2, ref IntPoint ip) { double b1, b2; if (SlopesEqual(edge1, edge2, m_UseFullRange)) { if (edge2.ybot > edge1.ybot) ip.Y = edge2.ybot; else ip.Y = edge1.ybot; return false; } else if (edge1.dx == 0) { ip.X = edge1.xbot; if (edge2.dx == horizontal) { ip.Y = edge2.ybot; } else { b2 = edge2.ybot - (edge2.xbot / edge2.dx); ip.Y = Round(ip.X / edge2.dx + b2); } } else if (edge2.dx == 0) { ip.X = edge2.xbot; if (edge1.dx == horizontal) { ip.Y = edge1.ybot; } else { b1 = edge1.ybot - (edge1.xbot / edge1.dx); ip.Y = Round(ip.X / edge1.dx + b1); } } else { b1 = edge1.xbot - edge1.ybot * edge1.dx; b2 = edge2.xbot - edge2.ybot * 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.ytop || ip.Y < edge2.ytop) { if (edge1.ytop > edge2.ytop) { ip.X = edge1.xtop; ip.Y = edge1.ytop; return TopX(edge2, edge1.ytop) < edge1.xtop; } else { ip.X = edge2.xtop; ip.Y = edge2.ytop; return TopX(edge1, edge2.ytop) > edge2.xtop; } } else return true; }
//------------------------------------------------------------------------------ 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; }
//------------------------------------------------------------------------------ internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange) { if (UseFullRange) return Int128.Int128Mul(e1.deltaY, e2.deltaX) == Int128.Int128Mul(e1.deltaX, e2.deltaY); else return (Int64)(e1.deltaY) * (e2.deltaX) == (Int64)(e1.deltaX) * (e2.deltaY); }
//------------------------------------------------------------------------------ private TEdge GetNextInAEL(TEdge e, Direction Direction) { return Direction == Direction.dLeftToRight ? e.nextInAEL : e.prevInAEL; }
//------------------------------------------------------------------------------ private void SetDx(TEdge e) { e.deltaX = (e.xtop - e.xbot); e.deltaY = (e.ytop - e.ybot); if (e.deltaY == 0) e.dx = horizontal; else e.dx = (double)(e.deltaX) / (e.deltaY); }
//------------------------------------------------------------------------------ private bool IsMinima(TEdge e) { return e != null && (e.prev.nextInLML != e) && (e.next.nextInLML != e); }
//------------------------------------------------------------------------------ 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 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; }