OrcaSlicer latest
OrcaSlicer
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< SurfaceFeature > get_feature (size_t face_idx, const Vec3d &point, const Transform3d &world_tran, bool only_select_plane)
int get_num_of_planes () const
const std::vector< int > & get_plane_triangle_indices (int idx) const
std::vector< int > * get_plane_tri_indices (int idx)
const std::vector< SurfaceFeature > & get_plane_features (unsigned int plane_id)
std::vector< SurfaceFeature > * get_plane_features_pointer (unsigned int plane_id)
const indexed_triangle_set & get_its () const

Private Member Functions

void update_planes ()
void extract_features (int plane_idx)

Private Attributes

std::vector< PlaneData > m_planes
std::vector< size_t > m_face_to_plane
indexed_triangle_set m_its

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
139: m_its(its)
140{
142
143 // Extracting features will be done as needed.
144 // To extract all planes at once, run the following:
145#if DEBUG_EXTRACT_ALL_FEATURES_AT_ONCE
146 for (int i=0; i<int(m_planes.size()); ++i)
148#endif
149}
indexed_triangle_set m_its
Definition Measure.cpp:130
void update_planes()
Definition Measure.cpp:152
std::vector< PlaneData > m_planes
Definition Measure.cpp:128
void extract_features(int plane_idx)
Definition Measure.cpp:314

References extract_features(), m_its, 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
315{
316 assert(! m_planes[plane_idx].features_extracted);
317
318 PlaneData& plane = m_planes[plane_idx];
319 plane.surface_features.clear();
320 const Vec3d& normal = plane.normal;
321
322 Eigen::Quaterniond q;
323 q.setFromTwoVectors(plane.normal, Vec3d::UnitZ());
324 Transform3d trafo = Transform3d::Identity();
325 trafo.rotate(q);
326 const Transform3d trafo_inv = trafo.inverse();
327
328 std::vector<double> angles; // placed in outer scope to prevent reallocations
329 std::vector<double> lengths;
330
331 for (const std::vector<Vec3d>& border : plane.borders) {
332 if (border.size() <= 1)
333 continue;
334
335 bool done = false;
336
337 if (border.size() > 4) {
338 const auto& [center, radius, err] = get_center_and_radius(border, trafo, trafo_inv);
339
340 if (err < 0.05) {
341 // The whole border is one circle. Just add it into the list of features
342 // and we are done.
343
344 bool is_polygon = border.size()>4 && border.size()<=8;
345 bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) {
346 return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01);
347 });
348
349 if (lengths_match && (is_polygon || border.size() > 8)) {
350 if (is_polygon) {
351 // This is a polygon, add the separate edges with the center.
352 for (int j=0; j<int(border.size()); ++j)
353 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge,
354 border[j==0 ? border.size()-1 : j-1], border[j],
355 std::make_optional(center)));
356 } else {
357 // The fit went well and it has more than 8 points - let's consider this a circle.
358 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
359 }
360 done = true;
361 }
362 }
363 }
364
365 if (! done) {
366 // In this case, the border is not a circle and may contain circular
367 // segments. Try to find them and then add all remaining edges as edges.
368
369 auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
370 auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); };
371
372
373 // Given an idx into border, return the index that is idx+offset position,
374 // while taking into account the need for wrap-around and the fact that
375 // the first and last point are the same.
376 auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int {
377 assert(std::abs(offset) < border_size);
378 int out = idx+offset;
379 if (out >= border_size)
380 out = out - border_size;
381 else if (out < 0)
382 out = border_size + out;
383
384 return out;
385 };
386
387 // First calculate angles at all the vertices.
388 angles.clear();
389 lengths.clear();
390 int first_different_angle_idx = 0;
391 for (int i=0; i<int(border.size()); ++i) {
392 const Vec3d& v2 = border[i] - (i == 0 ? border[border.size()-1] : border[i-1]);
393 const Vec3d& v1 = (i == int(border.size()-1) ? border[0] : border[i+1]) - border[i];
394 double angle = atan2(-normal.dot(v1.cross(v2)), -v1.dot(v2)) + M_PI;
395 if (angle > M_PI)
396 angle = 2*M_PI - angle;
397
398 angles.push_back(angle);
399 lengths.push_back(v2.norm());
400 if (first_different_angle_idx == 0 && angles.size() > 1) {
401 if (! are_angles_same(angles.back(), angles[angles.size()-2]))
402 first_different_angle_idx = angles.size()-1;
403 }
404 }
405 assert(border.size() == angles.size());
406 assert(border.size() == lengths.size());
407
408 // First go around the border and pick what might be circular segments.
409 // Save pair of indices to where such potential segments start and end.
410 // Also remember the length of these segments.
411 int start_idx = -1;
412 bool circle = false;
413 bool first_iter = true;
414 std::vector<SurfaceFeature> circles;
415 std::vector<SurfaceFeature> edges;
416 std::vector<std::pair<int, int>> circles_idxs;
417 //std::vector<double> circles_lengths;
418 std::vector<Vec3d> single_circle; // could be in loop-scope, but reallocations
419 double single_circle_length = 0.;
420 int first_pt_idx = offset_to_index(first_different_angle_idx, 1);
421 int i = first_pt_idx;
422 while (i != first_pt_idx || first_iter) {
423 if (are_angles_same(angles[i], angles[offset_to_index(i,-1)])
424 && i != offset_to_index(first_pt_idx, -1) // not the last point
425 && i != start_idx ) {
426 // circle
427 if (! circle) {
428 circle = true;
429 single_circle.clear();
430 single_circle_length = 0.;
431 start_idx = offset_to_index(i, -2);
432 single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] };
433 single_circle_length += lengths[offset_to_index(i, -1)];
434 }
435 single_circle.emplace_back(border[i]);
436 single_circle_length += lengths[i];
437 } else {
438 if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle.
439 single_circle.emplace_back(border[i]);
440 single_circle_length += lengths[i];
441
442 bool accept_circle = true;
443 {
444 // Check that lengths of internal (!!!) edges match.
445 int j = offset_to_index(start_idx, 3);
446 while (j != i) {
447 if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) {
448 accept_circle = false;
449 break;
450 }
451 j = offset_to_index(j, 1);
452 }
453 }
454
455 if (accept_circle) {
456 const auto& [center, radius, err] = get_center_and_radius(single_circle, trafo, trafo_inv);
457
458 // Check that the fit went well. The tolerance is high, only to
459 // reject complete failures.
460 accept_circle &= err < 0.05;
461
462 // If the segment subtends less than 90 degrees, throw it away.
463 accept_circle &= single_circle_length / radius > 0.9*M_PI/2.;
464
465 if (accept_circle) {
466 // Add the circle and remember indices into borders.
467 circles_idxs.emplace_back(start_idx, i);
468 circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius));
469 }
470 }
471 }
472 circle = false;
473 }
474 // Take care of the wrap around.
475 first_iter = false;
476 i = offset_to_index(i, 1);
477 }
478
479 // We have the circles. Now go around again and pick edges, while jumping over circles.
480 if (circles_idxs.empty()) {
481 // Just add all edges.
482 for (int i=1; i<int(border.size()); ++i)
483 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i-1], border[i]));
484 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[0], border[border.size()-1]));
485 } else if (circles_idxs.size() > 1 || circles_idxs.front().first != circles_idxs.front().second) {
486 // There is at least one circular segment. Start at its end and add edges until the start of the next one.
487 int i = circles_idxs.front().second;
488 int circle_idx = 1;
489 while (true) {
490 i = offset_to_index(i, 1);
491 edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[offset_to_index(i,-1)], border[i]));
492 if (circle_idx < int(circles_idxs.size()) && i == circles_idxs[circle_idx].first) {
493 i = circles_idxs[circle_idx].second;
494 ++circle_idx;
495 }
496 if (i == circles_idxs.front().first)
497 break;
498 }
499 }
500
501 // Merge adjacent edges where needed.
502 assert(std::all_of(edges.begin(), edges.end(),
503 [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; }));
504 for (int i=edges.size()-1; i>=0; --i) {
505 const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge();
506 const auto& [second_start, second_end] = edges[i].get_edge();
507
508 if (Slic3r::is_approx(first_end, second_start)
509 && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) {
510 // The edges have the same direction and share a point. Merge them.
511 edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end);
512 edges.erase(edges.begin() + i);
513 }
514 }
515
516 // Now move the circles and edges into the feature list for the plane.
517 assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) {
518 return f.get_type() == SurfaceFeatureType::Circle;
519 }));
520 assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) {
521 return f.get_type() == SurfaceFeatureType::Edge;
522 }));
523 plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()),
524 std::make_move_iterator(circles.end()));
525 plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()),
526 std::make_move_iterator(edges.end()));
527 }
528 }
529
530 // The last surface feature is the plane itself.
531 Vec3d cog = Vec3d::Zero();
532 size_t counter = 0;
533 for (const std::vector<Vec3d>& b : plane.borders) {
534 for (size_t i = 0; i < b.size(); ++i) {
535 cog += b[i];
536 ++counter;
537 }
538 }
539 cog /= double(counter);
540 plane.surface_features.emplace_back(SurfaceFeature(SurfaceFeatureType::Plane,
541 plane.normal, cog, std::optional<Vec3d>(), plane_idx + 0.0001));
542
543 plane.borders.clear();
544 plane.borders.shrink_to_fit();
545
546 plane.features_extracted = true;
547}
#define M_PI
Definition ExtrusionSimulator.cpp:31
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:64
@ Plane
Definition Measure.hpp:28
@ Circle
Definition Measure.hpp:27
@ Edge
Definition Measure.hpp:26
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:96
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:320
Point normal(Point pt, double scale)
Definition TreeSupport.cpp:112
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:154

References Slic3r::angle(), Slic3r::Measure::MeasuringImpl::PlaneData::borders, Slic3r::center(), Slic3r::Measure::Circle, Slic3r::dot(), Slic3r::Measure::Edge, extract_features(), Slic3r::f(), Slic3r::Measure::MeasuringImpl::PlaneData::features_extracted, Slic3r::Measure::get_center_and_radius(), Slic3r::is_approx(), M_PI, m_planes, Slic3r::Measure::MeasuringImpl::PlaneData::normal, Slic3r::normal(), Slic3r::offset(), Slic3r::Measure::Plane, and Slic3r::Measure::MeasuringImpl::PlaneData::surface_features.

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

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,
const Transform3d & world_tran,
bool only_select_plane )
550{
551 if (face_idx >= m_face_to_plane.size())
552 return std::optional<SurfaceFeature>();
553
554 const PlaneData& plane = m_planes[m_face_to_plane[face_idx]];
555
556 if (! plane.features_extracted)
558
559 size_t closest_feature_idx = size_t(-1);
560 double min_dist = std::numeric_limits<double>::max();
561
562 MeasurementResult res;
563 SurfaceFeature point_sf(point);
564
565 assert(plane.surface_features.empty() || plane.surface_features.back().get_type() == SurfaceFeatureType::Plane);
566
567 if (!only_select_plane) {
568 for (size_t i = 0; i < plane.surface_features.size() - 1; ++i) {
569 // The -1 is there to prevent measuring distance to the plane itself,
570 // which is needless and relatively expensive.
571 res = get_measurement(plane.surface_features[i], point_sf);
572 if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented.
573 double dist = res.distance_strict->dist;
574 if (dist < feature_hover_limit && dist < min_dist) {
575 min_dist = std::min(dist, min_dist);
576 closest_feature_idx = i;
577 }
578 }
579 }
580
581 if (closest_feature_idx != size_t(-1)) {
582 const SurfaceFeature &f = plane.surface_features[closest_feature_idx];
583 if (f.get_type() == SurfaceFeatureType::Edge) {
584 // If this is an edge, check if we are not close to the endpoint. If so,
585 // we will include the endpoint as well. Close = 10% of the lenghth of
586 // the edge, clamped between 0.025 and 0.5 mm.
587 const auto &[sp, ep] = f.get_edge();
588 double len_sq = (ep - sp).squaredNorm();
589 double limit_sq = std::max(0.025 * 0.025, std::min(0.5 * 0.5, 0.1 * 0.1 * len_sq));
590 if ((point - sp).squaredNorm() < limit_sq) {
591 SurfaceFeature local_f(sp);
592 local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
593 local_f.translate(world_tran);
594 return std::make_optional(local_f);
595 }
596
597 if ((point - ep).squaredNorm() < limit_sq) {
598 SurfaceFeature local_f(ep);
599 local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
600 local_f.translate(world_tran);
601 return std::make_optional(local_f);
602 }
603 }
604 SurfaceFeature f_tran(f);
605 f_tran.origin_surface_feature = std::make_shared<SurfaceFeature>(f);
606 f_tran.translate(world_tran);
607 return std::make_optional(f_tran);
608 }
609 }
610
611 // Nothing detected, return the plane as a whole.
612 assert(plane.surface_features.back().get_type() == SurfaceFeatureType::Plane);
613 auto cur_plane = const_cast<PlaneData*>(&plane);
614 SurfaceFeature f_tran(cur_plane->surface_features.back());
615 f_tran.origin_surface_feature = std::make_shared<SurfaceFeature>(cur_plane->surface_features.back());
616 f_tran.translate(world_tran);
617 return std::make_optional(f_tran);
618}
std::vector< size_t > m_face_to_plane
Definition Measure.cpp:129
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298
constexpr double feature_hover_limit
Definition Measure.cpp:62
MeasurementResult get_measurement(const SurfaceFeature &a, const SurfaceFeature &b, bool deal_circle_result)
Definition Measure.cpp:856

References Slic3r::Geometry::dist(), Slic3r::Measure::MeasurementResult::distance_strict, Slic3r::Measure::Edge, extract_features(), Slic3r::f(), Slic3r::Measure::feature_hover_limit, Slic3r::Measure::MeasuringImpl::PlaneData::features_extracted, get_feature(), Slic3r::Measure::get_measurement(), m_face_to_plane, m_planes, Slic3r::Measure::SurfaceFeature::origin_surface_feature, Slic3r::Measure::Plane, Slic3r::Measure::MeasuringImpl::PlaneData::surface_features, and Slic3r::Measure::SurfaceFeature::translate().

Referenced by get_feature().

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

◆ get_its()

const indexed_triangle_set & Slic3r::Measure::MeasuringImpl::get_its ( ) const
659{
660 return this->m_its;
661}

References get_its(), and m_its.

Referenced by get_its().

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

◆ get_num_of_planes()

int Slic3r::Measure::MeasuringImpl::get_num_of_planes ( ) const
625{
626 return (m_planes.size());
627}

References get_num_of_planes(), and m_planes.

Referenced by get_num_of_planes().

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

◆ get_plane_features()

const std::vector< SurfaceFeature > & Slic3r::Measure::MeasuringImpl::get_plane_features ( unsigned int plane_id)
644{
645 assert(plane_id < m_planes.size());
646 if (! m_planes[plane_id].features_extracted)
647 extract_features(plane_id);
648 return m_planes[plane_id].surface_features;
649}

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

Referenced by get_plane_features().

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

◆ get_plane_features_pointer()

std::vector< SurfaceFeature > * Slic3r::Measure::MeasuringImpl::get_plane_features_pointer ( unsigned int plane_id)
651 {
652 assert(plane_id < m_planes.size());
653 if (!m_planes[plane_id].features_extracted)
654 extract_features(plane_id);
655 return &m_planes[plane_id].surface_features;
656}

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

Referenced by get_plane_features_pointer().

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

◆ get_plane_tri_indices()

std::vector< int > * Slic3r::Measure::MeasuringImpl::get_plane_tri_indices ( int idx)
638{
639 assert(idx >= 0 && idx < int(m_planes.size()));
640 return &m_planes[idx].facets;
641}

References get_plane_tri_indices(), and m_planes.

Referenced by get_plane_tri_indices().

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

◆ get_plane_triangle_indices()

const std::vector< int > & Slic3r::Measure::MeasuringImpl::get_plane_triangle_indices ( int idx) const
632{
633 assert(idx >= 0 && idx < int(m_planes.size()));
634 return m_planes[idx].facets;
635}

References get_plane_triangle_indices(), and m_planes.

Referenced by get_plane_triangle_indices().

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

◆ update_planes()

void Slic3r::Measure::MeasuringImpl::update_planes ( )
private
153{
154 // Now we'll go through all the facets and append Points of facets sharing the same normal.
155 // This part is still performed in mesh coordinate system.
156 const size_t num_of_facets = m_its.indices.size();
157 m_face_to_plane.resize(num_of_facets, size_t(-1));
158 const std::vector<Vec3f> face_normals = its_face_normals(m_its);
159 const std::vector<Vec3i32> face_neighbors = its_face_neighbors(m_its);
160 std::vector<int> facet_queue(num_of_facets, 0);
161 int facet_queue_cnt = 0;
162 const stl_normal* normal_ptr = nullptr;
163 size_t seed_facet_idx = 0;
164
165 auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool {
166 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);
167 };
168
169 m_planes.clear();
170 m_planes.reserve(num_of_facets / 5); // empty plane data object is quite lightweight, let's save the initial reallocations
171
172
173 // First go through all the triangles and fill in m_planes vector. For each "plane"
174 // detected on the model, it will contain list of facets that are part of it.
175 // We will also fill in m_face_to_plane, which contains index into m_planes
176 // for each of the source facets.
177 while (1) {
178 // Find next unvisited triangle:
179 for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx)
180 if (m_face_to_plane[seed_facet_idx] == size_t(-1)) {
181 facet_queue[facet_queue_cnt ++] = seed_facet_idx;
182 normal_ptr = &face_normals[seed_facet_idx];
183 m_face_to_plane[seed_facet_idx] = m_planes.size();
184 m_planes.emplace_back();
185 break;
186 }
187 if (seed_facet_idx == num_of_facets)
188 break; // Everything was visited already
189
190 while (facet_queue_cnt > 0) {
191 int facet_idx = facet_queue[-- facet_queue_cnt];
192 const stl_normal& this_normal = face_normals[facet_idx];
193 if (is_same_normal(this_normal, *normal_ptr)) {
194// const Vec3i32& face = m_its.indices[facet_idx];
195
196 m_face_to_plane[facet_idx] = m_planes.size() - 1;
197 m_planes.back().facets.emplace_back(facet_idx);
198 for (int j = 0; j < 3; ++ j)
199 if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && m_face_to_plane[neighbor_idx] == size_t(-1))
200 facet_queue[facet_queue_cnt ++] = neighbor_idx;
201 }
202 }
203
204 m_planes.back().normal = normal_ptr->cast<double>();
205 std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end());
206 }
207
208 // Check that each facet is part of one of the planes.
209 assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); }));
210
211 // Now we will walk around each of the planes and save vertices which form the border.
212 const SurfaceMesh sm(m_its);
213
214 const auto& face_to_plane = m_face_to_plane;
215 auto& planes = m_planes;
216
217 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_planes.size()),
218 [&planes, &face_to_plane, &face_neighbors, &sm](const tbb::blocked_range<size_t>& range) {
219 for (size_t plane_id = range.begin(); plane_id != range.end(); ++plane_id) {
220
221 const auto& facets = planes[plane_id].facets;
222 planes[plane_id].borders.clear();
223 std::vector<std::array<bool, 3>> visited(facets.size(), {false, false, false});
224
225 for (int face_id=0; face_id<int(facets.size()); ++face_id) {
226 assert(face_to_plane[facets[face_id]] == plane_id);
227
228 for (int edge_id=0; edge_id<3; ++edge_id) {
229 // Every facet's edge which has a neighbor from a different plane is
230 // part of an edge that we want to walk around. Skip the others.
231 int neighbor_idx = face_neighbors[facets[face_id]][edge_id];
232 if (neighbor_idx == -1)
233 goto PLANE_FAILURE;
234 if (visited[face_id][edge_id] || face_to_plane[neighbor_idx] == plane_id) {
235 visited[face_id][edge_id] = true;
236 continue;
237 }
238
239 Halfedge_index he = sm.halfedge(Face_index(facets[face_id]));
240 while (he.side() != edge_id)
241 he = sm.next(he);
242
243 // he is the first halfedge on the border. Now walk around and append the points.
244 //const Halfedge_index he_orig = he;
245 planes[plane_id].borders.emplace_back();
246 std::vector<Vec3d>& last_border = planes[plane_id].borders.back();
247 last_border.reserve(4);
248 last_border.emplace_back(sm.point(sm.source(he)).cast<double>());
249 //Vertex_index target = sm.target(he);
250 const Halfedge_index he_start = he;
251
252 Face_index fi = he.face();
253 auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi));
254 assert(face_it != facets.end());
255 assert(*face_it == int(fi));
256 visited[face_it - facets.begin()][he.side()] = true;
257
258 do {
259 const Halfedge_index he_orig = he;
260 he = sm.next_around_target(he);
261 if (he.is_invalid())
262 goto PLANE_FAILURE;
263
264 // For broken meshes, the iteration might never get back to he_orig.
265 // Remember all halfedges we saw to break out of such infinite loops.
266 boost::container::small_vector<Halfedge_index, 10> he_seen;
267
268 while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig) {
269 he_seen.emplace_back(he);
270 he = sm.next_around_target(he);
271 if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end())
272 goto PLANE_FAILURE;
273 }
274 he = sm.opposite(he);
275 if (he.is_invalid())
276 goto PLANE_FAILURE;
277
278 Face_index fi = he.face();
279 auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi));
280 if (face_it == facets.end() || *face_it != int(fi)) // This indicates a broken mesh.
281 goto PLANE_FAILURE;
282
283 if (visited[face_it - facets.begin()][he.side()] && he != he_start) {
284 last_border.resize(1);
285 break;
286 }
287 visited[face_it - facets.begin()][he.side()] = true;
288
289 last_border.emplace_back(sm.point(sm.source(he)).cast<double>());
290
291 // In case of broken meshes, this loop might be infinite. Break
292 // out in case it is clearly going bad.
293 if (last_border.size() > 3*facets.size()+1)
294 goto PLANE_FAILURE;
295
296 } while (he != he_start);
297
298 if (last_border.size() == 1)
299 planes[plane_id].borders.pop_back();
300 else {
301 assert(last_border.front() == last_border.back());
302 last_border.pop_back();
303 }
304 }
305 }
306 continue; // There was no failure.
307
308 PLANE_FAILURE:
309 planes[plane_id].borders.clear();
310 }});
311 m_planes.shrink_to_fit();
312}
std::vector< Vec3i32 > its_face_neighbors(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1615
auto range(Cont &&cont)
Definition libslic3r.h:405
std::vector< Vec3f > its_face_normals(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1625

References Slic3r::its_face_neighbors(), Slic3r::its_face_normals(), m_face_to_plane, m_its, m_planes, and Slic3r::range().

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_its

indexed_triangle_set Slic3r::Measure::MeasuringImpl::m_its
private

◆ m_planes


The documentation for this class was generated from the following file:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Measure.cpp