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

#include <src/libslic3r/TriangleSelector.hpp>

+ Inheritance diagram for Slic3r::TriangleSelector:
+ Collaboration diagram for Slic3r::TriangleSelector:

Classes

class  Capsule2D
 
class  Capsule3D
 
class  Circle
 
struct  ClippingPlane
 
class  Cursor
 
class  DoublePointCursor
 
class  SinglePointCursor
 
class  Sphere
 
class  Triangle
 
struct  Vertex
 

Public Types

enum  CursorType { CIRCLE , SPHERE , POINTER }
 

Public Member Functions

std::pair< std::vector< Vec3i >, std::vector< Vec3i > > precompute_all_neighbors () const
 
void precompute_all_neighbors_recursive (int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector< Vec3i > &neighbors_out, std::vector< Vec3i > &neighbors_normal_out) const
 
void set_edge_limit (float edge_limit)
 
 TriangleSelector (const TriangleMesh &mesh)
 
int select_unsplit_triangle (const Vec3f &hit, int facet_idx) const
 
int select_unsplit_triangle (const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const
 
void select_patch (int facet_start, std::unique_ptr< Cursor > &&cursor, EnforcerBlockerType new_state, const Transform3d &trafo_no_translate, bool triangle_splitting, float highlight_by_angle_deg=0.f)
 
void seed_fill_select_triangles (const Vec3f &hit, int facet_start, const Transform3d &trafo_no_translate, const ClippingPlane &clp, float seed_fill_angle, float highlight_by_angle_deg=0.f, bool force_reselection=false)
 
void bucket_fill_select_triangles (const Vec3f &hit, int facet_start, const ClippingPlane &clp, bool propagate, bool force_reselection=false)
 
bool has_facets (EnforcerBlockerType state) const
 
int num_facets (EnforcerBlockerType state) const
 
indexed_triangle_set get_facets (EnforcerBlockerType state) const
 
indexed_triangle_set get_facets_strict (EnforcerBlockerType state) const
 
std::vector< Vec2iget_seed_fill_contour () const
 
void set_facet (int facet_idx, EnforcerBlockerType state)
 
void reset ()
 
void garbage_collect ()
 
std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > serialize () const
 
void deserialize (const std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > &data, bool needs_reset=true)
 
void seed_fill_unselect_all_triangles ()
 
void seed_fill_apply_on_triangles (EnforcerBlockerType new_state)
 

Static Public Member Functions

static bool has_facets (const std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > &data, EnforcerBlockerType test_state)
 

Protected Attributes

std::vector< Vertexm_vertices
 
std::vector< Trianglem_triangles
 
const TriangleMeshm_mesh
 
const std::vector< Vec3im_neighbors
 
const std::vector< Vec3fm_face_normals
 
int m_invalid_triangles
 
float m_edge_limit_sqr = 1.f
 
int m_orig_size_vertices = 0
 
int m_orig_size_indices = 0
 
std::unique_ptr< Cursorm_cursor
 
float m_old_cursor_radius_sqr = 0
 

Private Types

enum class  Partition { First , Second }
 

Private Member Functions

bool select_triangle (int facet_idx, EnforcerBlockerType type, bool triangle_splitting)
 
bool select_triangle_recursive (int facet_idx, const Vec3i &neighbors, EnforcerBlockerType type, bool triangle_splitting)
 
void undivide_triangle (int facet_idx)
 
void split_triangle (int facet_idx, const Vec3i &neighbors)
 
void remove_useless_children (int facet_idx)
 
bool is_facet_clipped (int facet_idx, const ClippingPlane &clp) const
 
int push_triangle (int a, int b, int c, int source_triangle, EnforcerBlockerType state=EnforcerBlockerType{0})
 
void perform_split (int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state)
 
Vec3i child_neighbors (const Triangle &tr, const Vec3i &neighbors, int child_idx) const
 
Vec3i child_neighbors_propagated (const Triangle &tr, const Vec3i &neighbors_propagated, int child_idx, const Vec3i &child_neighbors) const
 
int neighbor_child (const Triangle &tr, int vertexi, int vertexj, Partition partition) const
 
int neighbor_child (int itriangle, int vertexi, int vertexj, Partition partition) const
 
int triangle_midpoint (const Triangle &tr, int vertexi, int vertexj) const
 
int triangle_midpoint (int itriangle, int vertexi, int vertexj) const
 
int triangle_midpoint_or_allocate (int itriangle, int vertexi, int vertexj)
 
std::pair< int, int > triangle_subtriangles (int itriangle, int vertexi, int vertexj) const
 
void append_touching_subtriangles (int itriangle, int vertexi, int vertexj, std::vector< int > &touching_subtriangles_out) const
 
void append_touching_edges (int itriangle, int vertexi, int vertexj, std::vector< Vec2i > &touching_edges_out) const
 
bool verify_triangle_neighbors (const Triangle &tr, const Vec3i &neighbors) const
 
bool verify_triangle_midpoints (const Triangle &tr) const
 
void get_facets_strict_recursive (const Triangle &tr, const Vec3i &neighbors, EnforcerBlockerType state, std::vector< stl_triangle_vertex_indices > &out_triangles) const
 
void get_facets_split_by_tjoints (const Vec3i &vertices, const Vec3i &neighbors, std::vector< stl_triangle_vertex_indices > &out_triangles) const
 
void get_seed_fill_contour_recursive (int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector< Vec2i > &edges_out) const
 

Static Private Member Functions

static std::pair< int, int > triangle_subtriangles (const Triangle &tr, int vertexi, int vertexj)
 

Private Attributes

int m_free_triangles_head { -1 }
 
int m_free_vertices_head { -1 }
 

Detailed Description

Member Enumeration Documentation

◆ CursorType

Enumerator
CIRCLE 
SPHERE 
POINTER 
25 {
26 CIRCLE,
27 SPHERE,
29 };
@ POINTER
Definition TriangleSelector.hpp:28
@ SPHERE
Definition TriangleSelector.hpp:27
@ CIRCLE
Definition TriangleSelector.hpp:26

◆ Partition

enum class Slic3r::TriangleSelector::Partition
strongprivate
Enumerator
First 
Second 

Constructor & Destructor Documentation

◆ TriangleSelector()

Slic3r::TriangleSelector::TriangleSelector ( const TriangleMesh mesh)
explicit
1187{
1188 reset();
1189}
const std::vector< Vec3f > m_face_normals
Definition TriangleSelector.hpp:326
const TriangleMesh & m_mesh
Definition TriangleSelector.hpp:324
void reset()
Definition TriangleSelector.cpp:1191
const std::vector< Vec3i > m_neighbors
Definition TriangleSelector.hpp:325
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

References reset().

+ Here is the call graph for this function:

Member Function Documentation

◆ append_touching_edges()

void Slic3r::TriangleSelector::append_touching_edges ( int  itriangle,
int  vertexi,
int  vertexj,
std::vector< Vec2i > &  touching_edges_out 
) const
private
412{
413 if (itriangle == -1)
414 return;
415
416 auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_edges_out](const int subtriangle_idx, Partition partition) -> void {
417 assert(subtriangle_idx != -1);
418 if (!m_triangles[subtriangle_idx].is_split()) {
419 if (!m_triangles[subtriangle_idx].is_selected_by_seed_fill()) {
420 int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj);
421 if (partition == Partition::First && midpoint != -1) {
422 touching_edges_out.emplace_back(vertexi, midpoint);
423 } else if (partition == Partition::First && midpoint == -1) {
424 touching_edges_out.emplace_back(vertexi, vertexj);
425 } else {
426 assert(midpoint != -1 && partition == Partition::Second);
427 touching_edges_out.emplace_back(midpoint, vertexj);
428 }
429 }
430 } else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
431 append_touching_edges(subtriangle_idx, partition == Partition::First ? vertexi : midpoint, partition == Partition::First ? midpoint : vertexj,
432 touching_edges_out);
433 else
434 append_touching_edges(subtriangle_idx, vertexi, vertexj, touching_edges_out);
435 };
436
437 std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj);
438 if (touching.first != -1)
439 process_subtriangle(touching.first, Partition::First);
440
441 if (touching.second != -1)
442 process_subtriangle(touching.second, Partition::Second);
443}
Partition
Definition TriangleSelector.hpp:356
static std::pair< int, int > triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj)
Definition TriangleSelector.cpp:591
int triangle_midpoint(const Triangle &tr, int vertexi, int vertexj) const
Definition TriangleSelector.cpp:622
std::vector< Triangle > m_triangles
Definition TriangleSelector.hpp:323
void append_touching_edges(int itriangle, int vertexi, int vertexj, std::vector< Vec2i > &touching_edges_out) const
Definition TriangleSelector.cpp:411
IGL_INLINE void partition(const Eigen::MatrixXd &W, const int k, Eigen::Matrix< int, Eigen::Dynamic, 1 > &G, Eigen::Matrix< int, Eigen::Dynamic, 1 > &S, Eigen::Matrix< double, Eigen::Dynamic, 1 > &D)
Definition partition.cpp:11

References append_touching_edges(), First, m_triangles, Second, triangle_midpoint(), and triangle_subtriangles().

Referenced by append_touching_edges(), and get_seed_fill_contour_recursive().

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

◆ append_touching_subtriangles()

void Slic3r::TriangleSelector::append_touching_subtriangles ( int  itriangle,
int  vertexi,
int  vertexj,
std::vector< int > &  touching_subtriangles_out 
) const
private
387{
388 if (itriangle == -1)
389 return;
390
391 auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_subtriangles_out](const int subtriangle_idx, Partition partition) -> void {
392 assert(subtriangle_idx != -1);
393 if (!m_triangles[subtriangle_idx].is_split())
394 touching_subtriangles_out.emplace_back(subtriangle_idx);
395 else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
396 append_touching_subtriangles(subtriangle_idx, partition == Partition::First ? vertexi : midpoint, partition == Partition::First ? midpoint : vertexj, touching_subtriangles_out);
397 else
398 append_touching_subtriangles(subtriangle_idx, vertexi, vertexj, touching_subtriangles_out);
399 };
400
401 std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj);
402 if (touching.first != -1)
403 process_subtriangle(touching.first, Partition::First);
404
405 if (touching.second != -1)
406 process_subtriangle(touching.second, Partition::Second);
407}
void append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector< int > &touching_subtriangles_out) const
Definition TriangleSelector.cpp:386

References append_touching_subtriangles(), First, m_triangles, Second, triangle_midpoint(), and triangle_subtriangles().

Referenced by append_touching_subtriangles(), and bucket_fill_select_triangles().

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

◆ bucket_fill_select_triangles()

void Slic3r::TriangleSelector::bucket_fill_select_triangles ( const Vec3f hit,
int  facet_start,
const ClippingPlane clp,
bool  propagate,
bool  force_reselection = false 
)
446{
447 int start_facet_idx = select_unsplit_triangle(hit, facet_start);
448 assert(start_facet_idx != -1);
449 // Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill or a clipping plane is active.
450 if (start_facet_idx == -1 || (m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection && !clp.is_active()))
451 return;
452
453 assert(!m_triangles[start_facet_idx].is_split());
454 EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state();
456
457 if (!propagate) {
458 m_triangles[start_facet_idx].select_by_seed_fill();
459 return;
460 }
461
462 auto get_all_touching_triangles = [this](int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated) -> std::vector<int> {
463 assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
464 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
465 std::vector<int> touching_triangles;
466 Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
467 append_touching_subtriangles(neighbors(0), vertices(1), vertices(0), touching_triangles);
468 append_touching_subtriangles(neighbors(1), vertices(2), vertices(1), touching_triangles);
469 append_touching_subtriangles(neighbors(2), vertices(0), vertices(2), touching_triangles);
470
471 for (int neighbor_idx : neighbors_propagated)
472 if (neighbor_idx != -1 && !m_triangles[neighbor_idx].is_split())
473 touching_triangles.emplace_back(neighbor_idx);
474
475 return touching_triangles;
476 };
477
478 auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors();
479 std::vector<bool> visited(m_triangles.size(), false);
480 std::queue<int> facet_queue;
481
482 facet_queue.push(start_facet_idx);
483 while (!facet_queue.empty()) {
484 int current_facet = facet_queue.front();
485 facet_queue.pop();
486 assert(!m_triangles[current_facet].is_split());
487
488 if (!visited[current_facet]) {
489 m_triangles[current_facet].select_by_seed_fill();
490
491 std::vector<int> touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]);
492 for(const int tr_idx : touching_triangles) {
493 if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state || is_facet_clipped(tr_idx, clp))
494 continue;
495
496 assert(!m_triangles[tr_idx].is_split());
497 facet_queue.push(tr_idx);
498 }
499 }
500
501 visited[current_facet] = true;
502 }
503}
void seed_fill_unselect_all_triangles()
Definition TriangleSelector.cpp:1756
std::pair< std::vector< Vec3i >, std::vector< Vec3i > > precompute_all_neighbors() const
Definition TriangleSelector.cpp:370
bool is_facet_clipped(int facet_idx, const ClippingPlane &clp) const
Definition TriangleSelector.cpp:277
int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const
Definition TriangleSelector.cpp:222
bool verify_triangle_neighbors(const Triangle &tr, const Vec3i &neighbors) const
Definition TriangleSelector.cpp:136
if(!(yy_init))
Definition lexer.c:1190
Eigen::Matrix< int, 3, 1, Eigen::DontAlign > Vec3i
Definition Point.hpp:40
EnforcerBlockerType
Definition Model.hpp:664

References append_touching_subtriangles(), Slic3r::TriangleSelector::ClippingPlane::is_active(), is_facet_clipped(), m_triangles, precompute_all_neighbors(), seed_fill_unselect_all_triangles(), select_unsplit_triangle(), and verify_triangle_neighbors().

+ Here is the call graph for this function:

◆ child_neighbors()

Vec3i Slic3r::TriangleSelector::child_neighbors ( const Triangle tr,
const Vec3i neighbors,
int  child_idx 
) const
private
702{
703 assert(this->verify_triangle_neighbors(tr, neighbors));
704
705 assert(child_idx >= 0 && child_idx <= tr.number_of_split_sides());
706 int i = tr.special_side();
707 int j = next_idx_modulo(i, 3);
708 int k = next_idx_modulo(j, 3);
709
710 Vec3i out;
711 switch (tr.number_of_split_sides()) {
712 case 1:
713 switch (child_idx) {
714 case 0:
715 out(0) = neighbors(i);
716 out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second);
717 out(2) = tr.children[1];
718 break;
719 default:
720 assert(child_idx == 1);
721 out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First);
722 out(1) = neighbors(k);
723 out(2) = tr.children[0];
724 break;
725 }
726 break;
727
728 case 2:
729 switch (child_idx) {
730 case 0:
731 out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second);
732 out(1) = tr.children[1];
733 out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First);
734 break;
735 case 1:
736 assert(child_idx == 1);
737 out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First);
738 out(1) = tr.children[2];
739 out(2) = tr.children[0];
740 break;
741 default:
742 assert(child_idx == 2);
743 out(0) = neighbors(j);
744 out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second);
745 out(2) = tr.children[1];
746 break;
747 }
748 break;
749
750 case 3:
751 assert(tr.special_side() == 0);
752 switch (child_idx) {
753 case 0:
754 out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second);
755 out(1) = tr.children[3];
756 out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First);
757 break;
758 case 1:
759 out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First);
760 out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second);
761 out(2) = tr.children[3];
762 break;
763 case 2:
764 out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First);
765 out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second);
766 out(2) = tr.children[3];
767 break;
768 default:
769 assert(child_idx == 3);
770 out(0) = tr.children[1];
771 out(1) = tr.children[2];
772 out(2) = tr.children[0];
773 break;
774 }
775 break;
776
777 default:
778 assert(false);
779 }
780
781 assert(this->verify_triangle_neighbors(tr, neighbors));
782 assert(this->verify_triangle_neighbors(m_triangles[tr.children[child_idx]], out));
783 return out;
784}
int neighbor_child(const Triangle &tr, int vertexi, int vertexj, Partition partition) const
Definition TriangleSelector.cpp:542
INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
Definition Utils.hpp:203

References Slic3r::TriangleSelector::Triangle::children, First, m_triangles, neighbor_child(), Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Second, Slic3r::TriangleSelector::Triangle::special_side(), verify_triangle_neighbors(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by child_neighbors_propagated(), deserialize(), get_seed_fill_contour_recursive(), perform_split(), and precompute_all_neighbors_recursive().

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

◆ child_neighbors_propagated()

Vec3i Slic3r::TriangleSelector::child_neighbors_propagated ( const Triangle tr,
const Vec3i neighbors_propagated,
int  child_idx,
const Vec3i child_neighbors 
) const
private
789{
790 int i = tr.special_side();
791 int j = next_idx_modulo(i, 3);
792 int k = next_idx_modulo(j, 3);
793
795 auto replace_if_not_exists = [&out, &neighbors_propagated](int index_to_replace, int neighbor_idx) {
796 if (out(index_to_replace) == -1)
797 out(index_to_replace) = neighbors_propagated(neighbor_idx);
798 };
799
800 switch (tr.number_of_split_sides()) {
801 case 1:
802 switch (child_idx) {
803 case 0:
804 replace_if_not_exists(0, i);
805 replace_if_not_exists(1, j);
806 break;
807 default:
808 assert(child_idx == 1);
809 replace_if_not_exists(0, j);
810 replace_if_not_exists(1, k);
811 break;
812 }
813 break;
814
815 case 2:
816 switch (child_idx) {
817 case 0:
818 replace_if_not_exists(0, i);
819 replace_if_not_exists(2, k);
820 break;
821 case 1:
822 assert(child_idx == 1);
823 replace_if_not_exists(0, i);
824 break;
825 default:
826 assert(child_idx == 2);
827 replace_if_not_exists(0, j);
828 replace_if_not_exists(1, k);
829 break;
830 }
831 break;
832
833 case 3:
834 assert(tr.special_side() == 0);
835 switch (child_idx) {
836 case 0:
837 replace_if_not_exists(0, 0);
838 replace_if_not_exists(2, 2);
839 break;
840 case 1:
841 replace_if_not_exists(0, 0);
842 replace_if_not_exists(1, 1);
843 break;
844 case 2:
845 replace_if_not_exists(0, 1);
846 replace_if_not_exists(1, 2);
847 break;
848 default:
849 assert(child_idx == 3);
850 break;
851 }
852 break;
853
854 default: assert(false);
855 }
856
857 return out;
858}
Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const
Definition TriangleSelector.cpp:701

References child_neighbors(), Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), and Slic3r::TriangleSelector::Triangle::special_side().

+ Here is the call graph for this function:

◆ deserialize()

void Slic3r::TriangleSelector::deserialize ( const std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > &  data,
bool  needs_reset = true 
)
1604{
1605 if (needs_reset)
1606 reset(); // dump any current state
1607
1608 // Reserve number of triangles as if each triangle was saved with 4 bits.
1609 // With MMU painting this estimate may be somehow low, but better than nothing.
1610 m_triangles.reserve(std::max(m_mesh.its.indices.size(), data.second.size() / 4));
1611 // Number of triangles is twice the number of vertices on a large manifold mesh of genus zero.
1612 // Here the triangles count account for both the nodes and leaves, thus the following line may overestimate.
1613 m_vertices.reserve(std::max(m_mesh.its.vertices.size(), m_triangles.size() / 2));
1614
1615 // Vector to store all parents that have offsprings.
1616 struct ProcessingInfo {
1617 int facet_id = 0;
1618 Vec3i neighbors { -1, -1, -1 };
1619 int processed_children = 0;
1620 int total_children = 0;
1621 };
1622 // Depth-first queue of a source mesh triangle and its childern.
1623 // kept outside of the loop to avoid re-allocating inside the loop.
1624 std::vector<ProcessingInfo> parents;
1625
1626 for (auto [triangle_id, ibit] : data.first) {
1627 assert(triangle_id < int(m_triangles.size()));
1628 assert(ibit < int(data.second.size()));
1629 auto next_nibble = [&data, &ibit = ibit]() {
1630 int n = 0;
1631 for (int i = 0; i < 4; ++ i)
1632 n |= data.second[ibit ++] << i;
1633 return n;
1634 };
1635
1636 parents.clear();
1637 while (true) {
1638 // Read next triangle info.
1639 int code = next_nibble();
1640 int num_of_split_sides = code & 0b11;
1641 int num_of_children = num_of_split_sides == 0 ? 0 : num_of_split_sides + 1;
1642 bool is_split = num_of_children != 0;
1643 // Only valid if not is_split. Value of the second nibble was subtracted by 3, so it is added back.
1644 auto state = is_split ? EnforcerBlockerType::NONE : EnforcerBlockerType((code & 0b1100) == 0b1100 ? next_nibble() + 3 : code >> 2);
1645 // Only valid if is_split.
1646 int special_side = code >> 2;
1647
1648 // Take care of the first iteration separately, so handling of the others is simpler.
1649 if (parents.empty()) {
1650 if (is_split) {
1651 // root is split, add it into list of parents and split it.
1652 // then go to the next.
1653 Vec3i neighbors = m_neighbors[triangle_id];
1654 parents.push_back({triangle_id, neighbors, 0, num_of_children});
1655 m_triangles[triangle_id].set_division(num_of_split_sides, special_side);
1656 perform_split(triangle_id, neighbors, EnforcerBlockerType::NONE);
1657 continue;
1658 } else {
1659 // root is not split. just set the state and that's it.
1660 m_triangles[triangle_id].set_state(state);
1661 break;
1662 }
1663 }
1664
1665 // This is not the first iteration. This triangle is a child of last seen parent.
1666 assert(! parents.empty());
1667 assert(parents.back().processed_children < parents.back().total_children);
1668
1669 if (ProcessingInfo& last = parents.back(); is_split) {
1670 // split the triangle and save it as parent of the next ones.
1671 const Triangle &tr = m_triangles[last.facet_id];
1672 int child_idx = last.total_children - last.processed_children - 1;
1673 Vec3i neighbors = this->child_neighbors(tr, last.neighbors, child_idx);
1674 int this_idx = tr.children[child_idx];
1675 m_triangles[this_idx].set_division(num_of_split_sides, special_side);
1676 perform_split(this_idx, neighbors, EnforcerBlockerType::NONE);
1677 parents.push_back({this_idx, neighbors, 0, num_of_children});
1678 } else {
1679 // this triangle belongs to last split one
1680 int child_idx = last.total_children - last.processed_children - 1;
1681 m_triangles[m_triangles[last.facet_id].children[child_idx]].set_state(state);
1682 ++last.processed_children;
1683 }
1684
1685 // If all children of the past parent triangle are claimed, move to grandparent.
1686 while (parents.back().processed_children == parents.back().total_children) {
1687 parents.pop_back();
1688
1689 if (parents.empty())
1690 break;
1691
1692 // And increment the grandparent children counter, because
1693 // we have just finished that branch and got back here.
1694 ++parents.back().processed_children;
1695 }
1696
1697 // In case we popped back the root, we should be done.
1698 if (parents.empty())
1699 break;
1700 }
1701 }
1702}
indexed_triangle_set its
Definition TriangleMesh.hpp:155
std::vector< Vertex > m_vertices
Definition TriangleSelector.hpp:322
void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state)
Definition TriangleSelector.cpp:1250
constexpr auto data(C &c) -> decltype(c.data())
Definition span.hpp:195
Kernel::Triangle_3 Triangle
Definition points_inside_component.cpp:33
std::vector< stl_vertex > vertices
Definition stl.h:165
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References child_neighbors(), Slic3r::TriangleSelector::Triangle::children, indexed_triangle_set::indices, Slic3r::TriangleMesh::its, m_mesh, m_neighbors, m_triangles, m_vertices, Slic3r::NONE, perform_split(), reset(), and indexed_triangle_set::vertices.

Referenced by Slic3r::FacetsAnnotation::get_facets(), and Slic3r::FacetsAnnotation::get_facets_strict().

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

◆ garbage_collect()

void Slic3r::TriangleSelector::garbage_collect ( )
1132{
1133 // First make a map from old to new triangle indices.
1134 int new_idx = m_orig_size_indices;
1135 std::vector<int> new_triangle_indices(m_triangles.size(), -1);
1136 for (int i = m_orig_size_indices; i<int(m_triangles.size()); ++i)
1137 if (m_triangles[i].valid())
1138 new_triangle_indices[i] = new_idx ++;
1139
1140 // Now we know which vertices are not referenced anymore. Make a map
1141 // from old idxs to new ones, like we did for triangles.
1142 new_idx = m_orig_size_vertices;
1143 std::vector<int> new_vertices_indices(m_vertices.size(), -1);
1144 for (int i=m_orig_size_vertices; i<int(m_vertices.size()); ++i) {
1145 assert(m_vertices[i].ref_cnt >= 0);
1146 if (m_vertices[i].ref_cnt != 0)
1147 new_vertices_indices[i] = new_idx ++;
1148 }
1149
1150 // We can remove all invalid triangles and vertices that are no longer referenced.
1151 m_triangles.erase(std::remove_if(m_triangles.begin()+m_orig_size_indices, m_triangles.end(),
1152 [](const Triangle& tr) { return ! tr.valid(); }),
1153 m_triangles.end());
1154 m_vertices.erase(std::remove_if(m_vertices.begin()+m_orig_size_vertices, m_vertices.end(),
1155 [](const Vertex& vert) { return vert.ref_cnt == 0; }),
1156 m_vertices.end());
1157
1158 // Now go through all remaining triangles and update changed indices.
1159 for (Triangle& tr : m_triangles) {
1160 assert(tr.valid());
1161
1162 if (tr.is_split()) {
1163 // There are children. Update their indices.
1164 for (int j=0; j<=tr.number_of_split_sides(); ++j) {
1165 assert(new_triangle_indices[tr.children[j]] != -1);
1166 tr.children[j] = new_triangle_indices[tr.children[j]];
1167 }
1168 }
1169
1170 // Update indices into m_vertices. The original vertices are never
1171 // touched and need not be reindexed.
1172 for (int& idx : tr.verts_idxs) {
1173 if (idx >= m_orig_size_vertices) {
1174 assert(new_vertices_indices[idx] != -1);
1175 idx = new_vertices_indices[idx];
1176 }
1177 }
1178 }
1179
1183}
int m_free_triangles_head
Definition TriangleSelector.hpp:386
int m_invalid_triangles
Definition TriangleSelector.hpp:329
int m_free_vertices_head
Definition TriangleSelector.hpp:387
int m_orig_size_vertices
Definition TriangleSelector.hpp:335
int m_orig_size_indices
Definition TriangleSelector.hpp:336

References Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::is_split(), m_free_triangles_head, m_free_vertices_head, m_invalid_triangles, m_orig_size_indices, m_orig_size_vertices, m_triangles, m_vertices, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Triangle::valid(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by select_triangle().

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

◆ get_facets()

indexed_triangle_set Slic3r::TriangleSelector::get_facets ( EnforcerBlockerType  state) const
1335{
1337 std::vector<int> vertex_map(m_vertices.size(), -1);
1338 for (const Triangle& tr : m_triangles) {
1339 if (tr.valid() && ! tr.is_split() && tr.get_state() == state) {
1341 for (int i=0; i<3; ++i) {
1342 int j = tr.verts_idxs[i];
1343 if (vertex_map[j] == -1) {
1344 vertex_map[j] = int(out.vertices.size());
1345 out.vertices.emplace_back(m_vertices[j].v);
1346 }
1347 indices[i] = vertex_map[j];
1348 }
1349 out.indices.emplace_back(indices);
1350 }
1351 }
1352 return out;
1353}
Definition stl.h:157

References indexed_triangle_set::indices, m_triangles, m_vertices, and indexed_triangle_set::vertices.

Referenced by Slic3r::FacetsAnnotation::get_facets().

+ Here is the caller graph for this function:

◆ get_facets_split_by_tjoints()

void Slic3r::TriangleSelector::get_facets_split_by_tjoints ( const Vec3i vertices,
const Vec3i neighbors,
std::vector< stl_triangle_vertex_indices > &  out_triangles 
) const
private
1398{
1399// Export this triangle, but first collect the T-joint vertices along its edges.
1400 Vec3i midpoints(
1401 this->triangle_midpoint(neighbors(0), vertices(1), vertices(0)),
1402 this->triangle_midpoint(neighbors(1), vertices(2), vertices(1)),
1403 this->triangle_midpoint(neighbors(2), vertices(0), vertices(2)));
1404 int splits = (midpoints(0) != -1) + (midpoints(1) != -1) + (midpoints(2) != -1);
1405 switch (splits) {
1406 case 0:
1407 // Just emit this triangle.
1408 out_triangles.emplace_back(vertices(0), vertices(1), vertices(2));
1409 break;
1410 case 1:
1411 {
1412 // Split to two triangles
1413 int i = midpoints(0) != -1 ? 2 : midpoints(1) != -1 ? 0 : 1;
1414 int j = next_idx_modulo(i, 3);
1415 int k = next_idx_modulo(j, 3);
1417 { vertices(i), vertices(j), midpoints(j) },
1418 { neighbors(i),
1419 this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::Second),
1420 -1 },
1421 out_triangles);
1423 { midpoints(j), vertices(k), vertices(i) },
1424 { this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::First),
1425 neighbors(k),
1426 -1 },
1427 out_triangles);
1428 break;
1429 }
1430 case 2:
1431 {
1432 // Split to three triangles.
1433 int i = midpoints(0) == -1 ? 2 : midpoints(1) == -1 ? 0 : 1;
1434 int j = next_idx_modulo(i, 3);
1435 int k = next_idx_modulo(j, 3);
1437 { vertices(i), midpoints(i), midpoints(k) },
1438 { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::Second),
1439 -1,
1440 this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::First) },
1441 out_triangles);
1443 { midpoints(i), vertices(j), midpoints(k) },
1444 { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::First),
1445 -1, -1 },
1446 out_triangles);
1448 { vertices(j), vertices(k), midpoints(k) },
1449 { neighbors(j),
1450 this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::Second),
1451 -1 },
1452 out_triangles);
1453 break;
1454 }
1455 default:
1456 assert(splits == 3);
1457 // Split to 4 triangles.
1459 { vertices(0), midpoints(0), midpoints(2) },
1460 { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::Second),
1461 -1,
1462 this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::First) },
1463 out_triangles);
1465 { midpoints(0), vertices(1), midpoints(1) },
1466 { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::First),
1467 this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::Second),
1468 -1 },
1469 out_triangles);
1471 { midpoints(1), vertices(2), midpoints(2) },
1472 { this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::First),
1473 this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::Second),
1474 -1 },
1475 out_triangles);
1476 out_triangles.emplace_back(midpoints);
1477 break;
1478 }
1479}
void get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector< stl_triangle_vertex_indices > &out_triangles) const
Definition TriangleSelector.cpp:1397

References First, get_facets_split_by_tjoints(), neighbor_child(), Slic3r::next_idx_modulo(), Second, and triangle_midpoint().

Referenced by get_facets_split_by_tjoints(), and get_facets_strict_recursive().

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

◆ get_facets_strict()

indexed_triangle_set Slic3r::TriangleSelector::get_facets_strict ( EnforcerBlockerType  state) const
1356{
1358
1359 size_t num_vertices = 0;
1360 for (const Vertex &v : m_vertices)
1361 if (v.ref_cnt > 0)
1362 ++ num_vertices;
1363 out.vertices.reserve(num_vertices);
1364 std::vector<int> vertex_map(m_vertices.size(), -1);
1365 for (size_t i = 0; i < m_vertices.size(); ++ i)
1366 if (const Vertex &v = m_vertices[i]; v.ref_cnt > 0) {
1367 vertex_map[i] = int(out.vertices.size());
1368 out.vertices.emplace_back(v.v);
1369 }
1370
1371 for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle)
1372 this->get_facets_strict_recursive(m_triangles[itriangle], m_neighbors[itriangle], state, out.indices);
1373
1374 for (auto &triangle : out.indices)
1375 for (int i = 0; i < 3; ++ i)
1376 triangle(i) = vertex_map[triangle(i)];
1377
1378 return out;
1379}
void get_facets_strict_recursive(const Triangle &tr, const Vec3i &neighbors, EnforcerBlockerType state, std::vector< stl_triangle_vertex_indices > &out_triangles) const
Definition TriangleSelector.cpp:1381

References get_facets_strict_recursive(), indexed_triangle_set::indices, m_neighbors, m_orig_size_indices, m_triangles, m_vertices, and indexed_triangle_set::vertices.

Referenced by Slic3r::FacetsAnnotation::get_facets_strict().

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

◆ get_facets_strict_recursive()

void Slic3r::TriangleSelector::get_facets_strict_recursive ( const Triangle tr,
const Vec3i neighbors,
EnforcerBlockerType  state,
std::vector< stl_triangle_vertex_indices > &  out_triangles 
) const
private
1386{
1387 if (tr.is_split()) {
1388 for (int i = 0; i <= tr.number_of_split_sides(); ++ i)
1390 m_triangles[tr.children[i]],
1391 this->child_neighbors(tr, neighbors, i),
1392 state, out_triangles);
1393 } else if (tr.get_state() == state)
1394 this->get_facets_split_by_tjoints({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, out_triangles);
1395}

References Slic3r::TriangleSelector::Triangle::children, get_facets_split_by_tjoints(), get_facets_strict_recursive(), Slic3r::TriangleSelector::Triangle::get_state(), Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by get_facets_strict(), and get_facets_strict_recursive().

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

◆ get_seed_fill_contour()

std::vector< Vec2i > Slic3r::TriangleSelector::get_seed_fill_contour ( ) const
1481 {
1482 std::vector<Vec2i> edges_out;
1483 for (int facet_idx = 0; facet_idx < m_orig_size_indices; ++facet_idx) {
1484 const Vec3i neighbors = m_neighbors[facet_idx];
1485 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
1486 this->get_seed_fill_contour_recursive(facet_idx, neighbors, neighbors, edges_out);
1487 }
1488
1489 return edges_out;
1490}
void get_seed_fill_contour_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector< Vec2i > &edges_out) const
Definition TriangleSelector.cpp:1492

References get_seed_fill_contour_recursive(), m_neighbors, m_orig_size_indices, m_triangles, and verify_triangle_neighbors().

Referenced by Slic3r::GUI::TriangleSelectorGUI::update_paint_contour().

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

◆ get_seed_fill_contour_recursive()

void Slic3r::TriangleSelector::get_seed_fill_contour_recursive ( int  facet_idx,
const Vec3i neighbors,
const Vec3i neighbors_propagated,
std::vector< Vec2i > &  edges_out 
) const
private
1492 {
1493 assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
1494 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
1495 const Triangle *tr = &m_triangles[facet_idx];
1496 if (!tr->valid())
1497 return;
1498
1499 if (tr->is_split()) {
1500 int num_of_children = tr->number_of_split_sides() + 1;
1501 if (num_of_children != 1) {
1502 for (int i = 0; i < num_of_children; ++i) {
1503 assert(i < int(tr->children.size()));
1504 assert(tr->children[i] < int(m_triangles.size()));
1505 // Recursion, deep first search over the children of this triangle.
1506 // All children of this triangle were created by splitting a single source triangle of the original mesh.
1507 const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
1508 this->get_seed_fill_contour_recursive(tr->children[i], child_neighbors,
1509 this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), edges_out);
1510 }
1511 }
1512 } else if (tr->is_selected_by_seed_fill()) {
1513 Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
1514 append_touching_edges(neighbors(0), vertices(1), vertices(0), edges_out);
1515 append_touching_edges(neighbors(1), vertices(2), vertices(1), edges_out);
1516 append_touching_edges(neighbors(2), vertices(0), vertices(2), edges_out);
1517
1518 // It appends the edges that are touching the triangle only by part of the edge that means the triangles are from lower depth.
1519 for (int idx = 0; idx < 3; ++idx)
1520 if (int neighbor_tr_idx = neighbors_propagated(idx); neighbor_tr_idx != -1 && !m_triangles[neighbor_tr_idx].is_split() && !m_triangles[neighbor_tr_idx].is_selected_by_seed_fill())
1521 edges_out.emplace_back(vertices(idx), vertices(next_idx_modulo(idx, 3)));
1522 }
1523}

References append_touching_edges(), child_neighbors(), Slic3r::TriangleSelector::Triangle::children, get_seed_fill_contour_recursive(), Slic3r::TriangleSelector::Triangle::is_selected_by_seed_fill(), Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Triangle::valid(), and verify_triangle_neighbors().

Referenced by get_seed_fill_contour(), and get_seed_fill_contour_recursive().

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

◆ has_facets() [1/2]

bool Slic3r::TriangleSelector::has_facets ( const std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > &  data,
EnforcerBlockerType  test_state 
)
static
1706{
1707 // Depth-first queue of a number of unvisited children.
1708 // Kept outside of the loop to avoid re-allocating inside the loop.
1709 std::vector<int> parents_children;
1710 parents_children.reserve(64);
1711
1712 for (const std::pair<int, int> &triangle_id_and_ibit : data.first) {
1713 int ibit = triangle_id_and_ibit.second;
1714 assert(ibit < int(data.second.size()));
1715 auto next_nibble = [&data, &ibit = ibit]() {
1716 int n = 0;
1717 for (int i = 0; i < 4; ++ i)
1718 n |= data.second[ibit ++] << i;
1719 return n;
1720 };
1721 // < 0 -> negative of a number of children
1722 // >= 0 -> state
1723 auto num_children_or_state = [&next_nibble]() -> int {
1724 int code = next_nibble();
1725 int num_of_split_sides = code & 0b11;
1726 return num_of_split_sides == 0 ?
1727 ((code & 0b1100) == 0b1100 ? next_nibble() + 3 : code >> 2) :
1728 - num_of_split_sides - 1;
1729 };
1730
1731 int state = num_children_or_state();
1732 if (state < 0) {
1733 // Root is split.
1734 parents_children.clear();
1735 parents_children.emplace_back(- state);
1736 do {
1737 if (-- parents_children.back() >= 0) {
1738 int state = num_children_or_state();
1739 if (state < 0)
1740 // Child is split.
1741 parents_children.emplace_back(- state);
1742 else if (state == int(test_state))
1743 // Child is not split and a face of test_state was found.
1744 return true;
1745 } else
1746 parents_children.pop_back();
1747 } while (! parents_children.empty());
1748 } else if (state == int(test_state))
1749 // Root is not split and a face of test_state was found.
1750 return true;
1751 }
1752
1753 return false;
1754}

◆ has_facets() [2/2]

bool Slic3r::TriangleSelector::has_facets ( EnforcerBlockerType  state) const
1318{
1319 for (const Triangle& tr : m_triangles)
1320 if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
1321 return true;
1322 return false;
1323}

References m_triangles.

◆ is_facet_clipped()

bool Slic3r::TriangleSelector::is_facet_clipped ( int  facet_idx,
const ClippingPlane clp 
) const
private
278{
279 for (int vert_idx : m_triangles[facet_idx].verts_idxs)
280 if (clp.is_active() && clp.is_mesh_point_clipped(m_vertices[vert_idx].v))
281 return true;
282
283 return false;
284}

References Slic3r::TriangleSelector::ClippingPlane::is_active(), Slic3r::TriangleSelector::ClippingPlane::is_mesh_point_clipped(), m_triangles, and m_vertices.

Referenced by bucket_fill_select_triangles(), and seed_fill_select_triangles().

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

◆ neighbor_child() [1/2]

int Slic3r::TriangleSelector::neighbor_child ( const Triangle tr,
int  vertexi,
int  vertexj,
Partition  partition 
) const
private
543{
544 if (tr.number_of_split_sides() == 0)
545 // If this triangle is not split, then there is no upper / lower subtriangle sharing the edge.
546 return -1;
547
548 // Find the triangle edge.
549 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
550 assert(tr.verts_idxs[edge] == vertexi);
551 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
552
553 int child_idx;
554 if (tr.number_of_split_sides() == 1) {
555 if (edge != next_idx_modulo(tr.special_side(), 3))
556 // A child may or may not be split at this side.
557 return this->neighbor_child(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj, partition);
558 child_idx = partition == Partition::First ? 0 : 1;
559 } else if (tr.number_of_split_sides() == 2) {
560 if (edge == next_idx_modulo(tr.special_side(), 3))
561 // A child may or may not be split at this side.
562 return this->neighbor_child(m_triangles[tr.children[2]], vertexi, vertexj, partition);
563 child_idx = edge == tr.special_side() ?
564 (partition == Partition::First ? 0 : 1) :
565 (partition == Partition::First ? 2 : 0);
566 } else {
567 assert(tr.number_of_split_sides() == 3);
568 assert(tr.special_side() == 0);
569 switch(edge) {
570 case 0: child_idx = partition == Partition::First ? 0 : 1; break;
571 case 1: child_idx = partition == Partition::First ? 1 : 2; break;
572 default: assert(edge == 2);
573 child_idx = partition == Partition::First ? 2 : 0; break;
574 }
575 }
576 return tr.children[child_idx];
577}

References Slic3r::TriangleSelector::Triangle::children, First, m_triangles, neighbor_child(), Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Triangle::special_side(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by child_neighbors(), get_facets_split_by_tjoints(), neighbor_child(), and neighbor_child().

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

◆ neighbor_child() [2/2]

int Slic3r::TriangleSelector::neighbor_child ( int  itriangle,
int  vertexi,
int  vertexj,
Partition  partition 
) const
private
582{
583 return itriangle == -1 ? -1 : this->neighbor_child(m_triangles[itriangle], vertexi, vertexj, partition);
584}

References m_triangles, and neighbor_child().

+ Here is the call graph for this function:

◆ num_facets()

int Slic3r::TriangleSelector::num_facets ( EnforcerBlockerType  state) const
1326{
1327 int cnt = 0;
1328 for (const Triangle& tr : m_triangles)
1329 if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
1330 ++ cnt;
1331 return cnt;
1332}

References m_triangles.

◆ perform_split()

void Slic3r::TriangleSelector::perform_split ( int  facet_idx,
const Vec3i neighbors,
EnforcerBlockerType  old_state 
)
private
1251{
1252 // Reserve space for the new triangles upfront, so that the reference to this triangle will not change.
1253 {
1254 size_t num_triangles_new = m_triangles.size() + m_triangles[facet_idx].number_of_split_sides() + 1;
1255 if (m_triangles.capacity() < num_triangles_new)
1256 m_triangles.reserve(next_highest_power_of_2(num_triangles_new));
1257 }
1258
1259 Triangle &tr = m_triangles[facet_idx];
1260 assert(tr.is_split());
1261
1262 // indices of triangle vertices
1263#ifdef NDEBUG
1264 boost::container::small_vector<int, 6> verts_idxs;
1265#else // NDEBUG
1266 // For easier debugging.
1267 std::vector<int> verts_idxs;
1268 verts_idxs.reserve(6);
1269#endif // NDEBUG
1270 for (int j=0, idx = tr.special_side(); j<3; ++j, idx = next_idx_modulo(idx, 3))
1271 verts_idxs.push_back(tr.verts_idxs[idx]);
1272
1273 auto get_alloc_vertex = [this, &neighbors, &verts_idxs](int edge, int i1, int i2) -> int {
1274 return this->triangle_midpoint_or_allocate(neighbors(edge), verts_idxs[i1], verts_idxs[i2]);
1275 };
1276
1277 int ichild = 0;
1278 switch (tr.number_of_split_sides()) {
1279 case 1:
1280 verts_idxs.insert(verts_idxs.begin()+2, get_alloc_vertex(next_idx_modulo(tr.special_side(), 3), 2, 1));
1281 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[2], tr.source_triangle, old_state);
1282 tr.children[ichild ] = push_triangle(verts_idxs[2], verts_idxs[3], verts_idxs[0], tr.source_triangle, old_state);
1283 break;
1284
1285 case 2:
1286 verts_idxs.insert(verts_idxs.begin()+1, get_alloc_vertex(tr.special_side(), 1, 0));
1287 verts_idxs.insert(verts_idxs.begin()+4, get_alloc_vertex(prev_idx_modulo(tr.special_side(), 3), 0, 3));
1288 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[4], tr.source_triangle, old_state);
1289 tr.children[ichild ++] = push_triangle(verts_idxs[1], verts_idxs[2], verts_idxs[4], tr.source_triangle, old_state);
1290 tr.children[ichild ] = push_triangle(verts_idxs[2], verts_idxs[3], verts_idxs[4], tr.source_triangle, old_state);
1291 break;
1292
1293 case 3:
1294 assert(tr.special_side() == 0);
1295 verts_idxs.insert(verts_idxs.begin()+1, get_alloc_vertex(0, 1, 0));
1296 verts_idxs.insert(verts_idxs.begin()+3, get_alloc_vertex(1, 3, 2));
1297 verts_idxs.insert(verts_idxs.begin()+5, get_alloc_vertex(2, 0, 4));
1298 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[5], tr.source_triangle, old_state);
1299 tr.children[ichild ++] = push_triangle(verts_idxs[1], verts_idxs[2], verts_idxs[3], tr.source_triangle, old_state);
1300 tr.children[ichild ++] = push_triangle(verts_idxs[3], verts_idxs[4], verts_idxs[5], tr.source_triangle, old_state);
1301 tr.children[ichild ] = push_triangle(verts_idxs[1], verts_idxs[3], verts_idxs[5], tr.source_triangle, old_state);
1302 break;
1303
1304 default:
1305 break;
1306 }
1307
1308#ifndef NDEBUG
1309 assert(this->verify_triangle_neighbors(tr, neighbors));
1310 for (int i = 0; i <= tr.number_of_split_sides(); ++i) {
1311 Vec3i n = this->child_neighbors(tr, neighbors, i);
1312 assert(this->verify_triangle_neighbors(m_triangles[tr.children[i]], n));
1313 }
1314#endif // NDEBUG
1315}
int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state=EnforcerBlockerType{0})
Definition TriangleSelector.cpp:1216
int triangle_midpoint_or_allocate(int itriangle, int vertexi, int vertexj)
Definition TriangleSelector.cpp:660
uint16_t next_highest_power_of_2(uint16_t v)
Definition Utils.hpp:125
INDEX_TYPE prev_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
Definition Utils.hpp:195

References child_neighbors(), Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, Slic3r::next_highest_power_of_2(), Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::prev_idx_modulo(), push_triangle(), Slic3r::TriangleSelector::Triangle::source_triangle, Slic3r::TriangleSelector::Triangle::special_side(), triangle_midpoint_or_allocate(), verify_triangle_neighbors(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by deserialize(), and split_triangle().

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

◆ precompute_all_neighbors()

std::pair< std::vector< Vec3i >, std::vector< Vec3i > > Slic3r::TriangleSelector::precompute_all_neighbors ( ) const
371{
372 std::vector<Vec3i> neighbors(m_triangles.size(), Vec3i(-1, -1, -1));
373 std::vector<Vec3i> neighbors_propagated(m_triangles.size(), Vec3i(-1, -1, -1));
374 for (int facet_idx = 0; facet_idx < m_orig_size_indices; ++facet_idx) {
375 neighbors[facet_idx] = m_neighbors[facet_idx];
376 neighbors_propagated[facet_idx] = neighbors[facet_idx];
377 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx]));
378 if (m_triangles[facet_idx].is_split())
379 this->precompute_all_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors_propagated[facet_idx], neighbors, neighbors_propagated);
380 }
381 return std::make_pair(std::move(neighbors), std::move(neighbors_propagated));
382}
void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector< Vec3i > &neighbors_out, std::vector< Vec3i > &neighbors_normal_out) const
Definition TriangleSelector.cpp:341

References m_neighbors, m_orig_size_indices, m_triangles, precompute_all_neighbors_recursive(), and verify_triangle_neighbors().

Referenced by bucket_fill_select_triangles().

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

◆ precompute_all_neighbors_recursive()

void Slic3r::TriangleSelector::precompute_all_neighbors_recursive ( int  facet_idx,
const Vec3i neighbors,
const Vec3i neighbors_propagated,
std::vector< Vec3i > &  neighbors_out,
std::vector< Vec3i > &  neighbors_normal_out 
) const
342{
343 assert(facet_idx < int(m_triangles.size()));
344
345 const Triangle *tr = &m_triangles[facet_idx];
346 if (!tr->valid())
347 return;
348
349 neighbors_out[facet_idx] = neighbors;
350 neighbors_propagated_out[facet_idx] = neighbors_propagated;
351 if (tr->is_split()) {
352 assert(this->verify_triangle_neighbors(*tr, neighbors));
353
354 int num_of_children = tr->number_of_split_sides() + 1;
355 if (num_of_children != 1) {
356 for (int i = 0; i < num_of_children; ++i) {
357 assert(i < int(tr->children.size()));
358 assert(tr->children[i] < int(m_triangles.size()));
359 // Recursion, deep first search over the children of this triangle.
360 // All children of this triangle were created by splitting a single source triangle of the original mesh.
361 const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
363 this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), neighbors_out,
364 neighbors_propagated_out);
365 }
366 }
367 }
368}

References child_neighbors(), Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), precompute_all_neighbors_recursive(), Slic3r::TriangleSelector::Triangle::valid(), and verify_triangle_neighbors().

Referenced by precompute_all_neighbors(), and precompute_all_neighbors_recursive().

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

◆ push_triangle()

int Slic3r::TriangleSelector::push_triangle ( int  a,
int  b,
int  c,
int  source_triangle,
EnforcerBlockerType  state = EnforcerBlockerType{0} 
)
private
1217{
1218 for (int i : {a, b, c}) {
1219 assert(i >= 0 && i < int(m_vertices.size()));
1220 ++m_vertices[i].ref_cnt;
1221 }
1222 int idx;
1223 if (m_free_triangles_head == -1) {
1224 // Allocate a new triangle.
1225 assert(m_invalid_triangles == 0);
1226 idx = int(m_triangles.size());
1227 m_triangles.emplace_back(a, b, c, source_triangle, state);
1228 } else {
1229 // Reuse triangle from the free list.
1230 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1231 assert(! m_triangles[m_free_triangles_head].valid());
1232 assert(m_invalid_triangles > 0);
1234 m_free_triangles_head = m_triangles[idx].children[0];
1236 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1237 assert(m_free_triangles_head == -1 || ! m_triangles[m_free_triangles_head].valid());
1238 assert(m_invalid_triangles >= 0);
1239 assert((m_invalid_triangles == 0) == (m_free_triangles_head == -1));
1240 m_triangles[idx] = {a, b, c, source_triangle, state};
1241 }
1242 assert(m_triangles[idx].valid());
1243 return idx;
1244}

References m_free_triangles_head, m_invalid_triangles, m_triangles, and m_vertices.

Referenced by perform_split(), and reset().

+ Here is the caller graph for this function:

◆ remove_useless_children()

void Slic3r::TriangleSelector::remove_useless_children ( int  facet_idx)
private
1094{
1095 // Check that all children are leafs of the same type. If not, try to
1096 // make them (recursive call). Remove them if sucessful.
1097
1098 assert(facet_idx < int(m_triangles.size()) && m_triangles[facet_idx].valid());
1099 Triangle& tr = m_triangles[facet_idx];
1100
1101 if (! tr.is_split()) {
1102 // This is a leaf, there nothing to do. This can happen during the
1103 // first (non-recursive call). Shouldn't otherwise.
1104 return;
1105 }
1106
1107 // Call this for all non-leaf children.
1108 for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
1109 assert(child_idx < int(m_triangles.size()) && m_triangles[child_idx].valid());
1110 if (m_triangles[tr.children[child_idx]].is_split())
1111 remove_useless_children(tr.children[child_idx]);
1112 }
1113
1114
1115 // Return if a child is not leaf or two children differ in type.
1117 for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
1118 if (m_triangles[tr.children[child_idx]].is_split())
1119 return;
1120 if (child_idx == 0)
1121 first_child_type = m_triangles[tr.children[0]].get_state();
1122 else if (m_triangles[tr.children[child_idx]].get_state() != first_child_type)
1123 return;
1124 }
1125
1126 // If we got here, the children can be removed.
1127 undivide_triangle(facet_idx);
1128 tr.set_state(first_child_type);
1129}
void remove_useless_children(int facet_idx)
Definition TriangleSelector.cpp:1093
void undivide_triangle(int facet_idx)
Definition TriangleSelector.cpp:1055

References Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, Slic3r::NONE, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), remove_useless_children(), Slic3r::TriangleSelector::Triangle::set_state(), and undivide_triangle().

Referenced by remove_useless_children(), seed_fill_apply_on_triangles(), and select_triangle().

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

◆ reset()

void Slic3r::TriangleSelector::reset ( )
1192{
1193 m_vertices.clear();
1194 m_triangles.clear();
1198 m_vertices.reserve(m_mesh.its.vertices.size());
1199 for (const stl_vertex& vert : m_mesh.its.vertices)
1200 m_vertices.emplace_back(vert);
1201 m_triangles.reserve(m_mesh.its.indices.size());
1202 for (size_t i = 0; i < m_mesh.its.indices.size(); ++i) {
1204 push_triangle(ind[0], ind[1], ind[2], int(i));
1205 }
1206 m_orig_size_vertices = int(m_vertices.size());
1207 m_orig_size_indices = int(m_triangles.size());
1208
1209}

References indexed_triangle_set::indices, Slic3r::TriangleMesh::its, m_free_triangles_head, m_free_vertices_head, m_invalid_triangles, m_mesh, m_orig_size_indices, m_orig_size_vertices, m_triangles, m_vertices, push_triangle(), and indexed_triangle_set::vertices.

Referenced by TriangleSelector(), and deserialize().

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

◆ seed_fill_apply_on_triangles()

void Slic3r::TriangleSelector::seed_fill_apply_on_triangles ( EnforcerBlockerType  new_state)
1764{
1765 for (Triangle &triangle : m_triangles)
1766 if (!triangle.is_split() && triangle.is_selected_by_seed_fill())
1767 triangle.set_state(new_state);
1768
1769 for (Triangle &triangle : m_triangles)
1770 if (triangle.is_split() && triangle.valid()) {
1771 size_t facet_idx = &triangle - &m_triangles.front();
1772 remove_useless_children(int(facet_idx));
1773 }
1774}

References m_triangles, and remove_useless_children().

+ Here is the call graph for this function:

◆ seed_fill_select_triangles()

void Slic3r::TriangleSelector::seed_fill_select_triangles ( const Vec3f hit,
int  facet_start,
const Transform3d trafo_no_translate,
const ClippingPlane clp,
float  seed_fill_angle,
float  highlight_by_angle_deg = 0.f,
bool  force_reselection = false 
)
289{
290 assert(facet_start < m_orig_size_indices);
291
292 // Recompute seed fill only if the cursor is pointing on facet unselected by seed fill or a clipping plane is active.
293 if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection && !clp.is_active())
294 return;
295
297
298 std::vector<bool> visited(m_triangles.size(), false);
299 std::queue<int> facet_queue;
300 facet_queue.push(facet_start);
301
302 const double facet_angle_limit = cos(Geometry::deg2rad(seed_fill_angle)) - EPSILON;
303 const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg));
304 Vec3f vec_down = (trafo_no_translate.inverse() * -Vec3d::UnitZ()).normalized().cast<float>();
305
306 // Depth-first traversal of neighbors of the face hit by the ray thrown from the mouse cursor.
307 while (!facet_queue.empty()) {
308 int current_facet = facet_queue.front();
309 facet_queue.pop();
310
311 const Vec3f &facet_normal = m_face_normals[m_triangles[current_facet].source_triangle];
312 if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || vec_down.dot(facet_normal) >= highlight_angle_limit)) {
313 if (m_triangles[current_facet].is_split()) {
314 for (int split_triangle_idx = 0; split_triangle_idx <= m_triangles[current_facet].number_of_split_sides(); ++split_triangle_idx) {
315 assert(split_triangle_idx < int(m_triangles[current_facet].children.size()));
316 assert(m_triangles[current_facet].children[split_triangle_idx] < int(m_triangles.size()));
317 if (int child = m_triangles[current_facet].children[split_triangle_idx]; !visited[child])
318 // Child triangle shares normal with its parent. Select it.
319 facet_queue.push(child);
320 }
321 } else
322 m_triangles[current_facet].select_by_seed_fill();
323
324 if (current_facet < m_orig_size_indices)
325 // Propagate over the original triangles.
326 for (int neighbor_idx : m_neighbors[current_facet]) {
327 assert(neighbor_idx >= -1);
328 if (neighbor_idx >= 0 && !visited[neighbor_idx] && !is_facet_clipped(neighbor_idx, clp)) {
329 // Check if neighbour_facet_idx is satisfies angle in seed_fill_angle and append it to facet_queue if it do.
330 const Vec3f &n1 = m_face_normals[m_triangles[neighbor_idx].source_triangle];
331 const Vec3f &n2 = m_face_normals[m_triangles[current_facet].source_triangle];
332 if (std::clamp(n1.dot(n2), 0.f, 1.f) >= facet_angle_limit)
333 facet_queue.push(neighbor_idx);
334 }
335 }
336 }
337 visited[current_facet] = true;
338 }
339}
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
static constexpr double EPSILON
Definition libslic3r.h:51
constexpr T deg2rad(const T angle)
Definition Geometry.hpp:289
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:49

References cos(), Slic3r::Geometry::deg2rad(), EPSILON, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::inverse(), Slic3r::TriangleSelector::ClippingPlane::is_active(), is_facet_clipped(), m_face_normals, m_neighbors, m_orig_size_indices, m_triangles, seed_fill_unselect_all_triangles(), and select_unsplit_triangle().

+ Here is the call graph for this function:

◆ seed_fill_unselect_all_triangles()

void Slic3r::TriangleSelector::seed_fill_unselect_all_triangles ( )
1757{
1758 for (Triangle &triangle : m_triangles)
1759 if (!triangle.is_split())
1760 triangle.unselect_by_seed_fill();
1761}

References m_triangles.

Referenced by bucket_fill_select_triangles(), and seed_fill_select_triangles().

+ Here is the caller graph for this function:

◆ select_patch()

void Slic3r::TriangleSelector::select_patch ( int  facet_start,
std::unique_ptr< Cursor > &&  cursor,
EnforcerBlockerType  new_state,
const Transform3d trafo_no_translate,
bool  triangle_splitting,
float  highlight_by_angle_deg = 0.f 
)
234{
235 assert(facet_start < m_orig_size_indices);
236
237 // Save current cursor center, squared radius and camera direction, so we don't
238 // have to pass it around.
239 m_cursor = std::move(cursor);
240
241 // In case user changed cursor size since last time, update triangle edge limit.
242 // It is necessary to compare the internal radius in m_cursor! radius is in
243 // world coords and does not change after scaling.
244 if (m_old_cursor_radius_sqr != m_cursor->radius_sqr) {
245 set_edge_limit(std::sqrt(m_cursor->radius_sqr) / 5.f);
246 m_old_cursor_radius_sqr = m_cursor->radius_sqr;
247 }
248
249 const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg));
250 Vec3f vec_down = (trafo_no_translate.inverse() * -Vec3d::UnitZ()).normalized().cast<float>();
251
252 // Now start with the facet the pointer points to and check all adjacent facets.
253 std::vector<int> facets_to_check;
254 facets_to_check.reserve(16);
255 facets_to_check.emplace_back(facet_start);
256 // Keep track of facets of the original mesh we already processed.
257 std::vector<bool> visited(m_orig_size_indices, false);
258 // Breadth-first search around the hit point. facets_to_check may grow significantly large.
259 // Head of the bread-first facets_to_check FIFO.
260 int facet_idx = 0;
261 while (facet_idx < int(facets_to_check.size())) {
262 int facet = facets_to_check[facet_idx];
263 const Vec3f &facet_normal = m_face_normals[m_triangles[facet].source_triangle];
264 if (!visited[facet] && (highlight_by_angle_deg == 0.f || vec_down.dot(facet_normal) >= highlight_angle_limit)) {
265 if (select_triangle(facet, new_state, triangle_splitting)) {
266 // add neighboring facets to list to be processed later
267 for (int neighbor_idx : m_neighbors[facet])
268 if (neighbor_idx >= 0 && m_cursor->is_facet_visible(neighbor_idx, m_face_normals))
269 facets_to_check.push_back(neighbor_idx);
270 }
271 }
272 visited[facet] = true;
273 ++facet_idx;
274 }
275}
bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting)
Definition TriangleSelector.cpp:510
std::unique_ptr< Cursor > m_cursor
Definition TriangleSelector.hpp:338
float m_old_cursor_radius_sqr
Definition TriangleSelector.hpp:340
void set_edge_limit(float edge_limit)
Definition TriangleSelector.cpp:1211

References cos(), Slic3r::Geometry::deg2rad(), Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::inverse(), m_cursor, m_face_normals, m_neighbors, m_old_cursor_radius_sqr, m_orig_size_indices, m_triangles, select_triangle(), and set_edge_limit().

Referenced by Slic3r::TriangleSelectorWrapper::enforce_spot().

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

◆ select_triangle()

bool Slic3r::TriangleSelector::select_triangle ( int  facet_idx,
EnforcerBlockerType  type,
bool  triangle_splitting 
)
private
511{
512 assert(facet_idx < int(m_triangles.size()));
513
514 if (! m_triangles[facet_idx].valid())
515 return false;
516
517 Vec3i neighbors = m_neighbors[facet_idx];
518 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
519
520 if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting))
521 return false;
522
523 // In case that all children are leafs and have the same state now,
524 // they may be removed and substituted by the parent triangle.
525 remove_useless_children(facet_idx);
526
527#ifdef EXPENSIVE_DEBUG_CHECKS
528 // Make sure that we did not lose track of invalid triangles.
529 assert(m_invalid_triangles == std::count_if(m_triangles.begin(), m_triangles.end(),
530 [](const Triangle& tr) { return ! tr.valid(); }));
531#endif // EXPENSIVE_DEBUG_CHECKS
532
533 // Do garbage collection maybe?
534 if (2*m_invalid_triangles > int(m_triangles.size()))
536
537 return true;
538}
bool select_triangle_recursive(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType type, bool triangle_splitting)
Definition TriangleSelector.cpp:860
void garbage_collect()
Definition TriangleSelector.cpp:1131

References garbage_collect(), m_invalid_triangles, m_neighbors, m_triangles, remove_useless_children(), select_triangle_recursive(), and verify_triangle_neighbors().

Referenced by select_patch().

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

◆ select_triangle_recursive()

bool Slic3r::TriangleSelector::select_triangle_recursive ( int  facet_idx,
const Vec3i neighbors,
EnforcerBlockerType  type,
bool  triangle_splitting 
)
private
861{
862 assert(facet_idx < int(m_triangles.size()));
863
864 Triangle* tr = &m_triangles[facet_idx];
865 if (! tr->valid())
866 return false;
867
868 assert(this->verify_triangle_neighbors(*tr, neighbors));
869
870 int num_of_inside_vertices = m_cursor->vertices_inside(*tr, m_vertices);
871
872 if (num_of_inside_vertices == 0
873 && ! m_cursor->is_pointer_in_triangle(*tr, m_vertices)
874 && ! m_cursor->is_edge_inside_cursor(*tr, m_vertices))
875 return false;
876
877 if (num_of_inside_vertices == 3) {
878 // dump any subdivision and select whole triangle
879 undivide_triangle(facet_idx);
880 tr->set_state(type);
881 } else {
882 // the triangle is partially inside, let's recursively divide it
883 // (if not already) and try selecting its children.
884
885 if (! tr->is_split() && tr->get_state() == type) {
886 // This is leaf triangle that is already of correct type as a whole.
887 // No need to split, all children would end up selected anyway.
888 return true;
889 }
890
891 if (triangle_splitting)
892 split_triangle(facet_idx, neighbors);
893 else if (!m_triangles[facet_idx].is_split())
894 m_triangles[facet_idx].set_state(type);
895 tr = &m_triangles[facet_idx]; // might have been invalidated by split_triangle().
896
897 int num_of_children = tr->number_of_split_sides() + 1;
898 if (num_of_children != 1) {
899 for (int i=0; i<num_of_children; ++i) {
900 assert(i < int(tr->children.size()));
901 assert(tr->children[i] < int(m_triangles.size()));
902 // Recursion, deep first search over the children of this triangle.
903 // All children of this triangle were created by splitting a single source triangle of the original mesh.
904 select_triangle_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), type, triangle_splitting);
905 tr = &m_triangles[facet_idx]; // might have been invalidated
906 }
907 }
908 }
909
910 return true;
911}
void split_triangle(int facet_idx, const Vec3i &neighbors)
Definition TriangleSelector.cpp:923

References Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::get_state(), Slic3r::TriangleSelector::Triangle::is_split(), m_cursor, m_triangles, m_vertices, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), select_triangle_recursive(), Slic3r::TriangleSelector::Triangle::set_state(), split_triangle(), undivide_triangle(), Slic3r::TriangleSelector::Triangle::valid(), and verify_triangle_neighbors().

Referenced by select_triangle(), and select_triangle_recursive().

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

◆ select_unsplit_triangle() [1/2]

int Slic3r::TriangleSelector::select_unsplit_triangle ( const Vec3f hit,
int  facet_idx 
) const
223{
224 assert(facet_idx < int(m_triangles.size()));
225 if (!m_triangles[facet_idx].valid())
226 return -1;
227
228 Vec3i neighbors = m_neighbors[facet_idx];
229 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
230 return this->select_unsplit_triangle(hit, facet_idx, neighbors);
231}

References m_neighbors, m_triangles, select_unsplit_triangle(), and verify_triangle_neighbors().

Referenced by bucket_fill_select_triangles(), seed_fill_select_triangles(), select_unsplit_triangle(), and select_unsplit_triangle().

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

◆ select_unsplit_triangle() [2/2]

int Slic3r::TriangleSelector::select_unsplit_triangle ( const Vec3f hit,
int  facet_idx,
const Vec3i neighbors 
) const
190{
191 assert(facet_idx < int(m_triangles.size()));
192 const Triangle *tr = &m_triangles[facet_idx];
193 if (!tr->valid())
194 return -1;
195
196 if (!tr->is_split()) {
197 if (const std::array<int, 3> &t_vert = m_triangles[facet_idx].verts_idxs; is_point_inside_triangle(hit, m_vertices[t_vert[0]].v, m_vertices[t_vert[1]].v, m_vertices[t_vert[2]].v))
198 return facet_idx;
199
200 return -1;
201 }
202
203 assert(this->verify_triangle_neighbors(*tr, neighbors));
204
205 int num_of_children = tr->number_of_split_sides() + 1;
206 if (num_of_children != 1) {
207 for (int i = 0; i < num_of_children; ++i) {
208 assert(i < int(tr->children.size()));
209 assert(tr->children[i] < int(m_triangles.size()));
210 // Recursion, deep first search over the children of this triangle.
211 // All children of this triangle were created by splitting a single source triangle of the original mesh.
212
213 const std::array<int, 3> &t_vert = m_triangles[tr->children[i]].verts_idxs;
214 if (is_point_inside_triangle(hit, m_vertices[t_vert[0]].v, m_vertices[t_vert[1]].v, m_vertices[t_vert[2]].v))
215 return this->select_unsplit_triangle(hit, tr->children[i], this->child_neighbors(*tr, neighbors, i));
216 }
217 }
218
219 return -1;
220}
bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3)
Definition TriangleSelector.cpp:168

References Slic3r::TriangleSelector::Triangle::children, Slic3r::is_point_inside_triangle(), Slic3r::TriangleSelector::Triangle::is_split(), m_triangles, m_vertices, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), select_unsplit_triangle(), Slic3r::TriangleSelector::Triangle::valid(), and verify_triangle_neighbors().

+ Here is the call graph for this function:

◆ serialize()

std::pair< std::vector< std::pair< int, int > >, std::vector< bool > > Slic3r::TriangleSelector::serialize ( ) const
1526{
1527 // Each original triangle of the mesh is assigned a number encoding its state
1528 // or how it is split. Each triangle is encoded by 4 bits (xxyy) or 8 bits (zzzzxxyy):
1529 // leaf triangle: xx = EnforcerBlockerType (Only values 0, 1, and 2. Value 3 is used as an indicator for additional 4 bits.), yy = 0
1530 // leaf triangle: xx = 0b11, yy = 0b00, zzzz = EnforcerBlockerType (subtracted by 3)
1531 // non-leaf: xx = special side, yy = number of split sides
1532 // These are bitwise appended and formed into one 64-bit integer.
1533
1534 // The function returns a map from original triangle indices to
1535 // stream of bits encoding state and offsprings.
1536
1537 // Using an explicit function object to support recursive call of Serializer::serialize().
1538 // This is cheaper than the previous implementation using a recursive call of type erased std::function.
1539 // (std::function calls using a pointer, while this implementation calls directly).
1540 struct Serializer {
1541 const TriangleSelector* triangle_selector;
1542 std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> data;
1543
1544 void serialize(int facet_idx) {
1545 const Triangle& tr = triangle_selector->m_triangles[facet_idx];
1546
1547 // Always save number of split sides. It is zero for unsplit triangles.
1548 int split_sides = tr.number_of_split_sides();
1549 assert(split_sides >= 0 && split_sides <= 3);
1550
1551 data.second.push_back(split_sides & 0b01);
1552 data.second.push_back(split_sides & 0b10);
1553
1554 if (split_sides) {
1555 // If this triangle is split, save which side is split (in case
1556 // of one split) or kept (in case of two splits). The value will
1557 // be ignored for 3-side split.
1558 assert(tr.is_split() && split_sides > 0);
1559 assert(tr.special_side() >= 0 && tr.special_side() <= 3);
1560 data.second.push_back(tr.special_side() & 0b01);
1561 data.second.push_back(tr.special_side() & 0b10);
1562 // Now save all children.
1563 // Serialized in reverse order for compatibility with PrusaSlicer 2.3.1.
1564 for (int child_idx = split_sides; child_idx >= 0; -- child_idx)
1565 this->serialize(tr.children[child_idx]);
1566 } else {
1567 // In case this is leaf, we better save information about its state.
1568 int n = int(tr.get_state());
1569 if (n >= 3) {
1570 assert(n <= 16);
1571 if (n <= 16) {
1572 // Store "11" plus 4 bits of (n-3).
1573 data.second.insert(data.second.end(), { true, true });
1574 n -= 3;
1575 for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx)
1576 data.second.push_back(n & (uint64_t(0b0001) << bit_idx));
1577 }
1578 } else {
1579 // Simple case, compatible with PrusaSlicer 2.3.1 and older for storing paint on supports and seams.
1580 // Store 2 bits of n.
1581 data.second.push_back(n & 0b01);
1582 data.second.push_back(n & 0b10);
1583 }
1584 }
1585 }
1586 } out { this };
1587
1588 out.data.first.reserve(m_orig_size_indices);
1589 for (int i=0; i<m_orig_size_indices; ++i)
1590 if (const Triangle& tr = m_triangles[i]; tr.is_split() || tr.get_state() != EnforcerBlockerType::NONE) {
1591 // Store index of the first bit assigned to ith triangle.
1592 out.data.first.emplace_back(i, int(out.data.second.size()));
1593 // out the triangle bits.
1594 out.serialize(i);
1595 }
1596
1597 // May be stored onto Undo / Redo stack, thus conserve memory.
1598 out.data.first.shrink_to_fit();
1599 out.data.second.shrink_to_fit();
1600 return out.data;
1601}
void serialize(Archive &ar, FacenamesSerializer &t, const std::uint32_t version)
Definition GLGizmoEmboss.cpp:1562
unsigned __int64 uint64_t
Definition unistd.h:80

References Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::get_state(), Slic3r::TriangleSelector::Triangle::is_split(), m_orig_size_indices, m_triangles, Slic3r::NONE, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), serialize(), and Slic3r::TriangleSelector::Triangle::special_side().

Referenced by Slic3r::FacetsAnnotation::set().

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

◆ set_edge_limit()

void Slic3r::TriangleSelector::set_edge_limit ( float  edge_limit)
1212{
1213 m_edge_limit_sqr = std::pow(edge_limit, 2.f);
1214}
float m_edge_limit_sqr
Definition TriangleSelector.hpp:332

References m_edge_limit_sqr.

Referenced by select_patch().

+ Here is the caller graph for this function:

◆ set_facet()

void Slic3r::TriangleSelector::set_facet ( int  facet_idx,
EnforcerBlockerType  state 
)
914{
915 assert(facet_idx < m_orig_size_indices);
916 undivide_triangle(facet_idx);
917 assert(! m_triangles[facet_idx].is_split());
918 m_triangles[facet_idx].set_state(state);
919}

References m_orig_size_indices, m_triangles, and undivide_triangle().

+ Here is the call graph for this function:

◆ split_triangle()

void Slic3r::TriangleSelector::split_triangle ( int  facet_idx,
const Vec3i neighbors 
)
private
924{
925 if (m_triangles[facet_idx].is_split()) {
926 // The triangle is divided already.
927 return;
928 }
929
930 Triangle* tr = &m_triangles[facet_idx];
931 assert(this->verify_triangle_neighbors(*tr, neighbors));
932
933 EnforcerBlockerType old_type = tr->get_state();
934
935 // If we got here, we are about to actually split the triangle.
936 const double limit_squared = m_edge_limit_sqr;
937
938 std::array<int, 3>& facet = tr->verts_idxs;
939 std::array<const stl_vertex*, 3> pts = { &m_vertices[facet[0]].v,
940 &m_vertices[facet[1]].v,
941 &m_vertices[facet[2]].v};
942 std::array<stl_vertex, 3> pts_transformed; // must stay in scope of pts !!!
943
944 // In case the object is non-uniformly scaled, transform the
945 // points to world coords.
946 if (! m_cursor->uniform_scaling) {
947 for (size_t i=0; i<pts.size(); ++i) {
948 pts_transformed[i] = m_cursor->trafo * (*pts[i]);
949 pts[i] = &pts_transformed[i];
950 }
951 }
952
953 std::array<double, 3> sides = {(*pts[2] - *pts[1]).squaredNorm(),
954 (*pts[0] - *pts[2]).squaredNorm(),
955 (*pts[1] - *pts[0]).squaredNorm()};
956
957 boost::container::small_vector<int, 3> sides_to_split;
958 int side_to_keep = -1;
959 for (int pt_idx = 0; pt_idx<3; ++pt_idx) {
960 if (sides[pt_idx] > limit_squared)
961 sides_to_split.push_back(pt_idx);
962 else
963 side_to_keep = pt_idx;
964 }
965 if (sides_to_split.empty()) {
966 // This shall be unselected.
967 tr->set_division(0, 0);
968 return;
969 }
970
971 // Save how the triangle will be split. Second argument makes sense only for one
972 // or two split sides, otherwise the value is ignored.
973 tr->set_division(int(sides_to_split.size()),
974 sides_to_split.size() == 2 ? side_to_keep : sides_to_split[0]);
975
976 perform_split(facet_idx, neighbors, old_type);
977}

References Slic3r::TriangleSelector::Triangle::get_state(), m_cursor, m_edge_limit_sqr, m_triangles, m_vertices, perform_split(), Slic3r::TriangleSelector::Triangle::set_division(), verify_triangle_neighbors(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by select_triangle_recursive().

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

◆ triangle_midpoint() [1/2]

int Slic3r::TriangleSelector::triangle_midpoint ( const Triangle tr,
int  vertexi,
int  vertexj 
) const
private
623{
624 if (tr.number_of_split_sides() == 0)
625 // If this triangle is not split, then there is no upper / lower subtriangle sharing the edge.
626 return -1;
627
628 // Find the triangle edge.
629 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
630 assert(tr.verts_idxs[edge] == vertexi);
631 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
632
633 if (tr.number_of_split_sides() == 1) {
634 return edge == next_idx_modulo(tr.special_side(), 3) ?
635 m_triangles[tr.children[0]].verts_idxs[2] :
636 this->triangle_midpoint(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj);
637 } else if (tr.number_of_split_sides() == 2) {
638 return edge == next_idx_modulo(tr.special_side(), 3) ?
639 this->triangle_midpoint(m_triangles[tr.children[2]], vertexi, vertexj) :
640 edge == tr.special_side() ?
641 m_triangles[tr.children[0]].verts_idxs[1] :
642 m_triangles[tr.children[1]].verts_idxs[2];
643 } else {
644 assert(tr.number_of_split_sides() == 3);
645 assert(tr.special_side() == 0);
646 return
647 (edge == 0) ? m_triangles[tr.children[0]].verts_idxs[1] :
648 (edge == 1) ? m_triangles[tr.children[1]].verts_idxs[2] :
649 m_triangles[tr.children[2]].verts_idxs[2];
650 }
651}

References Slic3r::TriangleSelector::Triangle::children, m_triangles, Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Triangle::special_side(), triangle_midpoint(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by append_touching_edges(), append_touching_subtriangles(), get_facets_split_by_tjoints(), triangle_midpoint(), triangle_midpoint(), triangle_midpoint_or_allocate(), and verify_triangle_midpoints().

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

◆ triangle_midpoint() [2/2]

int Slic3r::TriangleSelector::triangle_midpoint ( int  itriangle,
int  vertexi,
int  vertexj 
) const
private
656{
657 return itriangle == -1 ? -1 : this->triangle_midpoint(m_triangles[itriangle], vertexi, vertexj);
658}

References m_triangles, and triangle_midpoint().

+ Here is the call graph for this function:

◆ triangle_midpoint_or_allocate()

int Slic3r::TriangleSelector::triangle_midpoint_or_allocate ( int  itriangle,
int  vertexi,
int  vertexj 
)
private
661{
662 int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj);
663 if (midpoint == -1) {
664 Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v);
665#ifdef EXPENSIVE_DEBUG_CHECKS
666 // Verify that the vertex is really a new one.
667 auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [c](const Vertex &v) {
668 return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; });
669 assert(it == m_vertices.end());
670#endif // EXPENSIVE_DEBUG_CHECKS
671 // Allocate a new vertex, possibly reusing the free list.
672 if (m_free_vertices_head == -1) {
673 // Allocate a new vertex.
674 midpoint = int(m_vertices.size());
675 m_vertices.emplace_back(c);
676 } else {
677 // Reuse a vertex from the free list.
678 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
679 midpoint = m_free_vertices_head;
680 memcpy(&m_free_vertices_head, &m_vertices[midpoint].v[0], sizeof(m_free_vertices_head));
681 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
682 m_vertices[midpoint].v = c;
683 }
684 assert(m_vertices[midpoint].ref_cnt == 0);
685 } else {
686#ifndef NDEBUG
687 Vec3f c1 = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v);
688 Vec3f c2 = m_vertices[midpoint].v;
689 float d = (c2 - c1).norm();
690 assert(std::abs(d) < EPSILON);
691#endif // NDEBUG
692 assert(m_vertices[midpoint].ref_cnt > 0);
693 }
694 return midpoint;
695}

References EPSILON, m_free_vertices_head, m_vertices, and triangle_midpoint().

Referenced by perform_split().

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

◆ triangle_subtriangles() [1/2]

std::pair< int, int > Slic3r::TriangleSelector::triangle_subtriangles ( const Triangle tr,
int  vertexi,
int  vertexj 
)
staticprivate
592{
593 if (tr.number_of_split_sides() == 0)
594 // If this triangle is not split, then there is no subtriangles touching the edge.
595 return std::make_pair(-1, -1);
596
597 // Find the triangle edge.
598 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
599 assert(tr.verts_idxs[edge] == vertexi);
600 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
601
602 if (tr.number_of_split_sides() == 1) {
603 return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[0], tr.children[1]) :
604 std::make_pair(tr.children[edge == tr.special_side() ? 0 : 1], -1);
605 } else if (tr.number_of_split_sides() == 2) {
606 return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[2], -1) :
607 edge == tr.special_side() ? std::make_pair(tr.children[0], tr.children[1]) :
608 std::make_pair(tr.children[2], tr.children[0]);
609 } else {
610 assert(tr.number_of_split_sides() == 3);
611 assert(tr.special_side() == 0);
612 return edge == 0 ? std::make_pair(tr.children[0], tr.children[1]) :
613 edge == 1 ? std::make_pair(tr.children[1], tr.children[2]) :
614 std::make_pair(tr.children[2], tr.children[0]);
615 }
616
617 return std::make_pair(-1, -1);
618}
STL namespace.

References Slic3r::TriangleSelector::Triangle::children, Slic3r::next_idx_modulo(), Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Triangle::special_side(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by append_touching_edges(), append_touching_subtriangles(), and triangle_subtriangles().

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

◆ triangle_subtriangles() [2/2]

std::pair< int, int > Slic3r::TriangleSelector::triangle_subtriangles ( int  itriangle,
int  vertexi,
int  vertexj 
) const
private
587{
588 return itriangle == -1 ? std::make_pair(-1, -1) : Slic3r::TriangleSelector::triangle_subtriangles(m_triangles[itriangle], vertexi, vertexj);
589}
TriangleSelector(const TriangleMesh &mesh)
Definition TriangleSelector.cpp:1185
Definition avrdude-slic3r.cpp:16

References m_triangles, and triangle_subtriangles().

+ Here is the call graph for this function:

◆ undivide_triangle()

void Slic3r::TriangleSelector::undivide_triangle ( int  facet_idx)
private
1056{
1057 assert(facet_idx < int(m_triangles.size()));
1058 Triangle& tr = m_triangles[facet_idx];
1059
1060 if (tr.is_split()) {
1061 for (int i = 0; i <= tr.number_of_split_sides(); ++i) {
1062 int child = tr.children[i];
1063 Triangle &child_tr = m_triangles[child];
1064 assert(child_tr.valid());
1065 undivide_triangle(child);
1066 for (int j = 0; j < 3; ++j) {
1067 int iv = child_tr.verts_idxs[j];
1068 Vertex &v = m_vertices[iv];
1069 assert(v.ref_cnt > 0);
1070 if (-- v.ref_cnt == 0) {
1071 // Release this vertex.
1072 // Chain released vertices into a linked list through ref_cnt.
1073 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
1074 memcpy(&m_vertices[iv].v[0], &m_free_vertices_head, sizeof(m_free_vertices_head));
1076 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
1077 }
1078 }
1079 // Chain released triangles into a linked list through children[0].
1080 assert(child_tr.valid());
1081 child_tr.m_valid = false;
1082 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1083 assert(m_free_triangles_head == -1 || ! m_triangles[m_free_triangles_head].valid());
1084 child_tr.children[0] = m_free_triangles_head;
1085 m_free_triangles_head = child;
1086 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1088 }
1089 tr.set_division(0, 0); // not split
1090 }
1091}

References Slic3r::TriangleSelector::Triangle::children, Slic3r::TriangleSelector::Triangle::is_split(), m_free_triangles_head, m_free_vertices_head, m_invalid_triangles, m_triangles, Slic3r::TriangleSelector::Triangle::m_valid, m_vertices, Slic3r::TriangleSelector::Triangle::number_of_split_sides(), Slic3r::TriangleSelector::Vertex::ref_cnt, Slic3r::TriangleSelector::Triangle::set_division(), undivide_triangle(), Slic3r::TriangleSelector::Triangle::valid(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by remove_useless_children(), select_triangle_recursive(), set_facet(), and undivide_triangle().

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

◆ verify_triangle_midpoints()

bool Slic3r::TriangleSelector::verify_triangle_midpoints ( const Triangle tr) const
private
120{
121 for (int i = 0; i < 3; ++ i) {
122 int v1 = tr.verts_idxs[i];
123 int v2 = tr.verts_idxs[next_idx_modulo(i, 3)];
124 int vmid = this->triangle_midpoint(tr, v1, v2);
125 assert(vmid >= -1);
126 if (vmid != -1) {
127 Vec3f c1 = 0.5f * (m_vertices[v1].v + m_vertices[v2].v);
128 Vec3f c2 = m_vertices[vmid].v;
129 float d = (c2 - c1).norm();
130 assert(std::abs(d) < EPSILON);
131 }
132 }
133 return true;
134}

References EPSILON, m_vertices, Slic3r::next_idx_modulo(), triangle_midpoint(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by verify_triangle_neighbors().

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

◆ verify_triangle_neighbors()

bool Slic3r::TriangleSelector::verify_triangle_neighbors ( const Triangle tr,
const Vec3i neighbors 
) const
private
137{
138 assert(neighbors(0) >= -1);
139 assert(neighbors(1) >= -1);
140 assert(neighbors(2) >= -1);
141 assert(verify_triangle_midpoints(tr));
142
143 for (int i = 0; i < 3; ++i)
144 if (neighbors(i) != -1) {
145 const Triangle &tr2 = m_triangles[neighbors(i)];
146 assert(verify_triangle_midpoints(tr2));
147 int v1 = tr.verts_idxs[i];
148 int v2 = tr.verts_idxs[next_idx_modulo(i, 3)];
149 assert(tr2.verts_idxs[0] == v1 || tr2.verts_idxs[1] == v1 || tr2.verts_idxs[2] == v1);
150 int j = tr2.verts_idxs[0] == v1 ? 0 : tr2.verts_idxs[1] == v1 ? 1 : 2;
151 assert(tr2.verts_idxs[j] == v1);
152 assert(tr2.verts_idxs[prev_idx_modulo(j, 3)] == v2);
153 }
154 return true;
155}
bool verify_triangle_midpoints(const Triangle &tr) const
Definition TriangleSelector.cpp:119

References m_triangles, Slic3r::next_idx_modulo(), Slic3r::prev_idx_modulo(), verify_triangle_midpoints(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by bucket_fill_select_triangles(), child_neighbors(), get_seed_fill_contour(), get_seed_fill_contour_recursive(), perform_split(), precompute_all_neighbors(), precompute_all_neighbors_recursive(), select_triangle(), select_triangle_recursive(), select_unsplit_triangle(), select_unsplit_triangle(), and split_triangle().

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

Member Data Documentation

◆ m_cursor

std::unique_ptr<Cursor> Slic3r::TriangleSelector::m_cursor
protected

◆ m_edge_limit_sqr

float Slic3r::TriangleSelector::m_edge_limit_sqr = 1.f
protected

Referenced by set_edge_limit(), and split_triangle().

◆ m_face_normals

const std::vector<Vec3f> Slic3r::TriangleSelector::m_face_normals
protected

◆ m_free_triangles_head

int Slic3r::TriangleSelector::m_free_triangles_head { -1 }
private

◆ m_free_vertices_head

int Slic3r::TriangleSelector::m_free_vertices_head { -1 }
private

◆ m_invalid_triangles

int Slic3r::TriangleSelector::m_invalid_triangles
protected

◆ m_mesh

const TriangleMesh& Slic3r::TriangleSelector::m_mesh
protected

Referenced by deserialize(), and reset().

◆ m_neighbors

◆ m_old_cursor_radius_sqr

float Slic3r::TriangleSelector::m_old_cursor_radius_sqr = 0
protected

Referenced by select_patch().

◆ m_orig_size_indices

◆ m_orig_size_vertices

int Slic3r::TriangleSelector::m_orig_size_vertices = 0
protected

Referenced by garbage_collect(), and reset().

◆ m_triangles

◆ m_vertices


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