OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::FillLightning::Layer Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Fill/Lightning/Layer.hpp>

Collaboration diagram for Slic3r::FillLightning::Layer:

Public Member Functions

void generateNewTrees (const Polygons &current_overhang, const Polygons &current_outlines, const BoundingBox &current_outlines_bbox, const EdgeGrid::Grid &outline_locator, coord_t supporting_radius, coord_t wall_supporting_radius, const std::function< void()> &throw_on_cancel_callback)
GroundingLocation getBestGroundingLocation (const Point &unsupported_location, const Polygons &current_outlines, const BoundingBox &current_outlines_bbox, const EdgeGrid::Grid &outline_locator, coord_t supporting_radius, coord_t wall_supporting_radius, const SparseNodeGrid &tree_node_locator, const NodeSPtr &exclude_tree=nullptr)
bool attach (const Point &unsupported_location, const GroundingLocation &ground, NodeSPtr &new_child, NodeSPtr &new_root)
void reconnectRoots (std::vector< NodeSPtr > &to_be_reconnected_tree_roots, const Polygons &current_outlines, const BoundingBox &current_outlines_bbox, const EdgeGrid::Grid &outline_locator, coord_t supporting_radius, coord_t wall_supporting_radius)
Polylines convertToLines (const Polygons &limit_to_outline, coord_t line_overlap) const
coord_t getWeightedDistance (const Point &boundary_loc, const Point &unsupported_location)
void fillLocator (SparseNodeGrid &tree_node_locator, const BoundingBox &current_outlines_bbox)

Public Attributes

std::vector< NodeSPtr > tree_roots

Detailed Description

A layer of the lightning fill.

Contains the trees to be printed and propagated to the next layer below.

Member Function Documentation

◆ attach()

bool Slic3r::FillLightning::Layer::attach ( const Point & unsupported_location,
const GroundingLocation & ground,
NodeSPtr & new_child,
NodeSPtr & new_root )
Parameters
[out]new_childThe new child node introduced
[out]new_rootThe new root node if one had been made
Returns
Whether a new root was added
221{
222 // Update trees & distance fields.
223 if (grounding_loc.boundary_location) {
224 new_root = Node::create(grounding_loc.p(), std::make_optional(grounding_loc.p()));
225 new_child = new_root->addChild(unsupported_location);
226 tree_roots.push_back(new_root);
227 return true;
228 } else {
229 new_child = grounding_loc.tree_node->addChild(unsupported_location);
230 return false;
231 }
232}
std::vector< NodeSPtr > tree_roots
Definition Layer.hpp:43
static NodeSPtr create(Arg &&...arg)
Definition TreeNode.hpp:53

References attach(), Slic3r::FillLightning::GroundingLocation::boundary_location, Slic3r::FillLightning::Node::create(), Slic3r::FillLightning::GroundingLocation::p(), Slic3r::FillLightning::GroundingLocation::tree_node, and tree_roots.

Referenced by attach(), and generateNewTrees().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ convertToLines()

Polylines Slic3r::FillLightning::Layer::convertToLines ( const Polygons & limit_to_outline,
coord_t line_overlap ) const
451{
452 if (tree_roots.empty())
453 return {};
454
455 Polylines result_lines;
456 for (const auto &tree : tree_roots)
457 tree->convertToPolylines(result_lines, line_overlap);
458
459 return intersection_pl(result_lines, limit_to_outline);
460}
std::vector< Polyline > Polylines
Definition Polyline.hpp:22
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:1111

References convertToLines(), Slic3r::intersection_pl(), and tree_roots.

Referenced by Slic3r::FillLightning::Filler::_fill_surface_single(), and convertToLines().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fillLocator()

void Slic3r::FillLightning::Layer::fillLocator ( SparseNodeGrid & tree_node_locator,
const BoundingBox & current_outlines_bbox )
50{
51 std::function<void(NodeSPtr)> add_node_to_locator_func = [&tree_node_locator, &current_outlines_bbox](const NodeSPtr &node) {
52 tree_node_locator.insert(std::make_pair(to_grid_point(node->getLocation(), current_outlines_bbox), node));
53 };
54 for (auto& tree : tree_roots)
55 tree->visitNodes(add_node_to_locator_func);
56}
static Point to_grid_point(const Point &point, const BoundingBox &bbox)
Definition Layer.cpp:44
std::shared_ptr< Node > NodeSPtr
Definition Layer.hpp:25

References Slic3r::FillLightning::to_grid_point(), and tree_roots.

Referenced by generateNewTrees(), and reconnectRoots().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateNewTrees()

void Slic3r::FillLightning::Layer::generateNewTrees ( const Polygons & current_overhang,
const Polygons & current_outlines,
const BoundingBox & current_outlines_bbox,
const EdgeGrid::Grid & outline_locator,
coord_t supporting_radius,
coord_t wall_supporting_radius,
const std::function< void()> & throw_on_cancel_callback )
68{
69 DistanceField distance_field(supporting_radius, current_outlines, current_outlines_bbox, current_overhang);
70 throw_on_cancel_callback();
71
72 SparseNodeGrid tree_node_locator;
73 fillLocator(tree_node_locator, current_outlines_bbox);
74
75 // Until no more points need to be added to support all:
76 // Determine next point from tree/outline areas via distance-field
77 size_t unsupported_cell_idx = 0;
78 Point unsupported_location;
79 while (distance_field.tryGetNextPoint(&unsupported_location, &unsupported_cell_idx, unsupported_cell_idx)) {
80 throw_on_cancel_callback();
81 GroundingLocation grounding_loc = getBestGroundingLocation(
82 unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator);
83
84 NodeSPtr new_parent;
85 NodeSPtr new_child;
86 this->attach(unsupported_location, grounding_loc, new_child, new_parent);
87 tree_node_locator.insert(std::make_pair(to_grid_point(new_child->getLocation(), current_outlines_bbox), new_child));
88 if (new_parent)
89 tree_node_locator.insert(std::make_pair(to_grid_point(new_parent->getLocation(), current_outlines_bbox), new_parent));
90 // update distance field
91 distance_field.update(grounding_loc.p(), unsupported_location);
92 }
93
94#ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT
95 {
96 static int iRun = 0;
97 export_to_svg(debug_out_path("FillLightning-TreeNodes-%d.svg", iRun++), current_outlines, this->tree_roots);
98 }
99#endif /* LIGHTNING_TREE_NODE_DEBUG_OUTPUT */
100}
void fillLocator(SparseNodeGrid &tree_node_locator, const BoundingBox &current_outlines_bbox)
Definition Layer.cpp:49
GroundingLocation getBestGroundingLocation(const Point &unsupported_location, const Polygons &current_outlines, const BoundingBox &current_outlines_bbox, const EdgeGrid::Grid &outline_locator, coord_t supporting_radius, coord_t wall_supporting_radius, const SparseNodeGrid &tree_node_locator, const NodeSPtr &exclude_tree=nullptr)
Definition Layer.cpp:132
bool attach(const Point &unsupported_location, const GroundingLocation &ground, NodeSPtr &new_child, NodeSPtr &new_root)
Definition Layer.cpp:216
std::unordered_multimap< Point, std::weak_ptr< Node >, PointHash > SparseNodeGrid
Definition Layer.hpp:26
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
bool export_to_svg(const char *path, const Surfaces &surfaces, const float transparency)
Definition Surface.cpp:87
std::string debug_out_path(const char *name,...)
Definition utils.cpp:382

References attach(), Slic3r::debug_out_path(), Slic3r::export_to_svg(), fillLocator(), getBestGroundingLocation(), Slic3r::FillLightning::GroundingLocation::p(), Slic3r::FillLightning::to_grid_point(), tree_roots, Slic3r::FillLightning::DistanceField::tryGetNextPoint(), and Slic3r::FillLightning::DistanceField::update().

Referenced by Slic3r::FillLightning::Generator::generateTrees(), and Slic3r::FillLightning::Generator::generateTreesforSupport().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getBestGroundingLocation()

GroundingLocation Slic3r::FillLightning::Layer::getBestGroundingLocation ( const Point & unsupported_location,
const Polygons & current_outlines,
const BoundingBox & current_outlines_bbox,
const EdgeGrid::Grid & outline_locator,
coord_t supporting_radius,
coord_t wall_supporting_radius,
const SparseNodeGrid & tree_node_locator,
const NodeSPtr & exclude_tree = nullptr )

Determine & connect to connection point in tree/outline.

Parameters
min_dist_from_boundary_for_treeIf the unsupported point is closer to the boundary than this then don't consider connecting it to a tree
142{
143 // Closest point on current_outlines to unsupported_location:
144 Point node_location;
145 {
146 double d2 = std::numeric_limits<double>::max();
147 for (const Polygon &contour : current_outlines)
148 if (contour.size() > 2) {
149 Point prev = contour.points.back();
150 for (const Point &p2 : contour.points) {
151 Point closest_point;
152 if (double d = line_alg::distance_to_squared(Line{prev, p2}, unsupported_location, &closest_point); d < d2) {
153 d2 = d;
154 node_location = closest_point;
155 }
156 prev = p2;
157 }
158 }
159 }
160
161 const auto within_dist = coord_t((node_location - unsupported_location).cast<double>().norm());
162
163 NodeSPtr sub_tree{nullptr};
164 coord_t current_dist = getWeightedDistance(node_location, unsupported_location);
165 if (current_dist >= wall_supporting_radius) { // Only reconnect tree roots to other trees if they are not already close to the outlines.
166 const coord_t search_radius = std::min(current_dist, within_dist);
167 BoundingBox region(unsupported_location - Point(search_radius, search_radius), unsupported_location + Point(search_radius + locator_cell_size(), search_radius + locator_cell_size()));
168 region.min = to_grid_point(region.min, current_outlines_bbox);
169 region.max = to_grid_point(region.max, current_outlines_bbox);
170
171 Point current_dist_grid_addr{std::numeric_limits<coord_t>::lowest(), std::numeric_limits<coord_t>::lowest()};
172 std::mutex current_dist_mutex;
173 tbb::parallel_for(tbb::blocked_range2d<coord_t>(region.min.y(), region.max.y(), region.min.x(), region.max.x()), [&current_dist, current_dist_copy = current_dist, &current_dist_mutex, &sub_tree, &current_dist_grid_addr, &exclude_tree = std::as_const(exclude_tree), &outline_locator = std::as_const(outline_locator), &supporting_radius = std::as_const(supporting_radius), &tree_node_locator = std::as_const(tree_node_locator), &unsupported_location = std::as_const(unsupported_location)](const tbb::blocked_range2d<coord_t> &range) -> void {
174 for (coord_t grid_addr_y = range.rows().begin(); grid_addr_y < range.rows().end(); ++grid_addr_y)
175 for (coord_t grid_addr_x = range.cols().begin(); grid_addr_x < range.cols().end(); ++grid_addr_x) {
176 const Point local_grid_addr{grid_addr_x, grid_addr_y};
177 NodeSPtr local_sub_tree{nullptr};
178 coord_t local_current_dist = current_dist_copy;
179 const auto it_range = tree_node_locator.equal_range(local_grid_addr);
180 for (auto it = it_range.first; it != it_range.second; ++it) {
181 const NodeSPtr candidate_sub_tree = it->second.lock();
182 if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
183 !(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
184 !polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) {
185 if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < local_current_dist) {
186 local_current_dist = candidate_dist;
187 local_sub_tree = candidate_sub_tree;
188 }
189 }
190 }
191 // To always get the same result in a parallel version as in a non-parallel version,
192 // we need to preserve that for the same current_dist, we select the same sub_tree
193 // as in the non-parallel version. For this purpose, inside the variable
194 // current_dist_grid_addr is stored from with 2D grid position assigned sub_tree comes.
195 // And when there are two sub_tree with the same current_dist, one which will be found
196 // the first in the non-parallel version is selected.
197 {
198 std::lock_guard<std::mutex> lock(current_dist_mutex);
199 if (local_current_dist < current_dist ||
200 (local_current_dist == current_dist && (grid_addr_y < current_dist_grid_addr.y() ||
201 (grid_addr_y == current_dist_grid_addr.y() && grid_addr_x < current_dist_grid_addr.x())))) {
202 current_dist = local_current_dist;
203 sub_tree = local_sub_tree;
204 current_dist_grid_addr = local_grid_addr;
205 }
206 }
207 }
208 }); // end of parallel_for
209 }
210
211 return ! sub_tree ?
212 GroundingLocation{ nullptr, node_location } :
213 GroundingLocation{ sub_tree, std::optional<Point>() };
214}
coord_t getWeightedDistance(const Point &boundary_loc, const Point &unsupported_location)
Definition Layer.cpp:33
Points points
Definition MultiPoint.hpp:22
size_t size() const
Definition MultiPoint.hpp:50
int64_t coord_t
Definition libslic3r.h:48
coord_t locator_cell_size()
Definition TreeNode.hpp:29
double distance_to_squared(const L &line, const Vec< Dim< L >, Scalar< L > > &point, Vec< Dim< L >, Scalar< L > > *nearest_point)
Definition Line.hpp:46
auto range(Cont &&cont)
Definition libslic3r.h:405
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30

References Slic3r::cast(), Slic3r::contour(), Slic3r::line_alg::distance_to_squared(), getWeightedDistance(), Slic3r::FillLightning::locator_cell_size(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::range(), and Slic3r::FillLightning::to_grid_point().

Referenced by generateNewTrees(), and reconnectRoots().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getWeightedDistance()

coord_t Slic3r::FillLightning::Layer::getWeightedDistance ( const Point & boundary_loc,
const Point & unsupported_location )
34{
35 return coord_t((boundary_loc - unsupported_location).cast<double>().norm());
36}

References Slic3r::cast().

Referenced by getBestGroundingLocation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reconnectRoots()

void Slic3r::FillLightning::Layer::reconnectRoots ( std::vector< NodeSPtr > & to_be_reconnected_tree_roots,
const Polygons & current_outlines,
const BoundingBox & current_outlines_bbox,
const EdgeGrid::Grid & outline_locator,
coord_t supporting_radius,
coord_t wall_supporting_radius )
243{
244 constexpr coord_t tree_connecting_ignore_offset = 100;
245
246 SparseNodeGrid tree_node_locator;
247 fillLocator(tree_node_locator, current_outlines_bbox);
248
249 const coord_t within_max_dist = outline_locator.resolution() * 2;
250 for (const auto &root_ptr : to_be_reconnected_tree_roots)
251 {
252 auto old_root_it = std::find(tree_roots.begin(), tree_roots.end(), root_ptr);
253
254 if (root_ptr->getLastGroundingLocation())
255 {
256 const Point& ground_loc = *root_ptr->getLastGroundingLocation();
257 if (ground_loc != root_ptr->getLocation())
258 {
259 Point new_root_pt;
260 // Find an intersection of the line segment from root_ptr->getLocation() to ground_loc, at within_max_dist from ground_loc.
261 if (lineSegmentPolygonsIntersection(root_ptr->getLocation(), ground_loc, outline_locator, new_root_pt, within_max_dist)) {
262 auto new_root = Node::create(new_root_pt, new_root_pt);
263 root_ptr->addChild(new_root);
264 new_root->reroot();
265
266 tree_node_locator.insert(std::make_pair(to_grid_point(new_root->getLocation(), current_outlines_bbox), new_root));
267
268 *old_root_it = std::move(new_root); // replace old root with new root
269 continue;
270 }
271 }
272 }
273
274 const coord_t tree_connecting_ignore_width = wall_supporting_radius - tree_connecting_ignore_offset; // Ideally, the boundary size in which the valence rule is ignored would be configurable.
275 GroundingLocation ground =
277 (
278 root_ptr->getLocation(),
279 current_outlines,
280 current_outlines_bbox,
281 outline_locator,
282 supporting_radius,
283 tree_connecting_ignore_width,
284 tree_node_locator,
285 root_ptr
286 );
287 if (ground.boundary_location)
288 {
289 if (*ground.boundary_location == root_ptr->getLocation())
290 continue; // Already on the boundary.
291
292 auto new_root = Node::create(ground.p(), ground.p());
293 auto attach_ptr = root_ptr->closestNode(new_root->getLocation());
294 attach_ptr->reroot();
295
296 new_root->addChild(attach_ptr);
297 tree_node_locator.insert(std::make_pair(to_grid_point(new_root->getLocation(), current_outlines_bbox), new_root));
298
299 *old_root_it = std::move(new_root); // replace old root with new root
300 }
301 else
302 {
303 assert(ground.tree_node);
304 assert(ground.tree_node != root_ptr);
305 assert(!root_ptr->hasOffspring(ground.tree_node));
306 assert(!ground.tree_node->hasOffspring(root_ptr));
307
308 auto attach_ptr = root_ptr->closestNode(ground.tree_node->getLocation());
309 attach_ptr->reroot();
310
311 ground.tree_node->addChild(attach_ptr);
312
313 // remove old root
314 *old_root_it = std::move(tree_roots.back());
315 tree_roots.pop_back();
316 }
317 }
318}
bool lineSegmentPolygonsIntersection(const Point &a, const Point &b, const EdgeGrid::Grid &outline_locator, Point &result, const coord_t within_max_dist)
Definition TreeNode.cpp:165

References Slic3r::FillLightning::GroundingLocation::boundary_location, Slic3r::FillLightning::Node::create(), fillLocator(), getBestGroundingLocation(), Slic3r::FillLightning::lineSegmentPolygonsIntersection(), Slic3r::FillLightning::GroundingLocation::p(), reconnectRoots(), Slic3r::EdgeGrid::Grid::resolution(), Slic3r::FillLightning::to_grid_point(), Slic3r::FillLightning::GroundingLocation::tree_node, and tree_roots.

Referenced by Slic3r::FillLightning::Generator::generateTrees(), Slic3r::FillLightning::Generator::generateTreesforSupport(), and reconnectRoots().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ tree_roots


The documentation for this class was generated from the following files:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Fill/Lightning/Layer.hpp
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Fill/Lightning/Layer.cpp