Moved some math macros (sqr, lerp, clamp) to libslic3r.h

Added UNUSED macro to libslic3r.h, used it to reduce some compile warnings.

Split the Int128 class from Clipper library to a separate file,
extended Int128 with intrinsic types wherever possible for performance,
added new geometric predicates.

Added a draft of new FillRectilinear3, which should reduce overfill near the perimeters in the future.
This commit is contained in:
bubnikv 2017-07-27 10:39:43 +02:00
parent 3b51f64411
commit a6ea01a23f
19 changed files with 2106 additions and 289 deletions

View file

@ -49,6 +49,7 @@
#include <functional>
#include <assert.h>
#include <Shiny/Shiny.h>
#include <libslic3r/Int128.hpp>
namespace ClipperLib {
@ -128,109 +129,6 @@ bool PolyNode::IsHole() const
}
return result;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Int128 class (enables safe math on signed 64bit integers)
// 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:
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& operator = (const int64_t &val)
{
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 { 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)
{
hi += rhs.hi;
lo += rhs.lo;
if (lo < rhs.lo) hi++;
return *this;
}
Int128 operator + (const Int128 &rhs) const
{
Int128 result(*this);
result+= rhs;
return result;
}
Int128& operator -= (const Int128 &rhs)
{
*this += -rhs;
return *this;
}
Int128 operator - (const Int128 &rhs) const
{
Int128 result(*this);
result -= rhs;
return result;
}
Int128 operator-() const { return (lo == 0) ? Int128(-hi, 0) : Int128(~hi, ~lo + 1); }
operator double() const
{
const double shift64 = 18446744073709551616.0; //2^64
return (hi < 0) ?
((lo == 0) ?
(double)hi * shift64 :
-(double)(~lo + ~hi * shift64)) :
(double)(lo + hi * shift64);
}
static inline Int128 Multiply(int64_t lhs, int64_t rhs)
{
bool negate = (lhs < 0) != (rhs < 0);
if (lhs < 0) lhs = -lhs;
uint64_t int1Hi = uint64_t(lhs) >> 32;
uint64_t int1Lo = uint64_t(lhs & 0xFFFFFFFF);
if (rhs < 0) rhs = -rhs;
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)
uint64_t a = int1Hi * int2Hi;
uint64_t b = int1Lo * int2Lo;
//Result = A shl 64 + C shl 32 + B ...
uint64_t c = int1Hi * int2Lo + int1Lo * int2Hi;
Int128 tmp;
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;
}
};
//------------------------------------------------------------------------------
// Miscellaneous global functions
@ -375,32 +273,11 @@ 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) :
Int128::sign_determinant_2x2_filtered(dx1, dy1, dx2, dy2) == 0 :
// Int128::sign_determinant_2x2(dx1, dy1, dx2, dy2) == 0 :
// |dx1| < 2^31, |dx2| < 2^31 etc,
// therefore the following computation could be done with 64bit arithmetics.
dy1 * dx2 == dx1 * dy2;