//------------------------------------------------------------------------------ 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(PolygonClp 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; } }
//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); 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); }
public Int128(Int128 val) { hi = val.hi; lo = val.lo; }