Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::Measure::MeasuringImpl Class Reference
+ Collaboration diagram for Slic3r::Measure::MeasuringImpl:

Classes

struct  PlaneData
 

Public Member Functions

 MeasuringImpl (const indexed_triangle_set &its)
 
std::optional< SurfaceFeatureget_feature (size_t face_idx, const Vec3d &point)
 
int get_num_of_planes () const
 
const std::vector< int > & get_plane_triangle_indices (int idx) const
 
const std::vector< SurfaceFeature > & get_plane_features (unsigned int plane_id)
 
const TriangleMeshget_mesh () const
 

Private Member Functions

void update_planes ()
 
void extract_features (int plane_idx)
 

Private Attributes

std::vector< PlaneDatam_planes
 
std::vector< size_t > m_face_to_plane
 
TriangleMesh m_mesh
 

Detailed Description


Class Documentation

◆ Slic3r::Measure::MeasuringImpl::PlaneData

struct Slic3r::Measure::MeasuringImpl::PlaneData
+ Collaboration diagram for Slic3r::Measure::MeasuringImpl::PlaneData:
Class Members
float area
vector< vector< Vec3d > > borders
vector< int > facets
bool features_extracted = false
Vec3d normal
vector< SurfaceFeature > surface_features

Constructor & Destructor Documentation

◆ MeasuringImpl()

Slic3r::Measure::MeasuringImpl::MeasuringImpl ( const indexed_triangle_set its)
explicit
92: m_mesh(its)
93{
95
96 // Extracting features will be done as needed.
97 // To extract all planes at once, run the following:
98#if DEBUG_EXTRACT_ALL_FEATURES_AT_ONCE
99 for (int i=0; i<int(m_planes.size()); ++i)
101#endif
102}
TriangleMesh m_mesh
Definition Measure.cpp:83
void update_planes()
Definition Measure.cpp:105
std::vector< PlaneData > m_planes
Definition Measure.cpp:81
void extract_features(int plane_idx)
Definition Measure.cpp:263

References extract_features(), m_planes, and update_planes().

+ Here is the call graph for this function:

Member Function Documentation

◆ extract_features()

void Slic3r::Measure::MeasuringImpl::extract_features ( int  plane_idx)
private
264{
265 assert(! m_planes[plane_idx].features_extracted);
266
267 PlaneData& plane = m_planes[plane_idx];
268 plane.surface_features.clear();
269 const Vec3d& normal = plane.normal;
270
272 q.setFromTwoVectors(plane.normal, Vec3d::UnitZ());
274 trafo.rotate(q);
275 const Transform3d trafo_inv = trafo.inverse();
276
277 std::vector<double> angles; // placed in outer scope to prevent reallocations
278 std::vector<double> lengths;
279
280 for (const std::vector<Vec3d>& border : plane.borders) {
281 if (border.size() <= 1)
282 continue;
283
284 bool done = false;
285
286 if (border.size() > 4) {
287 const auto& [center, radius, err] = get_center_and_radius(border, trafo, trafo_inv);
288
289 if (err < 0.05) {
290 // The whole border is one circle. Just add it into the list of features
291 // and we are done.
292
293 bool is_polygon = border.size()>4 && border.size()<=8;
294 bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) {
295 return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01);
296 });
297
298 if (lengths_match && (is_polygon || border.size() > 8)) {
299 if (is_polygon) {
300 // This is a polygon, add the separate edges with the center.
301 for (int j=0; j<int(border.size()); ++j)
302 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge,
303 border[j==0 ? border.size()-1 : j-1], border[j],
304 std::make_optional(center)));
305 } else {
306 // The fit went well and it has more than 8 points - let's consider this a circle.
307 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
308 }
309 done = true;
310 }
311 }
312 }
313
314 if (! done) {
315 // In this case, the border is not a circle and may contain circular
316 // segments. Try to find them and then add all remaining edges as edges.
317
318 auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
319 auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
320
321
322 // Given an idx into border, return the index that is idx+offset position,
323 // while taking into account the need for wrap-around and the fact that
324 // the first and last point are the same.
325 auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int {
326 assert(std::abs(offset) < border_size);
327 int out = idx+offset;
328 if (out >= border_size)
329 out = out - border_size;
330 else if (out < 0)
331 out = border_size + out;
332
333 return out;
334 };
335
336 // First calculate angles at all the vertices.
337 angles.clear();
338 lengths.clear();
339 int first_different_angle_idx = 0;
340 for (int i=0; i<int(border.size()); ++i) {
341 const Vec3d& v2 = border[i] - (i == 0 ? border[border.size()-1] : border[i-1]);
342 const Vec3d& v1 = (i == int(border.size()-1) ? border[0] : border[i+1]) - border[i];
343 double angle = atan2(-normal.dot(v1.cross(v2)), -v1.dot(v2)) + M_PI;
344 if (angle > M_PI)
345 angle = 2*M_PI - angle;
346
347 angles.push_back(angle);
348 lengths.push_back(v2.norm());
349 if (first_different_angle_idx == 0 && angles.size() > 1) {
350 if (! are_angles_same(angles.back(), angles[angles.size()-2]))
351 first_different_angle_idx = angles.size()-1;
352 }
353 }
354 assert(border.size() == angles.size());
355 assert(border.size() == lengths.size());
356
357 // First go around the border and pick what might be circular segments.
358 // Save pair of indices to where such potential segments start and end.
359 // Also remember the length of these segments.
360 int start_idx = -1;
361 bool circle = false;
362 bool first_iter = true;
363 std::vector<SurfaceFeature> circles;
364 std::vector<SurfaceFeature> edges;
365 std::vector<std::pair<int, int>> circles_idxs;
366 //std::vector<double> circles_lengths;
367 std::vector<Vec3d> single_circle; // could be in loop-scope, but reallocations
368 double single_circle_length = 0.;
369 int first_pt_idx = offset_to_index(first_different_angle_idx, 1);
370 int i = first_pt_idx;
371 while (i != first_pt_idx || first_iter) {
372 if (are_angles_same(angles[i], angles[offset_to_index(i,-1)])
373 && i != offset_to_index(first_pt_idx, -1) // not the last point
374 && i != start_idx ) {
375 // circle
376 if (! circle) {
377 circle = true;
378 single_circle.clear();
379 single_circle_length = 0.;
380 start_idx = offset_to_index(i, -2);
381 single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] };
382 single_circle_length += lengths[offset_to_index(i, -1)];
383 }
384 single_circle.emplace_back(border[i]);
385 single_circle_length += lengths[i];
386 } else {
387 if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle.
388 single_circle.emplace_back(border[i]);
389 single_circle_length += lengths[i];
390
391 bool accept_circle = true;
392 {
393 // Check that lengths of internal (!!!) edges match.
394 int j = offset_to_index(start_idx, 3);
395 while (j != i) {
396 if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) {
397 accept_circle = false;
398 break;
399 }
400 j = offset_to_index(j, 1);
401 }
402 }
403
404 if (accept_circle) {
405 const auto& [center, radius, err] = get_center_and_radius(single_circle, trafo, trafo_inv);
406
407 // Check that the fit went well. The tolerance is high, only to
408 // reject complete failures.
409 accept_circle &= err < 0.05;
410
411 // If the segment subtends less than 90 degrees, throw it away.
412 accept_circle &= single_circle_length / radius > 0.9*M_PI/2.;
413
414 if (accept_circle) {
415 // Add the circle and remember indices into borders.
416 circles_idxs.emplace_back(start_idx, i);
417 circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
418 }
419 }
420 }
421 circle = false;
422 }
423 // Take care of the wrap around.
424 first_iter = false;
425 i = offset_to_index(i, 1);
426 }
427
428 // We have the circles. Now go around again and pick edges, while jumping over circles.
429 if (circles_idxs.empty()) {
430 // Just add all edges.
431 for (int i=1; i<int(border.size()); ++i)
432 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i-1], border[i]));
433 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[0], border[border.size()-1]));
434 } else if (circles_idxs.size() > 1 || circles_idxs.front().first != circles_idxs.front().second) {
435 // There is at least one circular segment. Start at its end and add edges until the start of the next one.
436 int i = circles_idxs.front().second;
437 int circle_idx = 1;
438 while (true) {
439 i = offset_to_index(i, 1);
440 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[offset_to_index(i,-1)], border[i]));
441 if (circle_idx < int(circles_idxs.size()) && i == circles_idxs[circle_idx].first) {
442 i = circles_idxs[circle_idx].second;
443 ++circle_idx;
444 }
445 if (i == circles_idxs.front().first)
446 break;
447 }
448 }
449
450 // Merge adjacent edges where needed.
451 assert(std::all_of(edges.begin(), edges.end(),
452 [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; }));
453 for (int i=edges.size()-1; i>=0; --i) {
454 const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge();
455 const auto& [second_start, second_end] = edges[i].get_edge();
456
457 if (Slic3r::is_approx(first_end, second_start)
458 && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) {
459 // The edges have the same direction and share a point. Merge them.
460 edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end);
461 edges.erase(edges.begin() + i);
462 }
463 }
464
465 // Now move the circles and edges into the feature list for the plane.
466 assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) {
467 return f.get_type() == SurfaceFeatureType::Circle;
468 }));
469 assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) {
470 return f.get_type() == SurfaceFeatureType::Edge;
471 }));
472 plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()),
473 std::make_move_iterator(circles.end()));
474 plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()),
475 std::make_move_iterator(edges.end()));
476 }
477 }
478
479 // The last surface feature is the plane itself.
480 Vec3d cog = Vec3d::Zero();
481 size_t counter = 0;
482 for (const std::vector<Vec3d>& b : plane.borders) {
483 for (size_t i = 1; i < b.size(); ++i) {
484 cog += b[i];
485 ++counter;
486 }
487 }
488 cog /= double(counter);
489 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane,
490 plane.normal, cog, std::optional<Vec3d>(), plane_idx + 0.0001));
491
492 plane.borders.clear();
493 plane.borders.shrink_to_fit();
494
495 plane.features_extracted = true;
496}
#define M_PI
Definition ExtrusionSimulator.cpp:20
static volatile int done
Definition bitbang.c:50
EIGEN_DEVICE_FUNC Transform inverse(TransformTraits traits=(TransformTraits) Mode) const
Definition Transform.h:1202
static EIGEN_DEVICE_FUNC const Transform Identity()
Returns an identity transformation.
Definition Transform.h:539
EIGEN_DEVICE_FUNC Derived & setFromTwoVectors(const MatrixBase< Derived1 > &a, const MatrixBase< Derived2 > &b)
Definition Quaternion.h:582
The quaternion class used to represent 3D orientations and rotations.
Definition Quaternion.h:233
static std::tuple< Vec3d, double, double > get_center_and_radius(const std::vector< Vec3d > &points, const Transform3d &trafo, const Transform3d &trafo_inv)
Definition Measure.cpp:19
Vec< 3, T > normal(const std::array< Vec< 3, T >, 3 > &tri)
Definition Rotfinder.cpp:43
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:81
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:52
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:12
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:271
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:143
IGL_INLINE void edges(const Eigen::MatrixBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedE > &E)
Definition edges.cpp:13
STL namespace.

References Slic3r::angle(), Slic3r::Measure::MeasuringImpl::PlaneData::borders, Slic3r::Measure::Circle, done, Slic3r::dot(), Slic3r::Measure::Edge, Slic3r::f(), Slic3r::Measure::MeasuringImpl::PlaneData::features_extracted, Slic3r::Measure::get_center_and_radius(), Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign >::Identity(), Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::inverse(), Slic3r::is_approx(), M_PI, m_planes, Slic3r::Measure::MeasuringImpl::PlaneData::normal, Slic3r::offset(), Slic3r::Measure::Plane, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::rotate(), Eigen::QuaternionBase< Derived >::setFromTwoVectors(), and Slic3r::Measure::MeasuringImpl::PlaneData::surface_features.

Referenced by MeasuringImpl(), get_feature(), and get_plane_features().

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

◆ get_feature()

std::optional< SurfaceFeature > Slic3r::Measure::MeasuringImpl::get_feature ( size_t  face_idx,
const Vec3d point 
)
506{
507 if (face_idx >= m_face_to_plane.size())
508 return std::optional<SurfaceFeature>();
509
510 const PlaneData& plane = m_planes[m_face_to_plane[face_idx]];
511
512 if (! plane.features_extracted)
514
515 size_t closest_feature_idx = size_t(-1);
516 double min_dist = std::numeric_limits<double>::max();
517
518 MeasurementResult res;
519 SurfaceFeature point_sf(point);
520
521 assert(plane.surface_features.empty() || plane.surface_features.back().get_type() == SurfaceFeatureType::Plane);
522
523 for (size_t i=0; i<plane.surface_features.size() - 1; ++i) {
524 // The -1 is there to prevent measuring distance to the plane itself,
525 // which is needless and relatively expensive.
526 res = get_measurement(plane.surface_features[i], point_sf);
527 if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented.
528 double dist = res.distance_strict->dist;
529 if (dist < feature_hover_limit && dist < min_dist) {
530 min_dist = std::min(dist, min_dist);
531 closest_feature_idx = i;
532 }
533 }
534 }
535
536 if (closest_feature_idx != size_t(-1)) {
537 const SurfaceFeature& f = plane.surface_features[closest_feature_idx];
538 if (f.get_type() == SurfaceFeatureType::Edge) {
539 // If this is an edge, check if we are not close to the endpoint. If so,
540 // we will include the endpoint as well. Close = 10% of the lenghth of
541 // the edge, clamped between 0.025 and 0.5 mm.
542 const auto& [sp, ep] = f.get_edge();
543 double len_sq = (ep-sp).squaredNorm();
544 double limit_sq = std::max(0.025*0.025, std::min(0.5*0.5, 0.1 * 0.1 * len_sq));
545
546 if ((point-sp).squaredNorm() < limit_sq)
547 return std::make_optional(SurfaceFeature(sp));
548 if ((point-ep).squaredNorm() < limit_sq)
549 return std::make_optional(SurfaceFeature(ep));
550 }
551 return std::make_optional(f);
552 }
553
554 // Nothing detected, return the plane as a whole.
555 assert(plane.surface_features.back().get_type() == SurfaceFeatureType::Plane);
556 return std::make_optional(plane.surface_features.back());
557}
std::vector< size_t > m_face_to_plane
Definition Measure.cpp:82
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:280
constexpr double feature_hover_limit
Definition Measure.cpp:17
MeasurementResult get_measurement(const SurfaceFeature &a, const SurfaceFeature &b, const Measuring *measuring)
Definition Measure.cpp:795

References Slic3r::Measure::MeasurementResult::distance_strict, Slic3r::Measure::Edge, extract_features(), Slic3r::f(), Slic3r::Measure::feature_hover_limit, Slic3r::Measure::MeasuringImpl::PlaneData::features_extracted, Slic3r::Measure::get_measurement(), m_face_to_plane, m_planes, Slic3r::Measure::Plane, and Slic3r::Measure::MeasuringImpl::PlaneData::surface_features.

+ Here is the call graph for this function:

◆ get_mesh()

const TriangleMesh & Slic3r::Measure::MeasuringImpl::get_mesh ( ) const
585{
586 return this->m_mesh;
587}

References m_mesh.

◆ get_num_of_planes()

int Slic3r::Measure::MeasuringImpl::get_num_of_planes ( ) const
564{
565 return (m_planes.size());
566}

References m_planes.

◆ get_plane_features()

const std::vector< SurfaceFeature > & Slic3r::Measure::MeasuringImpl::get_plane_features ( unsigned int  plane_id)
577{
578 assert(plane_id < m_planes.size());
579 if (! m_planes[plane_id].features_extracted)
580 extract_features(plane_id);
581 return m_planes[plane_id].surface_features;
582}

References extract_features(), and m_planes.

+ Here is the call graph for this function:

◆ get_plane_triangle_indices()

const std::vector< int > & Slic3r::Measure::MeasuringImpl::get_plane_triangle_indices ( int  idx) const
571{
572 assert(idx >= 0 && idx < int(m_planes.size()));
573 return m_planes[idx].facets;
574}

References m_planes.

◆ update_planes()

void Slic3r::Measure::MeasuringImpl::update_planes ( )
private
106{
107 m_planes.clear();
108
109 // Now we'll go through all the facets and append Points of facets sharing the same normal.
110 // This part is still performed in mesh coordinate system.
111 const size_t num_of_facets = m_mesh.its.indices.size();
112 m_face_to_plane.resize(num_of_facets, size_t(-1));
113 const std::vector<Vec3f> face_normals = its_face_normals(m_mesh.its);
114 const std::vector<Vec3i> face_neighbors = its_face_neighbors(m_mesh.its);
115 std::vector<int> facet_queue(num_of_facets, 0);
116 int facet_queue_cnt = 0;
117 const stl_normal* normal_ptr = nullptr;
118 size_t seed_facet_idx = 0;
119
120 auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool {
121 return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001);
122 };
123
124 // First go through all the triangles and fill in m_planes vector. For each "plane"
125 // detected on the model, it will contain list of facets that are part of it.
126 // We will also fill in m_face_to_plane, which contains index into m_planes
127 // for each of the source facets.
128 while (1) {
129 // Find next unvisited triangle:
130 for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx)
131 if (m_face_to_plane[seed_facet_idx] == size_t(-1)) {
132 facet_queue[facet_queue_cnt ++] = seed_facet_idx;
133 normal_ptr = &face_normals[seed_facet_idx];
134 m_face_to_plane[seed_facet_idx] = m_planes.size();
135 m_planes.emplace_back();
136 break;
137 }
138 if (seed_facet_idx == num_of_facets)
139 break; // Everything was visited already
140
141 while (facet_queue_cnt > 0) {
142 int facet_idx = facet_queue[-- facet_queue_cnt];
143 const stl_normal& this_normal = face_normals[facet_idx];
144 if (is_same_normal(this_normal, *normal_ptr)) {
145// const Vec3i& face = m_its.indices[facet_idx];
146
147 m_face_to_plane[facet_idx] = m_planes.size() - 1;
148 m_planes.back().facets.emplace_back(facet_idx);
149 for (int j = 0; j < 3; ++ j)
150 if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && m_face_to_plane[neighbor_idx] == size_t(-1))
151 facet_queue[facet_queue_cnt ++] = neighbor_idx;
152 }
153 }
154
155 m_planes.back().normal = normal_ptr->cast<double>();
156 std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end());
157 }
158
159 // Check that each facet is part of one of the planes.
160 assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); }));
161
162 // Now we will walk around each of the planes and save vertices which form the border.
163 SurfaceMesh sm(m_mesh.its);
164 for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) {
165 const auto& facets = m_planes[plane_id].facets;
166 m_planes[plane_id].borders.clear();
167 std::vector<std::array<bool, 3>> visited(facets.size(), {false, false, false});
168
169
170
171 for (int face_id=0; face_id<int(facets.size()); ++face_id) {
172 assert(m_face_to_plane[facets[face_id]] == plane_id);
173
174 for (int edge_id=0; edge_id<3; ++edge_id) {
175 // Every facet's edge which has a neighbor from a different plane is
176 // part of an edge that we want to walk around. Skip the others.
177 int neighbor_idx = face_neighbors[facets[face_id]][edge_id];
178 if (neighbor_idx == -1)
179 goto PLANE_FAILURE;
180 if (visited[face_id][edge_id] || (int)m_face_to_plane[neighbor_idx] == plane_id) {
181 visited[face_id][edge_id] = true;
182 continue;
183 }
184
185 Halfedge_index he = sm.halfedge(Face_index(facets[face_id]));
186 while (he.side() != edge_id)
187 he = sm.next(he);
188
189 // he is the first halfedge on the border. Now walk around and append the points.
190 //const Halfedge_index he_orig = he;
191 m_planes[plane_id].borders.emplace_back();
192 std::vector<Vec3d>& last_border = m_planes[plane_id].borders.back();
193 last_border.emplace_back(sm.point(sm.source(he)).cast<double>());
194 //Vertex_index target = sm.target(he);
195 const Halfedge_index he_start = he;
196
197 Face_index fi = he.face();
198 auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi));
199 assert(face_it != facets.end());
200 assert(*face_it == int(fi));
201 visited[face_it - facets.begin()][he.side()] = true;
202
203 do {
204 const Halfedge_index he_orig = he;
205 he = sm.next_around_target(he);
206 if (he.is_invalid())
207 goto PLANE_FAILURE;
208
209 // For broken meshes, the iteration might never get back to he_orig.
210 // Remember all halfedges we saw to break out of such infinite loops.
211 boost::container::small_vector<Halfedge_index, 10> he_seen;
212
213 while ( (int)m_face_to_plane[sm.face(he)] == plane_id && he != he_orig) {
214 he_seen.emplace_back(he);
215 he = sm.next_around_target(he);
216 if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end())
217 goto PLANE_FAILURE;
218 }
219 he = sm.opposite(he);
220 if (he.is_invalid())
221 goto PLANE_FAILURE;
222
223 Face_index fi = he.face();
224 auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi));
225 if (face_it == facets.end() || *face_it != int(fi)) // This indicates a broken mesh.
226 goto PLANE_FAILURE;
227
228 if (visited[face_it - facets.begin()][he.side()] && he != he_start) {
229 last_border.resize(1);
230 break;
231 }
232 visited[face_it - facets.begin()][he.side()] = true;
233
234 last_border.emplace_back(sm.point(sm.source(he)).cast<double>());
235
236 // In case of broken meshes, this loop might be infinite. Break
237 // out in case it is clearly going bad.
238 if (last_border.size() > 3*facets.size()+1)
239 goto PLANE_FAILURE;
240
241 } while (he != he_start);
242
243 if (last_border.size() == 1)
244 m_planes[plane_id].borders.pop_back();
245 else {
246 assert(last_border.front() == last_border.back());
247 last_border.pop_back();
248 }
249 }
250 }
251 continue; // There was no failure.
252
253 PLANE_FAILURE:
254 m_planes[plane_id].borders.clear();
255 }
256}
indexed_triangle_set its
Definition TriangleMesh.hpp:155
std::vector< Vec3f > its_face_normals(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1530
std::vector< Vec3i > its_face_neighbors(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1520
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References Slic3r::Halfedge_index::face(), Slic3r::SurfaceMesh::face(), Slic3r::SurfaceMesh::halfedge(), indexed_triangle_set::indices, Slic3r::Halfedge_index::is_invalid(), Slic3r::TriangleMesh::its, Slic3r::its_face_neighbors(), Slic3r::its_face_normals(), m_face_to_plane, m_mesh, m_planes, Slic3r::SurfaceMesh::next(), Slic3r::SurfaceMesh::next_around_target(), Slic3r::SurfaceMesh::opposite(), Slic3r::SurfaceMesh::point(), Slic3r::Halfedge_index::side(), and Slic3r::SurfaceMesh::source().

Referenced by MeasuringImpl().

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

Member Data Documentation

◆ m_face_to_plane

std::vector<size_t> Slic3r::Measure::MeasuringImpl::m_face_to_plane
private

Referenced by get_feature(), and update_planes().

◆ m_mesh

TriangleMesh Slic3r::Measure::MeasuringImpl::m_mesh
private

Referenced by get_mesh(), and update_planes().

◆ m_planes

std::vector<PlaneData> Slic3r::Measure::MeasuringImpl::m_planes
private

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