mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-07 07:41:06 +00:00
* Add Missing Includes Across src/libslic3r Every libslic3r source and header now directly includes the headers declaring what it uses, rather than relying on the precompiled header or transitive includes. Generated with clang-tidy misc-include-cleaner, with libslic3r headers spelled libslic3r/... so they resolve outside the library's private include paths. MultiMaterialSegmentation.hpp, Support/SupportParameters.hpp and Format/STEP.hpp are made self-contained by hand. * Make the libslic3r Headers Compile on Their Own Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Left out: I18N.hpp, which errors on purpose when included from GUI code, and VoxelizeCSGMesh.hpp and SLA/bicubic.h, which nothing includes and which no longer compile at all. * Add the Includes Missing From the Hand-Fixed libslic3r Headers clang-tidy would not edit these headers while they failed to compile on their own, so the first pass skipped them. With the headers now self-contained, a second pass adds the rest. * Keep Windows Setup Ahead of the Added libslic3r Includes Print.cpp and Thread.cpp open with a _WIN32 block that has to come first; without the precompiled header, Print.cpp otherwise reaches windows.h through OCCT with NONLS defined and boost/regex fails. OpenVDBUtils.cpp and SLA/SupportTreeBuilder.cpp had includes inside #ifndef NOMINMAX, which libslic3r defines on Windows, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory. * Re-Add libslic3r Includes After the Clipper2 2.0.1 Migration Rebasing onto main took main's version of the files the Clipper2 migration rewrote, so their added includes are restored here, along with includes for main's new code. Clipper2's individual headers are now ignored by clang-tidy: they only build the Z variant through clipper2_z.hpp, which defines USINGZ first, so including clipper.core.h and the like directly broke ClipperZUtils.cpp.
597 lines
38 KiB
C++
597 lines
38 KiB
C++
#ifndef slic3r_ClipperUtils_hpp_
|
|
#define slic3r_ClipperUtils_hpp_
|
|
|
|
#include "Point.hpp"
|
|
#include "Polyline.hpp"
|
|
#include "Line.hpp"
|
|
#include "libslic3r.h"
|
|
#include "ExPolygon.hpp"
|
|
#include "Polygon.hpp"
|
|
#include "Surface.hpp"
|
|
#include <cstddef>
|
|
#include <iterator>
|
|
#include <cassert>
|
|
#include <vector>
|
|
|
|
namespace Slic3r {
|
|
|
|
// Offset joins and ends, fill rules and boolean operations, named as in Clipper1.
|
|
enum JoinType { jtSquare, jtRound, jtMiter };
|
|
enum EndType { etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound };
|
|
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
|
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
|
|
|
|
} // namespace Slic3r
|
|
|
|
// import these wherever we're included
|
|
using Slic3r::jtMiter;
|
|
using Slic3r::jtRound;
|
|
using Slic3r::jtSquare;
|
|
|
|
namespace Slic3r {
|
|
|
|
static constexpr const float ClipperSafetyOffset = 10.f;
|
|
|
|
static constexpr const JoinType DefaultJoinType = jtMiter;
|
|
|
|
static constexpr const EndType DefaultEndType = etOpenButt;
|
|
|
|
//FIXME evaluate the default miter limit. 3 seems to be extreme, Cura uses 1.2.
|
|
// Mitter Limit 3 is useful for perimeter generator, where sharp corners are extruded without needing a gap fill.
|
|
// However such a high limit causes issues with large positive or negative offsets, where a sharp corner
|
|
// is extended excessively.
|
|
static constexpr const double DefaultMiterLimit = 3.;
|
|
|
|
static constexpr const JoinType DefaultLineJoinType = jtSquare;
|
|
// Miter limit is ignored for jtSquare.
|
|
static constexpr const double DefaultLineMiterLimit = 0.;
|
|
|
|
// Decimation factor applied on input contour when doing offset, multiplied by the offset distance.
|
|
static constexpr const double ClipperOffsetShortestEdgeFactor = 0.005;
|
|
|
|
enum class ApplySafetyOffset {
|
|
No,
|
|
Yes
|
|
};
|
|
|
|
namespace ClipperUtils {
|
|
class PathsProviderIteratorBase {
|
|
public:
|
|
using value_type = Points;
|
|
using difference_type = std::ptrdiff_t;
|
|
using pointer = const Points*;
|
|
using reference = const Points&;
|
|
using iterator_category = std::input_iterator_tag;
|
|
};
|
|
|
|
class EmptyPathsProvider {
|
|
public:
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
const Points& operator*() { assert(false); return s_empty_points; }
|
|
// all iterators point to end.
|
|
constexpr bool operator==(const iterator &rhs) const { return true; }
|
|
constexpr bool operator!=(const iterator &rhs) const { return false; }
|
|
const Points& operator++(int) { assert(false); return s_empty_points; }
|
|
const iterator& operator++() { assert(false); return *this; }
|
|
};
|
|
|
|
constexpr EmptyPathsProvider() {}
|
|
static constexpr iterator cend() throw() { return iterator{}; }
|
|
static constexpr iterator end() throw() { return cend(); }
|
|
static constexpr iterator cbegin() throw() { return cend(); }
|
|
static constexpr iterator begin() throw() { return cend(); }
|
|
static constexpr size_t size() throw() { return 0; }
|
|
|
|
static Points s_empty_points;
|
|
};
|
|
|
|
class SinglePathProvider {
|
|
public:
|
|
SinglePathProvider(const Points &points) : m_points(points) {}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(const Points &points) : m_ptr(&points) {}
|
|
const Points& operator*() const { return *m_ptr; }
|
|
bool operator==(const iterator &rhs) const { return m_ptr == rhs.m_ptr; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
const Points& operator++(int) { auto out = m_ptr; m_ptr = &s_end; return *out; }
|
|
iterator& operator++() { m_ptr = &s_end; return *this; }
|
|
private:
|
|
const Points *m_ptr;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_points); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(s_end); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return 1; }
|
|
|
|
private:
|
|
const Points &m_points;
|
|
static Points s_end;
|
|
};
|
|
|
|
template<typename PathType>
|
|
class PathsProvider {
|
|
public:
|
|
PathsProvider(const std::vector<PathType> &paths) : m_paths(paths) {}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(typename std::vector<PathType>::const_iterator it) : m_it(it) {}
|
|
const Points& operator*() const { return *m_it; }
|
|
bool operator==(const iterator &rhs) const { return m_it == rhs.m_it; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
const Points& operator++(int) { return *(m_it ++); }
|
|
iterator& operator++() { ++ m_it; return *this; }
|
|
private:
|
|
typename std::vector<PathType>::const_iterator m_it;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_paths.begin()); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_paths.end()); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_paths.size(); }
|
|
|
|
private:
|
|
const std::vector<PathType> &m_paths;
|
|
};
|
|
|
|
template<typename MultiPointsType>
|
|
class MultiPointsProvider {
|
|
public:
|
|
MultiPointsProvider(const MultiPointsType &multipoints) : m_multipoints(multipoints) {}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(typename MultiPointsType::const_iterator it) : m_it(it) {}
|
|
const Points& operator*() const { return m_it->points; }
|
|
bool operator==(const iterator &rhs) const { return m_it == rhs.m_it; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
const Points& operator++(int) { return (m_it ++)->points; }
|
|
iterator& operator++() { ++ m_it; return *this; }
|
|
private:
|
|
typename MultiPointsType::const_iterator m_it;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_multipoints.begin()); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_multipoints.end()); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_multipoints.size(); }
|
|
|
|
private:
|
|
const MultiPointsType &m_multipoints;
|
|
};
|
|
|
|
using PolygonsProvider = MultiPointsProvider<Polygons>;
|
|
using PolylinesProvider = MultiPointsProvider<Polylines>;
|
|
|
|
struct ExPolygonProvider {
|
|
ExPolygonProvider(const ExPolygon &expoly) : m_expoly(expoly) {}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(const ExPolygon &expoly, int idx) : m_expoly(expoly), m_idx(idx) {}
|
|
const Points& operator*() const { return (m_idx == 0) ? m_expoly.contour.points : m_expoly.holes[m_idx - 1].points; }
|
|
bool operator==(const iterator &rhs) const { assert(m_expoly == rhs.m_expoly); return m_idx == rhs.m_idx; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
const Points& operator++(int) { const Points &out = **this; ++ m_idx; return out; }
|
|
iterator& operator++() { ++ m_idx; return *this; }
|
|
private:
|
|
const ExPolygon &m_expoly;
|
|
int m_idx;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_expoly, 0); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_expoly, m_expoly.holes.size() + 1); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_expoly.holes.size() + 1; }
|
|
|
|
private:
|
|
const ExPolygon &m_expoly;
|
|
};
|
|
|
|
struct ExPolygonsProvider {
|
|
ExPolygonsProvider(const ExPolygons &expolygons) : m_expolygons(expolygons) {
|
|
m_size = 0;
|
|
for (const ExPolygon &expoly : expolygons)
|
|
m_size += expoly.holes.size() + 1;
|
|
}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(ExPolygons::const_iterator it) : m_it_expolygon(it), m_idx_contour(0) {}
|
|
const Points& operator*() const { return (m_idx_contour == 0) ? m_it_expolygon->contour.points : m_it_expolygon->holes[m_idx_contour - 1].points; }
|
|
bool operator==(const iterator &rhs) const { return m_it_expolygon == rhs.m_it_expolygon && m_idx_contour == rhs.m_idx_contour; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
iterator& operator++() {
|
|
if (++ m_idx_contour == m_it_expolygon->holes.size() + 1) {
|
|
++ m_it_expolygon;
|
|
m_idx_contour = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
const Points& operator++(int) {
|
|
const Points &out = **this;
|
|
++ (*this);
|
|
return out;
|
|
}
|
|
private:
|
|
ExPolygons::const_iterator m_it_expolygon;
|
|
size_t m_idx_contour;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_expolygons.cbegin()); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_expolygons.cend()); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_size; }
|
|
|
|
private:
|
|
const ExPolygons &m_expolygons;
|
|
size_t m_size;
|
|
};
|
|
|
|
struct SurfacesProvider {
|
|
SurfacesProvider(const Surfaces &surfaces) : m_surfaces(surfaces) {
|
|
m_size = 0;
|
|
for (const Surface &surface : surfaces)
|
|
m_size += surface.expolygon.holes.size() + 1;
|
|
}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(Surfaces::const_iterator it) : m_it_surface(it), m_idx_contour(0) {}
|
|
const Points& operator*() const { return (m_idx_contour == 0) ? m_it_surface->expolygon.contour.points : m_it_surface->expolygon.holes[m_idx_contour - 1].points; }
|
|
bool operator==(const iterator &rhs) const { return m_it_surface == rhs.m_it_surface && m_idx_contour == rhs.m_idx_contour; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
iterator& operator++() {
|
|
if (++ m_idx_contour == m_it_surface->expolygon.holes.size() + 1) {
|
|
++ m_it_surface;
|
|
m_idx_contour = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
const Points& operator++(int) {
|
|
const Points &out = **this;
|
|
++ (*this);
|
|
return out;
|
|
}
|
|
private:
|
|
Surfaces::const_iterator m_it_surface;
|
|
size_t m_idx_contour;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_surfaces.cbegin()); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_surfaces.cend()); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_size; }
|
|
|
|
private:
|
|
const Surfaces &m_surfaces;
|
|
size_t m_size;
|
|
};
|
|
|
|
struct SurfacesPtrProvider {
|
|
SurfacesPtrProvider(const SurfacesPtr &surfaces) : m_surfaces(surfaces) {
|
|
m_size = 0;
|
|
for (const Surface *surface : surfaces)
|
|
m_size += surface->expolygon.holes.size() + 1;
|
|
}
|
|
|
|
struct iterator : public PathsProviderIteratorBase {
|
|
public:
|
|
explicit iterator(SurfacesPtr::const_iterator it) : m_it_surface(it), m_idx_contour(0) {}
|
|
const Points& operator*() const { return (m_idx_contour == 0) ? (*m_it_surface)->expolygon.contour.points : (*m_it_surface)->expolygon.holes[m_idx_contour - 1].points; }
|
|
bool operator==(const iterator &rhs) const { return m_it_surface == rhs.m_it_surface && m_idx_contour == rhs.m_idx_contour; }
|
|
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
|
iterator& operator++() {
|
|
if (++ m_idx_contour == (*m_it_surface)->expolygon.holes.size() + 1) {
|
|
++ m_it_surface;
|
|
m_idx_contour = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
const Points& operator++(int) {
|
|
const Points &out = **this;
|
|
++ (*this);
|
|
return out;
|
|
}
|
|
private:
|
|
SurfacesPtr::const_iterator m_it_surface;
|
|
size_t m_idx_contour;
|
|
};
|
|
|
|
iterator cbegin() const { return iterator(m_surfaces.cbegin()); }
|
|
iterator begin() const { return this->cbegin(); }
|
|
iterator cend() const { return iterator(m_surfaces.cend()); }
|
|
iterator end() const { return this->cend(); }
|
|
size_t size() const { return m_size; }
|
|
|
|
private:
|
|
const SurfacesPtr &m_surfaces;
|
|
size_t m_size;
|
|
};
|
|
|
|
|
|
// Points with a Z coordinate.
|
|
using ZPoint = Vec3i32;
|
|
using ZPoints = std::vector<Vec3i32>;
|
|
|
|
// Clip source polygon to be used as a clipping polygon with a bouding box around the source (to be clipped) polygon.
|
|
// Useful as an optimization for expensive Clipper operations, for example when clipping source polygons one by one
|
|
// with a set of polygons covering the whole layer below.
|
|
void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons = false);
|
|
void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out);
|
|
[[nodiscard]] Points clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox);
|
|
[[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox);
|
|
void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out);
|
|
[[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, const bool get_entire_polygons = false);
|
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox);
|
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox, const bool get_entire_polygons = false);
|
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox, const bool get_entire_polygons = false);
|
|
|
|
}
|
|
|
|
// offset Polygons
|
|
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
|
|
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
|
|
// offset Polylines
|
|
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
|
|
// Input polygons for negative offset shall be "normalized": There must be no overlap / intersections between the input polygons.
|
|
Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType);
|
|
Slic3r::Polygons offset(const Slic3r::Polyline3 &polyline, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType);
|
|
Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType);
|
|
Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset_ex(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
// BBS
|
|
inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{
|
|
Slic3r::Polygons temp;
|
|
temp.push_back(polygon);
|
|
|
|
return offset_ex(temp, delta, joinType, miterLimit);
|
|
}
|
|
|
|
// convert stroke to path by offsetting of contour
|
|
Polygons contour_to_polygons(const Polygon &polygon, const float line_width, JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit);
|
|
Polygons contour_to_polygons(const Polygons &polygon, const float line_width, JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit);
|
|
|
|
inline Slic3r::Polygons union_safety_offset (const Slic3r::Polygons &polygons) { return offset (polygons, ClipperSafetyOffset); }
|
|
inline Slic3r::Polygons union_safety_offset (const Slic3r::ExPolygons &expolygons) { return offset (expolygons, ClipperSafetyOffset); }
|
|
inline Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons) { return offset_ex(polygons, ClipperSafetyOffset); }
|
|
inline Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::ExPolygons &expolygons) { return offset_ex(expolygons, ClipperSafetyOffset); }
|
|
|
|
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &expolygons);
|
|
Slic3r::Polygons union_safety_offset(const Slic3r::ExPolygons &expolygons);
|
|
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons);
|
|
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::ExPolygons &expolygons);
|
|
|
|
// Aliases for the various offset(...) functions, conveying the purpose of the offset.
|
|
inline Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset(polygon, delta, joinType, miterLimit); }
|
|
inline Slic3r::Polygons expand(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); }
|
|
inline Slic3r::Polygons expand(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons expand_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset_ex(polygons, delta, joinType, miterLimit); }
|
|
// Input polygons for shrinking shall be "normalized": There must be no overlap / intersections between the input polygons.
|
|
inline Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset(polygons, -delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons shrink_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset_ex(polygons, -delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons shrink_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset_ex(polygons, -delta, joinType, miterLimit); }
|
|
|
|
// Wherever applicable, please use the opening() / closing() variants instead, they convey their purpose better.
|
|
// Input polygons for negative offset shall be "normalized": There must be no overlap / intersections between the input polygons.
|
|
Slic3r::Polygons offset2(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::ExPolygons offset2_ex(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
|
|
// BBS
|
|
Slic3r::ExPolygons _clipper_ex(ClipType clipType,
|
|
const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
|
|
|
|
|
|
// Offset outside, then inside produces morphological closing. All deltas should be positive.
|
|
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
inline Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ return closing(polygons, delta, delta, joinType, miterLimit); }
|
|
Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
inline Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ return closing_ex(polygons, delta, delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons closing_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset2_ex(polygons, delta, - delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons closing_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset2_ex(surfaces, delta, - delta, joinType, miterLimit); }
|
|
|
|
// Offset inside, then outside produces morphological opening. All deltas should be positive.
|
|
// Input polygons for opening shall be "normalized": There must be no overlap / intersections between the input polygons.
|
|
Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
|
inline Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ return opening(polygons, delta, delta, joinType, miterLimit); }
|
|
inline Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ return opening(expolygons, delta, delta, joinType, miterLimit); }
|
|
inline Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ return opening(surfaces, delta, delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset2_ex(polygons, - delta, delta, joinType, miterLimit); }
|
|
inline Slic3r::ExPolygons opening_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit)
|
|
{ assert(delta > 0); return offset2_ex(surfaces, - delta, delta, joinType, miterLimit); }
|
|
|
|
Slic3r::Lines _clipper_ln(ClipType clipType, const Slic3r::Lines &subject, const Slic3r::Polygons &clip);
|
|
|
|
// Safety offset is applied to the clipping polygons only.
|
|
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
// Optimized version clipping the "clipping" polygon using clip_clipper_polygon_with_subject_bbox().
|
|
// To be used with complex clipping polygons, where majority of the clipping polygons are outside of the source polygon.
|
|
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &src, const Slic3r::Polygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &src, const Slic3r::ExPolygons &clipping, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
|
|
Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
|
|
|
|
// BBS
|
|
inline Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No)
|
|
{
|
|
Slic3r::ExPolygons subject_temp;
|
|
Slic3r::ExPolygons clip_temp;
|
|
|
|
subject_temp.push_back(subject);
|
|
clip_temp.push_back(clip);
|
|
return diff_ex(subject_temp, clip_temp);
|
|
}
|
|
|
|
inline Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygons& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No)
|
|
{
|
|
Slic3r::ExPolygons subject_temp;
|
|
subject_temp.push_back(subject);
|
|
|
|
return diff_ex(subject_temp, clip, do_safety_offset);
|
|
}
|
|
|
|
inline Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No)
|
|
{
|
|
Slic3r::ExPolygons clip_temp;
|
|
clip_temp.push_back(clip);
|
|
|
|
return diff_ex(subject, clip_temp, do_safety_offset);
|
|
}
|
|
|
|
inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip)
|
|
{
|
|
return _clipper_ln(ctDifference, subject, clip);
|
|
}
|
|
|
|
// Safety offset is applied to the clipping polygons only.
|
|
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, PolyFillType fill_type);
|
|
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
// Optimized version clipping the "clipping" polygon using clip_clipper_polygon_with_subject_bbox().
|
|
// To be used with complex clipping polygons, where majority of the clipping polygons are outside of the source polygon.
|
|
Slic3r::Polygons intersection_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
// BBS
|
|
Slic3r::Polygons intersection(const Slic3r::Polygons& subject, const Slic3r::Polygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygons& clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
|
|
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
|
|
Slic3r::Polylines3 intersection_pl(const Slic3r::Polylines3 &subject, const Slic3r::Polygon &clip);
|
|
Slic3r::Polylines3 intersection_pl(const Slic3r::Polylines3 &subject, const Slic3r::ExPolygon &clip);
|
|
|
|
// Orca: Sort and orient open polyline fragments produced by clipping `source` with
|
|
// intersection_pl(), so that they run in the same order and direction as the source polyline.
|
|
void restore_source_path_order(const Slic3r::Polyline &source, Slic3r::Polylines &fragments);
|
|
|
|
inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip)
|
|
{
|
|
return _clipper_ln(ctIntersection, subject, clip);
|
|
}
|
|
|
|
inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r::Polygons &clip)
|
|
{
|
|
Slic3r::Lines lines;
|
|
lines.emplace_back(subject);
|
|
return _clipper_ln(ctIntersection, lines, clip);
|
|
}
|
|
|
|
Slic3r::Polygons union_(const Slic3r::Polygons &subject);
|
|
Slic3r::Polygons union_(const Slic3r::ExPolygons &subject);
|
|
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const PolyFillType fillType);
|
|
Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2);
|
|
// May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative).
|
|
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type = pftNonZero);
|
|
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject);
|
|
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &subject2);
|
|
Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject);
|
|
|
|
Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& poly1, const Slic3r::ExPolygons& poly2, bool safety_offset_ = false);
|
|
|
|
Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
|
|
|
Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject);
|
|
|
|
/* OTHER */
|
|
Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject);
|
|
Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject);
|
|
|
|
Polygons top_level_islands(const Slic3r::Polygons &polygons);
|
|
// Top level expolygons of the even-odd union, the ones nested in their holes go to `nested`.
|
|
ExPolygons top_level_expolygons(const ExPolygons &expolygons, ExPolygons *nested = nullptr);
|
|
|
|
Points mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit);
|
|
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
|
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
|
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
|
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
|
|
|
Pointfs make_counter_clockwise(const Pointfs& pointfs);
|
|
|
|
} // namespace Slic3r
|
|
|
|
#endif // slic3r_ClipperUtils_hpp_
|