mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Experimental feature, which may make the Clipper offsets run faster
due to avoiding the 128bit multiply operations: A filtered predicate is tried to calculate SlopesEqual() to minimize the invocation of 128bit multiply operations.
This commit is contained in:
		
							parent
							
								
									bd93d2f334
								
							
						
					
					
						commit
						40a882d01e
					
				
					 3 changed files with 110 additions and 161 deletions
				
			
		|  | @ -130,67 +130,37 @@ bool PolyNode::IsHole() const | |||
| }   | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| #ifndef use_int32 | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| // Int128 class (enables safe math on signed 64bit integers)
 | ||||
| // eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
 | ||||
| //    Int128 val2((long64)9223372036854775807);
 | ||||
| // eg Int128 val1((int64_t)9223372036854775807); //ie 2^63 -1
 | ||||
| //    Int128 val2((int64_t)9223372036854775807);
 | ||||
| //    Int128 val3 = val1 * val2;
 | ||||
| //    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Used by the SlopesEqual() functions.
 | ||||
| class Int128 | ||||
| { | ||||
|   public: | ||||
|     ulong64 lo; | ||||
|     long64 hi; | ||||
| 
 | ||||
|     Int128(long64 _lo = 0) | ||||
|     { | ||||
|       lo = (ulong64)_lo;    | ||||
|       if (_lo < 0)  hi = -1; else hi = 0;  | ||||
|     } | ||||
| 
 | ||||
|     uint64_t lo; | ||||
|     int64_t  hi; | ||||
| 
 | ||||
|     Int128(int64_t _lo = 0) : lo((uint64_t)_lo), hi((_lo < 0) ? -1 : 0) {} | ||||
|     Int128(const Int128 &val) : lo(val.lo), hi(val.hi) {} | ||||
|     Int128(const int64_t& _hi, const uint64_t& _lo) : lo(_lo), hi(_hi) {} | ||||
|      | ||||
|     Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} | ||||
|      | ||||
|     Int128& operator = (const long64 &val) | ||||
|     Int128& operator = (const int64_t &val) | ||||
|     { | ||||
|       lo = (ulong64)val; | ||||
|       if (val < 0) hi = -1; else hi = 0; | ||||
|       lo = (uint64_t)val; | ||||
|       hi = (val < 0) ? -1 : 0; | ||||
|       return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool operator == (const Int128 &val) const | ||||
|       {return (hi == val.hi && lo == val.lo);} | ||||
| 
 | ||||
|     bool operator != (const Int128 &val) const | ||||
|       { return !(*this == val);} | ||||
| 
 | ||||
|     bool operator > (const Int128 &val) const | ||||
|     { | ||||
|       if (hi != val.hi) | ||||
|         return hi > val.hi; | ||||
|       else | ||||
|         return lo > val.lo; | ||||
|     } | ||||
| 
 | ||||
|     bool operator < (const Int128 &val) const | ||||
|     { | ||||
|       if (hi != val.hi) | ||||
|         return hi < val.hi; | ||||
|       else | ||||
|         return lo < val.lo; | ||||
|     } | ||||
| 
 | ||||
|     bool operator >= (const Int128 &val) const | ||||
|       { return !(*this < val);} | ||||
| 
 | ||||
|     bool operator <= (const Int128 &val) const | ||||
|       { return !(*this > val);} | ||||
|     bool operator == (const Int128 &val) const { return hi == val.hi && lo == val.lo; } | ||||
|     bool operator != (const Int128 &val) const { return ! (*this == val); } | ||||
|     bool operator >  (const Int128 &val) const { return (hi == val.hi) ? lo > val.lo : hi > val.hi; } | ||||
|     bool operator <  (const Int128 &val) const { return (hi == val.hi) ? lo < val.lo : hi < val.hi; } | ||||
|     bool operator >= (const Int128 &val) const { return ! (*this < val); } | ||||
|     bool operator <= (const Int128 &val) const { return ! (*this > val); } | ||||
| 
 | ||||
|     Int128& operator += (const Int128 &rhs) | ||||
|     { | ||||
|  | @ -220,58 +190,47 @@ class Int128 | |||
|       return result; | ||||
|     } | ||||
| 
 | ||||
|     Int128 operator-() const //unary negation
 | ||||
|     { | ||||
|       if (lo == 0) | ||||
|         return Int128(-hi, 0); | ||||
|       else | ||||
|         return Int128(~hi, ~lo + 1); | ||||
|     } | ||||
|     Int128 operator-() const { return (lo == 0) ? Int128(-hi, 0) : Int128(~hi, ~lo + 1); } | ||||
| 
 | ||||
|     operator double() const | ||||
|     { | ||||
|       const double shift64 = 18446744073709551616.0; //2^64
 | ||||
|       if (hi < 0) | ||||
|       { | ||||
|         if (lo == 0) return (double)hi * shift64; | ||||
|         else return -(double)(~lo + ~hi * shift64); | ||||
|       } | ||||
|       else | ||||
|         return (double)(lo + hi * shift64); | ||||
|       return (hi < 0) ? | ||||
|         ((lo == 0) ?  | ||||
|           (double)hi * shift64 : | ||||
|           -(double)(~lo + ~hi * shift64)) : | ||||
|         (double)(lo + hi * shift64); | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| inline Int128 Int128Mul (long64 lhs, long64 rhs) | ||||
|     static inline Int128 Multiply(int64_t lhs, int64_t rhs) | ||||
|     { | ||||
|       bool negate = (lhs < 0) != (rhs < 0); | ||||
| 
 | ||||
|       if (lhs < 0) lhs = -lhs; | ||||
|   ulong64 int1Hi = ulong64(lhs) >> 32; | ||||
|   ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); | ||||
|       uint64_t int1Hi = uint64_t(lhs) >> 32; | ||||
|       uint64_t int1Lo = uint64_t(lhs & 0xFFFFFFFF); | ||||
| 
 | ||||
|       if (rhs < 0) rhs = -rhs; | ||||
|   ulong64 int2Hi = ulong64(rhs) >> 32; | ||||
|   ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); | ||||
|       uint64_t int2Hi = uint64_t(rhs) >> 32; | ||||
|       uint64_t int2Lo = uint64_t(rhs & 0xFFFFFFFF); | ||||
| 
 | ||||
|       //because the high (sign) bits in both int1Hi & int2Hi have been zeroed,
 | ||||
|       //there's no risk of 64 bit overflow in the following assignment
 | ||||
|       //(ie: $7FFFFFFF*$FFFFFFFF + $7FFFFFFF*$FFFFFFFF < 64bits)
 | ||||
|   ulong64 a = int1Hi * int2Hi; | ||||
|   ulong64 b = int1Lo * int2Lo; | ||||
|       uint64_t a = int1Hi * int2Hi; | ||||
|       uint64_t b = int1Lo * int2Lo; | ||||
|       //Result = A shl 64 + C shl 32 + B ...
 | ||||
|   ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; | ||||
|       uint64_t c = int1Hi * int2Lo + int1Lo * int2Hi; | ||||
| 
 | ||||
|       Int128 tmp; | ||||
|   tmp.hi = long64(a + (c >> 32)); | ||||
|   tmp.lo = long64(c << 32); | ||||
|   tmp.lo += long64(b); | ||||
|       tmp.hi = int64_t(a + (c >> 32)); | ||||
|       tmp.lo = int64_t(c << 32); | ||||
|       tmp.lo += int64_t(b); | ||||
|       if (tmp.lo < b) tmp.hi++; | ||||
|       if (negate) tmp = -tmp; | ||||
|       return tmp; | ||||
|     } | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| // Miscellaneous global functions
 | ||||
|  | @ -330,11 +289,8 @@ int PointInPolygon(const IntPoint &pt, const Path &path) | |||
|   for(size_t i = 1; i <= cnt; ++i) | ||||
|   { | ||||
|     IntPoint ipNext = (i == cnt ? path[0] : path[i]); | ||||
|     if (ipNext.Y == pt.Y) | ||||
|     { | ||||
|         if ((ipNext.X == pt.X) || (ip.Y == pt.Y &&  | ||||
|           ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; | ||||
|     } | ||||
|     if (ipNext.Y == pt.Y && ((ipNext.X == pt.X) || (ip.Y == pt.Y && ((ipNext.X > pt.X) == (ip.X < pt.X))))) | ||||
|       return -1; | ||||
|     if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) | ||||
|     { | ||||
|       if (ip.X >= pt.X) | ||||
|  | @ -342,8 +298,7 @@ int PointInPolygon(const IntPoint &pt, const Path &path) | |||
|         if (ipNext.X > pt.X) result = 1 - result; | ||||
|         else | ||||
|         { | ||||
|           double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -  | ||||
|             (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); | ||||
|           double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); | ||||
|           if (!d) return -1; | ||||
|           if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; | ||||
|         } | ||||
|  | @ -351,8 +306,7 @@ int PointInPolygon(const IntPoint &pt, const Path &path) | |||
|       { | ||||
|         if (ipNext.X > pt.X) | ||||
|         { | ||||
|           double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -  | ||||
|             (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); | ||||
|           double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); | ||||
|           if (!d) return -1; | ||||
|           if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; | ||||
|         } | ||||
|  | @ -384,8 +338,7 @@ int PointInPolygon (const IntPoint &pt, OutPt *op) | |||
|         if (op->Next->Pt.X > pt.X) result = 1 - result; | ||||
|         else | ||||
|         { | ||||
|           double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -  | ||||
|             (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); | ||||
|           double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); | ||||
|           if (!d) return -1; | ||||
|           if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; | ||||
|         } | ||||
|  | @ -393,8 +346,7 @@ int PointInPolygon (const IntPoint &pt, OutPt *op) | |||
|       { | ||||
|         if (op->Next->Pt.X > pt.X) | ||||
|         { | ||||
|           double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -  | ||||
|             (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); | ||||
|           double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); | ||||
|           if (!d) return -1; | ||||
|           if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; | ||||
|         } | ||||
|  | @ -423,39 +375,43 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) | |||
| } | ||||
| //----------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Approximate calculation of SlopesEqual() for "UseFullInt64Range"
 | ||||
| // Returns true if the slopes are unequal for sure, 
 | ||||
| // otherwise returns false if the slopes may or may not be equal.
 | ||||
| inline bool SlopesUnequalFilter(cInt dx1, cInt dy1, cInt dx2, cInt dy2) { | ||||
|   // Round dx1, dy1, dx2, dy2 to 31 bits.
 | ||||
|   dx1 = (dx1 + (1 << 30)) >> 32; | ||||
|   dy1 = (dy1 + (1 << 30)) >> 32; | ||||
|   dx2 = (dx2 + (1 << 30)) >> 32; | ||||
|   dy2 = (dy2 + (1 << 30)) >> 32; | ||||
|   // Result fits 63 bits, it is an approximate of the determinant divided by 2^64.
 | ||||
|   cInt discr = std::abs(dy1 * dx2 - dx1 * dy2); | ||||
|   // Maximum absolute of the remainder of the exact determinant, divided by 2^64.
 | ||||
|   cInt error = ((std::abs(dx1) + std::abs(dy1) + std::abs(dx2) + std::abs(dy2)) >> 1) + 1; | ||||
|   return discr > error; | ||||
| } | ||||
| 
 | ||||
| inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool UseFullInt64Range) { | ||||
|   return (UseFullInt64Range) ? | ||||
|     // |dx1| < 2^63, |dx2| < 2^63 etc,
 | ||||
| #if 1 | ||||
|     // Instead of jumping to 128bit multiply on a 32bit or 64bit CPU,
 | ||||
|     // calculate an approximate value of the determinant and its error.
 | ||||
|     // If the determinant is above the error, the slopes are certainly not equal.
 | ||||
|     ! SlopesUnequalFilter(dx1, dy1, dx2, dy2) &&  | ||||
| #endif | ||||
|     Int128::Multiply(dy1, dx2) == Int128::Multiply(dx1, dy2) : | ||||
|     // |dx1| < 2^31, |dx2| < 2^31 etc,
 | ||||
|     // therefore the following computation could be done with 64bit arithmetics. 
 | ||||
|     dy1 * dx2 == dx1 * dy2; | ||||
| } | ||||
| inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) | ||||
| { | ||||
| #ifndef use_int32 | ||||
|   if (UseFullInt64Range) | ||||
|     return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y); | ||||
|   else  | ||||
| #endif | ||||
|     return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y; | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
|   { return SlopesEqual(e1.Delta.X, e1.Delta.Y, e2.Delta.X, e2.Delta.Y, UseFullInt64Range); } | ||||
| inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, bool UseFullInt64Range) | ||||
|   { return SlopesEqual(pt1.X-pt2.X, pt1.Y-pt2.Y, pt2.X-pt3.X, pt2.Y-pt3.Y, UseFullInt64Range); } | ||||
| inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, const IntPoint &pt4, bool UseFullInt64Range) | ||||
|   { return SlopesEqual(pt1.X-pt2.X, pt1.Y-pt2.Y, pt3.X-pt4.X, pt3.Y-pt4.Y, UseFullInt64Range); } | ||||
| 
 | ||||
| inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, | ||||
|   const IntPoint &pt3, bool UseFullInt64Range) | ||||
| { | ||||
| #ifndef use_int32 | ||||
|   if (UseFullInt64Range) | ||||
|     return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); | ||||
|   else  | ||||
| #endif | ||||
|     return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, | ||||
|   const IntPoint &pt3, const IntPoint &pt4, bool UseFullInt64Range) | ||||
| { | ||||
| #ifndef use_int32 | ||||
|   if (UseFullInt64Range) | ||||
|     return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); | ||||
|   else  | ||||
| #endif | ||||
|     return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| inline bool IsHorizontal(TEdge &e) | ||||
|  | @ -474,7 +430,8 @@ inline double GetDx(const IntPoint &pt1, const IntPoint &pt2) | |||
| inline cInt TopX(TEdge &edge, const cInt currentY) | ||||
| { | ||||
|   return (currentY == edge.Top.Y) ? | ||||
|     edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); | ||||
|     edge.Top.X :  | ||||
|     edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
|  | @ -519,10 +476,9 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) | |||
|     b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; | ||||
|     double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); | ||||
|     ip.Y = Round(q); | ||||
|     if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) | ||||
|       ip.X = Round(Edge1.Dx * q + b1); | ||||
|     else  | ||||
|       ip.X = Round(Edge2.Dx * q + b2); | ||||
|     ip.X = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?  | ||||
|       Round(Edge1.Dx * q + b1) : | ||||
|       Round(Edge2.Dx * q + b2); | ||||
|   } | ||||
| 
 | ||||
|   if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y)  | ||||
|  |  | |||
|  | @ -34,11 +34,9 @@ | |||
| #ifndef clipper_hpp | ||||
| #define clipper_hpp | ||||
| 
 | ||||
| #define CLIPPER_VERSION "6.2.6" | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| //use_int32: When enabled 32bit ints are used instead of 64bit ints. This
 | ||||
| //improve performance but coordinate values are limited to the range +/- 46340
 | ||||
| //#define use_int32
 | ||||
| #define CLIPPER_VERSION "6.2.6" | ||||
| 
 | ||||
| //use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
 | ||||
| //#define use_xyz
 | ||||
|  | @ -68,18 +66,12 @@ enum PolyType { ptSubject, ptClip }; | |||
| //see http://glprogramming.com/red/chapter11.html
 | ||||
| enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; | ||||
| 
 | ||||
| #ifdef use_int32 | ||||
|   typedef int cInt; | ||||
|   static cInt const loRange = 0x7FFF; | ||||
|   static cInt const hiRange = 0x7FFF; | ||||
| #else | ||||
|   typedef signed long long cInt; | ||||
| // Point coordinate type
 | ||||
| typedef int64_t cInt; | ||||
| // Maximum cInt value to allow a cross product calculation using 32bit expressions.
 | ||||
| static cInt const loRange = 0x3FFFFFFF; | ||||
| // Maximum allowed cInt value.
 | ||||
| static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; | ||||
|   typedef signed long long long64;     //used by Int128 class
 | ||||
|   typedef unsigned long long ulong64; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| struct IntPoint { | ||||
|   cInt X; | ||||
|  | @ -262,12 +254,11 @@ enum EdgeSide { esLeft = 1, esRight = 2}; | |||
|   }; | ||||
| 
 | ||||
|   // Point of an output polygon.
 | ||||
|   // 36B on 64bit system with not use_int32 and not use_xyz.
 | ||||
|   // 36B on 64bit system without use_xyz.
 | ||||
|   struct OutPt { | ||||
|     // 4B
 | ||||
|     int       Idx; | ||||
|     // 8B (if use_int32 and not use_xyz) or 16B (if not use_int32 and not use_xyz)
 | ||||
|     // or 12B (if use_int32 and use_xyz) or 24B (if not use_int32 and use_xyz)
 | ||||
|     // 16B without use_xyz / 24B with use_xyz
 | ||||
|     IntPoint  Pt; | ||||
|     // 4B on 32bit system, 8B on 64bit system
 | ||||
|     OutPt    *Next; | ||||
|  |  | |||
|  | @ -15,7 +15,9 @@ using ClipperLib::jtSquare; | |||
| // Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
 | ||||
| // for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
 | ||||
| // which is optionally executed by other functions (union, intersection, diff).
 | ||||
| // This scaling (cca 130t) is applied over the usual SCALING_FACTOR.
 | ||||
| // By the way, is the scalling for offset needed at all?
 | ||||
| // The reason to apply this scaling may be to match the resolution of the double mantissa.
 | ||||
| #define CLIPPER_OFFSET_POWER_OF_2 17 | ||||
| // 2^17=131072
 | ||||
| #define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv