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 {
|
||||
Points EmptyPathsProvider::s_empty_points;
|
||||
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)
|
||||
@ -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); }
|
||||
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); }
|
||||
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)
|
||||
{ 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)
|
||||
|
@ -24,6 +24,8 @@ using Slic3r::ClipperLib::jtSquare;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class BoundingBox;
|
||||
|
||||
static constexpr const float ClipperSafetyOffset = 10.f;
|
||||
|
||||
static constexpr const Slic3r::ClipperLib::JoinType DefaultJoinType = Slic3r::ClipperLib::jtMiter;
|
||||
@ -306,6 +308,21 @@ namespace ClipperUtils {
|
||||
const SurfacesPtr &m_surfaces;
|
||||
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
|
||||
@ -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::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::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);
|
||||
|
@ -115,76 +115,6 @@ static inline void check_self_intersections(const ExPolygon &expoly, const std::
|
||||
#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 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;
|
||||
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons& {
|
||||
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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user