From e8643125d8e682d03b36b34082e1a3dc693f80ba Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik <bubnikv@gmail.com> Date: Tue, 13 Apr 2021 11:31:54 +0200 Subject: [PATCH] Clipper / ClipperUtils: 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). --- src/clipper/clipper.cpp | 52 +++++++++++++-------- src/clipper/clipper.hpp | 31 ++++++++++--- src/libslic3r/ClipperUtils.cpp | 85 ++++++++++++++++++++++++++++++++-- src/libslic3r/ClipperUtils.hpp | 26 ++++++----- src/libslic3r/Geometry.cpp | 2 + 5 files changed, 155 insertions(+), 41 deletions(-) diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index 3c0057b22..cbe54a064 100644 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -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, @@ -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) @@ -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)) ? @@ -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) { @@ -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. @@ -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]); } } @@ -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; } //------------------------------------------------------------------------------ @@ -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); @@ -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; @@ -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 @@ -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 @@ -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) @@ -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); } //------------------------------------------------------------------------------ @@ -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); } //------------------------------------------------------------------------------ diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp index 8b34779e3..48e83d046 100644 --- a/src/clipper/clipper.hpp +++ b/src/clipper/clipper.hpp @@ -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; @@ -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); @@ -310,9 +324,14 @@ protected: // 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. diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 305ea134f..cd243dfb1 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -57,6 +57,7 @@ err: } #endif /* CLIPPER_UTILS_DEBUG */ +#ifdef CLIPPERUTILS_OFFSET_SCALE void scaleClipperPolygon(ClipperLib::Path &polygon) { CLIPPERUTILS_PROFILE_FUNC(); @@ -98,6 +99,7 @@ void unscaleClipperPolygons(ClipperLib::Paths &polygons) pit->Y >>= CLIPPER_OFFSET_POWER_OF_2; } } +#endif // CLIPPERUTILS_OFFSET_SCALE //----------------------------------------------------------- // legacy code from Clipper documentation @@ -222,8 +224,10 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) { +#ifdef CLIPPERUTILS_OFFSET_SCALE // scale input scaleClipperPolygons(input); +#endif // CLIPPERUTILS_OFFSET_SCALE // perform offset ClipperLib::ClipperOffset co; @@ -231,14 +235,20 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType co.ArcTolerance = miterLimit; else co.MiterLimit = miterLimit; +#ifdef CLIPPERUTILS_OFFSET_SCALE float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + float delta_scaled = delta; +#endif // CLIPPERUTILS_OFFSET_SCALE co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPaths(input, joinType, endType); ClipperLib::Paths retval; co.Execute(retval, delta_scaled); +#ifdef CLIPPERUTILS_OFFSET_SCALE // unscale output unscaleClipperPolygons(retval); +#endif // CLIPPERUTILS_OFFSET_SCALE return retval; } @@ -257,14 +267,24 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, { // printf("new ExPolygon offset\n"); // 1) Offset the outer contour. - const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); +#ifdef CLIPPERUTILS_OFFSET_SCALE + float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + float delta_scaled = delta; +#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour); +#ifdef CLIPPERUTILS_OFFSET_SCALE scaleClipperPolygon(input); +#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) +#ifdef CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + co.ArcTolerance = miterLimit; +#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); @@ -278,17 +298,23 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, holes.reserve(expolygon.holes.size()); for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); +#ifdef CLIPPERUTILS_OFFSET_SCALE scaleClipperPolygon(input); +#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) +#ifdef CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + co.ArcTolerance = miterLimit; +#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); - holes.insert(holes.end(), out.begin(), out.end()); + append(holes, std::move(out)); } } @@ -305,7 +331,9 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, } // 4) Unscale the output. +#ifdef CLIPPERUTILS_OFFSET_SCALE unscaleClipperPolygons(output); +#endif // CLIPPERUTILS_OFFSET_SCALE return output; } @@ -315,7 +343,11 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) { - const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); +#ifdef CLIPPERUTILS_OFFSET_SCALE + float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + float delta_scaled = delta; +#endif // CLIPPERUTILS_OFFSET_SCALE // Offsetted ExPolygons before they are united. ClipperLib::Paths contours_cummulative; contours_cummulative.reserve(expolygons.size()); @@ -327,10 +359,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour); +#ifdef CLIPPERUTILS_OFFSET_SCALE scaleClipperPolygon(input); +#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) +#ifdef CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + co.ArcTolerance = miterLimit; +#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); @@ -351,10 +389,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); +#ifdef CLIPPERUTILS_OFFSET_SCALE scaleClipperPolygon(input); +#endif // CLIPPERUTILS_OFFSET_SCALE ClipperLib::ClipperOffset co; if (joinType == jtRound) +#ifdef CLIPPERUTILS_OFFSET_SCALE co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + co.ArcTolerance = miterLimit; +#endif // CLIPPERUTILS_OFFSET_SCALE else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); @@ -413,8 +457,10 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt output = std::move(contours_cummulative); } +#ifdef CLIPPERUTILS_OFFSET_SCALE // 4) Unscale the output. unscaleClipperPolygons(output); +#endif // CLIPPERUTILS_OFFSET_SCALE return output; } @@ -425,8 +471,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2, // read input ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons); +#ifdef CLIPPERUTILS_OFFSET_SCALE // scale input scaleClipperPolygons(input); +#endif // CLIPPERUTILS_OFFSET_SCALE // prepare ClipperOffset object ClipperLib::ClipperOffset co; @@ -435,8 +483,13 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2, } else { co.MiterLimit = miterLimit; } +#ifdef CLIPPERUTILS_OFFSET_SCALE float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE); float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE); +#else // CLIPPERUTILS_OFFSET_SCALE + float delta_scaled1 = delta1; + float delta_scaled2 = delta2; +#endif // CLIPPERUTILS_OFFSET_SCALE co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR); // perform first offset @@ -450,8 +503,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2, ClipperLib::Paths retval; co.Execute(retval, delta_scaled2); +#ifdef CLIPPERUTILS_OFFSET_SCALE // unscale output unscaleClipperPolygons(retval); +#endif // CLIPPERUTILS_OFFSET_SCALE return retval; } @@ -789,8 +844,10 @@ void safety_offset(ClipperLib::Paths* paths) { CLIPPERUTILS_PROFILE_FUNC(); +#ifdef CLIPPERUTILS_OFFSET_SCALE // scale input scaleClipperPolygons(*paths); +#endif // CLIPPERUTILS_OFFSET_SCALE // perform offset (delta = scale 1e-05) ClipperLib::ClipperOffset co; @@ -816,7 +873,11 @@ void safety_offset(ClipperLib::Paths* paths) CLIPPERUTILS_PROFILE_BLOCK(safety_offset_Execute); // offset outside by 10um ClipperLib::Paths out_this; +#ifdef CLIPPERUTILS_OFFSET_SCALE co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE)); +#else // CLIPPERUTILS_OFFSET_SCALE + co.Execute(out_this, ccw ? 10.f : -10.f); +#endif // CLIPPERUTILS_OFFSET_SCALE if (! ccw) { // Reverse the resulting contours once again. for (ClipperLib::Paths::iterator it = out_this.begin(); it != out_this.end(); ++ it) @@ -830,8 +891,10 @@ void safety_offset(ClipperLib::Paths* paths) } *paths = std::move(out); +#ifdef CLIPPERUTILS_OFFSET_SCALE // unscale output unscaleClipperPolygons(*paths); +#endif // CLIPPERUTILS_OFFSET_SCALE } Polygons top_level_islands(const Slic3r::Polygons &polygons) @@ -925,8 +988,10 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v // Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt. auto add_offset_point = [&out](Vec2d pt) { +#ifdef CLIPPERUTILS_OFFSET_SCALE pt *= double(CLIPPER_OFFSET_SCALE); - pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0)); +#endif // CLIPPERUTILS_OFFSET_SCALE + pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0)); out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y())); }; @@ -1075,8 +1140,10 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } +#ifdef CLIPPERUTILS_OFFSET_SCALE // 4) Unscale the output. unscaleClipperPolygons(output); +#endif // CLIPPERUTILS_OFFSET_SCALE return ClipperPaths_to_Slic3rPolygons(output); } @@ -1119,8 +1186,10 @@ for (const std::vector<float>& ds : deltas) clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } +#ifdef CLIPPERUTILS_OFFSET_SCALE // 4) Unscale the output. unscaleClipperPolygons(output); +#endif // CLIPPERUTILS_OFFSET_SCALE return ClipperPaths_to_Slic3rPolygons(output); } @@ -1152,7 +1221,9 @@ for (const std::vector<float>& ds : deltas) #endif /* NDEBUG */ // 3) Subtract holes from the contours. +#ifdef CLIPPERUTILS_OFFSET_SCALE unscaleClipperPolygons(contours); +#endif // CLIPPERUTILS_OFFSET_SCALE ExPolygons output; if (holes.empty()) { output.reserve(contours.size()); @@ -1160,7 +1231,9 @@ for (const std::vector<float>& ds : deltas) output.emplace_back(ClipperPath_to_Slic3rPolygon(path)); } else { ClipperLib::Clipper clipper; +#ifdef CLIPPERUTILS_OFFSET_SCALE unscaleClipperPolygons(holes); +#endif // CLIPPERUTILS_OFFSET_SCALE clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); ClipperLib::PolyTree polytree; @@ -1200,7 +1273,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s #endif /* NDEBUG */ // 3) Subtract holes from the contours. +#ifdef CLIPPERUTILS_OFFSET_SCALE unscaleClipperPolygons(contours); +#endif // CLIPPERUTILS_OFFSET_SCALE ExPolygons output; if (holes.empty()) { output.reserve(contours.size()); @@ -1208,7 +1283,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s output.emplace_back(ClipperPath_to_Slic3rPolygon(path)); } else { ClipperLib::Clipper clipper; +#ifdef CLIPPERUTILS_OFFSET_SCALE unscaleClipperPolygons(holes); +#endif // CLIPPERUTILS_OFFSET_SCALE clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); ClipperLib::PolyTree polytree; diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index cd966435b..c1b887583 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -12,17 +12,21 @@ using ClipperLib::jtMiter; using ClipperLib::jtRound; 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) -#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1) -#define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE) +// #define CLIPPERUTILS_OFFSET_SCALE + +#ifdef CLIPPERUTILS_OFFSET_SCALE + // 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) + #define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1) + #define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE) +#endif // CLIPPERUTILS_OFFSET_SCALE namespace Slic3r { diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index aac7c7752..d5ef41125 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1087,11 +1087,13 @@ bool MedialAxis::validate_edge(const VD::edge_type* edge) { // prevent overflows and detect almost-infinite edges +#ifndef CLIPPERLIB_INT32 if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) || std::abs(edge->vertex0()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) || std::abs(edge->vertex1()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) || std::abs(edge->vertex1()->y()) > double(CLIPPER_MAX_COORD_UNSCALED)) return false; +#endif // CLIPPERLIB_INT32 // construct the line representing this edge of the Voronoi diagram const Line line(