>::Value;
/**
* \brief A point pair base class for other point pairs (segment, box, ...).
@@ -474,8 +484,8 @@ inline _Box _Box
::infinite(const P& center) {
// It is important for Mx and My to be strictly less than half of the
// range of type C. width(), height() and area() will not overflow this way.
- C Mx = C((std::numeric_limits::lowest() + 2 * getX(center)) / 2.01);
- C My = C((std::numeric_limits::lowest() + 2 * getY(center)) / 2.01);
+ C Mx = C((std::numeric_limits::lowest() + 2 * getX(center)) / 4.01);
+ C My = C((std::numeric_limits::lowest() + 2 * getY(center)) / 4.01);
ret.maxCorner() = center - P{Mx, My};
ret.minCorner() = center + P{Mx, My};
@@ -587,9 +597,9 @@ inline void reserve(RawPath& p, size_t vertex_capacity, const PathTag&)
}
template
-inline void addVertex(S& sh, const PathTag&, Args...args)
+inline void addVertex(S& sh, const PathTag&, const TPoint &p)
{
- sh.emplace_back(std::forward(args)...);
+ sh.emplace_back(p);
}
template
@@ -841,9 +851,9 @@ template auto rbegin(P& p) -> decltype(_backward(end(p)))
return _backward(end(p));
}
-template auto rcbegin(const P& p) -> decltype(_backward(end(p)))
+template auto rcbegin(const P& p) -> decltype(_backward(cend(p)))
{
- return _backward(end(p));
+ return _backward(cend(p));
}
template auto rend(P& p) -> decltype(_backward(begin(p)))
@@ -873,16 +883,16 @@ inline void reserve(T& sh, size_t vertex_capacity) {
reserve(sh, vertex_capacity, Tag());
}
-template
-inline void addVertex(S& sh, const PolygonTag&, Args...args)
+template
+inline void addVertex(S& sh, const PolygonTag&, const TPoint &p)
{
- addVertex(contour(sh), PathTag(), std::forward(args)...);
+ addVertex(contour(sh), PathTag(), p);
}
-template // Tag dispatcher
-inline void addVertex(S& sh, Args...args)
+template // Tag dispatcher
+inline void addVertex(S& sh, const TPoint &p)
{
- addVertex(sh, Tag(), std::forward(args)...);
+ addVertex(sh, Tag(), p);
}
template
diff --git a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
index 29a1ccd047..d9f9478026 100644
--- a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
+++ b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
@@ -28,7 +28,7 @@ inline void buildPolygon(const EdgeList& edgelist,
auto& rsh = sl::contour(rpoly);
- sl::reserve(rsh, 2*edgelist.size());
+ sl::reserve(rsh, 2 * edgelist.size());
// Add the two vertices from the first edge into the final polygon.
sl::addVertex(rsh, edgelist.front().first());
@@ -57,7 +57,6 @@ inline void buildPolygon(const EdgeList& edgelist,
tmp = std::next(tmp);
}
-
}
template
@@ -214,15 +213,24 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
// Reserve the needed memory
edgelist.reserve(cap);
sl::reserve(rsh, static_cast(cap));
+ auto add_edge = [&edgelist](const Vertex &v1, const Vertex &v2) {
+ Edge e{v1, v2};
+ if (e.sqlength() > 0)
+ edgelist.emplace_back(e);
+ };
{ // place all edges from sh into edgelist
auto first = sl::cbegin(sh);
auto next = std::next(first);
while(next != sl::cend(sh)) {
- edgelist.emplace_back(*(first), *(next));
+ add_edge(*(first), *(next));
+
++first; ++next;
}
+
+ if constexpr (ClosureTypeV == Closure::OPEN)
+ add_edge(*sl::rcbegin(sh), *sl::cbegin(sh));
}
{ // place all edges from other into edgelist
@@ -230,15 +238,19 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
auto next = std::next(first);
while(next != sl::cend(other)) {
- edgelist.emplace_back(*(next), *(first));
+ add_edge(*(next), *(first));
+
++first; ++next;
}
+
+ if constexpr (ClosureTypeV == Closure::OPEN)
+ add_edge(*sl::cbegin(other), *sl::rcbegin(other));
}
- std::sort(edgelist.begin(), edgelist.end(),
- [](const Edge& e1, const Edge& e2)
+ std::sort(edgelist.begin(), edgelist.end(),
+ [](const Edge& e1, const Edge& e2)
{
- Vertex ax(1, 0); // Unit vector for the X axis
+ const Vertex ax(1, 0); // Unit vector for the X axis
// get cectors from the edges
Vertex p1 = e1.second() - e1.first();
@@ -284,12 +296,18 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
// If Ratio is an actual rational type, there is no precision loss
auto pcos1 = Ratio(lcos[0]) / lsq1 * sign * lcos[0];
auto pcos2 = Ratio(lcos[1]) / lsq2 * sign * lcos[1];
-
- return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
+
+ if constexpr (is_clockwise())
+ return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
+ else
+ return q[0] < 2 ? pcos1 > pcos2 : pcos1 < pcos2;
}
// If in different quadrants, compare the quadrant indices only.
- return q[0] > q[1];
+ if constexpr (is_clockwise())
+ return q[0] > q[1];
+ else
+ return q[0] < q[1];
});
__nfp::buildPolygon(edgelist, rsh, top_nfp);
diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp
index 9d24a25696..a4cf7dc569 100644
--- a/src/libnest2d/include/libnest2d/libnest2d.hpp
+++ b/src/libnest2d/include/libnest2d/libnest2d.hpp
@@ -7,6 +7,10 @@
#include
#endif
+#ifdef LIBNEST2D_GEOMETRIES_libslic3r
+#include
+#endif
+
#ifdef LIBNEST2D_OPTIMIZER_nlopt
// We include the stock optimizers for local and global optimization
#include // Local subplex for NfpPlacer
diff --git a/src/libnest2d/include/libnest2d/nester.hpp b/src/libnest2d/include/libnest2d/nester.hpp
index 20da9b9a1e..52c738a4c1 100644
--- a/src/libnest2d/include/libnest2d/nester.hpp
+++ b/src/libnest2d/include/libnest2d/nester.hpp
@@ -96,7 +96,7 @@ public:
* @return The orientation type identifier for the _Item type.
*/
static BP2D_CONSTEXPR Orientation orientation() {
- return OrientationType::Value;
+ return OrientationType>::Value;
}
/**
@@ -446,44 +446,32 @@ private:
}
};
+template Sh create_rect(TCoord width, TCoord height)
+{
+ auto sh = sl::create(
+ {{0, 0}, {0, height}, {width, height}, {width, 0}});
+
+ if constexpr (ClosureTypeV == Closure::CLOSED)
+ sl::addVertex(sh, {0, 0});
+
+ if constexpr (OrientationTypeV == Orientation::COUNTER_CLOCKWISE)
+ std::reverse(sl::begin(sh), sl::end(sh));
+
+ return sh;
+}
+
/**
* \brief Subclass of _Item for regular rectangle items.
*/
-template
-class _Rectangle: public _Item {
- using _Item::vertex;
+template
+class _Rectangle: public _Item {
+ using _Item::vertex;
using TO = Orientation;
public:
- using Unit = TCoord>;
+ using Unit = TCoord;
- template::Value>
- inline _Rectangle(Unit width, Unit height,
- // disable this ctor if o != CLOCKWISE
- enable_if_t< o == TO::CLOCKWISE, int> = 0 ):
- _Item( sl::create( {
- {0, 0},
- {0, height},
- {width, height},
- {width, 0},
- {0, 0}
- } ))
- {
- }
-
- template::Value>
- inline _Rectangle(Unit width, Unit height,
- // disable this ctor if o != COUNTER_CLOCKWISE
- enable_if_t< o == TO::COUNTER_CLOCKWISE, int> = 0 ):
- _Item( sl::create( {
- {0, 0},
- {width, 0},
- {width, height},
- {0, height},
- {0, 0}
- } ))
- {
- }
+ inline _Rectangle(Unit w, Unit h): _Item{create_rect(w, h)} {}
inline Unit width() const BP2D_NOEXCEPT {
return getX(vertex(2));
diff --git a/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp b/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
index e1a4ffbd92..a067194dc9 100644
--- a/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
@@ -365,44 +365,50 @@ protected:
// the additional vertices for maintaning min object distance
sl::reserve(rsh, finish-start+4);
- /*auto addOthers = [&rsh, finish, start, &item](){
+ auto addOthers_ = [&rsh, finish, start, &item](){
for(size_t i = start+1; i < finish; i++)
sl::addVertex(rsh, item.vertex(i));
- };*/
+ };
- auto reverseAddOthers = [&rsh, finish, start, &item](){
+ auto reverseAddOthers_ = [&rsh, finish, start, &item](){
for(auto i = finish-1; i > start; i--)
- sl::addVertex(rsh, item.vertex(
- static_cast(i)));
+ sl::addVertex(rsh, item.vertex(static_cast(i)));
+ };
+
+ auto addOthers = [&addOthers_, &reverseAddOthers_]() {
+ if constexpr (!is_clockwise())
+ addOthers_();
+ else
+ reverseAddOthers_();
};
// Final polygon construction...
- static_assert(OrientationType::Value ==
- Orientation::CLOCKWISE,
- "Counter clockwise toWallPoly() Unimplemented!");
-
// Clockwise polygon construction
sl::addVertex(rsh, topleft_vertex);
- if(dir == Dir::LEFT) reverseAddOthers();
+ if(dir == Dir::LEFT) addOthers();
else {
- sl::addVertex(rsh, getX(topleft_vertex), 0);
- sl::addVertex(rsh, getX(bottomleft_vertex), 0);
+ sl::addVertex(rsh, {getX(topleft_vertex), 0});
+ sl::addVertex(rsh, {getX(bottomleft_vertex), 0});
}
sl::addVertex(rsh, bottomleft_vertex);
if(dir == Dir::LEFT) {
- sl::addVertex(rsh, 0, getY(bottomleft_vertex));
- sl::addVertex(rsh, 0, getY(topleft_vertex));
+ sl::addVertex(rsh, {0, getY(bottomleft_vertex)});
+ sl::addVertex(rsh, {0, getY(topleft_vertex)});
}
- else reverseAddOthers();
+ else addOthers();
// Close the polygon
- sl::addVertex(rsh, topleft_vertex);
+ if constexpr (ClosureTypeV == Closure::CLOSED)
+ sl::addVertex(rsh, topleft_vertex);
+
+ if constexpr (!is_clockwise())
+ std::reverse(rsh.begin(), rsh.end());
return ret;
}
diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
index bd9c603558..47ba7bbdc5 100644
--- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
@@ -250,8 +250,8 @@ template class EdgeCache {
Vertex ret = edge.first();
// Get the point on the edge which lies in ed distance from the start
- ret += { static_cast(std::round(ed*std::cos(angle))),
- static_cast(std::round(ed*std::sin(angle))) };
+ ret += Vertex(static_cast(std::round(ed*std::cos(angle))),
+ static_cast(std::round(ed*std::sin(angle))));
return ret;
}
@@ -724,8 +724,7 @@ private:
auto rawobjfunc = [_objfunc, iv, startpos]
(Vertex v, Item& itm)
{
- auto d = v - iv;
- d += startpos;
+ auto d = (v - iv) + startpos;
itm.translation(d);
return _objfunc(itm);
};
@@ -742,8 +741,7 @@ private:
&item, &bin, &iv, &startpos] (const Optimum& o)
{
auto v = getNfpPoint(o);
- auto d = v - iv;
- d += startpos;
+ auto d = (v - iv) + startpos;
item.translation(d);
merged_pile.emplace_back(item.transformedShape());
@@ -877,8 +875,7 @@ private:
}
if( best_score < global_score ) {
- auto d = getNfpPoint(optimum) - iv;
- d += startpos;
+ auto d = (getNfpPoint(optimum) - iv) + startpos;
final_tr = d;
final_rot = initial_rot + rot;
can_pack = true;
diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
index 16dee513b2..d6213d0edd 100644
--- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
+++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
@@ -19,7 +19,7 @@
#pragma warning(pop)
#endif
// this should be removed to not confuse the compiler
-// #include
+// #include "../libnest2d.hpp"
namespace bp2d {
@@ -30,6 +30,10 @@ using libnest2d::PolygonImpl;
using libnest2d::PathImpl;
using libnest2d::Orientation;
using libnest2d::OrientationType;
+using libnest2d::OrientationTypeV;
+using libnest2d::ClosureType;
+using libnest2d::Closure;
+using libnest2d::ClosureTypeV;
using libnest2d::getX;
using libnest2d::getY;
using libnest2d::setX;
@@ -213,8 +217,15 @@ struct ToBoostOrienation {
static const order_selector Value = counterclockwise;
};
-static const bp2d::Orientation RealOrientation =
- bp2d::OrientationType::Value;
+template struct ToBoostClosure {};
+
+template<> struct ToBoostClosure {
+ static const constexpr closure_selector Value = closure_selector::open;
+};
+
+template<> struct ToBoostClosure {
+ static const constexpr closure_selector Value = closure_selector::closed;
+};
// Ring implementation /////////////////////////////////////////////////////////
@@ -225,12 +236,13 @@ template<> struct tag {
template<> struct point_order {
static const order_selector value =
- ToBoostOrienation::Value;
+ ToBoostOrienation>::Value;
};
// All our Paths should be closed for the bin packing application
template<> struct closure {
- static const closure_selector value = closed;
+ static const constexpr closure_selector value =
+ ToBoostClosure< bp2d::ClosureTypeV >::Value;
};
// Polygon implementation //////////////////////////////////////////////////////
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index 3800d49e31..61a32678b9 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -3,7 +3,7 @@
#include "BoundingBox.hpp"
-#include
+#include
#include
#include
#include
@@ -54,23 +54,22 @@ namespace Slic3r {
template, int...EigenArgs>
inline constexpr Eigen::Matrix unscaled(
- const ClipperLib::IntPoint &v) noexcept
+ const Slic3r::ClipperLib::IntPoint &v) noexcept
{
- return Eigen::Matrix{unscaled(v.X),
- unscaled(v.Y)};
+ return Eigen::Matrix{unscaled(v.x()),
+ unscaled(v.y())};
}
namespace arrangement {
using namespace libnest2d;
-namespace clppr = ClipperLib;
// Get the libnest2d types for clipper backend
-using Item = _Item;
-using Box = _Box;
-using Circle = _Circle;
-using Segment = _Segment;
-using MultiPolygon = TMultiShape;
+using Item = _Item;
+using Box = _Box;
+using Circle = _Circle;
+using Segment = _Segment;
+using MultiPolygon = ExPolygons;
// Summon the spatial indexing facilities from boost
namespace bgi = boost::geometry::index;
@@ -127,8 +126,8 @@ template
class AutoArranger {
public:
// Useful type shortcuts...
- using Placer = typename placers::_NofitPolyPlacer;
- using Selector = selections::_FirstFitSelection;
+ using Placer = typename placers::_NofitPolyPlacer;
+ using Selector = selections::_FirstFitSelection;
using Packer = _Nester;
using PConfig = typename Packer::PlacementConfig;
using Distance = TCoord;
@@ -168,7 +167,7 @@ protected:
// as it possibly can be but at the same time, it has to provide
// reasonable results.
std::tuple
- objfunc(const Item &item, const clppr::IntPoint &bincenter)
+ objfunc(const Item &item, const Point &bincenter)
{
const double bin_area = m_bin_area;
const SpatIndex& spatindex = m_rtree;
@@ -220,12 +219,12 @@ protected:
switch (compute_case) {
case BIG_ITEM: {
- const clppr::IntPoint& minc = ibb.minCorner(); // bottom left corner
- const clppr::IntPoint& maxc = ibb.maxCorner(); // top right corner
+ const Point& minc = ibb.minCorner(); // bottom left corner
+ const Point& maxc = ibb.maxCorner(); // top right corner
// top left and bottom right corners
- clppr::IntPoint top_left{getX(minc), getY(maxc)};
- clppr::IntPoint bottom_right{getX(maxc), getY(minc)};
+ Point top_left{getX(minc), getY(maxc)};
+ Point bottom_right{getX(maxc), getY(minc)};
// Now the distance of the gravity center will be calculated to the
// five anchor points and the smallest will be chosen.
@@ -452,7 +451,7 @@ template<> std::function AutoArranger::get_objfn()
// Specialization for a generalized polygon.
// Warning: this is unfinished business. It may or may not work.
template<>
-std::function AutoArranger::get_objfn()
+std::function AutoArranger::get_objfn()
{
auto bincenter = sl::boundingBox(m_bin).center();
return [this, bincenter](const Item &item) {
@@ -521,7 +520,7 @@ void _arrange(
inline Box to_nestbin(const BoundingBox &bb) { return Box{{bb.min(X), bb.min(Y)}, {bb.max(X), bb.max(Y)}};}
inline Circle to_nestbin(const CircleBed &c) { return Circle({c.center()(0), c.center()(1)}, c.radius()); }
-inline clppr::Polygon to_nestbin(const Polygon &p) { return sl::create(Slic3rMultiPoint_to_ClipperPath(p)); }
+inline ExPolygon to_nestbin(const Polygon &p) { return ExPolygon{p}; }
inline Box to_nestbin(const InfiniteBed &bed) { return Box::infinite({bed.center.x(), bed.center.y()}); }
inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x(); }
@@ -568,19 +567,12 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
const Vec2crd &offs = arrpoly.translation;
double rotation = arrpoly.rotation;
- if (p.is_counter_clockwise()) p.reverse();
-
- clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
-
// This fixes:
// https://github.com/prusa3d/PrusaSlicer/issues/2209
- if (clpath.Contour.size() < 3)
+ if (p.points.size() < 3)
return;
- auto firstp = clpath.Contour.front();
- clpath.Contour.emplace_back(firstp);
-
- outp.emplace_back(std::move(clpath));
+ outp.emplace_back(std::move(p));
outp.back().rotation(rotation);
outp.back().translation({offs.x(), offs.y()});
outp.back().binId(arrpoly.bed_idx);
@@ -624,7 +616,7 @@ void arrange(ArrangePolygons & arrangables,
const BedT & bed,
const ArrangeParams & params)
{
- namespace clppr = ClipperLib;
+ namespace clppr = Slic3r::ClipperLib;
std::vector- items, fixeditems;
items.reserve(arrangables.size());
@@ -643,8 +635,8 @@ void arrange(ArrangePolygons & arrangables,
_arrange(items, fixeditems, to_nestbin(bed), params, pri, cfn);
for(size_t i = 0; i < items.size(); ++i) {
- clppr::IntPoint tr = items[i].translation();
- arrangables[i].translation = {coord_t(tr.X), coord_t(tr.Y)};
+ Point tr = items[i].translation();
+ arrangables[i].translation = {coord_t(tr.x()), coord_t(tr.y())};
arrangables[i].rotation = items[i].rotation();
arrangables[i].bed_idx = items[i].binId();
}
diff --git a/src/libslic3r/BoundingBox.cpp b/src/libslic3r/BoundingBox.cpp
index eb4e042a08..4f52c5108d 100644
--- a/src/libslic3r/BoundingBox.cpp
+++ b/src/libslic3r/BoundingBox.cpp
@@ -225,24 +225,11 @@ BoundingBox3Base::max_size() const
template coordf_t BoundingBox3Base::max_size() const;
template coordf_t BoundingBox3Base::max_size() const;
-// Align a coordinate to a grid. The coordinate may be negative,
-// the aligned value will never be bigger than the original one.
-static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
- // Current C++ standard defines the result of integer division to be rounded to zero,
- // for both positive and negative numbers. Here we want to round down for negative
- // numbers as well.
- coord_t aligned = (coord < 0) ?
- ((coord - spacing + 1) / spacing) * spacing :
- (coord / spacing) * spacing;
- assert(aligned <= coord);
- return aligned;
-}
-
void BoundingBox::align_to_grid(const coord_t cell_size)
{
if (this->defined) {
- min(0) = _align_to_grid(min(0), cell_size);
- min(1) = _align_to_grid(min(1), cell_size);
+ min(0) = Slic3r::align_to_grid(min(0), cell_size);
+ min(1) = Slic3r::align_to_grid(min(1), cell_size);
}
}
diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp
index ff33e81d53..cd90a1f03d 100644
--- a/src/libslic3r/BridgeDetector.cpp
+++ b/src/libslic3r/BridgeDetector.cpp
@@ -40,7 +40,7 @@ void BridgeDetector::initialize()
this->angle = -1.;
// Outset our bridge by an arbitrary amout; we'll use this outer margin for detecting anchors.
- Polygons grown = offset(to_polygons(this->expolygons), float(this->spacing));
+ Polygons grown = offset(this->expolygons, float(this->spacing));
// Detect possible anchoring edges of this bridging region.
// Detect what edges lie on lower slices by turning bridge contour and holes
@@ -227,29 +227,33 @@ void ExPolygon::get_trapezoids(ExPolygon clone, Polygons* polygons, double angle
// This algorithm may return more trapezoids than necessary
// (i.e. it may break a single trapezoid in several because
// other parts of the object have x coordinates in the middle)
-static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons)
+static void get_trapezoids2(const ExPolygon& expoly, Polygons* polygons)
{
Polygons src_polygons = to_polygons(expoly);
// get all points of this ExPolygon
- const Points pp = to_points(src_polygons);
-
+ const Points pp = to_points(src_polygons);
+
// build our bounding box
BoundingBox bb(pp);
-
+
// get all x coordinates
std::vector xx;
xx.reserve(pp.size());
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
xx.push_back(p->x());
std::sort(xx.begin(), xx.end());
-
+
// find trapezoids by looping from first to next-to-last coordinate
+ Polygons rectangle;
+ rectangle.emplace_back(Polygon());
for (std::vector::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
- if (*x != next_x)
+ if (*x != next_x) {
// intersect with rectangle
// append results to return value
- polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, src_polygons));
+ rectangle.front() = { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } };
+ polygons_append(*polygons, intersection(rectangle, src_polygons));
+ }
}
}
@@ -302,7 +306,7 @@ Polygons BridgeDetector::coverage(double angle) const
covered = union_(covered);
// Intersect trapezoids with actual bridge area to remove extra margins and append it to result.
polygons_rotate(covered, -(PI/2.0 - angle));
- covered = intersection(covered, to_polygons(this->expolygons));
+ covered = intersection(this->expolygons, covered);
#if 0
{
my @lines = map @{$_->lines}, @$trapezoids;
diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp
index 08bedc5c04..68851e051e 100644
--- a/src/libslic3r/Brim.cpp
+++ b/src/libslic3r/Brim.cpp
@@ -78,7 +78,7 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
// Assign the maximum Z from four points. This values is valid index of the island
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
- pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
+ pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
});
// Add islands
clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true);
@@ -90,9 +90,9 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
ConstPrintObjectPtrs top_level_objects_with_brim;
for (int i = 0; i < islands_polytree.ChildCount(); ++i) {
for (const ClipperLib_Z::IntPoint &point : islands_polytree.Childs[i]->Contour) {
- if (point.Z != 0 && processed_objects_idx.find(island_to_object[point.Z - 1]->id().id) == processed_objects_idx.end()) {
- top_level_objects_with_brim.emplace_back(island_to_object[point.Z - 1]);
- processed_objects_idx.insert(island_to_object[point.Z - 1]->id().id);
+ if (point.z() != 0 && processed_objects_idx.find(island_to_object[point.z() - 1]->id().id) == processed_objects_idx.end()) {
+ top_level_objects_with_brim.emplace_back(island_to_object[point.z() - 1]);
+ processed_objects_idx.insert(island_to_object[point.z() - 1]->id().id);
}
}
}
@@ -139,7 +139,7 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
Polygons no_brim_area_object;
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) && is_top_outer_brim)
- append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset)));
+ append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset)));
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, offset(ex_poly.holes, -no_brim_offset));
@@ -156,7 +156,7 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
}
}
- return diff_ex(to_polygons(std::move(brim_area)), no_brim_area);
+ return diff_ex(brim_area, no_brim_area);
}
static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
@@ -183,14 +183,14 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs
if (top_outer_brim)
no_brim_area_object.emplace_back(ex_poly);
else
- append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset), offset_ex(ex_poly.contour, brim_offset)));
+ append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset)));
}
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner)
append(brim_area_object, diff_ex(offset_ex(ex_poly.holes, -brim_offset), offset_ex(ex_poly.holes, -brim_width - brim_offset)));
if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ex_poly.contour, no_brim_offset));
+ append(no_brim_area_object, to_expolygons(offset(ex_poly.contour, no_brim_offset)));
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset));
@@ -317,7 +317,7 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), jtSquare);
}
- loops = union_pt_chained_outside_in(loops, false);
+ loops = union_pt_chained_outside_in(loops);
std::reverse(loops.begin(), loops.end());
extrusion_entities_append_loops(brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()),
float(flow.width()), float(print.skirt_first_layer_height()));
@@ -342,7 +342,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
poly.douglas_peucker(SCALED_RESOLUTION);
polygons_append(loops, offset(islands, -0.5f * float(flow.scaled_spacing())));
}
- loops = union_pt_chained_outside_in(loops, false);
+ loops = union_pt_chained_outside_in(loops);
std::vector loops_pl_by_levels;
{
@@ -456,7 +456,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) {
// Assign a valid input loop identifier. Such an identifier is strictly positive, the next line is safe even in case one side of a segment
// hat the Z coordinate not set to the contour coordinate.
- pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
+ pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
});
// add polygons
clipper.AddPaths(input_clip, ClipperLib_Z::ptSubject, false);
@@ -474,8 +474,8 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
for (const ClipperLib_Z::Path &path : loops_trimmed) {
size_t input_idx = 0;
for (const ClipperLib_Z::IntPoint &pt : path)
- if (pt.Z > 0) {
- input_idx = (size_t)pt.Z;
+ if (pt.z() > 0) {
+ input_idx = (size_t)pt.z();
break;
}
assert(input_idx != 0);
@@ -492,14 +492,14 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
size_t j = i + 1;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
- if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
+ if (i + 1 == j && first_path.size() > 3 && first_path.front().x() == first_path.back().x() && first_path.front().y() == first_path.back().y()) {
auto *loop = new ExtrusionLoop();
brim.entities.emplace_back(loop);
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
Points &points = loop->paths.front().polyline.points;
points.reserve(first_path.size());
for (const ClipperLib_Z::IntPoint &pt : first_path)
- points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
+ points.emplace_back(coord_t(pt.x()), coord_t(pt.y()));
i = j;
} else {
//FIXME The path chaining here may not be optimal.
@@ -511,7 +511,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
Points &points = static_cast(this_loop_trimmed.entities.back())->polyline.points;
points.reserve(path.size());
for (const ClipperLib_Z::IntPoint &pt : path)
- points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
+ points.emplace_back(coord_t(pt.x()), coord_t(pt.y()));
}
chain_and_reorder_extrusion_entities(this_loop_trimmed.entities, &last_pt);
brim.entities.reserve(brim.entities.size() + this_loop_trimmed.entities.size());
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 4a762f7e15..16299f442d 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -23,6 +23,8 @@ add_library(libslic3r STATIC
BridgeDetector.hpp
Brim.cpp
Brim.hpp
+ clipper.cpp
+ clipper.hpp
ClipperUtils.cpp
ClipperUtils.hpp
Config.cpp
@@ -219,6 +221,9 @@ add_library(libslic3r STATIC
SimplifyMeshImpl.hpp
SimplifyMesh.cpp
MarchingSquares.hpp
+ Execution/Execution.hpp
+ Execution/ExecutionSeq.hpp
+ Execution/ExecutionTBB.hpp
Optimize/Optimizer.hpp
Optimize/NLoptOptimizer.hpp
Optimize/BruteforceOptimizer.hpp
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index 305ea134f0..8bca3b25a3 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -24,7 +24,6 @@
namespace Slic3r {
#ifdef CLIPPER_UTILS_DEBUG
-bool clipper_export_enabled = false;
// For debugging the Clipper library, for providing bug reports to the Clipper author.
bool export_clipper_input_polygons_bin(const char *path, const ClipperLib::Paths &input_subject, const ClipperLib::Paths &input_clip)
{
@@ -57,377 +56,265 @@ err:
}
#endif /* CLIPPER_UTILS_DEBUG */
-void scaleClipperPolygon(ClipperLib::Path &polygon)
-{
- CLIPPERUTILS_PROFILE_FUNC();
- for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
- pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
- pit->Y <<= CLIPPER_OFFSET_POWER_OF_2;
- }
+namespace ClipperUtils {
+ Points EmptyPathsProvider::s_empty_points;
+ Points SinglePathProvider::s_end;
}
-void scaleClipperPolygons(ClipperLib::Paths &polygons)
+static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree)
{
- CLIPPERUTILS_PROFILE_FUNC();
- for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
- for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
- pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
- pit->Y <<= CLIPPER_OFFSET_POWER_OF_2;
+ struct Inner {
+ static void PolyTreeToExPolygonsRecursive(ClipperLib::PolyNode &&polynode, ExPolygons *expolygons)
+ {
+ size_t cnt = expolygons->size();
+ expolygons->resize(cnt + 1);
+ (*expolygons)[cnt].contour.points = std::move(polynode.Contour);
+ (*expolygons)[cnt].holes.resize(polynode.ChildCount());
+ for (int i = 0; i < polynode.ChildCount(); ++ i) {
+ (*expolygons)[cnt].holes[i].points = std::move(polynode.Childs[i]->Contour);
+ // Add outer polygons contained by (nested within) holes.
+ for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j)
+ PolyTreeToExPolygonsRecursive(std::move(*polynode.Childs[i]->Childs[j]), expolygons);
+ }
}
-}
-void unscaleClipperPolygon(ClipperLib::Path &polygon)
-{
- CLIPPERUTILS_PROFILE_FUNC();
- for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
- pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
- pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
- pit->X >>= CLIPPER_OFFSET_POWER_OF_2;
- pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
- }
-}
-
-void unscaleClipperPolygons(ClipperLib::Paths &polygons)
-{
- CLIPPERUTILS_PROFILE_FUNC();
- for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
- for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
- pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
- pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
- pit->X >>= CLIPPER_OFFSET_POWER_OF_2;
- pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
+ static size_t PolyTreeCountExPolygons(const ClipperLib::PolyNode &polynode)
+ {
+ size_t cnt = 1;
+ for (int i = 0; i < polynode.ChildCount(); ++ i) {
+ for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j)
+ cnt += PolyTreeCountExPolygons(*polynode.Childs[i]->Childs[j]);
+ }
+ return cnt;
}
-}
+ };
-//-----------------------------------------------------------
-// legacy code from Clipper documentation
-void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, ExPolygons* expolygons)
-{
- size_t cnt = expolygons->size();
- expolygons->resize(cnt + 1);
- (*expolygons)[cnt].contour = ClipperPath_to_Slic3rPolygon(polynode.Contour);
- (*expolygons)[cnt].holes.resize(polynode.ChildCount());
- for (int i = 0; i < polynode.ChildCount(); ++i)
- {
- (*expolygons)[cnt].holes[i] = ClipperPath_to_Slic3rPolygon(polynode.Childs[i]->Contour);
- //Add outer polygons contained by (nested within) holes ...
- for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j)
- AddOuterPolyNodeToExPolygons(*polynode.Childs[i]->Childs[j], expolygons);
- }
-}
-
-ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree)
-{
ExPolygons retval;
- for (int i = 0; i < polytree.ChildCount(); ++i)
- AddOuterPolyNodeToExPolygons(*polytree.Childs[i], &retval);
- return retval;
-}
-//-----------------------------------------------------------
-
-Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input)
-{
- Polygon retval;
- for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.emplace_back(pit->X, pit->Y);
+ size_t cnt = 0;
+ for (int i = 0; i < polytree.ChildCount(); ++ i)
+ cnt += Inner::PolyTreeCountExPolygons(*polytree.Childs[i]);
+ retval.reserve(cnt);
+ for (int i = 0; i < polytree.ChildCount(); ++ i)
+ Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree.Childs[i]), &retval);
return retval;
}
-Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input)
+Polylines PolyTreeToPolylines(ClipperLib::PolyTree &&polytree)
{
- Polyline retval;
- for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.emplace_back(pit->X, pit->Y);
- return retval;
-}
+ struct Inner {
+ static void AddPolyNodeToPaths(ClipperLib::PolyNode &polynode, Polylines &out)
+ {
+ if (! polynode.Contour.empty())
+ out.emplace_back(std::move(polynode.Contour));
+ for (ClipperLib::PolyNode *child : polynode.Childs)
+ AddPolyNodeToPaths(*child, out);
+ }
+ };
-Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input)
-{
- Slic3r::Polygons retval;
- retval.reserve(input.size());
- for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it));
- return retval;
-}
-
-Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input)
-{
- Slic3r::Polylines retval;
- retval.reserve(input.size());
- for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it));
- return retval;
+ Polylines out;
+ out.reserve(polytree.Total());
+ Inner::AddPolyNodeToPaths(polytree, out);
+ return out;
}
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
{
- // init Clipper
ClipperLib::Clipper clipper;
- clipper.Clear();
-
- // perform union
clipper.AddPaths(input, ClipperLib::ptSubject, true);
ClipperLib::PolyTree polytree;
clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero
-
- // write to ExPolygons object
- return PolyTreeToExPolygons(polytree);
+ return PolyTreeToExPolygons(std::move(polytree));
}
-ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
+// Offset outside by 10um, one by one.
+template
+static ClipperLib::Paths safety_offset(PathsProvider &&paths)
{
- ClipperLib::Path retval;
- for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
- retval.emplace_back((*pit)(0), (*pit)(1));
- return retval;
-}
-
-ClipperLib::Path Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input)
-{
- ClipperLib::Path output;
- output.reserve(input.points.size());
- for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit)
- output.emplace_back((*pit)(0), (*pit)(1));
- return output;
-}
-
-ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input)
-{
- ClipperLib::Paths retval;
- for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it));
- return retval;
-}
-
-ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const ExPolygons &input)
-{
- ClipperLib::Paths retval;
- for (auto &ep : input) {
- retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(ep.contour));
-
- for (auto &h : ep.holes)
- retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(h));
+ ClipperLib::ClipperOffset co;
+ ClipperLib::Paths out;
+ out.reserve(paths.size());
+ ClipperLib::Paths out_this;
+ for (const ClipperLib::Path &path : paths) {
+ co.Clear();
+ co.MiterLimit = 2.;
+ co.AddPath(path, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
+ co.Execute(out_this, ClipperSafetyOffset);
+ append(out, std::move(out_this));
}
-
- return retval;
+ return out;
}
-ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input)
+template
+ClipperLib::Paths _offset(PathsProvider &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
{
- ClipperLib::Paths retval;
- for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it));
- return retval;
-}
-
-ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
-{
- // scale input
- scaleClipperPolygons(input);
-
// perform offset
ClipperLib::ClipperOffset co;
if (joinType == jtRound)
co.ArcTolerance = miterLimit;
else
co.MiterLimit = miterLimit;
- float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
+ float delta_scaled = delta;
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
- co.AddPaths(input, joinType, endType);
+ co.AddPaths(std::forward(input), joinType, endType);
ClipperLib::Paths retval;
co.Execute(retval, delta_scaled);
-
- // unscale output
- unscaleClipperPolygons(retval);
return retval;
}
-ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
-{
- ClipperLib::Paths paths;
- paths.emplace_back(std::move(input));
- return _offset(std::move(paths), endType, delta, joinType, miterLimit);
-}
+Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(ClipperUtils::SinglePathProvider(polygon.points), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
-// This is a safe variant of the polygon offset, tailored for a single ExPolygon:
-// a single polygon with multiple non-overlapping holes.
-// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
-ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
- ClipperLib::JoinType joinType, double miterLimit)
+#ifdef CLIPPERUTILS_UNSAFE_OFFSET
+Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(ClipperUtils::PolygonsProvider(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
+#endif // CLIPPERUTILS_UNSAFE_OFFSET
+
+Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(ClipperUtils::SinglePathProvider(polyline.points), ClipperLib::etOpenButt, delta, joinType, miterLimit)); }
+Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(ClipperUtils::PolylinesProvider(polylines), ClipperLib::etOpenButt, delta, joinType, miterLimit)); }
+
+#ifdef CLIPPERUTILS_UNSAFE_OFFSET
+Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return ClipperPaths_to_Slic3rExPolygons(_offset(ClipperUtils::PolygonsProvider(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
+#endif // CLIPPERUTILS_UNSAFE_OFFSET
+
+// returns number of expolygons collected (0 or 1).
+static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
{
-// printf("new ExPolygon offset\n");
// 1) Offset the outer contour.
- const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
ClipperLib::Paths contours;
{
- ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour);
- scaleClipperPolygon(input);
ClipperLib::ClipperOffset co;
if (joinType == jtRound)
- co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
+ co.ArcTolerance = miterLimit;
else
co.MiterLimit = miterLimit;
- co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
- co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
- co.Execute(contours, delta_scaled);
+ co.ShortestEdgeLength = double(std::abs(delta * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
+ co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon);
+ co.Execute(contours, delta);
}
+ if (contours.empty())
+ // No need to try to offset the holes.
+ return 0;
- // 2) Offset the holes one by one, collect the results.
- ClipperLib::Paths holes;
- {
- 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);
- scaleClipperPolygon(input);
- ClipperLib::ClipperOffset co;
- if (joinType == jtRound)
- co.ArcTolerance = miterLimit * double(CLIPPER_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());
+ if (expoly.holes.empty()) {
+ // No need to subtract holes from the offsetted expolygon, we are done.
+ append(out, std::move(contours));
+ } else {
+ // 2) Offset the holes one by one, collect the offsetted holes.
+ ClipperLib::Paths holes;
+ {
+ for (const Polygon &hole : expoly.holes) {
+ ClipperLib::ClipperOffset co;
+ if (joinType == jtRound)
+ co.ArcTolerance = miterLimit;
+ else
+ co.MiterLimit = miterLimit;
+ co.ShortestEdgeLength = double(std::abs(delta * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
+ co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon);
+ ClipperLib::Paths out2;
+ // Execute reorients the contours so that the outer most contour has a positive area. Thus the output
+ // contours will be CCW oriented even though the input paths are CW oriented.
+ // Offset is applied after contour reorientation, thus the signum of the offset value is reversed.
+ co.Execute(out2, - delta);
+ append(holes, std::move(out2));
+ }
+ }
+
+ // 3) Subtract holes from the contours.
+ if (holes.empty()) {
+ // No hole remaining after an offset. Just copy the outer contour.
+ append(out, std::move(contours));
+ } else if (delta < 0) {
+ // Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
+ // Subtract the offsetted holes from the offsetted contours.
+ ClipperLib::Clipper clipper;
+ clipper.Clear();
+ clipper.AddPaths(contours, ClipperLib::ptSubject, true);
+ clipper.AddPaths(holes, ClipperLib::ptClip, true);
+ ClipperLib::Paths output;
+ clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
+ if (! output.empty()) {
+ append(out, std::move(output));
+ } else {
+ // The offsetted holes have eaten up the offsetted outer contour.
+ return 0;
+ }
+ } else {
+ // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller
+ // area than the original hole or even disappear, therefore there will be no new intersections.
+ // Just collect the reversed holes.
+ out.reserve(contours.size() + holes.size());
+ append(out, std::move(contours));
+ // Reverse the holes in place.
+ for (size_t i = 0; i < holes.size(); ++ i)
+ std::reverse(holes[i].begin(), holes[i].end());
+ append(out, std::move(holes));
}
}
- // 3) Subtract holes from the contours.
- ClipperLib::Paths output;
- if (holes.empty()) {
- output = std::move(contours);
- } else {
- ClipperLib::Clipper clipper;
- clipper.Clear();
- clipper.AddPaths(contours, ClipperLib::ptSubject, true);
- clipper.AddPaths(holes, ClipperLib::ptClip, true);
- clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
- }
-
- // 4) Unscale the output.
- unscaleClipperPolygons(output);
- return output;
+ return 1;
+}
+
+static int offset_expolygon_inner(const Slic3r::Surface &surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
+ { return offset_expolygon_inner(surface.expolygon, delta, joinType, miterLimit, out); }
+static int offset_expolygon_inner(const Slic3r::Surface *surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out)
+ { return offset_expolygon_inner(surface->expolygon, delta, joinType, miterLimit, out); }
+
+ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+{
+ ClipperLib::Paths out;
+ offset_expolygon_inner(expolygon, delta, joinType, miterLimit, out);
+ return out;
}
// This is a safe variant of the polygons offset, tailored for multiple ExPolygons.
// It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours.
// Each ExPolygon is offsetted separately, then the offsetted ExPolygons are united.
-ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta,
- ClipperLib::JoinType joinType, double miterLimit)
+template
+ClipperLib::Paths _offset(const ExPolygonVector &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
{
- const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
// Offsetted ExPolygons before they are united.
- ClipperLib::Paths contours_cummulative;
- contours_cummulative.reserve(expolygons.size());
- // How many non-empty offsetted expolygons were actually collected into contours_cummulative?
+ ClipperLib::Paths output;
+ output.reserve(expolygons.size());
+ // How many non-empty offsetted expolygons were actually collected into output?
// If only one, then there is no need to do a final union.
size_t expolygons_collected = 0;
- for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) {
- // 1) Offset the outer contour.
- ClipperLib::Paths contours;
- {
- ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour);
- scaleClipperPolygon(input);
- ClipperLib::ClipperOffset co;
- if (joinType == jtRound)
- co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
- else
- co.MiterLimit = miterLimit;
- co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
- co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
- co.Execute(contours, delta_scaled);
- }
- if (contours.empty())
- // No need to try to offset the holes.
- continue;
-
- if (it_expoly->holes.empty()) {
- // No need to subtract holes from the offsetted expolygon, we are done.
- contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
- ++ expolygons_collected;
- } else {
- // 2) Offset the holes one by one, collect the offsetted holes.
- ClipperLib::Paths holes;
- {
- 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);
- scaleClipperPolygon(input);
- ClipperLib::ClipperOffset co;
- if (joinType == jtRound)
- co.ArcTolerance = miterLimit * double(CLIPPER_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());
- }
- }
-
- // 3) Subtract holes from the contours.
- if (holes.empty()) {
- // No hole remaining after an offset. Just copy the outer contour.
- contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
- ++ expolygons_collected;
- } else if (delta < 0) {
- // Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
- // Subtract the offsetted holes from the offsetted contours.
- ClipperLib::Clipper clipper;
- clipper.Clear();
- clipper.AddPaths(contours, ClipperLib::ptSubject, true);
- clipper.AddPaths(holes, ClipperLib::ptClip, true);
- ClipperLib::Paths output;
- clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
- if (! output.empty()) {
- contours_cummulative.insert(contours_cummulative.end(), output.begin(), output.end());
- ++ expolygons_collected;
- } else {
- // The offsetted holes have eaten up the offsetted outer contour.
- }
- } else {
- // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller
- // area than the original hole or even disappear, therefore there will be no new intersections.
- // Just collect the reversed holes.
- contours_cummulative.reserve(contours.size() + holes.size());
- contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
- // Reverse the holes in place.
- for (size_t i = 0; i < holes.size(); ++ i)
- std::reverse(holes[i].begin(), holes[i].end());
- contours_cummulative.insert(contours_cummulative.end(), holes.begin(), holes.end());
- ++ expolygons_collected;
- }
- }
- }
+ for (const auto &expoly : expolygons)
+ expolygons_collected += offset_expolygon_inner(expoly, delta, joinType, miterLimit, output);
// 4) Unite the offsetted expolygons.
- ClipperLib::Paths output;
if (expolygons_collected > 1 && delta > 0) {
// There is a chance that the outwards offsetted expolygons may intersect. Perform a union.
ClipperLib::Clipper clipper;
clipper.Clear();
- clipper.AddPaths(contours_cummulative, ClipperLib::ptSubject, true);
+ clipper.AddPaths(output, ClipperLib::ptSubject, true);
clipper.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
} else {
// Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output.
- output = std::move(contours_cummulative);
}
- // 4) Unscale the output.
- unscaleClipperPolygons(output);
return output;
}
-ClipperLib::Paths
-_offset2(const Polygons &polygons, const float delta1, const float delta2,
- const ClipperLib::JoinType joinType, const double miterLimit)
+Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(expolygon, delta, joinType, miterLimit)); }
+Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(expolygons, delta, joinType, miterLimit)); }
+Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(surfaces, delta, joinType, miterLimit)); }
+Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return to_polygons(_offset(surfaces, delta, joinType, miterLimit)); }
+Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygon, delta, joinType, miterLimit)); }
+Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return ClipperPaths_to_Slic3rExPolygons(_offset(expolygons, delta, joinType, miterLimit)); }
+Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
+ { return ClipperPaths_to_Slic3rExPolygons(_offset(surfaces, delta, joinType, miterLimit)); }
+
+ClipperLib::Paths _offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{
- // read input
- ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons);
-
- // scale input
- scaleClipperPolygons(input);
-
// prepare ClipperOffset object
ClipperLib::ClipperOffset co;
if (joinType == jtRound) {
@@ -435,13 +322,13 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
} else {
co.MiterLimit = miterLimit;
}
- float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE);
- float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE);
+ float delta_scaled1 = delta1;
+ float delta_scaled2 = delta2;
co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR);
// perform first offset
ClipperLib::Paths output1;
- co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
+ co.AddPaths(ClipperUtils::PolygonsProvider(polygons), joinType, ClipperLib::etClosedPolygon);
co.Execute(output1, delta_scaled1);
// perform second offset
@@ -450,104 +337,81 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
ClipperLib::Paths retval;
co.Execute(retval, delta_scaled2);
- // unscale output
- unscaleClipperPolygons(retval);
return retval;
}
-Polygons
-offset2(const Polygons &polygons, const float delta1, const float delta2,
- const ClipperLib::JoinType joinType, const double miterLimit)
+Polygons offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{
- // perform offset
- ClipperLib::Paths output = _offset2(polygons, delta1, delta2, joinType, miterLimit);
-
- // convert into ExPolygons
- return ClipperPaths_to_Slic3rPolygons(output);
+ return to_polygons(_offset2(polygons, delta1, delta2, joinType, miterLimit));
}
-ExPolygons
-offset2_ex(const Polygons &polygons, const float delta1, const float delta2,
- const ClipperLib::JoinType joinType, const double miterLimit)
+ExPolygons offset2_ex(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{
- // perform offset
- ClipperLib::Paths output = _offset2(polygons, delta1, delta2, joinType, miterLimit);
-
- // convert into ExPolygons
- return ClipperPaths_to_Slic3rExPolygons(output);
+ return ClipperPaths_to_Slic3rExPolygons(_offset2(polygons, delta1, delta2, joinType, miterLimit));
}
//FIXME Vojtech: This functon may likely be optimized to avoid some of the Slic3r to Clipper
-// conversions and unnecessary Clipper calls.
-ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1,
- const float delta2, ClipperLib::JoinType joinType, double miterLimit)
+// conversions and unnecessary Clipper calls. It is not that bad now as Clipper uses Slic3r's own Point / Polygon types directly.
+Polygons offset2(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
{
- Polygons polys;
- for (const ExPolygon &expoly : expolygons)
- append(polys,
- offset(offset_ex(expoly, delta1, joinType, miterLimit),
- delta2, joinType, miterLimit));
- return union_ex(polys);
+ return offset(offset_ex(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit);
+}
+ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
+{
+ return offset_ex(offset_ex(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit);
}
-template
-T _clipper_do(const ClipperLib::ClipType clipType,
- TSubj && subject,
- TClip && clip,
- const ClipperLib::PolyFillType fillType,
- const bool safety_offset_)
+template
+TResult _clipper_do(
+ const ClipperLib::ClipType clipType,
+ TSubj && subject,
+ TClip && clip,
+ const ClipperLib::PolyFillType fillType)
{
- // read input
- ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(std::forward(subject));
- ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(std::forward(clip));
-
- // perform safety offset
- if (safety_offset_) {
- if (clipType == ClipperLib::ctUnion) {
- safety_offset(&input_subject);
- } else {
- safety_offset(&input_clip);
- }
- }
-
- // init Clipper
ClipperLib::Clipper clipper;
- clipper.Clear();
-
- // add polygons
- clipper.AddPaths(input_subject, ClipperLib::ptSubject, true);
- clipper.AddPaths(input_clip, ClipperLib::ptClip, true);
-
- // perform operation
- T retval;
+ clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, true);
+ clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true);
+ TResult retval;
clipper.Execute(clipType, retval, fillType, fillType);
return retval;
}
+template
+TResult _clipper_do(
+ const ClipperLib::ClipType clipType,
+ TSubj && subject,
+ TClip && clip,
+ const ClipperLib::PolyFillType fillType,
+ const bool do_safety_offset)
+{
+ return do_safety_offset ?
+ (clipType == ClipperLib::ctUnion ?
+ _clipper_do(clipType, safety_offset(std::forward(subject)), std::forward(clip), fillType) :
+ _clipper_do(clipType, std::forward