//------------------------------------------------------------------------------ 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 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; }
//------------------------------------------------------------------------------ private void ReversePolyPtLinks(OutPt pp) { OutPt pp1; OutPt pp2; pp1 = pp; do { pp2 = pp1.next; pp1.next = pp1.prev; pp1.prev = pp2; pp1 = pp2; } while (pp1 != pp); }
//------------------------------------------------------------------------------ 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 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 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 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, 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, true) && SlopesEqual(pt1a, pt2a, pp.pt, true) && 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(); m_PolyOuts.Add(outRec); outRec.idx = m_PolyOuts.Count -1; e.outIdx = outRec.idx; OutPt op = new OutPt(); outRec.pts = op; outRec.bottomPt = 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, opBot; if (ToFront && PointsEqual(pt, op.pt) || (!ToFront && PointsEqual(pt, op.prev.pt))) return; if ((e.side | outRec.sides) != outRec.sides) { //check for 'rounding' artefacts ... if (outRec.sides == EdgeSide.esNeither && pt.Y == op.pt.Y) if (ToFront) { if (pt.X == op.pt.X + 1) return; //ie wrong side of bottomPt } else if (pt.X == op.pt.X - 1) return; //ie wrong side of bottomPt outRec.sides = (EdgeSide)(outRec.sides | e.side); if (outRec.sides == EdgeSide.esBoth) { //A vertex from each side has now been added. //Vertices of one side of an output polygon are quite commonly close to //or even 'touching' edges of the other side of the output polygon. //Very occasionally vertices from one side can 'cross' an edge on the //the other side. The distance 'crossed' is always less that a unit //and is purely an artefact of coordinate rounding. Nevertheless, this //results in very tiny self-intersections. Because of the way //orientation is calculated, even tiny self-intersections can cause //the Orientation function to return the wrong result. Therefore, it's //important to ensure that any self-intersections close to BottomPt are //detected and removed before orientation is assigned. if (ToFront) { opBot = outRec.pts; op2 = opBot.next; //op2 == right side if (opBot.pt.Y != op2.pt.Y && opBot.pt.Y != pt.Y && ((opBot.pt.X - pt.X) / (opBot.pt.Y - pt.Y) < (opBot.pt.X - op2.pt.X) / (opBot.pt.Y - op2.pt.Y))) outRec.bottomFlag = opBot; } else { opBot = outRec.pts.prev; op2 = opBot.next; //op2 == left side if (opBot.pt.Y != op2.pt.Y && opBot.pt.Y != pt.Y && ((opBot.pt.X - pt.X) / (opBot.pt.Y - pt.Y) > (opBot.pt.X - op2.pt.X) / (opBot.pt.Y - op2.pt.Y))) outRec.bottomFlag = opBot; } } } op2 = new OutPt(); op2.pt = pt; op2.idx = outRec.idx; if (op2.pt.Y == outRec.bottomPt.pt.Y && op2.pt.X < outRec.bottomPt.pt.X) outRec.bottomPt = op2; 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; pp.prev.next = null; while (pp != null) { pp = pp.next; } }
//------------------------------------------------------------------------------ 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; } }