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

#include <src/libslic3r/JumpPointSearch.hpp>

+ Collaboration diagram for Slic3r::JPSPathFinder:

Public Member Functions

 JPSPathFinder ()=default
 
void init_bed_shape (const Points &bed_shape)
 
void clear ()
 
void add_obstacles (const Lines &obstacles)
 
void add_obstacles (const Layer *layer, const Point &global_origin)
 
Polyline find_path (const Point &start, const Point &end)
 

Private Types

using Pixel = Point
 

Private Member Functions

Pixel pixelize (const Point &p)
 
Point unpixelize (const Pixel &p)
 

Private Attributes

std::unordered_set< Pixel, PointHashinpassable
 
coordf_t print_z
 
BoundingBox max_search_box
 
Lines bed_shape
 
const coord_t resolution = scaled(1.5)
 

Detailed Description

Member Typedef Documentation

◆ Pixel

Constructor & Destructor Documentation

◆ JPSPathFinder()

Slic3r::JPSPathFinder::JPSPathFinder ( )
default

Member Function Documentation

◆ add_obstacles() [1/2]

void Slic3r::JPSPathFinder::add_obstacles ( const Layer layer,
const Point global_origin 
)
211{
212 if (layer == nullptr) return;
213
214 this->print_z = layer->print_z;
215 Lines obstacles;
216 obstacles.reserve(layer->curled_lines.size());
217 for (const Line &l : layer->curled_lines) { obstacles.push_back(Line{l.a + global_origin, l.b + global_origin}); }
218 add_obstacles(obstacles);
219}
coordf_t print_z
Definition JumpPointSearch.hpp:19
void add_obstacles(const Lines &obstacles)
Definition JumpPointSearch.cpp:192
std::vector< Line > Lines
Definition Line.hpp:17

References Slic3r::Line::a, add_obstacles(), Slic3r::Layer::curled_lines, print_z, and Slic3r::Layer::print_z.

+ Here is the call graph for this function:

◆ add_obstacles() [2/2]

void Slic3r::JPSPathFinder::add_obstacles ( const Lines obstacles)
193{
194 auto store_obstacle = [&](coord_t x, coord_t y) {
195 max_search_box.max.x() = std::max(max_search_box.max.x(), x);
196 max_search_box.max.y() = std::max(max_search_box.max.y(), y);
197 max_search_box.min.x() = std::min(max_search_box.min.x(), x);
198 max_search_box.min.y() = std::min(max_search_box.min.y(), y);
199 inpassable.insert(Pixel{x, y});
200 return true;
201 };
202
203 for (const Line &l : obstacles) {
204 Pixel start = pixelize(l.a);
205 Pixel end = pixelize(l.b);
206 double_dda_with_offset(start.x(), start.y(), end.x(), end.y(), store_obstacle);
207 }
208}
PointType max
Definition BoundingBox.hpp:17
PointType min
Definition BoundingBox.hpp:16
Pixel pixelize(const Point &p)
Definition JumpPointSearch.hpp:24
Point Pixel
Definition JumpPointSearch.hpp:17
std::unordered_set< Pixel, PointHash > inpassable
Definition JumpPointSearch.hpp:18
BoundingBox max_search_box
Definition JumpPointSearch.hpp:20
int32_t coord_t
Definition libslic3r.h:39
const Scalar & y
Definition MathFunctions.h:552
void double_dda_with_offset(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
Definition JumpPointSearch.cpp:60
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620

References Slic3r::double_dda_with_offset(), inpassable, Slic3r::BoundingBoxBase< PointType, APointsType >::max, max_search_box, Slic3r::BoundingBoxBase< PointType, APointsType >::min, and pixelize().

Referenced by add_obstacles(), clear(), and Slic3r::GCode::process_layer().

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

◆ clear()

void Slic3r::JPSPathFinder::clear ( )
185{
186 inpassable.clear();
187 max_search_box.max = Pixel(std::numeric_limits<coord_t>::min(), std::numeric_limits<coord_t>::min());
188 max_search_box.min = Pixel(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max());
190}
Lines bed_shape
Definition JumpPointSearch.hpp:21

References add_obstacles(), bed_shape, inpassable, Slic3r::BoundingBoxBase< PointType, APointsType >::max, max_search_box, and Slic3r::BoundingBoxBase< PointType, APointsType >::min.

Referenced by Slic3r::GCode::process_layer().

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

◆ find_path()

Polyline Slic3r::JPSPathFinder::find_path ( const Point start,
const Point end 
)
222{
223 Pixel start = pixelize(p0);
224 Pixel end = pixelize(p1);
225 if (inpassable.empty() || (start - end).cast<float>().norm() < 3.0) { return Polyline{p0, p1}; }
226
227 if (inpassable.find(start) != inpassable.end()) {
228 dda(start.x(), start.y(), end.x(), end.y(), [&](coord_t x, coord_t y) {
229 if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
230 start = Pixel(x, y);
231 return false;
232 }
233 return true;
234 });
235 }
236
237 if (inpassable.find(end) != inpassable.end()) {
238 dda(end.x(), end.y(), start.x(), start.y(), [&](coord_t x, coord_t y) {
239 if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable
240 end = Pixel(x, y);
241 return false;
242 }
243 return true;
244 });
245 }
246
247 BoundingBox search_box = max_search_box;
248 search_box.max -= Pixel(1, 1);
249 search_box.min += Pixel(1, 1);
250
251 BoundingBox bounding_square(Points{start, end});
252 bounding_square.max += Pixel(5, 5);
253 bounding_square.min -= Pixel(5, 5);
254 coord_t bounding_square_size = 2 * std::max(bounding_square.size().x(), bounding_square.size().y());
255 bounding_square.max.x() += (bounding_square_size - bounding_square.size().x()) / 2;
256 bounding_square.min.x() -= (bounding_square_size - bounding_square.size().x()) / 2;
257 bounding_square.max.y() += (bounding_square_size - bounding_square.size().y()) / 2;
258 bounding_square.min.y() -= (bounding_square_size - bounding_square.size().y()) / 2;
259
260 // Intersection - limit the search box to a square area around the start and end, to fasten the path searching
261 search_box.max = search_box.max.cwiseMin(bounding_square.max);
262 search_box.min = search_box.min.cwiseMax(bounding_square.min);
263
264 auto cell_query = [&](Pixel pixel) {
265 return search_box.contains(pixel) && (pixel == start || pixel == end || inpassable.find(pixel) == inpassable.end());
266 };
267
268 JPSTracer<Pixel, decltype(cell_query)> tracer(end, cell_query);
269 using QNode = astar::QNode<JPSTracer<Pixel, decltype(cell_query)>>;
270
271 std::unordered_map<size_t, QNode> astar_cache{};
272 std::vector<Pixel, PointsAllocator<Pixel>> out_path;
273 std::vector<decltype(tracer)::Node> out_nodes;
274
275 if (!astar::search_route(tracer, {start, {0, 0}}, std::back_inserter(out_nodes), astar_cache)) {
276 // path not found - just reconstruct the best path from astar cache.
277 // Note that astar_cache is NOT empty - at least the starting point should always be there
278 auto coordiante_func = [&astar_cache](size_t idx, size_t dim) { return float(astar_cache[idx].node.position[dim]); };
279 std::vector<size_t> keys;
280 keys.reserve(astar_cache.size());
281 for (const auto &pair : astar_cache) { keys.push_back(pair.first); }
282 KDTreeIndirect<2, float, decltype(coordiante_func)> kd_tree(coordiante_func, keys);
283 size_t closest_qnode = find_closest_point(kd_tree, end.cast<float>());
284
285 out_path.push_back(end);
286 while (closest_qnode != astar::Unassigned) {
287 out_path.push_back(astar_cache[closest_qnode].node.position);
288 closest_qnode = astar_cache[closest_qnode].parent;
289 }
290 } else {
291 for (const auto &node : out_nodes) { out_path.push_back(node.position); }
292 out_path.push_back(start);
293 }
294
295#ifdef DEBUG_FILES
296 auto scaled_points = [](const Points &ps) {
297 Points r;
298 for (const Point &p : ps) { r.push_back(Point::new_scale(p.x(), p.y())); }
299 return r;
300 };
301 auto scaled_point = [](const Point &p) { return Point::new_scale(p.x(), p.y()); };
302 ::Slic3r::SVG svg(debug_out_path(("path_jps" + std::to_string(print_z) + "_" + std::to_string(rand() % 1000)).c_str()).c_str(),
303 BoundingBox(scaled_point(search_box.min), scaled_point(search_box.max)));
304 for (const auto &p : inpassable) { svg.draw(scaled_point(p), "black", scale_(0.4)); }
305 for (const auto &qn : astar_cache) { svg.draw(scaled_point(qn.second.node.position), "blue", scale_(0.3)); }
306 svg.draw(Polyline(scaled_points(out_path)), "yellow", scale_(0.25));
307 svg.draw(scaled_point(end), "purple", scale_(0.4));
308 svg.draw(scaled_point(start), "green", scale_(0.4));
309#endif
310
311 std::vector<Pixel, PointsAllocator<Pixel>> tmp_path;
312 tmp_path.reserve(out_path.size());
313 // Some path found, reverse and remove points that do not change direction
314 std::reverse(out_path.begin(), out_path.end());
315 {
316 tmp_path.push_back(out_path.front()); // first point
317 for (size_t i = 1; i < out_path.size() - 1; i++) {
318 if ((out_path[i] - out_path[i - 1]).cast<float>().normalized() != (out_path[i + 1] - out_path[i]).cast<float>().normalized()) {
319 tmp_path.push_back(out_path[i]);
320 }
321 }
322 tmp_path.push_back(out_path.back()); // last_point
323 out_path = tmp_path;
324 }
325
326#ifdef DEBUG_FILES
327 svg.draw(Polyline(scaled_points(out_path)), "orange", scale_(0.20));
328#endif
329
330 tmp_path.clear();
331 // remove redundant jump points - there are points that change direction but are not needed - this inefficiency arises from the
332 // usage of grid search The removal alg tries to find the longest Px Px+k path without obstacles. If Px Px+k+1 is blocked, it will
333 // insert the Px+k point to result and continue search from Px+k
334 {
335 tmp_path.push_back(out_path.front()); // first point
336 size_t index_of_last_stored_point = 0;
337 for (size_t i = 1; i < out_path.size(); i++) {
338 if (i - index_of_last_stored_point < 2) continue;
339 bool passable = true;
340 auto store_obstacle = [&](coord_t x, coord_t y) {
341 if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) {
342 passable = false;
343 return false;
344 }
345 return true;
346 };
347 dda(tmp_path.back().x(), tmp_path.back().y(), out_path[i].x(), out_path[i].y(), store_obstacle);
348 if (!passable) {
349 tmp_path.push_back(out_path[i - 1]);
350 index_of_last_stored_point = i - 1;
351 }
352 }
353 tmp_path.push_back(out_path.back()); // last_point
354 out_path = tmp_path;
355 }
356
357#ifdef DEBUG_FILES
358 svg.draw(Polyline(scaled_points(out_path)), "red", scale_(0.15));
359 svg.Close();
360#endif
361
362 // before returing the path, transform it from pixels back to points.
363 // Also replace the first and last pixel by input points so that result path patches input params exactly.
364 for (Pixel &p : out_path) { p = unpixelize(p); }
365 out_path.front() = p0;
366 out_path.back() = p1;
367
368 return Polyline(out_path);
369}
Point unpixelize(const Pixel &p)
Definition JumpPointSearch.hpp:25
Definition SVG.hpp:14
#define scale_(val)
Definition libslic3r.h:69
constexpr auto Unassigned
Definition AStar.hpp:59
bool search_route(const Tracer &tracer, const TracerNodeT< Tracer > &source, It out, NodeMap &&cached_nodes={})
Definition AStar.hpp:100
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
void dda(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn)
Definition JumpPointSearch.cpp:32
size_t find_closest_point(const KDTreeIndirect< D, CoordT, CoordFn > &kdtree, const PointType &point, FilterFn filter)
Definition KDTreeIndirect.hpp:266
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:58
Kernel::Point_2 Point
Definition point_areas.cpp:20

References Slic3r::dda(), inpassable, and pixelize().

Referenced by Slic3r::GCode::travel_to().

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

◆ init_bed_shape()

void Slic3r::JPSPathFinder::init_bed_shape ( const Points bed_shape)
inline
29{ this->bed_shape = (to_lines(Polygon{bed_shape})); };
Lines to_lines(const ExPolygon &src)
Definition ExPolygon.hpp:117

References bed_shape, and Slic3r::to_lines().

Referenced by Slic3r::GCode::_do_export().

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

◆ pixelize()

Pixel Slic3r::JPSPathFinder::pixelize ( const Point p)
inlineprivate
24{ return p / resolution; }
const coord_t resolution
Definition JumpPointSearch.hpp:23

References resolution.

Referenced by add_obstacles(), and find_path().

+ Here is the caller graph for this function:

◆ unpixelize()

Point Slic3r::JPSPathFinder::unpixelize ( const Pixel p)
inlineprivate
25{ return p * resolution; }

References resolution.

Member Data Documentation

◆ bed_shape

Lines Slic3r::JPSPathFinder::bed_shape
private

Referenced by clear(), and init_bed_shape().

◆ inpassable

std::unordered_set<Pixel, PointHash> Slic3r::JPSPathFinder::inpassable
private

Referenced by add_obstacles(), clear(), and find_path().

◆ max_search_box

BoundingBox Slic3r::JPSPathFinder::max_search_box
private

Referenced by add_obstacles(), and clear().

◆ print_z

coordf_t Slic3r::JPSPathFinder::print_z
private

Referenced by add_obstacles().

◆ resolution

const coord_t Slic3r::JPSPathFinder::resolution = scaled(1.5)
private

Referenced by pixelize(), and unpixelize().


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