Skip to content

Commit

Permalink
Clipper / ClipperUtils:
Browse files Browse the repository at this point in the history
1) Let Clipper use int32_t for representing its coordinates. This
   reduces memory and allows to skip conversion between Slic3r Polygon
   and Clipper polygon.
2) Disable additional offset before executing the Clipper Offset algorithm.
   We don't see any reason for that and it required 64bit Clipper coordinates,
   which were disabled with 1).
  • Loading branch information
bubnikv committed Apr 13, 2021
1 parent dbd1c09 commit e864312
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 41 deletions.
52 changes: 32 additions & 20 deletions src/clipper/clipper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
}
//----------------------------------------------------------------------

#ifdef CLIPPERLIB_INT32
inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool /* UseFullInt64Range */) {
return int64_t(dy1) * int64_t(dx2) == int64_t(dx1) * int64_t(dy2);
}
#else
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,
Expand All @@ -296,6 +301,8 @@ inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cI
// therefore the following computation could be done with 64bit arithmetics.
dy1 * dx2 == dx1 * dy2;
}
#endif

inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
{ 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)
Expand Down Expand Up @@ -363,8 +370,8 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
}
else
{
b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
b1 = double(Edge1.Bot.X) - double(Edge1.Bot.Y) * Edge1.Dx;
b2 = double(Edge2.Bot.X) - double(Edge2.Bot.Y) * Edge2.Dx;
double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
ip.Y = Round(q);
ip.X = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?
Expand Down Expand Up @@ -569,6 +576,7 @@ bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
// ClipperBase class methods ...
//------------------------------------------------------------------------------

#ifndef CLIPPERLIB_INT32
// Called from ClipperBase::AddPath() to verify the scale of the input polygon coordinates.
inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
{
Expand All @@ -583,6 +591,7 @@ inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
RangeTest(Pt, useFullRange);
}
}
#endif // CLIPPERLIB_INT32
//------------------------------------------------------------------------------

// Called from ClipperBase::AddPath() to construct the Local Minima List.
Expand Down Expand Up @@ -805,13 +814,17 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
try
{
edges[1].Curr = pg[1];
#ifndef CLIPPERLIB_INT32
RangeTest(pg[0], m_UseFullRange);
RangeTest(pg[highI], m_UseFullRange);
#endif // CLIPPERLIB_INT32
InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
for (int i = highI - 1; i >= 1; --i)
{
#ifndef CLIPPERLIB_INT32
RangeTest(pg[i], m_UseFullRange);
#endif // CLIPPERLIB_INT32
InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
}
}
Expand Down Expand Up @@ -967,7 +980,9 @@ void ClipperBase::Clear()
CLIPPERLIB_PROFILE_FUNC();
m_MinimaList.clear();
m_edges.clear();
#ifndef CLIPPERLIB_INT32
m_UseFullRange = false;
#endif // CLIPPERLIB_INT32
m_HasOpenPaths = false;
}
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -3322,9 +3337,9 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
if(pt2.X == pt1.X && pt2.Y == pt1.Y)
return DoublePoint(0, 0);

double Dx = (double)(pt2.X - pt1.X);
double dy = (double)(pt2.Y - pt1.Y);
double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy );
double Dx = double(pt2.X - pt1.X);
double dy = double(pt2.Y - pt1.Y);
double f = 1.0 / std::sqrt( Dx*Dx + dy*dy );
Dx *= f;
dy *= f;
return DoublePoint(dy, -Dx);
Expand Down Expand Up @@ -3530,8 +3545,9 @@ void ClipperOffset::DoOffset(double delta)
}

//see offset_triginometry3.svg in the documentation folder ...
if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit);
else m_miterLim = 0.5;
m_miterLim = (MiterLimit > 2) ?
2. / (MiterLimit * MiterLimit) :
0.5;

double y;
if (ArcTolerance <= 0.0) y = def_arc_tolerance;
Expand Down Expand Up @@ -3633,11 +3649,9 @@ void ClipperOffset::DoOffset(double delta)
if (node.m_endtype == etOpenButt)
{
int j = len - 1;
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X *
delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
m_destPoly.push_back(pt1);
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X *
delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X * delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
m_destPoly.push_back(pt1);
}
else
Expand All @@ -3662,11 +3676,9 @@ void ClipperOffset::DoOffset(double delta)

if (node.m_endtype == etOpenButt)
{
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta),
Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta), Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
m_destPoly.push_back(pt1);
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta),
Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta), Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
m_destPoly.push_back(pt1);
}
else
Expand Down Expand Up @@ -3753,7 +3765,7 @@ void ClipperOffset::DoRound(int j, int k)
{
double a = std::atan2(m_sinA,
m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
auto steps = std::max<int>(Round(m_StepsPerRad * std::fabs(a)), 1);

double X = m_normals[k].X, Y = m_normals[k].Y, X2;
for (int i = 0; i < steps; ++i)
Expand Down Expand Up @@ -3885,8 +3897,8 @@ void SimplifyPolygons(Paths &polys, PolyFillType fillType)

inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
{
double Dx = ((double)pt1.X - pt2.X);
double dy = ((double)pt1.Y - pt2.Y);
auto Dx = double(pt1.X - pt2.X);
auto dy = double(pt1.Y - pt2.Y);
return (Dx*Dx + dy*dy);
}
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -3937,8 +3949,8 @@ bool SlopesNearCollinear(const IntPoint& pt1,

bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
{
double Dx = (double)pt1.X - pt2.X;
double dy = (double)pt1.Y - pt2.Y;
auto Dx = double(pt1.X - pt2.X);
auto dy = double(pt1.Y - pt2.Y);
return ((Dx * Dx) + (dy * dy) <= distSqrd);
}
//------------------------------------------------------------------------------
Expand Down
31 changes: 25 additions & 6 deletions src/clipper/clipper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,22 @@ enum PolyType { ptSubject, ptClip };
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };

// If defined, Clipper will work with 32bit signed int coordinates to reduce memory
// consumption and to speed up exact orientation predicate calculation.
// In that case, coordinates and their differences (vectors of the coordinates) have to fit int32_t.
#define CLIPPERLIB_INT32

// 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;
#ifdef CLIPPERLIB_INT32
// Coordinates and their differences (vectors of the coordinates) have to fit int32_t.
typedef int32_t cInt;
#else
typedef int64_t cInt;
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
static constexpr cInt const loRange = 0x3FFFFFFF; // 0x3FFFFFFF = 1 073 741 823
// Maximum allowed cInt value.
static constexpr cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
#endif // CLIPPERLIB_INT32

struct IntPoint {
cInt X;
Expand Down Expand Up @@ -289,7 +299,11 @@ enum EdgeSide { esLeft = 1, esRight = 2};
class ClipperBase
{
public:
ClipperBase() : m_UseFullRange(false), m_HasOpenPaths(false) {}
ClipperBase() :
#ifndef CLIPPERLIB_INT32
m_UseFullRange(false),
#endif // CLIPPERLIB_INT32
m_HasOpenPaths(false) {}
~ClipperBase() { Clear(); }
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
Expand All @@ -310,9 +324,14 @@ class ClipperBase
// Local minima (Y, left edge, right edge) sorted by ascending Y.
std::vector<LocalMinimum> m_MinimaList;

#ifdef CLIPPERLIB_INT32
static constexpr const bool m_UseFullRange = false;
#else // CLIPPERLIB_INT32
// True if the input polygons have abs values higher than loRange, but lower than hiRange.
// False if the input polygons have abs values lower or equal to loRange.
bool m_UseFullRange;
#endif // CLIPPERLIB_INT32

// A vector of edges per each input path.
std::vector<std::vector<TEdge>> m_edges;
// Don't remove intermediate vertices of a collinear sequence of points.
Expand Down
Loading

0 comments on commit e864312

Please sign in to comment.