Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction > Class Template Reference

#include <src/libslic3r/Arachne/utils/PolylineStitcher.hpp>

Public Member Functions

bool canReverse (const PathsPointIndex< VariableWidthLines > &ppi)
 
bool canReverse (const PathsPointIndex< Polygons > &)
 
bool canConnect (const ExtrusionLine &a, const ExtrusionLine &b)
 
bool canConnect (const Polygon &, const Polygon &)
 
bool isOdd (const ExtrusionLine &line)
 
bool isOdd (const Polygon &)
 

Static Public Member Functions

static void stitch (const Paths &lines, Paths &result_lines, Paths &result_polygons, coord_t max_stitch_distance=scaled< coord_t >(0.1), coord_t snap_distance=scaled< coord_t >(0.01))
 
static bool canReverse (const PathsPointIndex< Paths > &polyline)
 
static bool canConnect (const Path &a, const Path &b)
 
static bool isOdd (const Path &line)
 

Detailed Description

template<typename Paths, typename Path, typename Junction>
class Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >

Class for stitching polylines into longer polylines or into polygons

Member Function Documentation

◆ canConnect() [1/3]

◆ canConnect() [2/3]

template<typename Paths , typename Path , typename Junction >
static bool Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::canConnect ( const Path &  a,
const Path &  b 
)
static

Whether two paths are allowed to be connected. (Not true for an odd and an even wall.)

Referenced by Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::stitch().

+ Here is the caller graph for this function:

◆ canConnect() [3/3]

28{
29 return true;
30}

◆ canReverse() [1/3]

template<typename Paths , typename Path , typename Junction >
static bool Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::canReverse ( const PathsPointIndex< Paths > &  polyline)
static

Whether a polyline is allowed to be reversed. (Not true for wall polylines which are not odd)

Referenced by Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::stitch().

+ Here is the caller graph for this function:

◆ canReverse() [2/3]

18{
19 return true;
20}

◆ canReverse() [3/3]

10{
11 if ((*ppi.polygons)[ppi.poly_idx].is_odd)
12 return true;
13 else
14 return false;
15}

References Slic3r::Arachne::PathsPointIndex< Paths >::poly_idx, and Slic3r::Arachne::PathsPointIndex< Paths >::polygons.

◆ isOdd() [1/3]

◆ isOdd() [2/3]

template<typename Paths , typename Path , typename Junction >
static bool Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::isOdd ( const Path &  line)
static

Referenced by Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::stitch().

+ Here is the caller graph for this function:

◆ isOdd() [3/3]

38{
39 return false;
40}

◆ stitch()

template<typename Paths , typename Path , typename Junction >
static void Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::stitch ( const Paths &  lines,
Paths &  result_lines,
Paths &  result_polygons,
coord_t  max_stitch_distance = scaled<coord_t>(0.1),
coord_t  snap_distance = scaled<coord_t>(0.01) 
)
inlinestatic

Stitch together the separate lines into result_lines and if they can be closed into result_polygons.

Only introduce new segments shorter than max_stitch_distance, and larger than snap_distance but always try to take the shortest connection possible.

Only stitch polylines into closed polygons if they are larger than 3 * max_stitch_distance, in order to prevent small segments to accidentally get closed into a polygon.

Warning
Tiny polylines (smaller than 3 * max_stitch_distance) will not be closed into polygons.
Note
Resulting polylines and polygons are added onto the existing containers, so you can directly output onto a polygons container with existing polygons in it. However, you shouldn't call this function with the same parameter in lines as result_lines, because that would duplicate (some of) the polylines.
Parameters
linesThe lines to stitch together.
result_lines[out]The stitched parts that are not closed polygons will be stored in here.
result_polygons[out]The stitched parts that were closed as polygons will be stored in here.
max_stitch_distanceThe maximum distance that will be bridged to connect two lines.
snap_distancePoints closer than this distance are considered to be the same point.
53 {
54 if (lines.empty())
55 return;
56
57 SparsePointGrid<PathsPointIndex<Paths>, PathsPointIndexLocator<Paths>> grid(max_stitch_distance, lines.size() * 2);
58
59 // populate grid
60 for (size_t line_idx = 0; line_idx < lines.size(); line_idx++)
61 {
62 const auto line = lines[line_idx];
63 grid.insert(PathsPointIndex<Paths>(&lines, line_idx, 0));
64 grid.insert(PathsPointIndex<Paths>(&lines, line_idx, line.size() - 1));
65 }
66
67 std::vector<bool> processed(lines.size(), false);
68
69 for (size_t line_idx = 0; line_idx < lines.size(); line_idx++)
70 {
71 if (processed[line_idx])
72 {
73 continue;
74 }
75 processed[line_idx] = true;
76 const auto line = lines[line_idx];
77 bool should_close = isOdd(line);
78
79 Path chain = line;
80 bool closest_is_closing_polygon = false;
81 for (bool go_in_reverse_direction : { false, true }) // first go in the unreversed direction, to try to prevent the chain.reverse() operation.
82 { // NOTE: Implementation only works for this order; we currently only re-reverse the chain when it's closed.
83 if (go_in_reverse_direction)
84 { // try extending chain in the other direction
85 chain.reverse();
86 }
87 int64_t chain_length = chain.polylineLength();
88
89 while (true)
90 {
91 Point from = make_point(chain.back());
92
93 PathsPointIndex<Paths> closest;
94 coord_t closest_distance = std::numeric_limits<coord_t>::max();
95 grid.processNearby(from, max_stitch_distance,
96 std::function<bool (const PathsPointIndex<Paths>&)> (
97 [from, &chain, &closest, &closest_is_closing_polygon, &closest_distance, &processed, &chain_length, go_in_reverse_direction, max_stitch_distance, snap_distance, should_close]
98 (const PathsPointIndex<Paths>& nearby)->bool
99 {
100 bool is_closing_segment = false;
101 coord_t dist = (nearby.p().template cast<int64_t>() - from.template cast<int64_t>()).norm();
102 if (dist > max_stitch_distance)
103 {
104 return true; // keep looking
105 }
106 if ((nearby.p().template cast<int64_t>() - make_point(chain.front()).template cast<int64_t>()).squaredNorm() < snap_distance * snap_distance)
107 {
108 if (chain_length + dist < 3 * max_stitch_distance // prevent closing of small poly, cause it might be able to continue making a larger polyline
109 || chain.size() <= 2) // don't make 2 vert polygons
110 {
111 return true; // look for a better next line
112 }
113 is_closing_segment = true;
114 if (!should_close)
115 {
116 dist += scaled<coord_t>(0.01); // prefer continuing polyline over closing a polygon; avoids closed zigzags from being printed separately
117 // continue to see if closing segment is also the closest
118 // there might be a segment smaller than [max_stitch_distance] which closes the polygon better
119 }
120 else
121 {
122 dist -= scaled<coord_t>(0.01); //Prefer closing the polygon if it's 100% even lines. Used to create closed contours.
123 //Continue to see if closing segment is also the closest.
124 }
125 }
126 else if (processed[nearby.poly_idx])
127 { // it was already moved to output
128 return true; // keep looking for a connection
129 }
130 bool nearby_would_be_reversed = nearby.point_idx != 0;
131 nearby_would_be_reversed = nearby_would_be_reversed != go_in_reverse_direction; // flip nearby_would_be_reversed when searching in the reverse direction
132 if (!canReverse(nearby) && nearby_would_be_reversed)
133 { // connecting the segment would reverse the polygon direction
134 return true; // keep looking for a connection
135 }
136 if (!canConnect(chain, (*nearby.polygons)[nearby.poly_idx]))
137 {
138 return true; // keep looking for a connection
139 }
140 if (dist < closest_distance)
141 {
142 closest_distance = dist;
143 closest = nearby;
144 closest_is_closing_polygon = is_closing_segment;
145 }
146 if (dist < snap_distance)
147 { // we have found a good enough next line
148 return false; // stop looking for alternatives
149 }
150 return true; // keep processing elements
151 })
152 );
153
154 if (!closest.initialized() // we couldn't find any next line
155 || closest_is_closing_polygon // we closed the polygon
156 )
157 {
158 break;
159 }
160
161 coord_t segment_dist = (make_point(chain.back()).template cast<int64_t>() - closest.p().template cast<int64_t>()).norm();
162 assert(segment_dist <= max_stitch_distance + scaled<coord_t>(0.01));
163 const size_t old_size = chain.size();
164 if (closest.point_idx == 0)
165 {
166 auto start_pos = (*closest.polygons)[closest.poly_idx].begin();
167 if (segment_dist < snap_distance)
168 {
169 ++start_pos;
170 }
171 chain.insert(chain.end(), start_pos, (*closest.polygons)[closest.poly_idx].end());
172 }
173 else
174 {
175 auto start_pos = (*closest.polygons)[closest.poly_idx].rbegin();
176 if (segment_dist < snap_distance)
177 {
178 ++start_pos;
179 }
180 chain.insert(chain.end(), start_pos, (*closest.polygons)[closest.poly_idx].rend());
181 }
182 for(size_t i = old_size; i < chain.size(); ++i) //Update chain length.
183 {
184 chain_length += (make_point(chain[i]).template cast<int64_t>() - make_point(chain[i - 1]).template cast<int64_t>()).norm();
185 }
186 should_close = should_close & !isOdd((*closest.polygons)[closest.poly_idx]); //If we connect an even to an odd line, we should no longer try to close it.
187 assert( ! processed[closest.poly_idx]);
188 processed[closest.poly_idx] = true;
189 }
190 if (closest_is_closing_polygon)
191 {
192 if (go_in_reverse_direction)
193 { // re-reverse chain to retain original direction
194 // NOTE: not sure if this code could ever be reached, since if a polygon can be closed that should be already possible in the forward direction
195 chain.reverse();
196 }
197
198 break; // don't consider reverse direction
199 }
200 }
201 if (closest_is_closing_polygon)
202 {
203 result_polygons.emplace_back(chain);
204 }
205 else
206 {
207 PathsPointIndex<Paths> ppi_here(&lines, line_idx, 0);
208 if ( ! canReverse(ppi_here))
209 { // Since closest_is_closing_polygon is false we went through the second iterations of the for-loop, where go_in_reverse_direction is true
210 // the polyline isn't allowed to be reversed, so we re-reverse it.
211 chain.reverse();
212 }
213 result_lines.emplace_back(chain);
214 }
215 }
216 }
static bool canReverse(const PathsPointIndex< Paths > &polyline)
static bool isOdd(const Path &line)
static bool canConnect(const Path &a, const Path &b)
int32_t coord_t
Definition libslic3r.h:39
std::vector< IntPoint, Allocator< IntPoint > > Path
Definition clipper.hpp:121
const Point & make_point(const ExtrusionJunction &ej)
Definition ExtrusionJunction.hpp:51
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
std::vector< ArithmeticOnly< T > > grid(const T &start, const T &stop, const T &stride)
A set of equidistant values starting from 'start' (inclusive), ending in the closest multiple of 'str...
Definition MTUtils.hpp:125
Kernel::Point_2 Point
Definition point_areas.cpp:20
__int64 int64_t
Definition unistd.h:76

References Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::canConnect(), Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::canReverse(), Slic3r::grid(), Slic3r::Arachne::PathsPointIndex< Paths >::initialized(), Slic3r::Arachne::PolylineStitcher< Paths, Path, Junction >::isOdd(), Slic3r::Arachne::make_point(), Slic3r::Arachne::PathsPointIndex< Paths >::p(), Slic3r::Arachne::PathsPointIndex< Paths >::point_idx, Slic3r::Arachne::PathsPointIndex< Paths >::poly_idx, and Slic3r::Arachne::PathsPointIndex< Paths >::polygons.

Referenced by Slic3r::Arachne::WallToolPaths::stitchToolPaths().

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

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