//------------------------------------------------------------------------------ internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFulllongRange) { OutPt pp2 = pp; bool result = false; if (UseFulllongRange) { do { if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) || ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.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 { if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) || ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.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; }
//------------------------------------------------------------------------------ internal bool PointIsVertex(IntPoint pt, OutPt pp) { OutPt pp2 = pp; do { if (PointsEqual(pp2.pt, pt)) return true; pp2 = pp2.next; } while (pp2 != pp); return false; }
//------------------------------------------------------------------------------ internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullInt64Range) { OutPt pp2 = pp; while (true) { if (PointOnLineSegment(pt, pp2.pt, pp2.next.pt, UseFullInt64Range)) return true; pp2 = pp2.next; if (pp2 == pp) break; } return false; }
//---------------------------------------------------------------------- private void FixupJoinRecs(JoinRec j, OutPt pt, int startIdx) { for (int k = startIdx; k < m_Joins.Count; k++) { JoinRec j2 = m_Joins[k]; if (j2.poly1Idx == j.poly1Idx && PointIsVertex(j2.pt1a, pt)) j2.poly1Idx = j.poly2Idx; if (j2.poly2Idx == j.poly1Idx && PointIsVertex(j2.pt2a, pt)) j2.poly2Idx = j.poly2Idx; } }
//---------------------------------------------------------------------- private bool Poly2ContainsPoly1(OutPt outPt1, OutPt outPt2, bool UseFullInt64Range) { 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, UseFullInt64Range)) { pt = pt.next; while (pt != outPt1 && PointOnPolygon(pt.pt, outPt2, UseFullInt64Range)) pt = pt.next; if (pt == outPt1) return true; } return PointInPolygon(pt.pt, outPt2, UseFullInt64Range); }
//------------------------------------------------------------------------------ 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 bool JoinPoints(JoinRec j, out OutPt p1, out OutPt p2) { p1 = null; p2 = null; OutRec outRec1 = m_PolyOuts[j.poly1Idx]; OutRec outRec2 = m_PolyOuts[j.poly2Idx]; if (outRec1 == null || outRec2 == null) return false; OutPt pp1a = outRec1.pts; OutPt pp2a = outRec2.pts; IntPoint pt1 = j.pt2a, pt2 = j.pt2b; IntPoint pt3 = j.pt1a, pt4 = j.pt1b; if (!FindSegment(ref pp1a, m_UseFullRange, ref pt1, ref pt2)) return false; if (outRec1 == outRec2) { //we're searching the same polygon for overlapping segments so //segment 2 mustn't be the same as segment 1 ... pp2a = pp1a.next; if (!FindSegment(ref pp2a, m_UseFullRange, ref pt3, ref pt4) || (pp2a == pp1a)) return false; } else if (!FindSegment(ref pp2a, m_UseFullRange, ref pt3, ref pt4)) return false; if (!GetOverlapSegment(pt1, pt2, pt3, pt4, ref pt1, ref pt2)) return false; OutPt p3, p4, prev = pp1a.prev; //get p1 & p2 polypts - the overlap start & endpoints on poly1 if (PointsEqual(pp1a.pt, pt1)) p1 = pp1a; else if (PointsEqual(prev.pt, pt1)) p1 = prev; else p1 = InsertPolyPtBetween(pp1a, prev, pt1); if (PointsEqual(pp1a.pt, pt2)) p2 = pp1a; else if (PointsEqual(prev.pt, pt2)) p2 = prev; else if ((p1 == pp1a) || (p1 == prev)) p2 = InsertPolyPtBetween(pp1a, prev, pt2); else if (Pt3IsBetweenPt1AndPt2(pp1a.pt, p1.pt, pt2)) p2 = InsertPolyPtBetween(pp1a, p1, pt2); else p2 = InsertPolyPtBetween(p1, prev, pt2); //get p3 & p4 polypts - the overlap start & endpoints on poly2 prev = pp2a.prev; if (PointsEqual(pp2a.pt, pt1)) p3 = pp2a; else if (PointsEqual(prev.pt, pt1)) p3 = prev; else p3 = InsertPolyPtBetween(pp2a, prev, pt1); if (PointsEqual(pp2a.pt, pt2)) p4 = pp2a; else if (PointsEqual(prev.pt, pt2)) p4 = prev; else if ((p3 == pp2a) || (p3 == prev)) p4 = InsertPolyPtBetween(pp2a, prev, pt2); else if (Pt3IsBetweenPt1AndPt2(pp2a.pt, p3.pt, pt2)) p4 = InsertPolyPtBetween(pp2a, p3, pt2); else p4 = InsertPolyPtBetween(p3, prev, pt2); //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ... if (p1.next == p2 && p3.prev == p4) { p1.next = p3; p3.prev = p1; p2.prev = p4; p4.next = p2; return true; } else if (p1.prev == p2 && p3.next == p4) { p1.prev = p3; p3.next = p1; p2.next = p4; p4.prev = p2; return true; } else return false; //an orientation is probably wrong }
//------------------------------------------------------------------------------ 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 (!PointsEqual(dups.pt, pp.pt)) dups = dups.next; } } return pp; }
//------------------------------------------------------------------------------ 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 bool FirstIsBottomPt(OutPt btmPt1, OutPt btmPt2) { OutPt p = btmPt1.prev; while (PointsEqual(p.pt, btmPt1.pt) && (p != btmPt1)) p = p.prev; double dx1p = Math.Abs(GetDx(btmPt1.pt, p.pt)); p = btmPt1.next; while (PointsEqual(p.pt, btmPt1.pt) && (p != btmPt1)) p = p.next; double dx1n = Math.Abs(GetDx(btmPt1.pt, p.pt)); p = btmPt2.prev; while (PointsEqual(p.pt, btmPt2.pt) && (p != btmPt2)) p = p.prev; double dx2p = Math.Abs(GetDx(btmPt2.pt, p.pt)); p = btmPt2.next; while (PointsEqual(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 bool FindSegment(ref OutPt pp, bool UseFullInt64Range, ref IntPoint pt1, ref IntPoint pt2) { if (pp == null) return false; OutPt pp2 = pp; IntPoint pt1a = new IntPoint(pt1); IntPoint pt2a = new IntPoint(pt2); do { if (SlopesEqual(pt1a, pt2a, pp.pt, pp.prev.pt, UseFullInt64Range) && SlopesEqual(pt1a, pt2a, pp.pt, UseFullInt64Range) && GetOverlapSegment(pt1a, pt2a, pp.pt, pp.prev.pt, ref pt1, ref pt2)) return true; pp = pp.next; } while (pp != pp2); return false; }
//------------------------------------------------------------------------------ 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 DisposeOutPts(OutPt pp) { if (pp == null) return; OutPt tmpPp = null; pp.prev.next = null; while (pp != null) { tmpPp = pp; pp = pp.next; tmpPp = null; } }