Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::Algorithm Namespace Reference

Classes

struct  RegionExpansion
 
struct  RegionExpansionEx
 
struct  RegionExpansionParameters
 
struct  WaveSeed
 

Typedefs

using AABBTreeBBoxes = AABBTreeIndirect::Tree< 2, coord_t >
 
using WaveSeeds = std::vector< WaveSeed >
 

Functions

template<typename RandomAccessIterator , typename ToLines >
void sort_paths (RandomAccessIterator begin, RandomAccessIterator end, Point start, double touch_limit_distance, ToLines convert_to_lines)
 
double clipper_round_offset_error (double offset, double arc_tolerance)
 
static ClipperLib_Z::Paths expolygons_to_zpaths_expanded_opened (const ExPolygons &src, const float expansion, coord_t &base_idx)
 
static void merge_splits (ClipperLib_Z::Paths &paths, std::vector< std::pair< ClipperLib_Z::IntPoint, int > > &splits)
 
static AABBTreeBBoxes build_aabb_tree_over_expolygons (const ExPolygons &expolygons)
 
static int sample_in_expolygons (const AABBTreeBBoxes &aabb_tree, const ExPolygons &expolygons, const Point &sample)
 
std::vector< WaveSeedwave_seeds (const ExPolygons &src, const ExPolygons &boundary, float tiny_expansion, bool sorted)
 
static ClipperLib::Paths wavefront_initial (ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polylines, float offset)
 
static ClipperLib::Paths wavefront_step (ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polygons, float offset)
 
static ClipperLib::Paths wavefront_clip (const ClipperLib::Paths &wavefront, const Polygons &clipping)
 
static Polygons propagate_wave_from_boundary (ClipperLib::ClipperOffset &co, const ClipperLib::Paths &seed, const ExPolygon &boundary, const float initial_step, const float other_step, const size_t num_other_steps, const float max_inflation)
 
std::vector< RegionExpansionpropagate_waves (const WaveSeeds &seeds, const ExPolygons &boundary, const RegionExpansionParameters &params)
 
std::vector< RegionExpansionpropagate_waves (const ExPolygons &src, const ExPolygons &boundary, const RegionExpansionParameters &params)
 
std::vector< RegionExpansionpropagate_waves (const ExPolygons &src, const ExPolygons &boundary, float expansion, float expansion_step, size_t max_nr_steps)
 
std::vector< RegionExpansionExpropagate_waves_ex (const WaveSeeds &seeds, const ExPolygons &boundary, const RegionExpansionParameters &params)
 
std::vector< RegionExpansionExpropagate_waves_ex (const ExPolygons &src, const ExPolygons &boundary, float full_expansion, float expansion_step, size_t max_nr_expansion_steps)
 
std::vector< Polygonsexpand_expolygons (const ExPolygons &src, const ExPolygons &boundary, float expansion, float expansion_step, size_t max_nr_steps)
 
std::vector< ExPolygonmerge_expansions_into_expolygons (ExPolygons &&src, std::vector< RegionExpansion > &&expanded)
 
std::vector< ExPolygonexpand_merge_expolygons (ExPolygons &&src, const ExPolygons &boundary, const RegionExpansionParameters &params)
 
bool lower_by_boundary_and_src (const WaveSeed &l, const WaveSeed &r)
 
bool lower_by_src_and_boundary (const WaveSeed &l, const WaveSeed &r)
 

Class Documentation

◆ Slic3r::Algorithm::RegionExpansion

struct Slic3r::Algorithm::RegionExpansion
+ Collaboration diagram for Slic3r::Algorithm::RegionExpansion:
Class Members
uint32_t boundary_id
Polygon polygon
uint32_t src_id

◆ Slic3r::Algorithm::RegionExpansionEx

struct Slic3r::Algorithm::RegionExpansionEx
+ Collaboration diagram for Slic3r::Algorithm::RegionExpansionEx:
Class Members
uint32_t boundary_id
ExPolygon expolygon
uint32_t src_id

◆ Slic3r::Algorithm::WaveSeed

struct Slic3r::Algorithm::WaveSeed
+ Collaboration diagram for Slic3r::Algorithm::WaveSeed:
Class Members
uint32_t boundary
Points path
uint32_t src

Typedef Documentation

◆ AABBTreeBBoxes

◆ WaveSeeds

using Slic3r::Algorithm::WaveSeeds = typedef std::vector<WaveSeed>

Function Documentation

◆ build_aabb_tree_over_expolygons()

static AABBTreeBBoxes Slic3r::Algorithm::build_aabb_tree_over_expolygons ( const ExPolygons expolygons)
static
160{
161 // Calculate bounding boxes of internal slices.
162 std::vector<AABBTreeIndirect::BoundingBoxWrapper> bboxes;
163 bboxes.reserve(expolygons.size());
164 for (size_t i = 0; i < expolygons.size(); ++ i)
165 bboxes.emplace_back(i, get_extents(expolygons[i].contour));
166 // Build AABB tree over bounding boxes of boundary expolygons.
167 AABBTreeBBoxes out;
168 out.build_modify_input(bboxes);
169 return out;
170}
void build_modify_input(std::vector< SourceNode > &input)
Definition AABBTreeIndirect.hpp:93
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352

References Slic3r::AABBTreeIndirect::Tree< ANumDimensions, ACoordType >::build_modify_input(), Slic3r::contour(), and Slic3r::get_extents().

Referenced by merge_expansions_into_expolygons(), and wave_seeds().

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

◆ clipper_round_offset_error()

double Slic3r::Algorithm::clipper_round_offset_error ( double  offset,
double  arc_tolerance 
)
inline
15{
16 static constexpr const double def_arc_tolerance = 0.25;
17 const double y =
18 arc_tolerance <= 0 ?
19 def_arc_tolerance :
20 arc_tolerance > offset * def_arc_tolerance ?
21 offset * def_arc_tolerance :
22 arc_tolerance;
23 double steps = std::min(M_PI / std::acos(1. - y / offset), offset * M_PI);
24 return offset * (1. - cos(M_PI / steps));
25}
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
#define M_PI
Definition ExtrusionSimulator.cpp:20

References cos(), M_PI, and Slic3r::offset().

+ Here is the call graph for this function:

◆ expand_expolygons()

std::vector< Polygons > Slic3r::Algorithm::expand_expolygons ( const ExPolygons src,
const ExPolygons boundary,
float  expansion,
float  expansion_step,
size_t  max_nr_steps 
)
476{
477 std::vector<Polygons> out(src.size(), Polygons{});
478 for (RegionExpansion &r : propagate_waves(src, boundary, expansion, expansion_step, max_nr_steps))
479 out[r.src_id].emplace_back(std::move(r.polygon));
480 return out;
481}
std::vector< RegionExpansion > propagate_waves(const WaveSeeds &seeds, const ExPolygons &boundary, const RegionExpansionParameters &params)
Definition RegionExpansion.cpp:387
Definition RegionExpansion.hpp:68
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
STL namespace.

References expand_expolygons(), and propagate_waves().

Referenced by expand_expolygons().

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

◆ expand_merge_expolygons()

std::vector< ExPolygon > Slic3r::Algorithm::expand_merge_expolygons ( ExPolygons &&  src,
const ExPolygons boundary,
const RegionExpansionParameters params 
)
537{
538 // expanded regions are sorted by boundary id and source id
539 std::vector<RegionExpansion> expanded = propagate_waves(src, boundary, params);
540 return merge_expansions_into_expolygons(std::move(src), std::move(expanded));
541}
std::vector< ExPolygon > merge_expansions_into_expolygons(ExPolygons &&src, std::vector< RegionExpansion > &&expanded)
Definition RegionExpansion.cpp:483

References expand_merge_expolygons(), merge_expansions_into_expolygons(), and propagate_waves().

Referenced by expand_merge_expolygons().

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

◆ expolygons_to_zpaths_expanded_opened()

static ClipperLib_Z::Paths Slic3r::Algorithm::expolygons_to_zpaths_expanded_opened ( const ExPolygons src,
const float  expansion,
coord_t base_idx 
)
static
80{
81 ClipperLib_Z::Paths out;
82 out.reserve(2 * std::accumulate(src.begin(), src.end(), size_t(0),
83 [](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); }));
85 offsetter.ShortestEdgeLength = expansion * ClipperOffsetShortestEdgeFactor;
86 ClipperLib::Paths expansion_cache;
87 for (const ExPolygon &expoly : src) {
88 for (size_t icontour = 0; icontour < expoly.num_contours(); ++ icontour) {
89 // Execute reorients the contours so that the outer most contour has a positive area. Thus the output
90 // contours will be CCW oriented even though the input paths are CW oriented.
91 // Offset is applied after contour reorientation, thus the signum of the offset value is reversed.
92 offsetter.Clear();
94 expansion_cache.clear();
95 offsetter.Execute(expansion_cache, icontour == 0 ? expansion : -expansion);
96 append(out, ClipperZUtils::to_zpaths<true>(expansion_cache, base_idx));
97 }
98 ++ base_idx;
99 }
100 return out;
101}
Definition clipper.hpp:540
void AddPath(const Path &path, JoinType joinType, EndType endType)
Definition clipper.cpp:3328
double ShortestEdgeLength
Definition clipper.hpp:556
void Clear()
Definition clipper.cpp:3319
void Execute(Paths &solution, double delta)
Definition clipper.cpp:3418
Definition ExPolygon.hpp:16
size_t num_contours() const
Definition ExPolygon.hpp:80
Polygon & contour_or_hole(size_t idx)
Definition ExPolygon.hpp:81
Points points
Definition MultiPoint.hpp:18
@ jtSquare
Definition clipper.hpp:138
@ etClosedPolygon
Definition clipper.hpp:139
std::vector< Path, Allocator< Path > > Paths
Definition clipper.hpp:122

References ClipperLib::ClipperOffset::AddPath(), Slic3r::append(), ClipperLib::ClipperOffset::Clear(), Slic3r::ClipperOffsetShortestEdgeFactor, Slic3r::ExPolygon::contour_or_hole(), ClipperLib::etClosedPolygon, ClipperLib::ClipperOffset::Execute(), ClipperLib::jtSquare, Slic3r::ExPolygon::num_contours(), Slic3r::MultiPoint::points, and ClipperLib::ClipperOffset::ShortestEdgeLength.

Referenced by wave_seeds().

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

◆ lower_by_boundary_and_src()

bool Slic3r::Algorithm::lower_by_boundary_and_src ( const WaveSeed l,
const WaveSeed r 
)
inline
47{
48 return l.boundary < r.boundary || (l.boundary == r.boundary && l.src < r.src);
49}
uint32_t boundary
Definition RegionExpansion.hpp:41
uint32_t src
Definition RegionExpansion.hpp:40

References Slic3r::Algorithm::WaveSeed::boundary, and Slic3r::Algorithm::WaveSeed::src.

Referenced by wave_seeds().

+ Here is the caller graph for this function:

◆ lower_by_src_and_boundary()

bool Slic3r::Algorithm::lower_by_src_and_boundary ( const WaveSeed l,
const WaveSeed r 
)
inline
52{
53 return l.src < r.src || (l.src == r.src && l.boundary < r.boundary);
54}

References Slic3r::Algorithm::WaveSeed::boundary, and Slic3r::Algorithm::WaveSeed::src.

◆ merge_expansions_into_expolygons()

std::vector< ExPolygon > Slic3r::Algorithm::merge_expansions_into_expolygons ( ExPolygons &&  src,
std::vector< RegionExpansion > &&  expanded 
)
484{
485 // expanded regions will be merged into source regions, thus they will be re-sorted by source id.
486 std::sort(expanded.begin(), expanded.end(), [](const auto &l, const auto &r) { return l.src_id < r.src_id; });
487 uint32_t last = 0;
488 Polygons acc;
489 ExPolygons out;
490 out.reserve(src.size());
491 for (auto it = expanded.begin(); it != expanded.end();) {
492 for (; last < it->src_id; ++ last)
493 out.emplace_back(std::move(src[last]));
494 acc.clear();
495 assert(it->src_id == last);
496 for (; it != expanded.end() && it->src_id == last; ++ it)
497 acc.emplace_back(std::move(it->polygon));
498 //FIXME offset & merging could be more efficient, for example one does not need to copy the source expolygon
499 ExPolygon &src_ex = src[last ++];
500 assert(! src_ex.contour.empty());
501#if 0
502 {
503 static int iRun = 0;
504 BoundingBox bbox = get_extents(acc);
505 bbox.merge(get_extents(src_ex));
506 SVG svg(debug_out_path("expand_merge_expolygons-failed-union=%d.svg", iRun ++).c_str(), bbox);
507 svg.draw(acc);
508 svg.draw_outline(acc, "black", scale_(0.05));
509 svg.draw(src_ex, "red");
510 svg.Close();
511 }
512#endif
513 Point sample = src_ex.contour.front();
514 append(acc, to_polygons(std::move(src_ex)));
516 // Expanding one expolygon by waves should not change connectivity of the source expolygon:
517 // Single expolygon should be produced possibly with increased number of holes.
518 if (merged.size() > 1) {
519 // assert(merged.size() == 1);
520 // There is something wrong with the initial waves. Most likely the bridge was not valid at all
521 // or the boundary region was very close to some bridge edge, but not really touching.
522 // Pick only a single merged expolygon, which contains one sample point of the source expolygon.
523 auto aabb_tree = build_aabb_tree_over_expolygons(merged);
524 int id = sample_in_expolygons(aabb_tree, merged, sample);
525 assert(id != -1);
526 if (id != -1)
527 out.emplace_back(std::move(merged[id]));
528 } else if (merged.size() == 1)
529 out.emplace_back(std::move(merged.front()));
530 }
531 for (; last < uint32_t(src.size()); ++ last)
532 out.emplace_back(std::move(src[last]));
533 return out;
534}
void merge(const PointType &point)
Definition BoundingBox.cpp:62
Definition BoundingBox.hpp:181
Polygon contour
Definition ExPolygon.hpp:35
bool empty() const
Definition MultiPoint.hpp:40
const Point & front() const
Definition MultiPoint.hpp:36
Definition Point.hpp:158
Definition SVG.hpp:14
#define scale_(val)
Definition libslic3r.h:69
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:354
unsigned __int32 uint32_t
Definition unistd.h:79

References build_aabb_tree_over_expolygons(), Slic3r::SVG::Close(), Slic3r::ExPolygon::contour, Slic3r::debug_out_path(), Slic3r::SVG::draw(), Slic3r::SVG::draw_outline(), Slic3r::MultiPoint::empty(), Slic3r::MultiPoint::front(), Slic3r::get_extents(), Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), merge_expansions_into_expolygons(), sample_in_expolygons(), scale_, Slic3r::to_polygons(), and Slic3r::union_safety_offset_ex().

Referenced by expand_merge_expolygons(), and merge_expansions_into_expolygons().

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

◆ merge_splits()

static void Slic3r::Algorithm::merge_splits ( ClipperLib_Z::Paths &  paths,
std::vector< std::pair< ClipperLib_Z::IntPoint, int > > &  splits 
)
inlinestatic
108{
109 for (auto it_path = paths.begin(); it_path != paths.end(); ) {
110 ClipperLib_Z::Path &path = *it_path;
111 assert(path.size() >= 2);
112 bool merged = false;
113 if (path.size() >= 2) {
114 const ClipperLib_Z::IntPoint &front = path.front();
115 const ClipperLib_Z::IntPoint &back = path.back();
116 // The path before clipping was supposed to cross the clipping boundary or be fully out of it.
117 // Thus the clipped contour is supposed to become open, with one exception: The anchor expands into a closed hole.
118 if (front.x() != back.x() || front.y() != back.y()) {
119 // Look up the ends in "splits", possibly join the contours.
120 // "splits" maps into the other piece connected to the same end point.
121 auto find_end = [&splits](const ClipperLib_Z::IntPoint &pt) -> std::pair<ClipperLib_Z::IntPoint, int>* {
122 auto it = std::lower_bound(splits.begin(), splits.end(), pt,
123 [](const auto &l, const auto &r){ return ClipperZUtils::zpoint_lower(l.first, r); });
124 return it != splits.end() && it->first == pt ? &(*it) : nullptr;
125 };
126 auto *end = find_end(front);
127 bool end_front = true;
128 if (! end) {
129 end_front = false;
130 end = find_end(back);
131 }
132 if (end) {
133 // This segment ends at a split point of the source closed contour before clipping.
134 if (end->second == -1) {
135 // Open end was found, not matched yet.
136 end->second = int(it_path - paths.begin());
137 } else {
138 // Open end was found and matched with end->second
139 ClipperLib_Z::Path &other_path = paths[end->second];
140 polylines_merge(other_path, other_path.front() == end->first, std::move(path), end_front);
141 if (std::next(it_path) == paths.end()) {
142 paths.pop_back();
143 break;
144 }
145 path = std::move(paths.back());
146 paths.pop_back();
147 merged = true;
148 }
149 }
150 }
151 }
152 if (! merged)
153 ++ it_path;
154 }
155}
void polylines_merge(PointsType &dst, bool dst_first, PointsType &&src, bool src_first)
Definition Polyline.hpp:162
S::iterator end(S &sh, const PathTag &)
Definition geometry_traits.hpp:620

References Slic3r::polylines_merge().

Referenced by wave_seeds().

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

◆ propagate_wave_from_boundary()

static Polygons Slic3r::Algorithm::propagate_wave_from_boundary ( ClipperLib::ClipperOffset co,
const ClipperLib::Paths seed,
const ExPolygon boundary,
const float  initial_step,
const float  other_step,
const size_t  num_other_steps,
const float  max_inflation 
)
static
376{
377 assert(! seed.empty() && seed.front().size() >= 2);
378 Polygons clipping = ClipperUtils::clip_clipper_polygons_with_subject_bbox(boundary, get_extents<true>(seed).inflated(max_inflation));
379 ClipperLib::Paths polygons = wavefront_clip(wavefront_initial(co, seed, initial_step), clipping);
380 // Now offset the remaining
381 for (size_t ioffset = 0; ioffset < num_other_steps; ++ ioffset)
382 polygons = wavefront_clip(wavefront_step(co, polygons, other_step), clipping);
383 return to_polygons(polygons);
384}
static ClipperLib::Paths wavefront_initial(ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polylines, float offset)
Definition RegionExpansion.cpp:310
static ClipperLib::Paths wavefront_clip(const ClipperLib::Paths &wavefront, const Polygons &clipping)
Definition RegionExpansion.cpp:351
static ClipperLib::Paths wavefront_step(ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polygons, float offset)
Definition RegionExpansion.cpp:328

References Slic3r::ClipperUtils::clip_clipper_polygons_with_subject_bbox(), Slic3r::get_extents< true >(), Slic3r::to_polygons(), wavefront_clip(), wavefront_initial(), and wavefront_step().

Referenced by propagate_waves().

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

◆ propagate_waves() [1/3]

std::vector< RegionExpansion > Slic3r::Algorithm::propagate_waves ( const ExPolygons src,
const ExPolygons boundary,
const RegionExpansionParameters params 
)
411{
412 return propagate_waves(wave_seeds(src, boundary, params.tiny_expansion, true), boundary, params);
413}
std::vector< WaveSeed > wave_seeds(const ExPolygons &src, const ExPolygons &boundary, float tiny_expansion, bool sorted)
Definition RegionExpansion.cpp:197
float tiny_expansion
Definition RegionExpansion.hpp:15

References propagate_waves(), Slic3r::Algorithm::RegionExpansionParameters::tiny_expansion, and wave_seeds().

+ Here is the call graph for this function:

◆ propagate_waves() [2/3]

std::vector< RegionExpansion > Slic3r::Algorithm::propagate_waves ( const ExPolygons src,
const ExPolygons boundary,
float  expansion,
float  expansion_step,
size_t  max_nr_steps 
)
422{
423 return propagate_waves(src, boundary, RegionExpansionParameters::build(expansion, expansion_step, max_nr_steps));
424}

References propagate_waves().

+ Here is the call graph for this function:

◆ propagate_waves() [3/3]

std::vector< RegionExpansion > Slic3r::Algorithm::propagate_waves ( const WaveSeeds seeds,
const ExPolygons boundary,
const RegionExpansionParameters params 
)
388{
389 std::vector<RegionExpansion> out;
390 ClipperLib::Paths paths;
392 co.ArcTolerance = params.arc_tolerance;
394 for (auto it_seed = seeds.begin(); it_seed != seeds.end();) {
395 auto it = it_seed;
396 paths.clear();
397 for (; it != seeds.end() && it->boundary == it_seed->boundary && it->src == it_seed->src; ++ it)
398 paths.emplace_back(it->path);
399 // Propagate the wavefront while clipping it with the trimmed boundary.
400 // Collect the expanded polygons, merge them with the source polygons.
402 for (Polygon &polygon : propagate_wave_from_boundary(co, paths, boundary[it_seed->boundary], params.initial_step, params.other_step, params.num_other_steps, params.max_inflation))
403 out.push_back({ std::move(polygon), it_seed->src, it_seed->boundary });
404 it_seed = it;
405 }
406
407 return out;
408}
double ArcTolerance
Definition clipper.hpp:555
Definition Polygon.hpp:24
static Polygons propagate_wave_from_boundary(ClipperLib::ClipperOffset &co, const ClipperLib::Paths &seed, const ExPolygon &boundary, const float initial_step, const float other_step, const size_t num_other_steps, const float max_inflation)
Definition RegionExpansion.cpp:361
double arc_tolerance
Definition RegionExpansion.hpp:27
double shortest_edge_length
Definition RegionExpansion.hpp:28

References Slic3r::Algorithm::RegionExpansionParameters::arc_tolerance, ClipperLib::ClipperOffset::ArcTolerance, Slic3r::Algorithm::RegionExpansionParameters::initial_step, Slic3r::Algorithm::RegionExpansionParameters::max_inflation, Slic3r::Algorithm::RegionExpansionParameters::num_other_steps, Slic3r::Algorithm::RegionExpansionParameters::other_step, propagate_wave_from_boundary(), Slic3r::Algorithm::RegionExpansionParameters::shortest_edge_length, and ClipperLib::ClipperOffset::ShortestEdgeLength.

Referenced by expand_expolygons(), expand_merge_expolygons(), propagate_waves(), propagate_waves(), and propagate_waves_ex().

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

◆ propagate_waves_ex() [1/2]

std::vector< RegionExpansionEx > Slic3r::Algorithm::propagate_waves_ex ( const ExPolygons src,
const ExPolygons boundary,
float  full_expansion,
float  expansion_step,
size_t  max_nr_expansion_steps 
)
464{
465 auto params = RegionExpansionParameters::build(full_expansion, expansion_step, max_nr_expansion_steps);
466 return propagate_waves_ex(wave_seeds(src, boundary, params.tiny_expansion, true), boundary, params);
467}
std::vector< RegionExpansionEx > propagate_waves_ex(const WaveSeeds &seeds, const ExPolygons &boundary, const RegionExpansionParameters &params)
Definition RegionExpansion.cpp:427

References propagate_waves_ex(), and wave_seeds().

+ Here is the call graph for this function:

◆ propagate_waves_ex() [2/2]

std::vector< RegionExpansionEx > Slic3r::Algorithm::propagate_waves_ex ( const WaveSeeds seeds,
const ExPolygons boundary,
const RegionExpansionParameters params 
)
428{
429 std::vector<RegionExpansion> expanded = propagate_waves(seeds, boundary, params);
430 assert(std::is_sorted(seeds.begin(), seeds.end(), [](const auto &l, const auto &r){ return l.boundary < r.boundary || (l.boundary == r.boundary && l.src < r.src); }));
431 Polygons acc;
432 std::vector<RegionExpansionEx> out;
433 for (auto it = expanded.begin(); it != expanded.end(); ) {
434 auto it2 = it;
435 acc.clear();
436 for (; it2 != expanded.end() && it2->boundary_id == it->boundary_id && it2->src_id == it->src_id; ++ it2)
437 acc.emplace_back(std::move(it2->polygon));
438 size_t size = it2 - it;
439 if (size == 1)
440 out.push_back({ ExPolygon{std::move(acc.front())}, it->src_id, it->boundary_id });
441 else {
442 ExPolygons expolys = union_ex(acc);
443 reserve_more_power_of_2(out, expolys.size());
444 for (ExPolygon &ex : expolys)
445 out.push_back({ std::move(ex), it->src_id, it->boundary_id });
446 }
447 it = it2;
448 }
449 return out;
450}

References propagate_waves(), propagate_waves_ex(), Slic3r::reserve_more_power_of_2(), and Slic3r::union_ex().

Referenced by propagate_waves_ex(), and propagate_waves_ex().

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

◆ sample_in_expolygons()

static int Slic3r::Algorithm::sample_in_expolygons ( const AABBTreeBBoxes aabb_tree,
const ExPolygons expolygons,
const Point sample 
)
static
177{
178 int out = -1;
179 AABBTreeIndirect::traverse(aabb_tree,
180 [&sample](const AABBTreeBBoxes::Node &node) {
181 return node.bbox.contains(sample);
182 },
183 [&expolygons, &sample, &out](const AABBTreeBBoxes::Node &node) {
184 assert(node.is_leaf());
185 assert(node.is_valid());
186 if (expolygons[node.idx].contains(sample)) {
187 out = int(node.idx);
188 // Stop traversal.
189 return false;
190 }
191 // Continue traversal.
192 return true;
193 });
194 return out;
195}

References Slic3r::AABBTreeIndirect::traverse().

Referenced by merge_expansions_into_expolygons(), and wave_seeds().

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

◆ sort_paths()

template<typename RandomAccessIterator , typename ToLines >
void Slic3r::Algorithm::sort_paths ( RandomAccessIterator  begin,
RandomAccessIterator  end,
Point  start,
double  touch_limit_distance,
ToLines  convert_to_lines 
)
28{
29 size_t paths_count = std::distance(begin, end);
30 if (paths_count <= 1)
31 return;
32
33 auto paths_touch = [touch_limit_distance](const AABBTreeLines::LinesDistancer<Line> &left,
35 for (const Line &l : left.get_lines()) {
36 if (right.distance_from_lines<false>(l.a) < touch_limit_distance) {
37 return true;
38 }
39 }
40 if (right.distance_from_lines<false>(left.get_lines().back().b) < touch_limit_distance) {
41 return true;
42 }
43
44 for (const Line &l : right.get_lines()) {
45 if (left.distance_from_lines<false>(l.a) < touch_limit_distance) {
46 return true;
47 }
48 }
49 if (left.distance_from_lines<false>(right.get_lines().back().b) < touch_limit_distance) {
50 return true;
51 }
52 return false;
53 };
54
55 std::vector<AABBTreeLines::LinesDistancer<Line>> distancers(paths_count);
56 for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
57 distancers[path_idx] = AABBTreeLines::LinesDistancer<Line>{convert_to_lines(*std::next(begin, path_idx))};
58 }
59
60 std::vector<std::unordered_set<size_t>> dependencies(paths_count);
61 for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
62 for (size_t next_path_idx = path_idx + 1; next_path_idx < paths_count; next_path_idx++) {
63 if (paths_touch(distancers[path_idx], distancers[next_path_idx])) {
64 dependencies[next_path_idx].insert(path_idx);
65 }
66 }
67 }
68
69 Point current_point = start;
70
71 std::vector<std::pair<size_t, bool>> correct_order_and_direction(paths_count);
72 size_t unsorted_idx = 0;
73 size_t null_idx = size_t(-1);
74 size_t next_idx = null_idx;
75 bool reverse = false;
76 while (unsorted_idx < paths_count) {
77 next_idx = null_idx;
78 double lines_dist = std::numeric_limits<double>::max();
79 for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
80 if (!dependencies[path_idx].empty())
81 continue;
82
83 double ldist = distancers[path_idx].distance_from_lines<false>(current_point);
84 if (ldist < lines_dist) {
85 const auto &lines = distancers[path_idx].get_lines();
86 double dist_a = (lines.front().a - current_point).cast<double>().squaredNorm();
87 double dist_b = (lines.back().b - current_point).cast<double>().squaredNorm();
88 next_idx = path_idx;
89 reverse = dist_b < dist_a;
90 lines_dist = ldist;
91 }
92 }
93
94 // we have valid next_idx, sort it, update dependencies, update current point
95 correct_order_and_direction[next_idx] = {unsorted_idx, reverse};
96 unsorted_idx++;
97 current_point = reverse ? distancers[next_idx].get_lines().front().a : distancers[next_idx].get_lines().back().b;
98
99 dependencies[next_idx].insert(null_idx); // prevent it from being selected again
100 for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
101 dependencies[path_idx].erase(next_idx);
102 }
103 }
104
105 for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
106 if (correct_order_and_direction[path_idx].second) {
107 std::next(begin, path_idx)->reverse();
108 }
109 }
110
111 for (size_t i = 0; i < correct_order_and_direction.size() - 1; i++) {
112 bool swapped = false;
113 for (size_t j = 0; j < correct_order_and_direction.size() - i - 1; j++) {
114 if (correct_order_and_direction[j].first > correct_order_and_direction[j + 1].first) {
115 std::swap(correct_order_and_direction[j], correct_order_and_direction[j + 1]);
116 std::iter_swap(std::next(begin, j), std::next(begin, j + 1));
117 swapped = true;
118 }
119 }
120 if (swapped == false) {
121 break;
122 }
123 }
124}
Definition AABBTreeLines.hpp:297
Definition Line.hpp:155
bool paths_touch(const ExtrusionPath &path_one, const ExtrusionPath &path_two, double limit_distance)
Definition PerimeterGenerator.cpp:668
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229
Kernel::Point_2 Point
Definition point_areas.cpp:20

References Slic3r::empty(), and Slic3r::paths_touch().

+ Here is the call graph for this function:

◆ wave_seeds()

WaveSeeds Slic3r::Algorithm::wave_seeds ( const ExPolygons src,
const ExPolygons boundary,
float  tiny_expansion,
bool  sorted 
)
206{
207 assert(tiny_expansion > 0);
208
209 if (src.empty() || boundary.empty())
210 return {};
211
214
215 ClipperLib_Z::Paths segments;
216 Intersections intersections;
217
218 coord_t idx_boundary_begin = 1;
219 coord_t idx_boundary_end = idx_boundary_begin;
220 coord_t idx_src_end;
221
222 {
223 ClipperLib_Z::Clipper zclipper;
224 ClipperZUtils::ClipperZIntersectionVisitor visitor(intersections);
225 zclipper.ZFillFunction(visitor.clipper_callback());
226 // as closed contours
227 zclipper.AddPaths(ClipperZUtils::expolygons_to_zpaths(boundary, idx_boundary_end), ClipperLib_Z::ptClip, true);
228 // as open contours
229 std::vector<std::pair<ClipperLib_Z::IntPoint, int>> zsrc_splits;
230 {
231 idx_src_end = idx_boundary_end;
232 ClipperLib_Z::Paths zsrc = expolygons_to_zpaths_expanded_opened(src, tiny_expansion, idx_src_end);
233 zclipper.AddPaths(zsrc, ClipperLib_Z::ptSubject, false);
234 zsrc_splits.reserve(zsrc.size());
235 for (const ClipperLib_Z::Path &path : zsrc) {
236 assert(path.size() >= 2);
237 assert(path.front() == path.back());
238 zsrc_splits.emplace_back(path.front(), -1);
239 }
240 std::sort(zsrc_splits.begin(), zsrc_splits.end(), [](const auto &l, const auto &r){ return ClipperZUtils::zpoint_lower(l.first, r.first); });
241 }
242 ClipperLib_Z::PolyTree polytree;
243 zclipper.Execute(ClipperLib_Z::ctIntersection, polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero);
244 ClipperLib_Z::PolyTreeToPaths(std::move(polytree), segments);
245 merge_splits(segments, zsrc_splits);
246 }
247
248 // AABBTree over bounding boxes of boundaries.
249 // Only built if necessary, that is if any of the seed contours is closed, thus there is no intersection point
250 // with the boundary and all Z coordinates of the closed contour point to the source contour.
251 AABBTreeBBoxes aabb_tree;
252
253 // Sort paths into their respective islands.
254 // Each src x boundary will be processed (wave expanded) independently.
255 // Multiple pieces of a single src may intersect the same boundary.
256 WaveSeeds out;
257 out.reserve(segments.size());
258 int iseed = 0;
259 for (const ClipperLib_Z::Path &path : segments) {
260 assert(path.size() >= 2);
261 const ClipperLib_Z::IntPoint &front = path.front();
262 const ClipperLib_Z::IntPoint &back = path.back();
263 // Both ends of a seed segment are supposed to be inside a single boundary expolygon.
264 // Thus as long as the seed contour is not closed, it should be open at a boundary point.
265 assert((front == back && front.z() >= idx_boundary_end && front.z() < idx_src_end) ||
266 //(front.z() < 0 && back.z() < 0));
267 // Hope that at least one end of an open polyline is clipped by the boundary, thus an intersection point is created.
268 (front.z() < 0 || back.z() < 0));
269 const Intersection *intersection = nullptr;
270 auto intersection_point_valid = [idx_boundary_end, idx_src_end](const Intersection &is) {
271 return is.first >= 1 && is.first < idx_boundary_end &&
272 is.second >= idx_boundary_end && is.second < idx_src_end;
273 };
274 if (front.z() < 0) {
275 const Intersection &is = intersections[- front.z() - 1];
276 assert(intersection_point_valid(is));
277 if (intersection_point_valid(is))
278 intersection = &is;
279 }
280 if (! intersection && back.z() < 0) {
281 const Intersection &is = intersections[- back.z() - 1];
282 assert(intersection_point_valid(is));
283 if (intersection_point_valid(is))
284 intersection = &is;
285 }
286 if (intersection) {
287 // The path intersects the boundary contour at least at one side.
288 out.push_back({ uint32_t(intersection->second - idx_boundary_end), uint32_t(intersection->first - 1), ClipperZUtils::from_zpath(path) });
289 } else {
290 // This should be a closed contour.
291 assert(front == back && front.z() >= idx_boundary_end && front.z() < idx_src_end);
292 // Find a source boundary expolygon of one sample of this closed path.
293 if (aabb_tree.empty())
294 aabb_tree = build_aabb_tree_over_expolygons(boundary);
295 int boundary_id = sample_in_expolygons(aabb_tree, boundary, Point(front.x(), front.y()));
296 // Boundary that contains the sample point was found.
297 assert(boundary_id >= 0);
298 if (boundary_id >= 0)
299 out.push_back({ uint32_t(front.z() - idx_boundary_end), uint32_t(boundary_id), ClipperZUtils::from_zpath(path) });
300 }
301 ++ iseed;
302 }
303
304 if (sorted)
305 // Sort the seeds by their intersection boundary and source contour.
306 std::sort(out.begin(), out.end(), lower_by_boundary_and_src);
307 return out;
308}
std::pair< coord_t, coord_t > Intersection
Definition ClipperZUtils.hpp:105
std::vector< Intersection > Intersections
Definition ClipperZUtils.hpp:106
int32_t coord_t
Definition libslic3r.h:39
std::vector< WaveSeed > WaveSeeds
Definition RegionExpansion.hpp:44
static AABBTreeBBoxes build_aabb_tree_over_expolygons(const ExPolygons &expolygons)
Definition RegionExpansion.cpp:159
static void merge_splits(ClipperLib_Z::Paths &paths, std::vector< std::pair< ClipperLib_Z::IntPoint, int > > &splits)
Definition RegionExpansion.cpp:107
static int sample_in_expolygons(const AABBTreeBBoxes &aabb_tree, const ExPolygons &expolygons, const Point &sample)
Definition RegionExpansion.cpp:172
AABBTreeIndirect::Tree< 2, coord_t > AABBTreeBBoxes
Definition RegionExpansion.cpp:157
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:686
Definition AvoidCrossingPerimeters.cpp:30
TPoint< P > back(const P &p)
Definition geometry_traits.hpp:873
TPoint< P > front(const P &p)
Definition geometry_traits.hpp:872

References build_aabb_tree_over_expolygons(), Slic3r::ClipperZUtils::ClipperZIntersectionVisitor::clipper_callback(), Slic3r::AABBTreeIndirect::Tree< ANumDimensions, ACoordType >::empty(), Slic3r::ClipperZUtils::expolygons_to_zpaths(), expolygons_to_zpaths_expanded_opened(), Slic3r::ClipperZUtils::from_zpath(), Slic3r::intersection(), lower_by_boundary_and_src(), merge_splits(), and sample_in_expolygons().

Referenced by propagate_waves(), and propagate_waves_ex().

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

◆ wavefront_clip()

static ClipperLib::Paths Slic3r::Algorithm::wavefront_clip ( const ClipperLib::Paths wavefront,
const Polygons clipping 
)
static
352{
353 ClipperLib::Clipper clipper;
354 clipper.AddPaths(wavefront, ClipperLib::ptSubject, true);
358 return out;
359}
bool AddPaths(PathsProvider &&paths_provider, PolyType PolyTyp, bool Closed)
Definition clipper.hpp:334
Definition clipper.hpp:420
bool Execute(ClipType clipType, Paths &solution, PolyFillType fillType=pftEvenOdd)
Definition clipper.hpp:425
Definition ClipperUtils.hpp:137
@ ctIntersection
Definition clipper.hpp:75
@ ptClip
Definition clipper.hpp:76
@ ptSubject
Definition clipper.hpp:76
@ pftPositive
Definition clipper.hpp:81

References ClipperLib::ClipperBase::AddPaths(), ClipperLib::ctIntersection, ClipperLib::Clipper::Execute(), ClipperLib::pftPositive, ClipperLib::ptClip, and ClipperLib::ptSubject.

Referenced by propagate_wave_from_boundary().

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

◆ wavefront_initial()

static ClipperLib::Paths Slic3r::Algorithm::wavefront_initial ( ClipperLib::ClipperOffset co,
const ClipperLib::Paths polylines,
float  offset 
)
static
311{
313 out.reserve(polylines.size());
314 ClipperLib::Paths out_this;
315 for (const ClipperLib::Path &path : polylines) {
316 assert(path.size() >= 2);
317 co.Clear();
318 co.AddPath(path, jtRound, path.front() == path.back() ? ClipperLib::etClosedLine : ClipperLib::etOpenRound);
319 co.Execute(out_this, offset);
320 append(out, std::move(out_this));
321 }
322 return out;
323}
Definition clipper.cpp:60
std::vector< IntPoint, Allocator< IntPoint > > Path
Definition clipper.hpp:121
@ etClosedLine
Definition clipper.hpp:139

References ClipperLib::ClipperOffset::AddPath(), Slic3r::append(), ClipperLib::ClipperOffset::Clear(), ClipperLib::etClosedLine, ClipperLib::etOpenRound, ClipperLib::ClipperOffset::Execute(), and Slic3r::offset().

Referenced by propagate_wave_from_boundary().

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

◆ wavefront_step()

static ClipperLib::Paths Slic3r::Algorithm::wavefront_step ( ClipperLib::ClipperOffset co,
const ClipperLib::Paths polygons,
float  offset 
)
static
329{
331 out.reserve(polygons.size());
332 ClipperLib::Paths out_this;
333 for (const ClipperLib::Path &polygon : polygons) {
334 co.Clear();
335 // Execute reorients the contours so that the outer most contour has a positive area. Thus the output
336 // contours will be CCW oriented even though the input paths are CW oriented.
337 // Offset is applied after contour reorientation, thus the signum of the offset value is reversed.
338 co.AddPath(polygon, jtRound, ClipperLib::etClosedPolygon);
339 bool ccw = ClipperLib::Orientation(polygon);
340 co.Execute(out_this, ccw ? offset : - offset);
341 if (! ccw) {
342 // Reverse the resulting contours.
343 for (ClipperLib::Path &path : out_this)
344 std::reverse(path.begin(), path.end());
345 }
346 append(out, std::move(out_this));
347 }
348 return out;
349}
bool Orientation(const Path &poly)
Definition clipper.hpp:200

References ClipperLib::ClipperOffset::AddPath(), Slic3r::append(), ClipperLib::ClipperOffset::Clear(), ClipperLib::etClosedPolygon, ClipperLib::ClipperOffset::Execute(), Slic3r::offset(), and ClipperLib::Orientation().

Referenced by propagate_wave_from_boundary().

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