Reworked "only_retract_when_crossing_perimeters" feature, which
was terribly slow: Introduced RetractWhenCrossingPerimeters.cpp,hpp AABBTreeIndirect traverse template was extended to support early exit.
This commit is contained in:
parent
b1bfef44ba
commit
7309c729e0
@ -920,29 +920,35 @@ template<class G> auto within(const G &g) { return Within<G>{g}; }
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
// Returns true in case traversal should continue,
|
||||||
|
// returns false if traversal should stop (for example if the first hit was found).
|
||||||
template<int Dims, typename T, typename Pred, typename Fn>
|
template<int Dims, typename T, typename Pred, typename Fn>
|
||||||
void traverse_recurse(const Tree<Dims, T> &tree,
|
bool traverse_recurse(const Tree<Dims, T> &tree,
|
||||||
size_t idx,
|
size_t idx,
|
||||||
Pred && pred,
|
Pred && pred,
|
||||||
Fn && callback)
|
Fn && callback)
|
||||||
{
|
{
|
||||||
assert(tree.node(idx).is_valid());
|
assert(tree.node(idx).is_valid());
|
||||||
|
|
||||||
if (!pred(tree.node(idx))) return;
|
if (!pred(tree.node(idx)))
|
||||||
|
// Continue traversal.
|
||||||
|
return true;
|
||||||
|
|
||||||
if (tree.node(idx).is_leaf()) {
|
if (tree.node(idx).is_leaf()) {
|
||||||
callback(tree.node(idx));
|
// Callback returns true to continue traversal, false to stop traversal.
|
||||||
|
return callback(tree.node(idx));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// call this with left and right node idx:
|
// call this with left and right node idx:
|
||||||
auto trv = [&](size_t idx) {
|
auto trv = [&](size_t idx) -> bool {
|
||||||
traverse_recurse(tree, idx, std::forward<Pred>(pred),
|
return traverse_recurse(tree, idx, std::forward<Pred>(pred),
|
||||||
std::forward<Fn>(callback));
|
std::forward<Fn>(callback));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Left / right child node index.
|
// Left / right child node index.
|
||||||
trv(Tree<Dims, T>::left_child_idx(idx));
|
// Returns true if both children allow the traversal to continue.
|
||||||
trv(Tree<Dims, T>::right_child_idx(idx));
|
return trv(Tree<Dims, T>::left_child_idx(idx)) &&
|
||||||
|
trv(Tree<Dims, T>::right_child_idx(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,6 +958,7 @@ void traverse_recurse(const Tree<Dims, T> &tree,
|
|||||||
// traverse(tree, intersecting(QueryBox), [](size_t face_idx) {
|
// traverse(tree, intersecting(QueryBox), [](size_t face_idx) {
|
||||||
// /* ... */
|
// /* ... */
|
||||||
// });
|
// });
|
||||||
|
// Callback shall return true to continue traversal, false if it wants to stop traversal, for example if it found the answer.
|
||||||
template<int Dims, typename T, typename Predicate, typename Fn>
|
template<int Dims, typename T, typename Predicate, typename Fn>
|
||||||
void traverse(const Tree<Dims, T> &tree, Predicate &&pred, Fn &&callback)
|
void traverse(const Tree<Dims, T> &tree, Predicate &&pred, Fn &&callback)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +130,8 @@ set(SLIC3R_SOURCES
|
|||||||
GCode/PressureEqualizer.hpp
|
GCode/PressureEqualizer.hpp
|
||||||
GCode/PrintExtents.cpp
|
GCode/PrintExtents.cpp
|
||||||
GCode/PrintExtents.hpp
|
GCode/PrintExtents.hpp
|
||||||
|
GCode/RetractWhenCrossingPerimeters.cpp
|
||||||
|
GCode/RetractWhenCrossingPerimeters.hpp
|
||||||
GCode/SpiralVase.cpp
|
GCode/SpiralVase.cpp
|
||||||
GCode/SpiralVase.hpp
|
GCode/SpiralVase.hpp
|
||||||
GCode/SeamPlacer.cpp
|
GCode/SeamPlacer.cpp
|
||||||
|
@ -140,6 +140,21 @@ namespace ClipperUtils {
|
|||||||
out.reserve(src.size());
|
out.reserve(src.size());
|
||||||
for (const Polygon &p : src)
|
for (const Polygon &p : src)
|
||||||
out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox));
|
out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox));
|
||||||
|
out.erase(
|
||||||
|
std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }),
|
||||||
|
out.end());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
[[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox)
|
||||||
|
{
|
||||||
|
Polygons out;
|
||||||
|
out.reserve(src.num_contours());
|
||||||
|
out.emplace_back(clip_clipper_polygon_with_subject_bbox(src.contour, bbox));
|
||||||
|
for (const Polygon &p : src.holes)
|
||||||
|
out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox));
|
||||||
|
out.erase(
|
||||||
|
std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }),
|
||||||
|
out.end());
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -794,6 +809,8 @@ Polylines _clipper_pl_closed(ClipperLib::ClipType clipType, PathProvider1 &&subj
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
|
||||||
|
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
|
||||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
|
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
|
||||||
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
||||||
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip)
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip)
|
||||||
|
@ -323,6 +323,7 @@ namespace ClipperUtils {
|
|||||||
void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out);
|
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]] 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);
|
[[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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset Polygons
|
// offset Polygons
|
||||||
@ -427,6 +428,7 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPoly
|
|||||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surfaces &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::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::Polygons &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::Polylines &subject, const Slic3r::Polygons &clip);
|
||||||
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
|
||||||
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
|
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
|
||||||
|
@ -3090,7 +3090,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_config.only_retract_when_crossing_perimeters && m_layer != nullptr &&
|
if (m_config.only_retract_when_crossing_perimeters && m_layer != nullptr &&
|
||||||
m_config.fill_density.value > 0 && m_layer->any_internal_region_slice_contains(travel))
|
m_config.fill_density.value > 0 && m_retract_when_crossing_perimeters.travel_inside_internal_regions(*m_layer, travel))
|
||||||
// Skip retraction if travel is contained in an internal slice *and*
|
// Skip retraction if travel is contained in an internal slice *and*
|
||||||
// internal infill is enabled (so that stringing is entirely not visible).
|
// internal infill is enabled (so that stringing is entirely not visible).
|
||||||
//FIXME any_internal_region_slice_contains() is potentionally very slow, it shall test for the bounding boxes first.
|
//FIXME any_internal_region_slice_contains() is potentionally very slow, it shall test for the bounding boxes first.
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "GCode/AvoidCrossingPerimeters.hpp"
|
#include "GCode/AvoidCrossingPerimeters.hpp"
|
||||||
#include "GCode/CoolingBuffer.hpp"
|
#include "GCode/CoolingBuffer.hpp"
|
||||||
#include "GCode/FindReplace.hpp"
|
#include "GCode/FindReplace.hpp"
|
||||||
|
#include "GCode/RetractWhenCrossingPerimeters.hpp"
|
||||||
#include "GCode/SpiralVase.hpp"
|
#include "GCode/SpiralVase.hpp"
|
||||||
#include "GCode/ToolOrdering.hpp"
|
#include "GCode/ToolOrdering.hpp"
|
||||||
#include "GCode/WipeTower.hpp"
|
#include "GCode/WipeTower.hpp"
|
||||||
@ -349,6 +350,7 @@ private:
|
|||||||
Wipe m_wipe;
|
Wipe m_wipe;
|
||||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||||
JPSPathFinder m_avoid_curled_filaments;
|
JPSPathFinder m_avoid_curled_filaments;
|
||||||
|
RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters;
|
||||||
bool m_enable_loop_clipping;
|
bool m_enable_loop_clipping;
|
||||||
// If enabled, the G-code generator will put following comments at the ends
|
// If enabled, the G-code generator will put following comments at the ends
|
||||||
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
|
// of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
|
||||||
|
67
src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp
Normal file
67
src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "../ClipperUtils.hpp"
|
||||||
|
#include "../Layer.hpp"
|
||||||
|
#include "../Polyline.hpp"
|
||||||
|
|
||||||
|
#include "RetractWhenCrossingPerimeters.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
bool RetractWhenCrossingPerimeters::travel_inside_internal_regions(const Layer &layer, const Polyline &travel)
|
||||||
|
{
|
||||||
|
if (m_layer != &layer) {
|
||||||
|
// Update cache.
|
||||||
|
m_layer = &layer;
|
||||||
|
m_internal_islands.clear();
|
||||||
|
m_aabbtree_internal_islands.clear();
|
||||||
|
// Collect expolygons of internal slices.
|
||||||
|
for (const LayerRegion *layerm : layer.regions())
|
||||||
|
for (const Surface &surface : layerm->slices().surfaces)
|
||||||
|
if (surface.is_internal())
|
||||||
|
m_internal_islands.emplace_back(&surface.expolygon);
|
||||||
|
// Calculate bounding boxes of internal slices.
|
||||||
|
class BBoxWrapper {
|
||||||
|
public:
|
||||||
|
BBoxWrapper(const size_t idx, const BoundingBox &bbox) :
|
||||||
|
m_idx(idx),
|
||||||
|
// Inflate the bounding box a bit to account for numerical issues.
|
||||||
|
m_bbox(bbox.min - Point(SCALED_EPSILON, SCALED_EPSILON), bbox.max + Point(SCALED_EPSILON, SCALED_EPSILON)) {}
|
||||||
|
size_t idx() const { return m_idx; }
|
||||||
|
const AABBTree::BoundingBox& bbox() const { return m_bbox; }
|
||||||
|
Point centroid() const { return ((m_bbox.min().cast<int64_t>() + m_bbox.max().cast<int64_t>()) / 2).cast<int32_t>(); }
|
||||||
|
private:
|
||||||
|
size_t m_idx;
|
||||||
|
AABBTree::BoundingBox m_bbox;
|
||||||
|
};
|
||||||
|
std::vector<BBoxWrapper> bboxes;
|
||||||
|
bboxes.reserve(m_internal_islands.size());
|
||||||
|
for (size_t i = 0; i < m_internal_islands.size(); ++ i)
|
||||||
|
bboxes.emplace_back(i, get_extents(*m_internal_islands[i]));
|
||||||
|
// Build AABB tree over bounding boxes of internal slices.
|
||||||
|
m_aabbtree_internal_islands.build_modify_input(bboxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox bbox_travel = get_extents(travel);
|
||||||
|
AABBTree::BoundingBox bbox_travel_eigen{ bbox_travel.min, bbox_travel.max };
|
||||||
|
int result = -1;
|
||||||
|
bbox_travel.offset(SCALED_EPSILON);
|
||||||
|
AABBTreeIndirect::traverse(m_aabbtree_internal_islands,
|
||||||
|
[&bbox_travel_eigen](const AABBTree::Node &node) {
|
||||||
|
return bbox_travel_eigen.intersects(node.bbox);
|
||||||
|
},
|
||||||
|
[&travel, &bbox_travel, &result, &islands = m_internal_islands](const AABBTree::Node &node) {
|
||||||
|
assert(node.is_leaf());
|
||||||
|
assert(node.is_valid());
|
||||||
|
Polygons clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*islands[node.idx], bbox_travel);
|
||||||
|
if (diff_pl(travel, clipped).empty()) {
|
||||||
|
// Travel path is completely inside an "internal" island. Don't retract.
|
||||||
|
result = int(node.idx);
|
||||||
|
// Stop traversal.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Continue traversal.
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return result != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
32
src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp
Normal file
32
src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef slic3r_RetractWhenCrossingPerimeters_hpp_
|
||||||
|
#define slic3r_RetractWhenCrossingPerimeters_hpp_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../AABBTreeIndirect.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
// Forward declarations.
|
||||||
|
class ExPolygon;
|
||||||
|
class Layer;
|
||||||
|
class Polyline;
|
||||||
|
|
||||||
|
class RetractWhenCrossingPerimeters
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool travel_inside_internal_regions(const Layer &layer, const Polyline &travel);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Last object layer visited, for which a cache of internal islands was created.
|
||||||
|
const Layer *m_layer;
|
||||||
|
// Internal islands only, referencing data owned by m_layer->regions()->surfaces().
|
||||||
|
std::vector<const ExPolygon*> m_internal_islands;
|
||||||
|
// Search structure over internal islands.
|
||||||
|
using AABBTree = AABBTreeIndirect::Tree<2, coord_t>;
|
||||||
|
AABBTree m_aabbtree_internal_islands;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_RetractWhenCrossingPerimeters_hpp_
|
@ -413,6 +413,8 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
|||||||
[&part_to_drill, &hollowed_mesh](const auto& node)
|
[&part_to_drill, &hollowed_mesh](const auto& node)
|
||||||
{
|
{
|
||||||
part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[node.idx]);
|
part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[node.idx]);
|
||||||
|
// continue traversal
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal(
|
auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal(
|
||||||
|
Loading…
Reference in New Issue
Block a user