private TEdge AddBoundsToLML(TEdge e) { Contract.Requires(e != null); Contract.Requires(e.Next != null); //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 ... var newLm = new LocalMinima { Next = null, 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.Left; newLm.RightBound.Side = EdgeSide.Right; 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 AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt) { Contract.Requires(e1 != null); Contract.Requires(e2 != null); TEdge e, prevE; if (e2.Dx == HORIZONTAL || (e1.Dx > e2.Dx)) { AddOutPt(e1, pt); e2.OutIdx = e1.OutIdx; e1.Side = EdgeSide.Left; e2.Side = EdgeSide.Right; e = e1; prevE = e.PrevInAEL == e2 ? e2.PrevInAEL : e.PrevInAEL; } else { AddOutPt(e2, pt); e1.OutIdx = e2.OutIdx; e1.Side = EdgeSide.Right; e2.Side = EdgeSide.Left; e = e2; prevE = e.PrevInAEL == e1 ? e1.PrevInAEL : e.PrevInAEL; } if (prevE != null && prevE.OutIdx >= 0 && (TopX(prevE, pt.Y) == TopX(e, pt.Y)) && InternalHelpers.SlopesEqual(e, prevE)) AddJoin(e, prevE, -1, -1); }
private void AppendPolygon(TEdge e1, TEdge e2) { Contract.Requires(e1 != null); Contract.Requires(e1.OutIdx >= 0 && e1.OutIdx < _polyOuts.Count); Contract.Requires(e2 != null); Contract.Requires(e2.OutIdx >= 0 && e2.OutIdx < _polyOuts.Count); //get the start and ends of both output polygons ... var outRec1 = _polyOuts[e1.OutIdx]; var outRec2 = _polyOuts[e2.OutIdx]; OutRec holeStateRec; if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; else holeStateRec = GetLowermostRec(outRec1, outRec2); var p1Lft = outRec1.Pts; var p1Rt = p1Lft.Prev; var p2Lft = outRec2.Pts; var p2Rt = p2Lft.Prev; EdgeSide side; //join e2 poly onto e1 poly and delete pointers to e2 ... if (e1.Side == EdgeSide.Left) { if (e2.Side == EdgeSide.Left) { //z y x a b c ReversePolyPtLinks(p2Lft); p2Lft.Next = p1Lft; p1Lft.Prev = p2Lft; p1Rt.Next = p2Rt; p2Rt.Prev = p1Rt; outRec1.Pts = p2Rt; } else { //x y z a b c p2Rt.Next = p1Lft; p1Lft.Prev = p2Rt; p2Lft.Prev = p1Rt; p1Rt.Next = p2Lft; outRec1.Pts = p2Lft; } side = EdgeSide.Left; } else { if (e2.Side == EdgeSide.Right) { //a b c z y x ReversePolyPtLinks(p2Lft); p1Rt.Next = p2Rt; p2Rt.Prev = p1Rt; p2Lft.Next = p1Lft; p1Lft.Prev = p2Lft; } else { //a b c x y z p1Rt.Next = p2Lft; p2Lft.Prev = p1Rt; p1Lft.Prev = p2Rt; p2Rt.Next = p1Lft; } side = EdgeSide.Right; } 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; var okIdx = e1.OutIdx; var obsoleteIdx = e2.OutIdx; e1.OutIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly e2.OutIdx = -1; var e = _activeEdges; while (e != null) { if (e.OutIdx == obsoleteIdx) { e.OutIdx = okIdx; e.Side = side; break; } e = e.NextInAEL; } outRec2.Idx = outRec1.Idx; }
private void AddEdgeToSEL(TEdge edge) { Contract.Requires(edge != null); //SEL pointers in PEdge are reused to build a list of horizontal edges. //However, we don't need to worry about order with horizontal edge processing. if (_sortedEdges == null) { _sortedEdges = edge; edge.PrevInSEL = null; edge.NextInSEL = null; } else { edge.NextInSEL = _sortedEdges; edge.PrevInSEL = null; _sortedEdges.PrevInSEL = edge; _sortedEdges = edge; } }
private void AddJoin(TEdge e1, TEdge e2, int e1OutIdx, int e2OutIdx) { Contract.Requires(e1 != null); Contract.Requires(e2 != null); var jr = new JoinRec { Poly1Idx = e1OutIdx >= 0 ? e1OutIdx : e1.OutIdx, Pt1A = new IntPoint(e1.XCurr, e1.YCurr), Pt1B = new IntPoint(e1.XTop, e1.YTop), Poly2Idx = e2OutIdx >= 0 ? e2OutIdx : e2.OutIdx, Pt2A = new IntPoint(e2.XCurr, e2.YCurr), Pt2B = new IntPoint(e2.XTop, e2.YTop) }; _joins.Add(jr); }
protected override void Reset() { base.Reset(); _scanbeam = null; _activeEdges = null; _sortedEdges = null; DisposeAllPolyPts(); var lm = MinimaList; while (lm != null) { InsertScanbeam(lm.Y); lm = lm.Next; } }
private static bool IntersectPoint(TEdge edge1, TEdge edge2, ref IntPoint ip) { Contract.Requires(edge1 != null); Contract.Requires(edge2 != null); if (InternalHelpers.SlopesEqual(edge1, edge2)) { ip = new IntPoint( ip.X, edge2.YBot > edge1.YBot ? edge2.YBot : edge1.YBot ); return false; } else if (edge1.Dx == 0) { ip = new IntPoint( edge1.XBot, edge2.Dx == HORIZONTAL ? edge2.YBot : InternalHelpers.Round(ip.X / edge2.Dx + (edge2.YBot - edge2.XBot / edge2.Dx)) ); } else if (edge2.Dx == 0) { ip = new IntPoint( edge2.XBot, edge1.Dx == HORIZONTAL ? edge1.YBot : InternalHelpers.Round(ip.X / edge1.Dx + (edge1.YBot - edge1.XBot / edge1.Dx)) ); } else { var b1 = edge1.XBot - edge1.YBot * edge1.Dx; var b2 = edge2.XBot - edge2.YBot * edge2.Dx; var q = (b2 - b1) / (edge1.Dx - edge2.Dx); ip = new IntPoint( Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx) ? InternalHelpers.Round(edge1.Dx * q + b1) : InternalHelpers.Round(edge2.Dx * q + b2), InternalHelpers.Round(q) ); } if (ip.Y < edge1.YTop || ip.Y < edge2.YTop) { if (edge1.YTop > edge2.YTop) { ip = new IntPoint( edge1.XTop, edge1.YTop ); return TopX(edge2, edge1.YTop) < edge1.XTop; } else { ip = new IntPoint( edge2.XTop, edge2.YTop ); return TopX(edge1, edge2.YTop) > edge2.XTop; } } else return true; }
private void InsertIntersectNode(TEdge e1, TEdge e2, IntPoint pt) { Contract.Requires(e1 != null); Contract.Requires(e2 != null); var newNode = new IntersectNode { Edge1 = e1, Edge2 = e2, Pt = pt, Next = null }; if (_intersectNodes == null) _intersectNodes = newNode; else if (newNode.Pt.Y > _intersectNodes.Pt.Y) { newNode.Next = _intersectNodes; _intersectNodes = newNode; } else { var iNode = _intersectNodes; while (iNode.Next != null && newNode.Pt.Y < iNode.Next.Pt.Y) iNode = iNode.Next; newNode.Next = iNode.Next; iNode.Next = newNode; } }
private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, Protects protects) { Contract.Requires(e1 != null); Contract.Requires(e2 != null); //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 ... var e1Stops = (Protects.Left & protects) == 0 && e1.NextInLML == null && e1.XTop == pt.X && e1.YTop == pt.Y; var e2Stops = (Protects.Right & protects) == 0 && e2.NextInLML == null && e2.XTop == pt.X && e2.YTop == pt.Y; var e1Contributing = e1.OutIdx >= 0; var 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)) { var 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.Subject) { e1FillType = _subjFillType; e1FillType2 = _clipFillType; } else { e1FillType = _clipFillType; e1FillType2 = _subjFillType; } if (e2.PolyType == PolyType.Subject) { e2FillType = _subjFillType; e2FillType2 = _clipFillType; } else { e2FillType = _clipFillType; e2FillType2 = _subjFillType; } int e1Wc, e2Wc; switch (e1FillType) { case PolyFillType.Positive: e1Wc = e1.WindCnt; break; case PolyFillType.Negative: e1Wc = -e1.WindCnt; break; default: e1Wc = Math.Abs(e1.WindCnt); break; } switch (e2FillType) { case PolyFillType.Positive: e2Wc = e2.WindCnt; break; case PolyFillType.Negative: 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 && _clipType != ClipType.Xor)) AddLocalMaxPoly(e1, e2, pt); else { AddOutPt(e1, pt); AddOutPt(e2, pt); InternalHelpers.Swap(ref e1.Side, ref e2.Side); InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx); } } else if (e1Contributing) { if (e2Wc == 0 || e2Wc == 1) { AddOutPt(e1, pt); InternalHelpers.Swap(ref e1.Side, ref e2.Side); InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx); } } else if (e2Contributing) { if (e1Wc == 0 || e1Wc == 1) { AddOutPt(e2, pt); InternalHelpers.Swap(ref e1.Side, ref e2.Side); InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx); } } else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) && !e1Stops && !e2Stops) { //neither edge is currently contributing ... long e1Wc2, e2Wc2; switch (e1FillType2) { case PolyFillType.Positive: e1Wc2 = e1.WindCnt2; break; case PolyFillType.Negative: e1Wc2 = -e1.WindCnt2; break; default: e1Wc2 = Math.Abs(e1.WindCnt2); break; } switch (e2FillType2) { case PolyFillType.Positive: e2Wc2 = e2.WindCnt2; break; case PolyFillType.Negative: 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 (_clipType) { case ClipType.Intersection: if (e1Wc2 > 0 && e2Wc2 > 0) AddLocalMinPoly(e1, e2, pt); break; case ClipType.Union: if (e1Wc2 <= 0 && e2Wc2 <= 0) AddLocalMinPoly(e1, e2, pt); break; case ClipType.Difference: if (((e1.PolyType == PolyType.Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1.PolyType == PolyType.Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) AddLocalMinPoly(e1, e2, pt); break; case ClipType.Xor: AddLocalMinPoly(e1, e2, pt); break; } else InternalHelpers.Swap(ref e1.Side, ref e2.Side); } if ((e1Stops != e2Stops) && ((e1Stops && (e1.OutIdx >= 0)) || (e2Stops && (e2.OutIdx >= 0)))) { InternalHelpers.Swap(ref e1.Side, ref e2.Side); InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx); } //finally, delete any non-contributing maxima edges ... if (e1Stops) DeleteFromAEL(e1); if (e2Stops) DeleteFromAEL(e2); }
private void DoMaxima(TEdge e, long topY) { Contract.Requires(e != null); Contract.Requires(e.Next != null); var eMaxPair = InternalHelpers.GetMaximaPair(e); var x = e.XTop; var eNext = e.NextInAEL; while (eNext != eMaxPair) { if (eNext == null) throw new ClipperException("DoMaxima error"); IntersectEdges(e, eNext, new IntPoint(x, topY), Protects.Both); 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.None); } else throw new ClipperException("DoMaxima error"); }
private void InsertEdgeIntoAEL(TEdge edge) { Contract.Requires(edge != null); edge.PrevInAEL = null; edge.NextInAEL = null; if (_activeEdges == null) { _activeEdges = edge; } else if (E2InsertsBeforeE1(_activeEdges, edge)) { edge.NextInAEL = _activeEdges; _activeEdges.PrevInAEL = edge; _activeEdges = edge; } else { var e = _activeEdges; while (e.NextInAEL != null && !E2InsertsBeforeE1(e.NextInAEL, edge)) e = e.NextInAEL; edge.NextInAEL = e.NextInAEL; if (e.NextInAEL != null) e.NextInAEL.PrevInAEL = edge; edge.PrevInAEL = e; e.NextInAEL = edge; } }
private void DeleteFromSEL(TEdge e) { Contract.Requires(e != null); var selPrev = e.PrevInSEL; var selNext = e.NextInSEL; if (selPrev == null && selNext == null && (e != _sortedEdges)) return; //already deleted if (selPrev != null) selPrev.NextInSEL = selNext; else _sortedEdges = selNext; if (selNext != null) selNext.PrevInSEL = selPrev; e.NextInSEL = null; e.PrevInSEL = null; }
private void DeleteFromAEL(TEdge e) { Contract.Requires(e != null); var aelPrev = e.PrevInAEL; var aelNext = e.NextInAEL; if (aelPrev == null && aelNext == null && (e != _activeEdges)) return; //already deleted if (aelPrev != null) aelPrev.NextInAEL = aelNext; else _activeEdges = aelNext; if (aelNext != null) aelNext.PrevInAEL = aelPrev; e.NextInAEL = null; e.PrevInAEL = null; }
private void CopyAELToSEL() { var e = _activeEdges; _sortedEdges = e; while (e != null) { e.PrevInSEL = e.PrevInAEL; e.NextInSEL = e.NextInAEL; e = e.NextInAEL; } }
private void SwapPositionsInSEL(TEdge edge1, TEdge edge2) { Contract.Requires(edge1 != null); Contract.Requires(edge2 != null); if (edge1.NextInSEL == null && edge1.PrevInSEL == null) return; if (edge2.NextInSEL == null && edge2.PrevInSEL == null) return; if (edge1.NextInSEL == edge2) { var next = edge2.NextInSEL; if (next != null) next.PrevInSEL = edge1; var 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) { var next = edge1.NextInSEL; if (next != null) next.PrevInSEL = edge2; var prev = edge2.PrevInSEL; if (prev != null) prev.NextInSEL = edge1; edge1.PrevInSEL = prev; edge1.NextInSEL = edge2; edge2.PrevInSEL = edge1; edge2.NextInSEL = next; } else { var next = edge1.NextInSEL; var 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) _sortedEdges = edge1; else if (edge2.PrevInSEL == null) _sortedEdges = edge2; }
private bool IsContributing(TEdge edge) { Contract.Requires(edge != null); PolyFillType pft, pft2; if (edge.PolyType == PolyType.Subject) { pft = _subjFillType; pft2 = _clipFillType; } else { pft = _clipFillType; pft2 = _subjFillType; } switch (pft) { case PolyFillType.EvenOdd: case PolyFillType.NonZero: if (Math.Abs(edge.WindCnt) != 1) return false; break; case PolyFillType.Positive: if (edge.WindCnt != 1) return false; break; case PolyFillType.Negative: if (edge.WindCnt != -1) return false; break; default: throw new InvalidOperationException($"Unknown polyFillType '{pft}'"); } switch (_clipType) { case ClipType.Intersection: switch (pft2) { case PolyFillType.EvenOdd: case PolyFillType.NonZero: return edge.WindCnt2 != 0; case PolyFillType.Positive: return edge.WindCnt2 > 0; default: return edge.WindCnt2 < 0; } case ClipType.Union: switch (pft2) { case PolyFillType.EvenOdd: case PolyFillType.NonZero: return edge.WindCnt2 == 0; case PolyFillType.Positive: return edge.WindCnt2 <= 0; default: return edge.WindCnt2 >= 0; } case ClipType.Difference: if (edge.PolyType == PolyType.Subject) switch (pft2) { case PolyFillType.EvenOdd: case PolyFillType.NonZero: return edge.WindCnt2 == 0; case PolyFillType.Positive: return edge.WindCnt2 <= 0; default: return edge.WindCnt2 >= 0; } else switch (pft2) { case PolyFillType.EvenOdd: case PolyFillType.NonZero: return edge.WindCnt2 != 0; case PolyFillType.Positive: return edge.WindCnt2 > 0; default: return edge.WindCnt2 < 0; } } return true; }
private void UpdateEdgeIntoAEL(ref TEdge e) { Contract.Requires(e != null); if (e.NextInLML == null) throw new ClipperException("UpdateEdgeIntoAEL: invalid call"); var aelPrev = e.PrevInAEL; var aelNext = e.NextInAEL; e.NextInLML.OutIdx = e.OutIdx; if (aelPrev != null) aelPrev.NextInAEL = e.NextInLML; else _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 bool IsEvenOddFillType(TEdge edge) { Contract.Requires(edge != null); if (edge.PolyType == PolyType.Subject) return _subjFillType == PolyFillType.EvenOdd; else return _clipFillType == PolyFillType.EvenOdd; }
private static bool E2InsertsBeforeE1(TEdge e1, TEdge e2) { Contract.Requires(e1 != null); Contract.Requires(e2 != null); if (e2.XCurr == e1.XCurr) { if (e2.YTop > e1.YTop) return e2.XTop < TopX(e1, e2.YTop); else return e1.XTop > TopX(e2, e1.YTop); } else return e2.XCurr < e1.XCurr; }
private bool IsTopHorz(TEdge horzEdge, double xPos) { var e = _sortedEdges; while (e != null) { if ((xPos >= Math.Min(e.XCurr, e.XTop)) && (xPos <= Math.Max(e.XCurr, e.XTop))) return false; e = e.NextInSEL; } return true; }
private static long TopX(TEdge edge, long currentY) { Contract.Requires(edge != null); if (currentY == edge.YTop) return edge.XTop; return edge.XBot + InternalHelpers.Round(edge.Dx * (currentY - edge.YBot)); }
private void ProcessHorizontal(TEdge horzEdge) { Contract.Requires(horzEdge != null); Direction direction; long horzLeft, horzRight; if (horzEdge.XCurr < horzEdge.XTop) { horzLeft = horzEdge.XCurr; horzRight = horzEdge.XTop; direction = Direction.LeftToRight; } else { horzLeft = horzEdge.XTop; horzRight = horzEdge.XCurr; direction = Direction.RightToLeft; } var eMaxPair = horzEdge.NextInLML != null ? null : InternalHelpers.GetMaximaPair(horzEdge); var e = InternalHelpers.GetNextInAEL(horzEdge, direction); while (e != null) { if (e.XCurr == horzEdge.XTop && eMaxPair == null) { if (InternalHelpers.SlopesEqual(e, horzEdge.NextInLML)) { //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; } var eNext = InternalHelpers.GetNextInAEL(e, direction); if (eMaxPair != null || ((direction == Direction.LeftToRight) && (e.XCurr < horzRight)) || ((direction == Direction.RightToLeft) && (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.LeftToRight) 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 && !InternalHelpers.IsMinima(e) && !(e.XCurr > e.XTop)) { if (direction == Direction.LeftToRight) IntersectEdges(horzEdge, e, new IntPoint(e.XCurr, horzEdge.YCurr), IsTopHorz(horzEdge, e.XCurr) ? Protects.Left : Protects.Both); else IntersectEdges(e, horzEdge, new IntPoint(e.XCurr, horzEdge.YCurr), IsTopHorz(horzEdge, e.XCurr) ? Protects.Right : Protects.Both); } else if (direction == Direction.LeftToRight) { IntersectEdges(horzEdge, e, new IntPoint(e.XCurr, horzEdge.YCurr), IsTopHorz(horzEdge, e.XCurr) ? Protects.Left : Protects.Both); } else { IntersectEdges(e, horzEdge, new IntPoint(e.XCurr, horzEdge.YCurr), IsTopHorz(horzEdge, e.XCurr) ? Protects.Right : Protects.Both); } SwapPositionsInAEL(horzEdge, e); } else if ((direction == Direction.LeftToRight && e.XCurr >= horzRight) || (direction == Direction.RightToLeft && 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.Both); DeleteFromAEL(eMaxPair); DeleteFromAEL(horzEdge); } }
private void AddHorzJoin(TEdge e, int idx) { _horizJoins.Add(new HorzJoinRec {Edge = e, SavedIdx = idx}); }
private bool ProcessIntersections(long botY, long topY) { if (_activeEdges == null) return true; try { BuildIntersectList(botY, topY); if (_intersectNodes == null) return true; if (_intersectNodes.Next == null || FixupIntersectionOrder()) ProcessIntersectList(); else return false; } catch { _sortedEdges = null; DisposeIntersectNodes(); throw new ClipperException("ProcessIntersections error"); } _sortedEdges = null; return true; }
private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt) { Contract.Requires(e1 != null); Contract.Requires(e1.OutIdx >= 0 && e1.OutIdx < _polyOuts.Count); Contract.Requires(e2 != null); 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 SetHoleState(TEdge e, OutRec outRec) { Contract.Requires(e != null); var isHole = false; var e2 = e.PrevInAEL; while (e2 != null) { if (e2.OutIdx >= 0) { isHole = !isHole; if (outRec.FirstLeft == null) outRec.FirstLeft = _polyOuts[e2.OutIdx]; } e2 = e2.PrevInAEL; } if (isHole) outRec.IsHole = true; }
private void AddOutPt(TEdge e, IntPoint pt) { Contract.Requires(e != null); Contract.Requires(e.OutIdx < 0 || e.OutIdx < _polyOuts.Count); var toFront = e.Side == EdgeSide.Left; if (e.OutIdx < 0) { var outRec = CreateOutRec(); e.OutIdx = outRec.Idx; var op = new OutPt(); outRec.Pts = op; op.Pt = pt; op.Next = op; op.Prev = op; SetHoleState(e, outRec); } else { var outRec = _polyOuts[e.OutIdx]; var op = outRec.Pts; if (toFront && pt.Equals(op.Pt) || (!toFront && pt.Equals(op.Prev.Pt))) return; var op2 = new OutPt { Pt = pt, Next = op, Prev = op.Prev }; op2.Prev.Next = op2; op.Prev = op2; if (toFront) outRec.Pts = op2; } }
private void SetWindingCount(TEdge edge) { Contract.Requires(edge != null); var e = edge.PrevInAEL; //find the edge of the same polytype that immediately preceeds 'edge' in AEL while (e != null && e.PolyType != edge.PolyType) e = e.PrevInAEL; if (e == null) { edge.WindCnt = edge.WindDelta; edge.WindCnt2 = 0; e = _activeEdges; //ie get ready to calc windCnt2 } else if (IsEvenOddFillType(edge)) { //even-odd filling ... edge.WindCnt = 1; edge.WindCnt2 = e.WindCnt2; e = e.NextInAEL; //ie get ready to calc windCnt2 } else { //nonZero filling ... if (e.WindCnt * e.WindDelta < 0) { if (Math.Abs(e.WindCnt) > 1) { if (e.WindDelta * edge.WindDelta < 0) edge.WindCnt = e.WindCnt; else edge.WindCnt = e.WindCnt + edge.WindDelta; } else edge.WindCnt = e.WindCnt + e.WindDelta + edge.WindDelta; } else { if (Math.Abs(e.WindCnt) > 1 && e.WindDelta * edge.WindDelta < 0) edge.WindCnt = e.WindCnt; else if (e.WindCnt + edge.WindDelta == 0) edge.WindCnt = e.WindCnt; else edge.WindCnt = e.WindCnt + edge.WindDelta; } edge.WindCnt2 = e.WindCnt2; e = e.NextInAEL; //ie get ready to calc windCnt2 } //update windCnt2 ... if (IsEvenOddAltFillType(edge)) { //even-odd filling ... while (e != edge) { edge.WindCnt2 = edge.WindCnt2 == 0 ? 1 : 0; e = e.NextInAEL; } } else { //nonZero filling ... while (e != edge) { edge.WindCnt2 += e.WindDelta; e = e.NextInAEL; } } }
private void BuildIntersectList(long botY, long topY) { if (_activeEdges == null) return; //prepare for sorting ... var e = _activeEdges; _sortedEdges = e; while (e != null) { e.PrevInSEL = e.PrevInAEL; e.NextInSEL = e.NextInAEL; e.XCurr = TopX(e, topY); e = e.NextInAEL; } //bubblesort ... var isModified = true; while (isModified && _sortedEdges != null) { isModified = false; e = _sortedEdges; while (e.NextInSEL != null) { var eNext = e.NextInSEL; var 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 = new IntPoint( TopX(e, pt.Y), botY ); } InsertIntersectNode(e, eNext, pt); SwapPositionsInSEL(e, eNext); isModified = true; } else e = eNext; } if (e.PrevInSEL != null) e.PrevInSEL.NextInSEL = null; else break; } _sortedEdges = null; }
private static void SwapX(TEdge e) { Contract.Requires(e != null); //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; }