public double ToDouble() { const double shift64 = 18446744073709551616.0; //2^64 const double bit64 = 9223372036854775808.0; if (hi < 0) { Int128 tmp = -this; if (tmp.lo < 0) { return((double)tmp.lo - bit64 - tmp.hi * shift64); } else { return(-(double)tmp.lo - tmp.hi * shift64); } } else if (lo < 0) { return(-(double)lo + bit64 + hi * shift64); } else { return((double)lo + (double)hi * shift64); } }
internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange) { if (UseFullRange) { return(Int128.Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128.Int128Mul(e1.Delta.X, e2.Delta.Y)); } return(e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y); }
protected static bool SlopesEqual(IntPoint pt1, IntPoint pt2, IntPoint pt3, IntPoint pt4, bool UseFullRange) { if (UseFullRange) { return(Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) == Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y)); } return((pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0); }
public override bool Equals(System.Object obj) { if (obj == null || !(obj is Int128)) { return(false); } Int128 i128 = (Int128)obj; return(i128.hi == hi && i128.lo == lo); }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) { throw new ArithmeticException("Int128: divide by zero"); } bool negate = (rhs.hi < 0) != (lhs.hi < 0); Int128 result = new Int128(lhs), denom = new Int128(rhs); if (result.hi < 0) { result = -result; } if (denom.hi < 0) { denom = -denom; } if (denom > result) { return(new Int128(0)); //result is only a fraction of 1 } denom = -denom; Int128 p = new Int128(0); for (int i = 0; i < 128; ++i) { p.hi = p.hi << 1; if (p.lo < 0) { p.hi++; } p.lo = (long)p.lo << 1; if (result.hi < 0) { p.lo++; } result.hi = result.hi << 1; if (result.lo < 0) { result.hi++; } result.lo = (long)result.lo << 1; if (p.hi >= 0) { p += denom; result.lo++; } } if (negate) { return(-result); } return(result); }
//------------------------------------------------------------------------------ internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange) { if (UseFullRange) { return(Int128.Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128.Int128Mul(e1.Delta.X, e2.Delta.Y)); } else { return((int)(e1.Delta.Y) * (e2.Delta.X) == (int)(e1.Delta.X) * (e2.Delta.Y)); } }
//------------------------------------------------------------------------------ internal static bool SlopesEqual(IntPoint pt1, IntPoint pt2, IntPoint pt3, IntPoint pt4, bool UseFullRange) { if (UseFullRange) { return(Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) == Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y)); } else { return ((int)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (int)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0); } }
//nb: Constructing two new Int128 objects every time we want to multiply longs //is slow. So, although calling the Int128Mul method doesn't look as clean, the //code runs significantly faster than if we'd used the * operator. public static Int128 Int128Mul(Int64 lhs, Int64 rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) { lhs = -lhs; } if (rhs < 0) { rhs = -rhs; } UInt64 int1Hi = (UInt64)lhs >> 32; UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF; UInt64 int2Hi = (UInt64)rhs >> 32; UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF; //nb: see comments in clipper.pas UInt64 a = int1Hi * int2Hi; UInt64 b = int1Lo * int2Lo; UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi; UInt64 lo; Int64 hi; hi = (Int64)(a + (c >> 32)); unchecked { lo = (c << 32) + b; } if (lo < b) { hi++; } Int128 result = new Int128(hi, lo); return(negate ? -result : result); }
//------------------------------------------------------------------------------ internal bool PointOnLineSegment(IntPoint pt, IntPoint linePt1, IntPoint linePt2, bool UseFullRange) { if (UseFullRange) { return(((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) == Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))))); } else { return(((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)))); } }
//------------------------------------------------------------------------------ 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 PointOnLineSegment(IntPoint pt, IntPoint linePt1, IntPoint linePt2, bool UseFullRange) { if (UseFullRange) { if ((pt.X != linePt1.X || pt.Y != linePt1.Y) && (pt.X != linePt2.X || pt.Y != linePt2.Y)) { if (pt.X > linePt1.X == pt.X < linePt2.X && pt.Y > linePt1.Y == pt.Y < linePt2.Y) { return(Int128.Int128Mul(pt.X - linePt1.X, linePt2.Y - linePt1.Y) == Int128.Int128Mul(linePt2.X - linePt1.X, pt.Y - linePt1.Y)); } return(false); } return(true); } if ((pt.X != linePt1.X || pt.Y != linePt1.Y) && (pt.X != linePt2.X || pt.Y != linePt2.Y)) { if (pt.X > linePt1.X == pt.X < linePt2.X && pt.Y > linePt1.Y == pt.Y < linePt2.Y) { return((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)); } return(false); } return(true); }
//nb: Constructing two new Int128 objects every time we want to multiply longs //is slow. So, although calling the Mul method doesn't look as clean, the //code runs significantly faster than if we'd used the * operator. public static Int128 Mul(long lhs, long rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) { lhs = -lhs; } if (rhs < 0) { rhs = -rhs; } ulong int1Hi = (ulong)lhs >> 32; ulong int1Lo = (ulong)lhs & 0xFFFFFFFF; ulong int2Hi = (ulong)rhs >> 32; ulong int2Lo = (ulong)rhs & 0xFFFFFFFF; //nb: see comments in clipper.pas ulong a = int1Hi * int2Hi; ulong b = int1Lo * int2Lo; ulong c = int1Hi * int2Lo + int1Lo * int2Hi; long lo, hi; hi = (long)(a + (c >> 32)); lo = (long)(c << 32); lo += (long)b; if ((ulong)lo < b) { hi++; } var result = new Int128(lo, hi); return(negate ? -result : result); }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) throw new ClipperException("Int128: divide by zero"); bool negate = (rhs.hi < 0) != (lhs.hi < 0); Int128 result = new Int128(lhs), denom = new Int128(rhs); if (result.hi < 0) Negate(result); if (denom.hi < 0) Negate(denom); if (denom > result) return new Int128(0); //result is only a fraction of 1 Negate(denom); Int128 p = new Int128(0), p2 = new Int128(0); for (int i = 0; i < 128; ++i) { p.hi = p.hi << 1; if (p.lo < 0) p.hi++; p.lo = (Int64)p.lo << 1; if (result.hi < 0) p.lo++; result.hi = result.hi << 1; if (result.lo < 0) result.hi++; result.lo = (Int64)result.lo << 1; p2.Assign(p); p += denom; if (p.hi < 0) p.Assign(p2); else result.lo++; } if (negate) Negate(result); return result; }
public static Int128 operator -(Int128 lhs, Int128 rhs) { Int128 tmp = new Int128(rhs); Negate(tmp); lhs += tmp; return lhs; }
public Int128(Int128 val) { Assign(val); }
//------------------------------------------------------------------------------ public static double Area(Polygon poly) { int highI = poly.Count - 1; if (highI < 2) return 0; bool UseFullInt64Range = false; RangeTest rt = TestRange(poly); switch (rt) { case RangeTest.rtHi: UseFullInt64Range = true; break; case RangeTest.rtError: throw new ClipperException("Coordinate exceeds range bounds."); } if (UseFullInt64Range) { Int128 a = new Int128(0); a = Int128.Int128Mul(poly[highI].X, poly[0].Y) - Int128.Int128Mul(poly[0].X, poly[highI].Y); for (int i = 0; i < highI; ++i) a += Int128.Int128Mul(poly[i].X, poly[i + 1].Y) - Int128.Int128Mul(poly[i + 1].X, poly[i].Y); return a.ToDouble() / 2; } else { double area = (double)poly[highI].X * (double)poly[0].Y - (double)poly[0].X * (double)poly[highI].Y; for (int i = 0; i < highI; ++i) area += (double)poly[i].X * (double)poly[i + 1].Y - (double)poly[i + 1].X * (double)poly[i].Y; return area / 2; } }
//------------------------------------------------------------------------------ double Area(OutRec outRec, bool UseFull64BitRange) { OutPt op = outRec.pts; if (op == null) return 0; if (UseFull64BitRange) { Int128 a = new Int128(0); do { a += Int128.Int128Mul(op.pt.X + op.prev.pt.X, op.prev.pt.Y - op.pt.Y); op = op.next; } while (op != outRec.pts); return a.ToDouble() / 2; } else { double a = 0; do { a = a + (op.pt.X + op.prev.pt.X) * (op.prev.pt.Y - op.pt.Y); op = op.next; } while (op != outRec.pts); return a/2; } }
//------------------------------------------------------------------------------ public static double Area(Polygon poly) { int highI = poly.Count - 1; if (highI < 2) return 0; if (FullRangeNeeded(poly)) { Int128 a = new Int128(0); a = Int128.Int128Mul(poly[highI].X + poly[0].X, poly[0].Y - poly[highI].Y); for (int i = 1; i <= highI; ++i) a += Int128.Int128Mul(poly[i - 1].X + poly[i].X, poly[i].Y - poly[i - 1].Y); return a.ToDouble() / 2; } else { double area = ((double)poly[highI].X + poly[0].X) * ((double)poly[0].Y - poly[highI].Y); for (int i = 1; i <= highI; ++i) area += ((double)poly[i - 1].X + poly[i].X) * ((double)poly[i].Y - poly[i -1].Y); return area / 2; } }
public Int128(Int128 val) { hi = val.hi; lo = val.lo; }
//nb: Constructing two new Int128 objects every time we want to multiply longs //is slow. So, although calling the Int128Mul method doesn't look as clean, the //code runs significantly faster than if we'd used the * operator. public static Int128 Int128Mul(Int64 lhs, Int64 rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) lhs = -lhs; if (rhs < 0) rhs = -rhs; UInt64 int1Hi = (UInt64)lhs >> 32; UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF; UInt64 int2Hi = (UInt64)rhs >> 32; UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF; //nb: see comments in clipper.pas UInt64 a = int1Hi * int2Hi; UInt64 b = int1Lo * int2Lo; UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi; UInt64 lo; Int64 hi; hi = (Int64)(a + (c >> 32)); unchecked { lo = (c << 32) + b; } if (lo < b) hi++; Int128 result = new Int128(hi, lo); return negate ? -result : result; }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) throw new ClipperException("Int128: divide by zero"); bool negate = (rhs.hi < 0) != (lhs.hi < 0); Int128 result = new Int128(lhs), denom = new Int128(rhs); if (result.hi < 0) result = -result; if (denom.hi < 0) denom = -denom; if (denom > result) return new Int128(0); //result is only a fraction of 1 denom = -denom; Int128 p = new Int128(0), p2 = new Int128(0); for (int i = 0; i < 128; ++i) { p.hi = p.hi << 1; if (p.lo < 0) p.hi++; p.lo = (Int64)p.lo << 1; if (result.hi < 0) p.lo++; result.hi = result.hi << 1; if (result.lo < 0) result.hi++; result.lo = (Int64)result.lo << 1; if (p.hi >= 0) { p += denom; result.lo++; } } return negate ? -result : result; }
public double ToDouble() { const double shift64 = 18446744073709551616.0; //2^64 const double bit64 = 9223372036854775808.0; if (hi < 0) { Int128 tmp = new Int128(this); Negate(tmp); if (tmp.lo < 0) return (double)tmp.lo - bit64 - tmp.hi * shift64; else return -(double)tmp.lo - tmp.hi * shift64; } else if (lo < 0) return -(double)lo + bit64 + hi * shift64; else return (double)lo + (double)hi * shift64; }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) { throw new ClipperException("Int128: divide by zero"); } bool negate = (rhs.hi < 0) != (lhs.hi < 0); if (lhs.hi < 0) { lhs = -lhs; } if (rhs.hi < 0) { rhs = -rhs; } if (rhs < lhs) { Int128 result = new Int128(0); Int128 cntr = new Int128(1); while (rhs.hi >= 0 && !(rhs > lhs)) { rhs.hi <<= 1; if ((Int64)rhs.lo < 0) { rhs.hi++; } rhs.lo <<= 1; cntr.hi <<= 1; if ((Int64)cntr.lo < 0) { cntr.hi++; } cntr.lo <<= 1; } rhs.lo >>= 1; if ((rhs.hi & 1) == 1) { rhs.lo |= 0x8000000000000000; } rhs.hi = (Int64)((UInt64)rhs.hi >> 1); cntr.lo >>= 1; if ((cntr.hi & 1) == 1) { cntr.lo |= 0x8000000000000000; } cntr.hi >>= 1; while (cntr.hi != 0 || cntr.lo != 0) { if (!(lhs < rhs)) { lhs -= rhs; result.hi |= cntr.hi; result.lo |= cntr.lo; } rhs.lo >>= 1; if ((rhs.hi & 1) == 1) { rhs.lo |= 0x8000000000000000; } rhs.hi >>= 1; cntr.lo >>= 1; if ((cntr.hi & 1) == 1) { cntr.lo |= 0x8000000000000000; } cntr.hi >>= 1; } return(negate ? -result : result); } else if (rhs == lhs) { return(new Int128(1)); } else { return(new Int128(0)); } }
//nb: Constructing two new Int128 objects every time we want to multiply longs //is slow. So, although calling the Int128Mul method doesn't look as clean, the //code runs significantly faster than if we'd used the * operator. public static Int128 Int128Mul(Int64 lhs, Int64 rhs) { bool negate = (lhs < 0) != (rhs < 0); if (lhs < 0) lhs = -lhs; if (rhs < 0) rhs = -rhs; UInt64 int1Hi = (UInt64)lhs >> 32; UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF; UInt64 int2Hi = (UInt64)rhs >> 32; UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF; //nb: see comments in clipper.pas UInt64 a = int1Hi * int2Hi; UInt64 b = int1Lo * int2Lo; UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi; Int128 result = new Int128(); result.hi = (Int64)(a + (c >> 32)); result.lo = (Int64)(c << 32); result.lo += (Int64)b; if ((UInt64)result.lo < b) result.hi++; if (negate) Negate(result); return result; }
public void Assign(Int128 val) { hi = val.hi; lo = val.lo; }
public static Int128 operator /(Int128 lhs, Int128 rhs) { if (rhs.lo == 0 && rhs.hi == 0) throw new ClipperException("Int128: divide by zero"); bool negate = (rhs.hi < 0) != (lhs.hi < 0); if (lhs.hi < 0) lhs = -lhs; if (rhs.hi < 0) rhs = -rhs; if (rhs < lhs) { Int128 result = new Int128(0); Int128 cntr = new Int128(1); while (rhs.hi >= 0 && !(rhs > lhs)) { rhs.hi <<= 1; if ((Int64)rhs.lo < 0) rhs.hi++; rhs.lo <<= 1; cntr.hi <<= 1; if ((Int64)cntr.lo < 0) cntr.hi++; cntr.lo <<= 1; } rhs.lo >>= 1; if ((rhs.hi & 1) == 1) rhs.lo |= 0x8000000000000000; rhs.hi = (Int64)((UInt64)rhs.hi >> 1); cntr.lo >>= 1; if ((cntr.hi & 1) == 1) cntr.lo |= 0x8000000000000000; cntr.hi >>= 1; while (cntr.hi != 0 || cntr.lo != 0) { if (!(lhs < rhs)) { lhs -= rhs; result.hi |= cntr.hi; result.lo |= cntr.lo; } rhs.lo >>= 1; if ((rhs.hi & 1) == 1) rhs.lo |= 0x8000000000000000; rhs.hi >>= 1; cntr.lo >>= 1; if ((cntr.hi & 1) == 1) cntr.lo |= 0x8000000000000000; cntr.hi >>= 1; } return negate ? -result : result; } else if (rhs == lhs) return new Int128(1); else return new Int128(0); }
private static void Negate(Int128 val) { if (val.lo == 0) { if( val.hi == 0) return; val.lo = ~val.lo; val.hi = ~val.hi +1; } else { val.lo = ~val.lo +1; val.hi = ~val.hi; } }
internal bool PointOnLineSegment(IntPoint pt, IntPoint linePt1, IntPoint linePt2, bool UseFullRange) { if (UseFullRange) { return((pt.X == linePt1.X && pt.Y == linePt1.Y) || (pt.X == linePt2.X && pt.Y == linePt2.Y) || (pt.X > linePt1.X == pt.X < linePt2.X && pt.Y > linePt1.Y == pt.Y < linePt2.Y && Int128.Int128Mul(pt.X - linePt1.X, linePt2.Y - linePt1.Y) == Int128.Int128Mul(linePt2.X - linePt1.X, pt.Y - linePt1.Y))); } return((pt.X == linePt1.X && pt.Y == linePt1.Y) || (pt.X == linePt2.X && pt.Y == linePt2.Y) || (pt.X > linePt1.X == pt.X < linePt2.X && pt.Y > linePt1.Y == pt.Y < linePt2.Y && (pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y))); }