internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt next = pp; bool flag = false; if (UseFullRange) { do { if ((next.Pt.Y > pt.Y) != (next.Prev.Pt.Y > pt.Y)) { Int128 introduced2 = Int128.Int128Mul(next.Prev.Pt.X - next.Pt.X, pt.Y - next.Pt.Y); if (new Int128(pt.X - next.Pt.X) < (introduced2 / new Int128(next.Prev.Pt.Y - next.Pt.Y))) { flag = !flag; } } next = next.Next; }while (next != pp); return(flag); } do { if (((next.Pt.Y > pt.Y) != (next.Prev.Pt.Y > pt.Y)) && ((pt.X - next.Pt.X) < (((next.Prev.Pt.X - next.Pt.X) * (pt.Y - next.Pt.Y)) / (next.Prev.Pt.Y - next.Pt.Y)))) { flag = !flag; } next = next.Next; }while (next != pp); return(flag); }
internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt outPt = pp; bool flag = false; if (UseFullRange) { do { if (outPt.Pt.Y > pt.Y != outPt.Prev.Pt.Y > pt.Y && new Int128(pt.X - outPt.Pt.X) < Int128.Int128Mul(outPt.Prev.Pt.X - outPt.Pt.X, pt.Y - outPt.Pt.Y) / new Int128(outPt.Prev.Pt.Y - outPt.Pt.Y)) { flag = !flag; } outPt = outPt.Next; }while (outPt != pp); } else { do { if (outPt.Pt.Y > pt.Y != outPt.Prev.Pt.Y > pt.Y && pt.X - outPt.Pt.X < (outPt.Prev.Pt.X - outPt.Pt.X) * (pt.Y - outPt.Pt.Y) / (outPt.Prev.Pt.Y - outPt.Pt.Y)) { flag = !flag; } outPt = outPt.Next; }while (outPt != pp); } return(flag); }
internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt next = pp; do { if (this.PointOnLineSegment(pt, next.Pt, next.Next.Pt, UseFullRange)) { return(true); } next = next.Next; }while (next != pp); return(false); }
internal bool PointIsVertex(IntPoint pt, OutPt pp) { OutPt outPt = pp; while (!(outPt.Pt == pt)) { outPt = outPt.Next; if (outPt == pp) { return(false); } } return(true); }
internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt outPt = pp; while (!this.PointOnLineSegment(pt, outPt.Pt, outPt.Next.Pt, UseFullRange)) { outPt = outPt.Next; if (outPt == pp) { return(false); } } return(true); }
//------------------------------------------------------------------------------ OutPt DupOutPt(OutPt outPt, bool InsertAfter) { OutPt result = new OutPt(); result.Pt = outPt.Pt; result.Idx = outPt.Idx; if (InsertAfter) { result.Next = outPt.Next; result.Prev = outPt; outPt.Next.Prev = result; outPt.Next = result; } else { result.Prev = outPt.Prev; result.Next = outPt; outPt.Prev.Next = result; outPt.Prev = result; } return result; }
//------------------------------------------------------------------------------ internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt pp2 = pp; while (true) { if (PointOnLineSegment(pt, pp2.Pt, pp2.Next.Pt, UseFullRange)) return true; pp2 = pp2.Next; if (pp2 == pp) break; } return false; }
//------------------------------------------------------------------------------ internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFullRange) { OutPt pp2 = pp; bool result = false; if (UseFullRange) { do { if (((pp2.Pt.Y > pt.Y) != (pp2.Prev.Pt.Y > pt.Y)) && (new Int128(pt.X - pp2.Pt.X) < Int128.Int128Mul(pp2.Prev.Pt.X - pp2.Pt.X, pt.Y - pp2.Pt.Y) / new Int128(pp2.Prev.Pt.Y - pp2.Pt.Y))) result = !result; pp2 = pp2.Next; } while (pp2 != pp); } else { do { //http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html if (((pp2.Pt.Y > pt.Y) != (pp2.Prev.Pt.Y > pt.Y)) && ((pt.X - pp2.Pt.X) < (pp2.Prev.Pt.X - pp2.Pt.X) * (pt.Y - pp2.Pt.Y) / (pp2.Prev.Pt.Y - pp2.Pt.Y))) result = !result; pp2 = pp2.Next; } while (pp2 != pp); } return result; }
//---------------------------------------------------------------------- private bool Poly2ContainsPoly1(OutPt outPt1, OutPt outPt2, bool UseFullRange) { OutPt pt = outPt1; //Because the polygons may be touching, we need to find a vertex that //isn't touching the other polygon ... if (PointOnPolygon(pt.Pt, outPt2, UseFullRange)) { pt = pt.Next; while (pt != outPt1 && PointOnPolygon(pt.Pt, outPt2, UseFullRange)) pt = pt.Next; if (pt == outPt1) return true; } return PointInPolygon(pt.Pt, outPt2, UseFullRange); }
//------------------------------------------------------------------------------ internal bool PointIsVertex(IntPoint pt, OutPt pp) { OutPt pp2 = pp; do { if (pp2.Pt == pt) return true; pp2 = pp2.Next; } while (pp2 != pp); return false; }
//------------------------------------------------------------------------------ private void AddJoin(OutPt Op1, OutPt Op2, IntPoint OffPt) { Join j = new Join(); j.OutPt1 = Op1; j.OutPt2 = Op2; j.OffPt = OffPt; m_Joins.Add(j); }
//------------------------------------------------------------------------------ private bool JoinPoints(Join j, out OutPt p1, out OutPt p2) { OutRec outRec1 = GetOutRec(j.OutPt1.Idx); OutRec outRec2 = GetOutRec(j.OutPt2.Idx); OutPt op1 = j.OutPt1, op1b; OutPt op2 = j.OutPt2, op2b; p1 = null; p2 = null; //There are 3 kinds of joins for output polygons ... //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are a vertices anywhere //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same //location at the Bottom of the overlapping segment (& Join.OffPt is above). //3. StrictlySimple joins where edges touch but are not collinear and where //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. bool isHorizontal = (j.OutPt1.Pt.Y == j.OffPt.Y); if (isHorizontal && (j.OffPt == j.OutPt1.Pt) && (j.OffPt == j.OutPt2.Pt)) { //Strictly Simple join ... op1b = j.OutPt1.Next; while (op1b != op1 && (op1b.Pt == j.OffPt)) op1b = op1b.Next; bool reverse1 = (op1b.Pt.Y > j.OffPt.Y); op2b = j.OutPt2.Next; while (op2b != op2 && (op2b.Pt == j.OffPt)) op2b = op2b.Next; bool reverse2 = (op2b.Pt.Y > j.OffPt.Y); if (reverse1 == reverse2) return false; if (reverse1) { op1b = DupOutPt(op1, false); op2b = DupOutPt(op2, true); op1.Prev = op2; op2.Next = op1; op1b.Next = op2b; op2b.Prev = op1b; p1 = op1; p2 = op1b; return true; } else { op1b = DupOutPt(op1, true); op2b = DupOutPt(op2, false); op1.Next = op2; op2.Prev = op1; op1b.Prev = op2b; op2b.Next = op1b; p1 = op1; p2 = op1b; return true; } } else if (isHorizontal) { //treat horizontal joins differently to non-horizontal joins since with //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt //may be anywhere along the horizontal edge. op1b = op1; while (op1.Prev.Pt.Y == op1.Pt.Y && op1.Prev != op1b && op1.Prev != op2) op1 = op1.Prev; while (op1b.Next.Pt.Y == op1b.Pt.Y && op1b.Next != op1 && op1b.Next != op2) op1b = op1b.Next; if (op1b.Next == op1 || op1b.Next == op2) return false; //a flat 'polygon' op2b = op2; while (op2.Prev.Pt.Y == op2.Pt.Y && op2.Prev != op2b && op2.Prev != op1b) op2 = op2.Prev; while (op2b.Next.Pt.Y == op2b.Pt.Y && op2b.Next != op2 && op2b.Next != op1) op2b = op2b.Next; if (op2b.Next == op2 || op2b.Next == op1) return false; //a flat 'polygon' cInt Left, Right; //Op1 -. Op1b & Op2 -. Op2b are the extremites of the horizontal edges if (!GetOverlap(op1.Pt.X, op1b.Pt.X, op2.Pt.X, op2b.Pt.X, out Left, out Right)) return false; //DiscardLeftSide: when overlapping edges are joined, a spike will created //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up //on the discard Side as either may still be needed for other joins ... IntPoint Pt; bool DiscardLeftSide; if (op1.Pt.X >= Left && op1.Pt.X <= Right) { Pt = op1.Pt; DiscardLeftSide = (op1.Pt.X > op1b.Pt.X); } else if (op2.Pt.X >= Left&& op2.Pt.X <= Right) { Pt = op2.Pt; DiscardLeftSide = (op2.Pt.X > op2b.Pt.X); } else if (op1b.Pt.X >= Left && op1b.Pt.X <= Right) { Pt = op1b.Pt; DiscardLeftSide = op1b.Pt.X > op1.Pt.X; } else { Pt = op2b.Pt; DiscardLeftSide = (op2b.Pt.X > op2.Pt.X); } p1 = op1; p2 = op2; return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); } else { //nb: For non-horizontal joins ... // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y // 2. Jr.OutPt1.Pt > Jr.OffPt.Y //make sure the polygons are correctly oriented ... op1b = op1.Next; while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Next; bool Reverse1 = ((op1b.Pt.Y > op1.Pt.Y) || !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange)); if (Reverse1) { op1b = op1.Prev; while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Prev; if ((op1b.Pt.Y > op1.Pt.Y) || !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange)) return false; }; op2b = op2.Next; while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Next; bool Reverse2 = ((op2b.Pt.Y > op2.Pt.Y) || !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange)); if (Reverse2) { op2b = op2.Prev; while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Prev; if ((op2b.Pt.Y > op2.Pt.Y) || !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange)) return false; } if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; if (Reverse1) { op1b = DupOutPt(op1, false); op2b = DupOutPt(op2, true); op1.Prev = op2; op2.Next = op1; op1b.Next = op2b; op2b.Prev = op1b; p1 = op1; p2 = op1b; return true; } else { op1b = DupOutPt(op1, true); op2b = DupOutPt(op2, false); op1.Next = op2; op2.Prev = op1; op1b.Prev = op2b; op2b.Next = op1b; p1 = op1; p2 = op1b; return true; } } }
//------------------------------------------------------------------------------ private int PointCount(OutPt pts) { if (pts == null) return 0; int result = 0; OutPt p = pts; do { result++; p = p.Next; } while (p != pts); return result; }
//------------------------------------------------------------------------------ private void AddGhostJoin(OutPt Op, IntPoint OffPt) { Join j = new Join(); j.OutPt1 = Op; j.OffPt = OffPt; m_GhostJoins.Add(j); }
//------------------------------------------------------------------------------ private void ReversePolyPtLinks(OutPt pp) { if (pp == null) return; OutPt pp1; OutPt pp2; pp1 = pp; do { pp2 = pp1.Next; pp1.Next = pp1.Prev; pp1.Prev = pp2; pp1 = pp2; } while (pp1 != pp); }
//------------------------------------------------------------------------------ private OutPt GetBottomPt(OutPt pp) { OutPt dups = null; OutPt p = pp.Next; while (p != pp) { if (p.Pt.Y > pp.Pt.Y) { pp = p; dups = null; } else if (p.Pt.Y == pp.Pt.Y && p.Pt.X <= pp.Pt.X) { if (p.Pt.X < pp.Pt.X) { dups = null; pp = p; } else { if (p.Next != pp && p.Prev != pp) dups = p; } } p = p.Next; } if (dups != null) { //there appears to be at least 2 vertices at bottomPt so ... while (dups != p) { if (!FirstIsBottomPt(p, dups)) pp = dups; dups = dups.Next; while (dups.Pt != pp.Pt) dups = dups.Next; } } return pp; }
//--------------------------------------------------------------------------- private bool FirstIsBottomPt(OutPt btmPt1, OutPt btmPt2) { OutPt p = btmPt1.Prev; while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Prev; double dx1p = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); p = btmPt1.Next; while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Next; double dx1n = Math.Abs(GetDx(btmPt1.Pt, p.Pt)); p = btmPt2.Prev; while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Prev; double dx2p = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); p = btmPt2.Next; while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Next; double dx2n = Math.Abs(GetDx(btmPt2.Pt, p.Pt)); return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); }
//------------------------------------------------------------------------------ private OutPt InsertPolyPtBetween(OutPt p1, OutPt p2, IntPoint pt) { OutPt result = new OutPt(); result.Pt = pt; if (p2 == p1.Next) { p1.Next = result; p2.Prev = result; result.Next = p2; result.Prev = p1; } else { p2.Next = result; p1.Prev = result; result.Next = p1; result.Prev = p2; } return result; }
//------------------------------------------------------------------------------ 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; } }
//------------------------------------------------------------------------------ bool JoinHorz(OutPt op1, OutPt op1b, OutPt op2, OutPt op2b, IntPoint Pt, bool DiscardLeft) { Direction Dir1 = (op1.Pt.X > op1b.Pt.X ? Direction.dRightToLeft : Direction.dLeftToRight); Direction Dir2 = (op2.Pt.X > op2b.Pt.X ? Direction.dRightToLeft : Direction.dLeftToRight); if (Dir1 == Dir2) return false; //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) //So, to facilitate this while inserting Op1b and Op2b ... //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) if (Dir1 == Direction.dLeftToRight) { while (op1.Next.Pt.X <= Pt.X && op1.Next.Pt.X >= op1.Pt.X && op1.Next.Pt.Y == Pt.Y) op1 = op1.Next; if (DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next; op1b = DupOutPt(op1, !DiscardLeft); if (op1b.Pt != Pt) { op1 = op1b; op1.Pt = Pt; op1b = DupOutPt(op1, !DiscardLeft); } } else { while (op1.Next.Pt.X >= Pt.X && op1.Next.Pt.X <= op1.Pt.X && op1.Next.Pt.Y == Pt.Y) op1 = op1.Next; if (!DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next; op1b = DupOutPt(op1, DiscardLeft); if (op1b.Pt != Pt) { op1 = op1b; op1.Pt = Pt; op1b = DupOutPt(op1, DiscardLeft); } } if (Dir2 == Direction.dLeftToRight) { while (op2.Next.Pt.X <= Pt.X && op2.Next.Pt.X >= op2.Pt.X && op2.Next.Pt.Y == Pt.Y) op2 = op2.Next; if (DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next; op2b = DupOutPt(op2, !DiscardLeft); if (op2b.Pt != Pt) { op2 = op2b; op2.Pt = Pt; op2b = DupOutPt(op2, !DiscardLeft); }; } else { while (op2.Next.Pt.X >= Pt.X && op2.Next.Pt.X <= op2.Pt.X && op2.Next.Pt.Y == Pt.Y) op2 = op2.Next; if (!DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next; op2b = DupOutPt(op2, DiscardLeft); if (op2b.Pt != Pt) { op2 = op2b; op2.Pt = Pt; op2b = DupOutPt(op2, DiscardLeft); }; }; if ((Dir1 == Direction.dLeftToRight) == DiscardLeft) { op1.Prev = op2; op2.Next = op1; op1b.Next = op2b; op2b.Prev = op1b; } else { op1.Next = op2; op2.Prev = op1; op1b.Prev = op2b; op2b.Next = op1b; } return true; }
//------------------------------------------------------------------------------ private void DisposeOutPts(OutPt pp) { if (pp == null) return; pp.Prev.Next = null; while (pp != null) { pp = pp.Next; } }