Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::FillLightning::Layer Class Reference

#include <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< NodeSPtrtree_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
207{
208 // Update trees & distance fields.
209 if (grounding_loc.boundary_location) {
210 new_root = Node::create(grounding_loc.p(), std::make_optional(grounding_loc.p()));
211 new_child = new_root->addChild(unsupported_location);
212 tree_roots.push_back(new_root);
213 return true;
214 } else {
215 new_child = grounding_loc.tree_node->addChild(unsupported_location);
216 return false;
217 }
218}
std::vector< NodeSPtr > tree_roots
Definition Layer.hpp:38
static NodeSPtr create(Arg &&...arg)
Definition TreeNode.hpp:45

References Slic3r::FillLightning::GroundingLocation::boundary_location, Slic3r::FillLightning::GroundingLocation::p(), and Slic3r::FillLightning::GroundingLocation::tree_node.

Referenced by 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
437{
438 if (tree_roots.empty())
439 return {};
440
441 Polylines result_lines;
442 for (const auto &tree : tree_roots)
443 tree->convertToPolylines(result_lines, line_overlap);
444
445 return intersection_pl(result_lines, limit_to_outline);
446}
std::vector< Polyline > Polylines
Definition Polyline.hpp:14
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:866

References Slic3r::intersection_pl().

Referenced by Slic3r::FillLightning::Filler::_fill_surface_single().

+ 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 
)
36{
37 std::function<void(NodeSPtr)> add_node_to_locator_func = [&tree_node_locator, &current_outlines_bbox](const NodeSPtr &node) {
38 tree_node_locator.insert(std::make_pair(to_grid_point(node->getLocation(), current_outlines_bbox), node));
39 };
40 for (auto& tree : tree_roots)
41 tree->visitNodes(add_node_to_locator_func);
42}
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
std::shared_ptr< Node > NodeSPtr
Definition Layer.hpp:20
static Point to_grid_point(const Point &point, const BoundingBox &bbox)
Definition Layer.cpp:30

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

Referenced by generateNewTrees().

+ 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 
)
54{
55 DistanceField distance_field(supporting_radius, current_outlines, current_outlines_bbox, current_overhang);
56 throw_on_cancel_callback();
57
58 SparseNodeGrid tree_node_locator;
59 fillLocator(tree_node_locator, current_outlines_bbox);
60
61 // Until no more points need to be added to support all:
62 // Determine next point from tree/outline areas via distance-field
63 size_t unsupported_cell_idx = 0;
64 Point unsupported_location;
65 while (distance_field.tryGetNextPoint(&unsupported_location, &unsupported_cell_idx, unsupported_cell_idx)) {
66 throw_on_cancel_callback();
67 GroundingLocation grounding_loc = getBestGroundingLocation(
68 unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator);
69
70 NodeSPtr new_parent;
71 NodeSPtr new_child;
72 this->attach(unsupported_location, grounding_loc, new_child, new_parent);
73 tree_node_locator.insert(std::make_pair(to_grid_point(new_child->getLocation(), current_outlines_bbox), new_child));
74 if (new_parent)
75 tree_node_locator.insert(std::make_pair(to_grid_point(new_parent->getLocation(), current_outlines_bbox), new_parent));
76 // update distance field
77 distance_field.update(grounding_loc.p(), unsupported_location);
78 }
79
80#ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT
81 {
82 static int iRun = 0;
83 export_to_svg(debug_out_path("FillLightning-TreeNodes-%d.svg", iRun++), current_outlines, this->tree_roots);
84 }
85#endif /* LIGHTNING_TREE_NODE_DEBUG_OUTPUT */
86}
void fillLocator(SparseNodeGrid &tree_node_locator, const BoundingBox &current_outlines_bbox)
Definition Layer.cpp:35
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:118
bool attach(const Point &unsupported_location, const GroundingLocation &ground, NodeSPtr &new_child, NodeSPtr &new_root)
Definition Layer.cpp:202
std::unordered_multimap< Point, std::weak_ptr< Node >, PointHash > SparseNodeGrid
Definition Layer.hpp:21
bool export_to_svg(const char *path, const Surfaces &surfaces, const float transparency)
Definition Surface.cpp:82
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
Kernel::Point_2 Point
Definition point_areas.cpp:20

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().

+ 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
128{
129 // Closest point on current_outlines to unsupported_location:
130 Point node_location;
131 {
132 double d2 = std::numeric_limits<double>::max();
133 for (const Polygon &contour : current_outlines)
134 if (contour.size() > 2) {
135 Point prev = contour.points.back();
136 for (const Point &p2 : contour.points) {
137 Point closest_point;
138 if (double d = line_alg::distance_to_squared(Line{prev, p2}, unsupported_location, &closest_point); d < d2) {
139 d2 = d;
140 node_location = closest_point;
141 }
142 prev = p2;
143 }
144 }
145 }
146
147 const auto within_dist = coord_t((node_location - unsupported_location).cast<double>().norm());
148
149 NodeSPtr sub_tree{nullptr};
150 coord_t current_dist = getWeightedDistance(node_location, unsupported_location);
151 if (current_dist >= wall_supporting_radius) { // Only reconnect tree roots to other trees if they are not already close to the outlines.
152 const coord_t search_radius = std::min(current_dist, within_dist);
153 BoundingBox region(unsupported_location - Point(search_radius, search_radius), unsupported_location + Point(search_radius + locator_cell_size, search_radius + locator_cell_size));
154 region.min = to_grid_point(region.min, current_outlines_bbox);
155 region.max = to_grid_point(region.max, current_outlines_bbox);
156
157 Point current_dist_grid_addr{std::numeric_limits<coord_t>::lowest(), std::numeric_limits<coord_t>::lowest()};
158 std::mutex current_dist_mutex;
159 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 {
160 for (coord_t grid_addr_y = range.rows().begin(); grid_addr_y < range.rows().end(); ++grid_addr_y)
161 for (coord_t grid_addr_x = range.cols().begin(); grid_addr_x < range.cols().end(); ++grid_addr_x) {
162 const Point local_grid_addr{grid_addr_x, grid_addr_y};
163 NodeSPtr local_sub_tree{nullptr};
164 coord_t local_current_dist = current_dist_copy;
165 const auto it_range = tree_node_locator.equal_range(local_grid_addr);
166 for (auto it = it_range.first; it != it_range.second; ++it) {
167 const NodeSPtr candidate_sub_tree = it->second.lock();
168 if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
169 !(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
170 !polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) {
171 if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < local_current_dist) {
172 local_current_dist = candidate_dist;
173 local_sub_tree = candidate_sub_tree;
174 }
175 }
176 }
177 // To always get the same result in a parallel version as in a non-parallel version,
178 // we need to preserve that for the same current_dist, we select the same sub_tree
179 // as in the non-parallel version. For this purpose, inside the variable
180 // current_dist_grid_addr is stored from with 2D grid position assigned sub_tree comes.
181 // And when there are two sub_tree with the same current_dist, one which will be found
182 // the first in the non-parallel version is selected.
183 {
184 std::lock_guard<std::mutex> lock(current_dist_mutex);
185 if (local_current_dist < current_dist ||
186 (local_current_dist == current_dist && (grid_addr_y < current_dist_grid_addr.y() ||
187 (grid_addr_y == current_dist_grid_addr.y() && grid_addr_x < current_dist_grid_addr.x())))) {
188 current_dist = local_current_dist;
189 sub_tree = local_sub_tree;
190 current_dist_grid_addr = local_grid_addr;
191 }
192 }
193 }
194 }); // end of parallel_for
195 }
196
197 return ! sub_tree ?
198 GroundingLocation{ nullptr, node_location } :
199 GroundingLocation{ sub_tree, std::optional<Point>() };
200}
coord_t getWeightedDistance(const Point &boundary_loc, const Point &unsupported_location)
Definition Layer.cpp:19
Points points
Definition MultiPoint.hpp:18
if(!(yy_init))
Definition lexer.c:1190
int32_t coord_t
Definition libslic3r.h:39
constexpr auto locator_cell_size
Definition TreeNode.hpp:21
double distance_to_squared(const L &line, const Vec< Dim< L >, Scalar< L > > &point, Vec< Dim< L >, Scalar< L > > *nearest_point)
Definition Line.hpp:43
auto range(Cont &&cont)
Definition libslic3r.h:356
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:21
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183

References 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::MultiPoint::points, Slic3r::range(), Slic3r::MultiPoint::size(), and Slic3r::FillLightning::to_grid_point().

Referenced by generateNewTrees().

+ 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 
)
20{
21 return coord_t((boundary_loc - unsupported_location).cast<double>().norm());
22}

Referenced by getBestGroundingLocation().

+ 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 
)
229{
230 constexpr coord_t tree_connecting_ignore_offset = 100;
231
232 SparseNodeGrid tree_node_locator;
233 fillLocator(tree_node_locator, current_outlines_bbox);
234
235 const coord_t within_max_dist = outline_locator.resolution() * 2;
236 for (const auto &root_ptr : to_be_reconnected_tree_roots)
237 {
238 auto old_root_it = std::find(tree_roots.begin(), tree_roots.end(), root_ptr);
239
240 if (root_ptr->getLastGroundingLocation())
241 {
242 const Point& ground_loc = *root_ptr->getLastGroundingLocation();
243 if (ground_loc != root_ptr->getLocation())
244 {
245 Point new_root_pt;
246 // Find an intersection of the line segment from root_ptr->getLocation() to ground_loc, at within_max_dist from ground_loc.
247 if (lineSegmentPolygonsIntersection(root_ptr->getLocation(), ground_loc, outline_locator, new_root_pt, within_max_dist)) {
248 auto new_root = Node::create(new_root_pt, new_root_pt);
249 root_ptr->addChild(new_root);
250 new_root->reroot();
251
252 tree_node_locator.insert(std::make_pair(to_grid_point(new_root->getLocation(), current_outlines_bbox), new_root));
253
254 *old_root_it = std::move(new_root); // replace old root with new root
255 continue;
256 }
257 }
258 }
259
260 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.
261 GroundingLocation ground =
263 (
264 root_ptr->getLocation(),
265 current_outlines,
266 current_outlines_bbox,
267 outline_locator,
268 supporting_radius,
269 tree_connecting_ignore_width,
270 tree_node_locator,
271 root_ptr
272 );
273 if (ground.boundary_location)
274 {
275 if (*ground.boundary_location == root_ptr->getLocation())
276 continue; // Already on the boundary.
277
278 auto new_root = Node::create(ground.p(), ground.p());
279 auto attach_ptr = root_ptr->closestNode(new_root->getLocation());
280 attach_ptr->reroot();
281
282 new_root->addChild(attach_ptr);
283 tree_node_locator.insert(std::make_pair(to_grid_point(new_root->getLocation(), current_outlines_bbox), new_root));
284
285 *old_root_it = std::move(new_root); // replace old root with new root
286 }
287 else
288 {
289 assert(ground.tree_node);
290 assert(ground.tree_node != root_ptr);
291 assert(!root_ptr->hasOffspring(ground.tree_node));
292 assert(!ground.tree_node->hasOffspring(root_ptr));
293
294 auto attach_ptr = root_ptr->closestNode(ground.tree_node->getLocation());
295 attach_ptr->reroot();
296
297 ground.tree_node->addChild(attach_ptr);
298
299 // remove old root
300 *old_root_it = std::move(tree_roots.back());
301 tree_roots.pop_back();
302 }
303 }
304}
bool lineSegmentPolygonsIntersection(const Point &a, const Point &b, const EdgeGrid::Grid &outline_locator, Point &result, const coord_t within_max_dist)
Definition TreeNode.cpp:144

References Slic3r::FillLightning::GroundingLocation::boundary_location, Slic3r::FillLightning::lineSegmentPolygonsIntersection(), Slic3r::FillLightning::GroundingLocation::p(), Slic3r::EdgeGrid::Grid::resolution(), Slic3r::FillLightning::to_grid_point(), and Slic3r::FillLightning::GroundingLocation::tree_node.

Referenced by Slic3r::FillLightning::Generator::generateTrees().

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

Member Data Documentation

◆ tree_roots

std::vector<NodeSPtr> Slic3r::FillLightning::Layer::tree_roots

The documentation for this class was generated from the following files: