clip_clipper_polygon_with_subject_bbox() and diff_clipped() extracted
from TreeSupports to ClipperUtils to be generally available. diff_clipped() is an 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.
This commit is contained in:
parent
db3f696888
commit
babc8a88a1
@ -48,6 +48,100 @@ err:
|
|||||||
namespace ClipperUtils {
|
namespace ClipperUtils {
|
||||||
Points EmptyPathsProvider::s_empty_points;
|
Points EmptyPathsProvider::s_empty_points;
|
||||||
Points SinglePathProvider::s_end;
|
Points SinglePathProvider::s_end;
|
||||||
|
|
||||||
|
// 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 ClipperLib operations, for example when clipping source polygons one by one
|
||||||
|
// with a set of polygons covering the whole layer below.
|
||||||
|
template<typename PointType>
|
||||||
|
inline void clip_clipper_polygon_with_subject_bbox_templ(const std::vector<PointType> &src, const BoundingBox &bbox, std::vector<PointType> &out)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
const size_t cnt = src.size();
|
||||||
|
if (cnt < 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
enum class Side {
|
||||||
|
Left = 1,
|
||||||
|
Right = 2,
|
||||||
|
Top = 4,
|
||||||
|
Bottom = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
auto sides = [bbox](const PointType &p) {
|
||||||
|
return int(p.x() < bbox.min.x()) * int(Side::Left) +
|
||||||
|
int(p.x() > bbox.max.x()) * int(Side::Right) +
|
||||||
|
int(p.y() < bbox.min.y()) * int(Side::Bottom) +
|
||||||
|
int(p.y() > bbox.max.y()) * int(Side::Top);
|
||||||
|
};
|
||||||
|
|
||||||
|
int sides_prev = sides(src.back());
|
||||||
|
int sides_this = sides(src.front());
|
||||||
|
const size_t last = cnt - 1;
|
||||||
|
for (size_t i = 0; i < last; ++ i) {
|
||||||
|
int sides_next = sides(src[i + 1]);
|
||||||
|
if (// This point is inside. Take it.
|
||||||
|
sides_this == 0 ||
|
||||||
|
// Either this point is outside and previous or next is inside, or
|
||||||
|
// the edge possibly cuts corner of the bounding box.
|
||||||
|
(sides_prev & sides_this & sides_next) == 0) {
|
||||||
|
out.emplace_back(src[i]);
|
||||||
|
sides_prev = sides_this;
|
||||||
|
} else {
|
||||||
|
// All the three points (this, prev, next) are outside at the same side.
|
||||||
|
// Ignore this point.
|
||||||
|
}
|
||||||
|
sides_this = sides_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never produce just a single point output polygon.
|
||||||
|
if (! out.empty())
|
||||||
|
if (int sides_next = sides(out.front());
|
||||||
|
// The last point is inside. Take it.
|
||||||
|
sides_this == 0 ||
|
||||||
|
// Either this point is outside and previous or next is inside, or
|
||||||
|
// the edge possibly cuts corner of the bounding box.
|
||||||
|
(sides_prev & sides_this & sides_next) == 0)
|
||||||
|
out.emplace_back(src.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out)
|
||||||
|
{ clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); }
|
||||||
|
void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out)
|
||||||
|
{ clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); }
|
||||||
|
|
||||||
|
template<typename PointType>
|
||||||
|
[[nodiscard]] std::vector<PointType> clip_clipper_polygon_with_subject_bbox_templ(const std::vector<PointType> &src, const BoundingBox &bbox)
|
||||||
|
{
|
||||||
|
std::vector<PointType> out;
|
||||||
|
clip_clipper_polygon_with_subject_bbox(src, bbox, out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Points clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox)
|
||||||
|
{ return clip_clipper_polygon_with_subject_bbox_templ(src, bbox); }
|
||||||
|
[[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox)
|
||||||
|
{ return clip_clipper_polygon_with_subject_bbox_templ(src, bbox); }
|
||||||
|
|
||||||
|
void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out)
|
||||||
|
{
|
||||||
|
clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox)
|
||||||
|
{
|
||||||
|
Polygon out;
|
||||||
|
clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox)
|
||||||
|
{
|
||||||
|
Polygons out;
|
||||||
|
out.reserve(src.size());
|
||||||
|
for (const Polygon &p : src)
|
||||||
|
out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree)
|
static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree)
|
||||||
@ -537,6 +631,8 @@ Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &cli
|
|||||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
|
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
|
||||||
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
||||||
|
Slic3r::Polygons diff_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||||
|
{ return diff(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); }
|
||||||
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
|
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
|
||||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
|
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
|
||||||
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||||
|
@ -24,6 +24,8 @@ using Slic3r::ClipperLib::jtSquare;
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class BoundingBox;
|
||||||
|
|
||||||
static constexpr const float ClipperSafetyOffset = 10.f;
|
static constexpr const float ClipperSafetyOffset = 10.f;
|
||||||
|
|
||||||
static constexpr const Slic3r::ClipperLib::JoinType DefaultJoinType = Slic3r::ClipperLib::jtMiter;
|
static constexpr const Slic3r::ClipperLib::JoinType DefaultJoinType = Slic3r::ClipperLib::jtMiter;
|
||||||
@ -306,6 +308,21 @@ namespace ClipperUtils {
|
|||||||
const SurfacesPtr &m_surfaces;
|
const SurfacesPtr &m_surfaces;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For ClipperLib with Z coordinates.
|
||||||
|
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 ClipperLib 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);
|
||||||
|
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);
|
||||||
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset Polygons
|
// offset Polygons
|
||||||
@ -391,6 +408,9 @@ Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, const Slic3r::Lines &su
|
|||||||
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
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::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);
|
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::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::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::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::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||||
|
@ -115,76 +115,6 @@ static inline void check_self_intersections(const ExPolygon &expoly, const std::
|
|||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clip_for_diff(const Polygon &src, const BoundingBox &bbox, Polygon &out)
|
|
||||||
{
|
|
||||||
out.clear();
|
|
||||||
const size_t cnt = src.points.size();
|
|
||||||
if (cnt < 3)
|
|
||||||
return;
|
|
||||||
|
|
||||||
enum class Side {
|
|
||||||
Left = 1,
|
|
||||||
Right = 2,
|
|
||||||
Top = 4,
|
|
||||||
Bottom = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
auto sides = [bbox](const Point &p) {
|
|
||||||
return int(p.x() < bbox.min.x()) * int(Side::Left) +
|
|
||||||
int(p.x() > bbox.max.x()) * int(Side::Right) +
|
|
||||||
int(p.y() < bbox.min.y()) * int(Side::Bottom) +
|
|
||||||
int(p.y() > bbox.max.y()) * int(Side::Top);
|
|
||||||
};
|
|
||||||
|
|
||||||
int sides_prev = sides(src.points.back());
|
|
||||||
int sides_this = sides(src.points.front());
|
|
||||||
const size_t last = cnt - 1;
|
|
||||||
for (size_t i = 0; i < last; ++ i) {
|
|
||||||
int sides_next = sides(src.points[i + 1]);
|
|
||||||
if (// This point is inside. Take it.
|
|
||||||
sides_this == 0 ||
|
|
||||||
// Either this point is outside and previous or next is inside, or
|
|
||||||
// the edge possibly cuts corner of the bounding box.
|
|
||||||
(sides_prev & sides_this & sides_next) == 0) {
|
|
||||||
out.points.emplace_back(src.points[i]);
|
|
||||||
sides_prev = sides_this;
|
|
||||||
} else {
|
|
||||||
// All the three points (this, prev, next) are outside at the same side.
|
|
||||||
// Ignore this point.
|
|
||||||
}
|
|
||||||
sides_this = sides_next;
|
|
||||||
}
|
|
||||||
// For the last point, if src is completely outside bbox, then out.points will be empty. Just use the first point instead.
|
|
||||||
int sides_next = sides(out.points.empty() ? src.points.front() : out.points.front());
|
|
||||||
if (// The last point is inside. Take it.
|
|
||||||
sides_this == 0 ||
|
|
||||||
// Either this point is outside and previous or next is inside, or
|
|
||||||
// the edge possibly cuts corner of the bounding box.
|
|
||||||
(sides_prev & sides_this & sides_next) == 0)
|
|
||||||
out.points.emplace_back(src.points.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static inline Polygon clip_for_diff(const Polygon &src, const BoundingBox &bbox)
|
|
||||||
{
|
|
||||||
Polygon out;
|
|
||||||
clip_for_diff(src, bbox, out);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static inline Polygons clip_for_diff(const Polygons &src, const BoundingBox &bbox)
|
|
||||||
{
|
|
||||||
Polygons out;
|
|
||||||
out.reserve(src.size());
|
|
||||||
for (const Polygon &p : src)
|
|
||||||
out.emplace_back(clip_for_diff(p, bbox));
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static inline Polygons diff_clipped(const Polygons &src, const Polygons &clipping)
|
|
||||||
{
|
|
||||||
return diff(src, clip_for_diff(clipping, get_extents(src).inflated(SCALED_EPSILON)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr const auto tiny_area_threshold = sqr(scaled<double>(0.001));
|
static constexpr const auto tiny_area_threshold = sqr(scaled<double>(0.001));
|
||||||
|
|
||||||
static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_meshes(const Print &print, const std::vector<size_t> &print_object_ids)
|
static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_meshes(const Print &print, const std::vector<size_t> &print_object_ids)
|
||||||
@ -821,7 +751,7 @@ static std::optional<std::pair<Point, size_t>> polyline_sample_next_point_at_dis
|
|||||||
Polygons collision_trimmed_buffer;
|
Polygons collision_trimmed_buffer;
|
||||||
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons& {
|
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons& {
|
||||||
if (collision_trimmed_buffer.empty() && ! collision.empty())
|
if (collision_trimmed_buffer.empty() && ! collision.empty())
|
||||||
collision_trimmed_buffer = clip_for_diff(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON));
|
collision_trimmed_buffer = ClipperUtils::clip_clipper_polygons_with_subject_bbox(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON));
|
||||||
return collision_trimmed_buffer;
|
return collision_trimmed_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user