OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::TriangleSelector Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/TriangleSelector.hpp>

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

Classes

struct  ClippingPlane
class  Cursor
class  SinglePointCursor
class  DoublePointCursor
class  Sphere
class  Circle
class  HeightRange
class  Capsule3D
class  Capsule2D
struct  TriangleBitStreamMapping
struct  TriangleSplittingData
struct  SavedPainting
class  Triangle
struct  Vertex

Public Types

enum  CursorType {
  CIRCLE , SPHERE , POINTER , HEIGHT_RANGE ,
  GAP_FILL
}

Public Member Functions

std::pair< std::vector< Vec3i32 >, std::vector< Vec3i32 > > precompute_all_neighbors () const
void precompute_all_neighbors_recursive (int facet_idx, const Vec3i32 &neighbors, const Vec3i32 &neighbors_propagated, std::vector< Vec3i32 > &neighbors_out, std::vector< Vec3i32 > &neighbors_normal_out) const
void set_edge_limit (float edge_limit)
 TriangleSelector (const TriangleMesh &mesh, float edge_limit=0.6f)
int select_unsplit_triangle (const Vec3f &hit, int facet_idx) const
int select_unsplit_triangle (const Vec3f &hit, int facet_idx, const Vec3i32 &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, const Vec3f &up_direction=Vec3f::UnitZ(), bool select_partially=false)
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, const Vec3f &up_direction=Vec3f::UnitZ(), bool force_reselection=false)
void bucket_fill_select_triangles (const Vec3f &hit, int facet_start, const ClippingPlane &clp, float seed_fill_angle, 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, std::vector< int > *out_source=nullptr) const
std::vector< Vec2i32 > get_seed_fill_contour () const
void get_facets (std::vector< indexed_triangle_set > &facets_per_type) const
void set_facet (int facet_idx, EnforcerBlockerType state)
void reset ()
void garbage_collect ()
void remap_triangle_state (const EnforcerBlockerStateMap &state_map)
TriangleSplittingData serialize () const
void deserialize (const TriangleSplittingData &data, bool needs_reset=true, EnforcerBlockerType max_ebt=EnforcerBlockerType::ExtruderMax, EnforcerBlockerType to_delete_filament=EnforcerBlockerType::NONE, EnforcerBlockerType replace_filament=EnforcerBlockerType::NONE)
void seed_fill_unselect_all_triangles ()
void shift_states_above (EnforcerBlockerType threshold, int delta)
void seed_fill_apply_on_triangles (EnforcerBlockerType new_state)

Static Public Member Functions

static bool has_facets (const TriangleSplittingData &data, EnforcerBlockerType test_state)
static std::vector< EnforcerBlockerType > extract_used_facet_states (const TriangleSplittingData &data)
static TriangleSplittingData remap_painting (const indexed_triangle_set &source_its, const TriangleSplittingData &source_painting, const indexed_triangle_set &target_its, const Transform3d &target_transform, const std::optional< std::reference_wrapper< const TriangleSplittingData > > &existing_painting)

Protected Member Functions

void append_touching_subtriangles (int itriangle, int vertexi, int vertexj, std::vector< int > &touching_subtriangles_out) const
bool verify_triangle_neighbors (const Triangle &tr, const Vec3i32 &neighbors) const

Protected Attributes

std::vector< Vertex > m_vertices
std::vector< Triangle > m_triangles
const TriangleMesh & m_mesh
const std::vector< Vec3i32 > m_neighbors
const std::vector< Vec3f > m_face_normals
float m_edge_limit = 0.6f
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< Cursor > m_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_partially)
bool select_triangle_recursive (int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting, bool select_partially)
void undivide_triangle (int facet_idx)
void split_triangle (int facet_idx, const Vec3i32 &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 Vec3i32 &neighbors, EnforcerBlockerType old_state)
Vec3i32 child_neighbors (const Triangle &tr, const Vec3i32 &neighbors, int child_idx) const
Vec3i32 child_neighbors_propagated (const Triangle &tr, const Vec3i32 &neighbors_propagated, int child_idx, const Vec3i32 &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_edges (int itriangle, int vertexi, int vertexj, std::vector< Vec2i32 > &touching_edges_out) const
bool verify_triangle_midpoints (const Triangle &tr) const
void get_facets_strict_recursive (const Triangle &tr, const Vec3i32 &neighbors, EnforcerBlockerType state, std::vector< stl_triangle_vertex_indices > &out_triangles) const
void get_facets_split_by_tjoints (const Vec3i32 &vertices, const Vec3i32 &neighbors, std::vector< stl_triangle_vertex_indices > &out_triangles) const
void get_seed_fill_contour_recursive (int facet_idx, const Vec3i32 &neighbors, const Vec3i32 &neighbors_propagated, std::vector< Vec2i32 > &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 }

Friends

class TriangleCursor

Detailed Description


Class Documentation

◆ Slic3r::TriangleSelector::SavedPainting

struct Slic3r::TriangleSelector::SavedPainting
Collaboration diagram for Slic3r::TriangleSelector::SavedPainting:
Class Members
TriangleSplittingData fuzzy
TriangleMesh mesh
TriangleSplittingData mmu
TriangleSplittingData seam
TriangleSplittingData supported

Member Enumeration Documentation

◆ CursorType

Enumerator
CIRCLE 
SPHERE 
POINTER 
HEIGHT_RANGE 
GAP_FILL 
81 {
82 CIRCLE,
83 SPHERE,
84 POINTER,
85 // BBS
88 };
@ POINTER
Definition TriangleSelector.hpp:84
@ HEIGHT_RANGE
Definition TriangleSelector.hpp:86
@ SPHERE
Definition TriangleSelector.hpp:83
@ GAP_FILL
Definition TriangleSelector.hpp:87
@ CIRCLE
Definition TriangleSelector.hpp:82

◆ Partition

enum class Slic3r::TriangleSelector::Partition
strongprivate
Enumerator
First 
Second 
565 {
566 First,
567 Second,
568 };

Constructor & Destructor Documentation

◆ TriangleSelector()

Slic3r::TriangleSelector::TriangleSelector ( const TriangleMesh & mesh,
float edge_limit = 0.6f )
explicit
1345 : m_mesh{mesh}, m_neighbors(its_face_neighbors(mesh.its)), m_face_normals(its_face_normals(mesh.its)), m_edge_limit(edge_limit)
1346{
1347 reset();
1348}
const std::vector< Vec3i32 > m_neighbors
Definition TriangleSelector.hpp:531
const std::vector< Vec3f > m_face_normals
Definition TriangleSelector.hpp:532
const TriangleMesh & m_mesh
Definition TriangleSelector.hpp:530
void reset()
Definition TriangleSelector.cpp:1350
float m_edge_limit
Definition TriangleSelector.hpp:535
std::vector< Vec3i32 > its_face_neighbors(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1615
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_edge_limit, m_face_normals, m_mesh, m_neighbors, and reset().

Referenced by Slic3r::GUI::TriangleSelectorGUI::TriangleSelectorGUI(), remap_painting(), and serialize().

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

Member Function Documentation

◆ append_touching_edges()

void Slic3r::TriangleSelector::append_touching_edges ( int itriangle,
int vertexi,
int vertexj,
std::vector< Vec2i32 > & touching_edges_out ) const
private
513{
514 if (itriangle == -1)
515 return;
516
517 auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_edges_out](const int subtriangle_idx, Partition partition) -> void {
518 assert(subtriangle_idx != -1);
519 if (!m_triangles[subtriangle_idx].is_split()) {
520 if (!m_triangles[subtriangle_idx].is_selected_by_seed_fill()) {
521 int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj);
522 if (partition == Partition::First && midpoint != -1) {
523 touching_edges_out.emplace_back(vertexi, midpoint);
524 } else if (partition == Partition::First && midpoint == -1) {
525 touching_edges_out.emplace_back(vertexi, vertexj);
526 } else {
527 assert(midpoint != -1 && partition == Partition::Second);
528 touching_edges_out.emplace_back(midpoint, vertexj);
529 }
530 }
531 } else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
532 append_touching_edges(subtriangle_idx, partition == Partition::First ? vertexi : midpoint, partition == Partition::First ? midpoint : vertexj,
533 touching_edges_out);
534 else
535 append_touching_edges(subtriangle_idx, vertexi, vertexj, touching_edges_out);
536 };
537
538 std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj);
539 if (touching.first != -1)
540 process_subtriangle(touching.first, Partition::First);
541
542 if (touching.second != -1)
543 process_subtriangle(touching.second, Partition::Second);
544}
Partition
Definition TriangleSelector.hpp:565
@ First
Definition TriangleSelector.hpp:566
@ Second
Definition TriangleSelector.hpp:567
static std::pair< int, int > triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj)
Definition TriangleSelector.cpp:701
int triangle_midpoint(const Triangle &tr, int vertexi, int vertexj) const
Definition TriangleSelector.cpp:732
std::vector< Triangle > m_triangles
Definition TriangleSelector.hpp:529
void append_touching_edges(int itriangle, int vertexi, int vertexj, std::vector< Vec2i32 > &touching_edges_out) const
Definition TriangleSelector.cpp:512

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
protected
488{
489 if (itriangle == -1)
490 return;
491
492 auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_subtriangles_out](const int subtriangle_idx, Partition partition) -> void {
493 assert(subtriangle_idx != -1);
494 if (!m_triangles[subtriangle_idx].is_split())
495 touching_subtriangles_out.emplace_back(subtriangle_idx);
496 else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
497 append_touching_subtriangles(subtriangle_idx, partition == Partition::First ? vertexi : midpoint, partition == Partition::First ? midpoint : vertexj, touching_subtriangles_out);
498 else
499 append_touching_subtriangles(subtriangle_idx, vertexi, vertexj, touching_subtriangles_out);
500 };
501
502 std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj);
503 if (touching.first != -1)
504 process_subtriangle(touching.first, Partition::First);
505
506 if (touching.second != -1)
507 process_subtriangle(touching.second, Partition::Second);
508}
void append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector< int > &touching_subtriangles_out) const
Definition TriangleSelector.cpp:487

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

Referenced by append_touching_subtriangles(), bucket_fill_select_triangles(), and Slic3r::GUI::TriangleSelectorPatch::update_triangles_per_patch().

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,
float seed_fill_angle,
bool propagate,
bool force_reselection = false )
548{
549 int start_facet_idx = select_unsplit_triangle(hit, facet_start);
550 assert(start_facet_idx != -1);
551 // Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill or a clipping plane is active.
552 if (start_facet_idx == -1 || (m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection && !clp.is_active()))
553 return;
554
555 assert(!m_triangles[start_facet_idx].is_split());
556 EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state();
558
559 if (!propagate) {
560 m_triangles[start_facet_idx].select_by_seed_fill();
561 return;
562 }
563
564 // seed_fill_angle < 0.f to disable edge detection
565 const double facet_angle_limit = (seed_fill_angle < 0.f ? -1.f : cos(Geometry::deg2rad(seed_fill_angle))) - EPSILON;
566
567 auto get_all_touching_triangles = [this](int facet_idx, const Vec3i32 &neighbors, const Vec3i32 &neighbors_propagated) -> std::vector<int> {
568 assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
569 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
570 std::vector<int> touching_triangles;
571 Vec3i32 vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
572 append_touching_subtriangles(neighbors(0), vertices(1), vertices(0), touching_triangles);
573 append_touching_subtriangles(neighbors(1), vertices(2), vertices(1), touching_triangles);
574 append_touching_subtriangles(neighbors(2), vertices(0), vertices(2), touching_triangles);
575
576 for (int neighbor_idx : neighbors_propagated)
577 if (neighbor_idx != -1 && !m_triangles[neighbor_idx].is_split())
578 touching_triangles.emplace_back(neighbor_idx);
579
580 return touching_triangles;
581 };
582
583 auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors();
584 std::vector<bool> visited(m_triangles.size(), false);
585 std::queue<int> facet_queue;
586
587 facet_queue.push(start_facet_idx);
588 while (!facet_queue.empty()) {
589 int current_facet = facet_queue.front();
590 facet_queue.pop();
591 assert(!m_triangles[current_facet].is_split());
592
593 if (!visited[current_facet]) {
594 m_triangles[current_facet].select_by_seed_fill();
595
596 std::vector<int> touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]);
597 for(const int tr_idx : touching_triangles) {
598 if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state || is_facet_clipped(tr_idx, clp))
599 continue;
600
601 const Vec3f& n1 = m_face_normals[m_triangles[tr_idx].source_triangle];
602 const Vec3f& n2 = m_face_normals[m_triangles[current_facet].source_triangle];
603 if (seed_fill_angle >= -EPSILON && std::clamp(n1.dot(n2), 0.f, 1.f) < facet_angle_limit)
604 continue;
605
606 assert(!m_triangles[tr_idx].is_split());
607 facet_queue.push(tr_idx);
608 }
609 }
610
611 visited[current_facet] = true;
612 }
613}
#define EPSILON
Definition ColorUtils.cpp:64
void seed_fill_unselect_all_triangles()
Definition TriangleSelector.cpp:2055
bool is_facet_clipped(int facet_idx, const ClippingPlane &clp) const
Definition TriangleSelector.cpp:377
int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const
Definition TriangleSelector.cpp:290
std::pair< std::vector< Vec3i32 >, std::vector< Vec3i32 > > precompute_all_neighbors() const
Definition TriangleSelector.cpp:471
bool verify_triangle_neighbors(const Triangle &tr, const Vec3i32 &neighbors) const
Definition TriangleSelector.cpp:159
constexpr T deg2rad(const T angle)
Definition Geometry.hpp:312
EnforcerBlockerType
Definition TriangleSelector.hpp:24
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65
Eigen::Matrix< int32_t, 3, 1, Eigen::DontAlign > Vec3i32
Definition Point.hpp:59

References append_touching_subtriangles(), Slic3r::Geometry::deg2rad(), EPSILON, Slic3r::TriangleSelector::ClippingPlane::is_active(), is_facet_clipped(), m_face_normals, 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()

Vec3i32 Slic3r::TriangleSelector::child_neighbors ( const Triangle & tr,
const Vec3i32 & neighbors,
int child_idx ) const
private
812{
813 assert(this->verify_triangle_neighbors(tr, neighbors));
814
815 assert(child_idx >= 0 && child_idx <= tr.number_of_split_sides());
816 int i = tr.special_side();
817 int j = next_idx_modulo(i, 3);
818 int k = next_idx_modulo(j, 3);
819
820 Vec3i32 out;
821 switch (tr.number_of_split_sides()) {
822 case 1:
823 switch (child_idx) {
824 case 0:
825 out(0) = neighbors(i);
826 out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second);
827 out(2) = tr.children[1];
828 break;
829 default:
830 assert(child_idx == 1);
831 out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First);
832 out(1) = neighbors(k);
833 out(2) = tr.children[0];
834 break;
835 }
836 break;
837
838 case 2:
839 switch (child_idx) {
840 case 0:
841 out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second);
842 out(1) = tr.children[1];
843 out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First);
844 break;
845 case 1:
846 assert(child_idx == 1);
847 out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First);
848 out(1) = tr.children[2];
849 out(2) = tr.children[0];
850 break;
851 default:
852 assert(child_idx == 2);
853 out(0) = neighbors(j);
854 out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second);
855 out(2) = tr.children[1];
856 break;
857 }
858 break;
859
860 case 3:
861 assert(tr.special_side() == 0);
862 switch (child_idx) {
863 case 0:
864 out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second);
865 out(1) = tr.children[3];
866 out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First);
867 break;
868 case 1:
869 out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First);
870 out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second);
871 out(2) = tr.children[3];
872 break;
873 case 2:
874 out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First);
875 out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second);
876 out(2) = tr.children[3];
877 break;
878 default:
879 assert(child_idx == 3);
880 out(0) = tr.children[1];
881 out(1) = tr.children[2];
882 out(2) = tr.children[0];
883 break;
884 }
885 break;
886
887 default:
888 assert(false);
889 }
890
891 assert(this->verify_triangle_neighbors(tr, neighbors));
892 assert(this->verify_triangle_neighbors(m_triangles[tr.children[child_idx]], out));
893 return out;
894}
int neighbor_child(const Triangle &tr, int vertexi, int vertexj, Partition partition) const
Definition TriangleSelector.cpp:652
INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
Definition Utils.hpp:453

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()

Vec3i32 Slic3r::TriangleSelector::child_neighbors_propagated ( const Triangle & tr,
const Vec3i32 & neighbors_propagated,
int child_idx,
const Vec3i32 & child_neighbors ) const
private
899{
900 int i = tr.special_side();
901 int j = next_idx_modulo(i, 3);
902 int k = next_idx_modulo(j, 3);
903
905 auto replace_if_not_exists = [&out, &neighbors_propagated](int index_to_replace, int neighbor_idx) {
906 if (out(index_to_replace) == -1)
907 out(index_to_replace) = neighbors_propagated(neighbor_idx);
908 };
909
910 switch (tr.number_of_split_sides()) {
911 case 1:
912 switch (child_idx) {
913 case 0:
914 replace_if_not_exists(0, i);
915 replace_if_not_exists(1, j);
916 break;
917 default:
918 assert(child_idx == 1);
919 replace_if_not_exists(0, j);
920 replace_if_not_exists(1, k);
921 break;
922 }
923 break;
924
925 case 2:
926 switch (child_idx) {
927 case 0:
928 replace_if_not_exists(0, i);
929 replace_if_not_exists(2, k);
930 break;
931 case 1:
932 assert(child_idx == 1);
933 replace_if_not_exists(0, i);
934 break;
935 default:
936 assert(child_idx == 2);
937 replace_if_not_exists(0, j);
938 replace_if_not_exists(1, k);
939 break;
940 }
941 break;
942
943 case 3:
944 assert(tr.special_side() == 0);
945 switch (child_idx) {
946 case 0:
947 replace_if_not_exists(0, 0);
948 replace_if_not_exists(2, 2);
949 break;
950 case 1:
951 replace_if_not_exists(0, 0);
952 replace_if_not_exists(1, 1);
953 break;
954 case 2:
955 replace_if_not_exists(0, 1);
956 replace_if_not_exists(1, 2);
957 break;
958 default:
959 assert(child_idx == 3);
960 break;
961 }
962 break;
963
964 default: assert(false);
965 }
966
967 return out;
968}
Vec3i32 child_neighbors(const Triangle &tr, const Vec3i32 &neighbors, int child_idx) const
Definition TriangleSelector.cpp:811

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 TriangleSplittingData & data,
bool needs_reset = true,
EnforcerBlockerType max_ebt = EnforcerBlockerType::ExtruderMax,
EnforcerBlockerType to_delete_filament = EnforcerBlockerType::NONE,
EnforcerBlockerType replace_filament = EnforcerBlockerType::NONE )
1818{
1819 if (needs_reset)
1820 reset(); // dump any current state
1821 for (auto [triangle_id, ibit] : data.triangles_to_split) {
1822 if (triangle_id >= int(m_triangles.size())) {
1823 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "array bound:error:triangle_id >= int(m_triangles.size())";
1824 return;
1825 }
1826 }
1827 // Reserve number of triangles as if each triangle was saved with 4 bits.
1828 // With MMU painting this estimate may be somehow low, but better than nothing.
1829 m_triangles.reserve(std::max(m_mesh.its.indices.size(), data.bitstream.size() / 4));
1830 // Number of triangles is twice the number of vertices on a large manifold mesh of genus zero.
1831 // Here the triangles count account for both the nodes and leaves, thus the following line may overestimate.
1832 m_vertices.reserve(std::max(m_mesh.its.vertices.size(), m_triangles.size() / 2));
1833
1834 // Vector to store all parents that have offsprings.
1835 struct ProcessingInfo {
1836 int facet_id = 0;
1837 Vec3i32 neighbors { -1, -1, -1 };
1838 int processed_children = 0;
1839 int total_children = 0;
1840 };
1841 // Depth-first queue of a source mesh triangle and its childern.
1842 // kept outside of the loop to avoid re-allocating inside the loop.
1843 std::vector<ProcessingInfo> parents;
1844
1845 for (auto [triangle_id, ibit] : data.triangles_to_split) {
1846 assert(triangle_id < int(m_triangles.size()));
1847 // Set when the bitstream runs out or holds an impossible split before this triangle's tree is complete.
1848 bool corrupt = false;
1849 auto next_nibble = [&data, &ibit = ibit, &corrupt]() {
1850 int n = 0;
1851 if (! data.read_nibble(ibit, n))
1852 corrupt = true;
1853 return n;
1854 };
1855 // Decode a leaf state stored behind the "11" prefix: one nibble of (state-3) for states
1856 // 3..17, or 0b1111 followed by a nibble of (state-18) above that.
1857 auto decode_leaf_state = [&next_nibble]() {
1858 const int nibble = next_nibble();
1859 return EnforcerBlockerType(nibble == 0b1111 ? next_nibble() + 18 : nibble + 3);
1860 };
1861
1862 parents.clear();
1863 while (true) {
1864 // Read next triangle info.
1865 int code = next_nibble();
1866 int num_of_split_sides = code & 0b11;
1867 int num_of_children = num_of_split_sides == 0 ? 0 : num_of_split_sides + 1;
1868 bool is_split = num_of_children != 0;
1869 // Only valid if not is_split.
1870 auto state = is_split ? EnforcerBlockerType::NONE : ((code & 0b1100) == 0b1100 ? decode_leaf_state() : EnforcerBlockerType(code >> 2));
1871 if (is_split && ! split_code_valid(code))
1872 corrupt = true;
1873 if (corrupt)
1874 break;
1875
1876 // BBS
1877 if (state == to_delete_filament)
1878 state = replace_filament;
1879 else if (to_delete_filament != EnforcerBlockerType::NONE && state != EnforcerBlockerType::NONE) {
1880 state = state > to_delete_filament ? EnforcerBlockerType((int)state - 1) : state;
1881 }
1882
1883 if (state > max_ebt) {
1884 assert(false);
1886 }
1887
1888 // Only valid if is_split.
1889 int special_side = num_of_split_sides == 3 ? 0 : code >> 2;
1890
1891 // Take care of the first iteration separately, so handling of the others is simpler.
1892 if (parents.empty()) {
1893 if (is_split) {
1894 // root is split, add it into list of parents and split it.
1895 // then go to the next.
1896 Vec3i32 neighbors = m_neighbors[triangle_id];
1897 parents.push_back({triangle_id, neighbors, 0, num_of_children});
1898 m_triangles[triangle_id].set_division(num_of_split_sides, special_side);
1899 perform_split(triangle_id, neighbors, EnforcerBlockerType::NONE);
1900 continue;
1901 } else {
1902 // root is not split. just set the state and that's it.
1903 m_triangles[triangle_id].set_state(state);
1904 break;
1905 }
1906 }
1907
1908 // This is not the first iteration. This triangle is a child of last seen parent.
1909 assert(! parents.empty());
1910 assert(parents.back().processed_children < parents.back().total_children);
1911
1912 if (ProcessingInfo& last = parents.back(); is_split) {
1913 // split the triangle and save it as parent of the next ones.
1914 const Triangle &tr = m_triangles[last.facet_id];
1915 int child_idx = last.total_children - last.processed_children - 1;
1916 Vec3i32 neighbors = this->child_neighbors(tr, last.neighbors, child_idx);
1917 int this_idx = tr.children[child_idx];
1918 m_triangles[this_idx].set_division(num_of_split_sides, special_side);
1919 perform_split(this_idx, neighbors, EnforcerBlockerType::NONE);
1920 parents.push_back({this_idx, neighbors, 0, num_of_children});
1921 } else {
1922 // this triangle belongs to last split one
1923 int child_idx = last.total_children - last.processed_children - 1;
1924 m_triangles[m_triangles[last.facet_id].children[child_idx]].set_state(state);
1925 ++last.processed_children;
1926 }
1927
1928 // If all children of the past parent triangle are claimed, move to grandparent.
1929 while (parents.back().processed_children == parents.back().total_children) {
1930 parents.pop_back();
1931
1932 if (parents.empty())
1933 break;
1934
1935 // And increment the grandparent children counter, because
1936 // we have just finished that branch and got back here.
1937 ++parents.back().processed_children;
1938 }
1939
1940 // In case we popped back the root, we should be done.
1941 if (parents.empty())
1942 break;
1943 }
1944
1945 if (corrupt) {
1946 // Every split above allocated all of its children, so the partial tree unwinds cleanly.
1947 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": malformed paint data, dropping paint of triangle " << triangle_id;
1948 undivide_triangle(triangle_id);
1949 m_triangles[triangle_id].set_state(EnforcerBlockerType::NONE);
1950 }
1951 }
1952}
Definition TriangleSelector.hpp:450
void perform_split(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType old_state)
Definition TriangleSelector.cpp:1408
std::vector< Vertex > m_vertices
Definition TriangleSelector.hpp:528
void undivide_triangle(int facet_idx)
Definition TriangleSelector.cpp:1198
static bool split_code_valid(int code)
Definition TriangleSelector.cpp:1808
@ NONE
Definition TriangleSelector.hpp:26

References Slic3r::TriangleSelector::TriangleSplittingData::bitstream, child_neighbors(), Slic3r::TriangleSelector::Triangle::children, m_mesh, m_neighbors, m_triangles, m_vertices, Slic3r::NONE, perform_split(), Slic3r::TriangleSelector::TriangleSplittingData::read_nibble(), reset(), Slic3r::split_code_valid(), Slic3r::TriangleSelector::TriangleSplittingData::triangles_to_split, and undivide_triangle().

Referenced by Slic3r::build_texture_displacement_in_place(), Slic3r::anonymous_namespace{TextureDisplacement.cpp}::build_texture_displacement_v2(), Slic3r::GUI::GLGizmoTextureDisplacement::collect_paint_region(), Slic3r::extract_painted_patch(), Slic3r::SeamPlacerImpl::gather_enforcers_blockers(), Slic3r::FacetsAnnotation::get_facets(), Slic3r::FacetsAnnotation::get_facets(), Slic3r::FacetsAnnotation::get_facets_strict(), Slic3r::GUI::GLGizmoTextureDisplacement::painted_colors(), Slic3r::anonymous_namespace{TextureDisplacement.cpp}::prepare_sampleable_layers(), Slic3r::GUI::GLGizmoTextureDisplacement::rebuild_other_paint_overlay(), remap_painting(), Slic3r::FacetsAnnotation::remap_states(), Slic3r::GUI::anonymous_namespace{GLGizmoTextureDisplacement.cpp}::remap_texture_paint_spatial(), Slic3r::FacetsAnnotation::set_enforcer_block_type_limit(), Slic3r::FacetsAnnotation::shift_states_above(), and Slic3r::transfer_facet_paint().

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

◆ extract_used_facet_states()

std::vector< EnforcerBlockerType > Slic3r::TriangleSelector::extract_used_facet_states ( const TriangleSplittingData & data)
static
2341{
2342 std::vector<EnforcerBlockerType> out;
2343 for (size_t i = 0; i < data.used_states.size(); ++i) {
2344 if (data.used_states[i])
2345 out.push_back(static_cast<EnforcerBlockerType>(i));
2346 }
2347 return out;
2348}

References Slic3r::TriangleSelector::TriangleSplittingData::used_states.

Referenced by Slic3r::GUI::GLGizmoTextureDisplacement::painted_colors(), and Slic3r::GUI::GLGizmoMmuSegmentation::update_used_filaments().

Here is the caller graph for this function:

◆ garbage_collect()

void Slic3r::TriangleSelector::garbage_collect ( )
1275{
1276 // First make a map from old to new triangle indices.
1277 int new_idx = m_orig_size_indices;
1278 std::vector<int> new_triangle_indices(m_triangles.size(), -1);
1279 for (int i = m_orig_size_indices; i<int(m_triangles.size()); ++i)
1280 if (m_triangles[i].valid())
1281 new_triangle_indices[i] = new_idx ++;
1282
1283 // Now we know which vertices are not referenced anymore. Make a map
1284 // from old idxs to new ones, like we did for triangles.
1285 new_idx = m_orig_size_vertices;
1286 std::vector<int> new_vertices_indices(m_vertices.size(), -1);
1287 for (int i=m_orig_size_vertices; i<int(m_vertices.size()); ++i) {
1288 assert(m_vertices[i].ref_cnt >= 0);
1289 if (m_vertices[i].ref_cnt != 0)
1290 new_vertices_indices[i] = new_idx ++;
1291 }
1292
1293 // We can remove all invalid triangles and vertices that are no longer referenced.
1294 m_triangles.erase(std::remove_if(m_triangles.begin()+m_orig_size_indices, m_triangles.end(),
1295 [](const Triangle& tr) { return ! tr.valid(); }),
1296 m_triangles.end());
1297 m_vertices.erase(std::remove_if(m_vertices.begin()+m_orig_size_vertices, m_vertices.end(),
1298 [](const Vertex& vert) { return vert.ref_cnt == 0; }),
1299 m_vertices.end());
1300
1301 // Now go through all remaining triangles and update changed indices.
1302 for (Triangle& tr : m_triangles) {
1303 assert(tr.valid());
1304
1305 if (tr.is_split()) {
1306 // There are children. Update their indices.
1307 for (int j=0; j<=tr.number_of_split_sides(); ++j) {
1308 assert(new_triangle_indices[tr.children[j]] != -1);
1309 tr.children[j] = new_triangle_indices[tr.children[j]];
1310 }
1311 }
1312
1313 // Update indices into m_vertices. The original vertices are never
1314 // touched and need not be reindexed.
1315 for (int& idx : tr.verts_idxs) {
1316 if (idx >= m_orig_size_vertices) {
1317 assert(new_vertices_indices[idx] != -1);
1318 idx = new_vertices_indices[idx];
1319 }
1320 }
1321 }
1322
1326}
int m_free_triangles_head
Definition TriangleSelector.hpp:595
int m_invalid_triangles
Definition TriangleSelector.hpp:538
int m_free_vertices_head
Definition TriangleSelector.hpp:596
int m_orig_size_vertices
Definition TriangleSelector.hpp:544
int m_orig_size_indices
Definition TriangleSelector.hpp:545
Definition TriangleSelector.hpp:514

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() [1/2]

indexed_triangle_set Slic3r::TriangleSelector::get_facets ( EnforcerBlockerType state) const
1493{
1494 indexed_triangle_set out;
1495 std::vector<int> vertex_map(m_vertices.size(), -1);
1496 for (const Triangle& tr : m_triangles) {
1497 if (tr.valid() && ! tr.is_split() && tr.get_state() == state) {
1498 stl_triangle_vertex_indices indices;
1499 for (int i=0; i<3; ++i) {
1500 int j = tr.verts_idxs[i];
1501 if (vertex_map[j] == -1) {
1502 vertex_map[j] = int(out.vertices.size());
1503 out.vertices.emplace_back(m_vertices[j].v);
1504 }
1505 indices[i] = vertex_map[j];
1506 }
1507 out.indices.emplace_back(indices);
1508 }
1509 }
1510 return out;
1511}

References m_triangles, and m_vertices.

Referenced by Slic3r::SeamPlacerImpl::gather_enforcers_blockers(), Slic3r::FacetsAnnotation::get_facets(), Slic3r::FacetsAnnotation::get_facets(), and Slic3r::transfer_facet_paint().

Here is the caller graph for this function:

◆ get_facets() [2/2]

void Slic3r::TriangleSelector::get_facets ( std::vector< indexed_triangle_set > & facets_per_type) const
1515{
1516 facets_per_type.clear();
1517
1518 for (int type = (int)EnforcerBlockerType::NONE; type <= (int)EnforcerBlockerType::ExtruderMax; type++) {
1519 facets_per_type.emplace_back();
1520 indexed_triangle_set& its = facets_per_type.back();
1521 std::vector<int> vertex_map(m_vertices.size(), -1);
1522
1523 for (const Triangle& tr : m_triangles) {
1524 if (tr.valid() && !tr.is_split() && tr.get_state() == (EnforcerBlockerType)type) {
1525 stl_triangle_vertex_indices indices;
1526 for (int i = 0; i < 3; ++i) {
1527 int j = tr.verts_idxs[i];
1528 if (vertex_map[j] == -1) {
1529 vertex_map[j] = int(its.vertices.size());
1530 its.vertices.emplace_back(m_vertices[j].v);
1531 }
1532 indices[i] = vertex_map[j];
1533 }
1534 its.indices.emplace_back(indices);
1535 }
1536 }
1537 }
1538}
@ ExtruderMax
Definition TriangleSelector.hpp:66

References Slic3r::ExtruderMax, m_triangles, m_vertices, and Slic3r::NONE.

◆ get_facets_split_by_tjoints()

void Slic3r::TriangleSelector::get_facets_split_by_tjoints ( const Vec3i32 & vertices,
const Vec3i32 & neighbors,
std::vector< stl_triangle_vertex_indices > & out_triangles ) const
private
1590{
1591// Export this triangle, but first collect the T-joint vertices along its edges.
1592 Vec3i32 midpoints(
1593 this->triangle_midpoint(neighbors(0), vertices(1), vertices(0)),
1594 this->triangle_midpoint(neighbors(1), vertices(2), vertices(1)),
1595 this->triangle_midpoint(neighbors(2), vertices(0), vertices(2)));
1596 int splits = (midpoints(0) != -1) + (midpoints(1) != -1) + (midpoints(2) != -1);
1597 switch (splits) {
1598 case 0:
1599 // Just emit this triangle.
1600 out_triangles.emplace_back(vertices(0), vertices(1), vertices(2));
1601 break;
1602 case 1:
1603 {
1604 // Split to two triangles
1605 int i = midpoints(0) != -1 ? 2 : midpoints(1) != -1 ? 0 : 1;
1606 int j = next_idx_modulo(i, 3);
1607 int k = next_idx_modulo(j, 3);
1609 { vertices(i), vertices(j), midpoints(j) },
1610 { neighbors(i),
1611 this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::Second),
1612 -1 },
1613 out_triangles);
1615 { midpoints(j), vertices(k), vertices(i) },
1616 { this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::First),
1617 neighbors(k),
1618 -1 },
1619 out_triangles);
1620 break;
1621 }
1622 case 2:
1623 {
1624 // Split to three triangles.
1625 int i = midpoints(0) == -1 ? 2 : midpoints(1) == -1 ? 0 : 1;
1626 int j = next_idx_modulo(i, 3);
1627 int k = next_idx_modulo(j, 3);
1629 { vertices(i), midpoints(i), midpoints(k) },
1630 { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::Second),
1631 -1,
1632 this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::First) },
1633 out_triangles);
1635 { midpoints(i), vertices(j), midpoints(k) },
1636 { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::First),
1637 -1, -1 },
1638 out_triangles);
1640 { vertices(j), vertices(k), midpoints(k) },
1641 { neighbors(j),
1642 this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::Second),
1643 -1 },
1644 out_triangles);
1645 break;
1646 }
1647 default:
1648 assert(splits == 3);
1649 // Split to 4 triangles.
1651 { vertices(0), midpoints(0), midpoints(2) },
1652 { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::Second),
1653 -1,
1654 this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::First) },
1655 out_triangles);
1657 { midpoints(0), vertices(1), midpoints(1) },
1658 { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::First),
1659 this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::Second),
1660 -1 },
1661 out_triangles);
1663 { midpoints(1), vertices(2), midpoints(2) },
1664 { this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::First),
1665 this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::Second),
1666 -1 },
1667 out_triangles);
1668 out_triangles.emplace_back(midpoints);
1669 break;
1670 }
1671}
void get_facets_split_by_tjoints(const Vec3i32 &vertices, const Vec3i32 &neighbors, std::vector< stl_triangle_vertex_indices > &out_triangles) const
Definition TriangleSelector.cpp:1589

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,
std::vector< int > * out_source = nullptr ) const
1541{
1542 indexed_triangle_set out;
1543 if (out_source)
1544 out_source->clear();
1545
1546 size_t num_vertices = 0;
1547 for (const Vertex &v : m_vertices)
1548 if (v.ref_cnt > 0)
1549 ++ num_vertices;
1550 out.vertices.reserve(num_vertices);
1551 std::vector<int> vertex_map(m_vertices.size(), -1);
1552 for (size_t i = 0; i < m_vertices.size(); ++ i)
1553 if (const Vertex &v = m_vertices[i]; v.ref_cnt > 0) {
1554 vertex_map[i] = int(out.vertices.size());
1555 out.vertices.emplace_back(v.v);
1556 }
1557
1558 for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle) {
1559 this->get_facets_strict_recursive(m_triangles[itriangle], m_neighbors[itriangle], state, out.indices);
1560 // Everything the recursion just appended came from this original triangle, whatever depth it
1561 // was split to. Recording it here keeps the recursive helpers untouched.
1562 if (out_source)
1563 out_source->resize(out.indices.size(), itriangle);
1564 }
1565
1566 for (auto &triangle : out.indices)
1567 for (int i = 0; i < 3; ++ i)
1568 triangle(i) = vertex_map[triangle(i)];
1569
1570 return out;
1571}
void get_facets_strict_recursive(const Triangle &tr, const Vec3i32 &neighbors, EnforcerBlockerType state, std::vector< stl_triangle_vertex_indices > &out_triangles) const
Definition TriangleSelector.cpp:1573

References get_facets_strict_recursive(), m_neighbors, m_orig_size_indices, m_triangles, and m_vertices.

Referenced by Slic3r::build_texture_displacement_in_place(), Slic3r::anonymous_namespace{TextureDisplacement.cpp}::build_texture_displacement_v2(), Slic3r::GUI::GLGizmoTextureDisplacement::collect_paint_region(), Slic3r::extract_painted_patch(), Slic3r::SeamPlacerImpl::gather_enforcers_blockers(), Slic3r::FacetsAnnotation::get_facets_strict(), Slic3r::GUI::GLGizmoTextureDisplacement::painted_colors(), Slic3r::anonymous_namespace{TextureDisplacement.cpp}::prepare_sampleable_layers(), Slic3r::GUI::GLGizmoTextureDisplacement::rebuild_other_paint_overlay(), and Slic3r::GUI::anonymous_namespace{GLGizmoTextureDisplacement.cpp}::remap_texture_paint_spatial().

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 Vec3i32 & neighbors,
EnforcerBlockerType state,
std::vector< stl_triangle_vertex_indices > & out_triangles ) const
private
1578{
1579 if (tr.is_split()) {
1580 for (int i = 0; i <= tr.number_of_split_sides(); ++ i)
1582 m_triangles[tr.children[i]],
1583 this->child_neighbors(tr, neighbors, i),
1584 state, out_triangles);
1585 } else if (tr.get_state() == state)
1586 this->get_facets_split_by_tjoints({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, out_triangles);
1587}

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< Vec2i32 > Slic3r::TriangleSelector::get_seed_fill_contour ( ) const
1673 {
1674 std::vector<Vec2i32> edges_out;
1675 for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
1676 const Vec3i32 neighbors = m_neighbors[facet_idx];
1677 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
1678 this->get_seed_fill_contour_recursive(facet_idx, neighbors, neighbors, edges_out);
1679 }
1680
1681 return edges_out;
1682}
void get_seed_fill_contour_recursive(int facet_idx, const Vec3i32 &neighbors, const Vec3i32 &neighbors_propagated, std::vector< Vec2i32 > &edges_out) const
Definition TriangleSelector.cpp:1684

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 Vec3i32 & neighbors,
const Vec3i32 & neighbors_propagated,
std::vector< Vec2i32 > & edges_out ) const
private
1684 {
1685 assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
1686 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
1687 const Triangle *tr = &m_triangles[facet_idx];
1688 if (!tr->valid())
1689 return;
1690
1691 if (tr->is_split()) {
1692 int num_of_children = tr->number_of_split_sides() + 1;
1693 if (num_of_children != 1) {
1694 for (int i = 0; i < num_of_children; ++i) {
1695 assert(i < int(tr->children.size()));
1696 assert(tr->children[i] < int(m_triangles.size()));
1697 // Recursion, deep first search over the children of this triangle.
1698 // All children of this triangle were created by splitting a single source triangle of the original mesh.
1699 const Vec3i32 child_neighbors = this->child_neighbors(*tr, neighbors, i);
1700 this->get_seed_fill_contour_recursive(tr->children[i], child_neighbors,
1701 this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), edges_out);
1702 }
1703 }
1704 } else if (tr->is_selected_by_seed_fill()) {
1705 Vec3i32 vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
1706 append_touching_edges(neighbors(0), vertices(1), vertices(0), edges_out);
1707 append_touching_edges(neighbors(1), vertices(2), vertices(1), edges_out);
1708 append_touching_edges(neighbors(2), vertices(0), vertices(2), edges_out);
1709
1710 // It appends the edges that are touching the triangle only by part of the edge that means the triangles are from lower depth.
1711 for (int idx = 0; idx < 3; ++idx)
1712 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())
1713 edges_out.emplace_back(vertices(idx), vertices(next_idx_modulo(idx, 3)));
1714 }
1715}

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 TriangleSplittingData & data,
EnforcerBlockerType test_state )
static
1996 {
1997 // Depth-first queue of a number of unvisited children.
1998 // Kept outside of the loop to avoid re-allocating inside the loop.
1999 std::vector<int> parents_children;
2000 parents_children.reserve(64);
2001
2002 for (const TriangleBitStreamMapping &triangle_id_and_ibit : data.triangles_to_split) {
2003 int ibit = triangle_id_and_ibit.bitstream_start_idx;
2004 // Stop reading a triangle whose stream is truncated.
2005 bool truncated = false;
2006 auto next_nibble = [&data, &ibit = ibit, &truncated]() {
2007 int n = 0;
2008 if (! data.read_nibble(ibit, n))
2009 truncated = true;
2010 return n;
2011 };
2012 // < 0 -> negative of a number of children
2013 // >= 0 -> state
2014 auto num_children_or_state = [&next_nibble]() -> int {
2015 int code = next_nibble();
2016 int num_of_split_sides = code & 0b11;
2017 if (num_of_split_sides != 0)
2018 return - num_of_split_sides - 1;
2019 if ((code & 0b1100) != 0b1100)
2020 return code >> 2;
2021 // Leaf behind the "11" prefix: one nibble of (state-3), or 0b1111 + (state-18).
2022 const int nibble = next_nibble();
2023 return nibble == 0b1111 ? next_nibble() + 18 : nibble + 3;
2024 };
2025
2026 int state = num_children_or_state();
2027 if (truncated)
2028 continue;
2029 if (state < 0) {
2030 // Root is split.
2031 parents_children.clear();
2032 parents_children.emplace_back(- state);
2033 do {
2034 if (-- parents_children.back() >= 0) {
2035 int state = num_children_or_state();
2036 if (truncated)
2037 break;
2038 if (state < 0)
2039 // Child is split.
2040 parents_children.emplace_back(- state);
2041 else if (state == int(test_state))
2042 // Child is not split and a face of test_state was found.
2043 return true;
2044 } else
2045 parents_children.pop_back();
2046 } while (! parents_children.empty());
2047 } else if (state == int(test_state))
2048 // Root is not split and a face of test_state was found.
2049 return true;
2050 }
2051
2052 return false;
2053}
Definition TriangleSelector.hpp:270

References Slic3r::TriangleSelector::TriangleBitStreamMapping::bitstream_start_idx, Slic3r::TriangleSelector::TriangleSplittingData::read_nibble(), and Slic3r::TriangleSelector::TriangleSplittingData::triangles_to_split.

Here is the call graph for this function:

◆ has_facets() [2/2]

bool Slic3r::TriangleSelector::has_facets ( EnforcerBlockerType state) const
1476{
1477 for (const Triangle& tr : m_triangles)
1478 if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
1479 return true;
1480 return false;
1481}

References m_triangles.

Referenced by Slic3r::GUI::GLGizmoTextureDisplacement::collect_paint_region(), Slic3r::FacetsAnnotation::has_facets(), and Slic3r::GUI::GLGizmoTextureDisplacement::prepare_mesh().

Here is the caller graph for this function:

◆ is_facet_clipped()

bool Slic3r::TriangleSelector::is_facet_clipped ( int facet_idx,
const ClippingPlane & clp ) const
private
378{
379 for (int vert_idx : m_triangles[facet_idx].verts_idxs)
380 if (clp.is_active() && clp.is_mesh_point_clipped(m_vertices[vert_idx].v))
381 return true;
382
383 return false;
384}

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
653{
654 if (tr.number_of_split_sides() == 0)
655 // If this triangle is not split, then there is no upper / lower subtriangle sharing the edge.
656 return -1;
657
658 // Find the triangle edge.
659 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
660 assert(tr.verts_idxs[edge] == vertexi);
661 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
662
663 int child_idx;
664 if (tr.number_of_split_sides() == 1) {
665 if (edge != next_idx_modulo(tr.special_side(), 3))
666 // A child may or may not be split at this side.
667 return this->neighbor_child(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj, partition);
668 child_idx = partition == Partition::First ? 0 : 1;
669 } else if (tr.number_of_split_sides() == 2) {
670 if (edge == next_idx_modulo(tr.special_side(), 3))
671 // A child may or may not be split at this side.
672 return this->neighbor_child(m_triangles[tr.children[2]], vertexi, vertexj, partition);
673 child_idx = edge == tr.special_side() ?
674 (partition == Partition::First ? 0 : 1) :
675 (partition == Partition::First ? 2 : 0);
676 } else {
677 assert(tr.number_of_split_sides() == 3);
678 assert(tr.special_side() == 0);
679 switch(edge) {
680 case 0: child_idx = partition == Partition::First ? 0 : 1; break;
681 case 1: child_idx = partition == Partition::First ? 1 : 2; break;
682 default: assert(edge == 2);
683 child_idx = partition == Partition::First ? 2 : 0; break;
684 }
685 }
686 return tr.children[child_idx];
687}

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
692{
693 return itriangle == -1 ? -1 : this->neighbor_child(m_triangles[itriangle], vertexi, vertexj, partition);
694}

References m_triangles, and neighbor_child().

Here is the call graph for this function:

◆ num_facets()

int Slic3r::TriangleSelector::num_facets ( EnforcerBlockerType state) const
1484{
1485 int cnt = 0;
1486 for (const Triangle& tr : m_triangles)
1487 if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
1488 ++ cnt;
1489 return cnt;
1490}

References m_triangles.

◆ perform_split()

void Slic3r::TriangleSelector::perform_split ( int facet_idx,
const Vec3i32 & neighbors,
EnforcerBlockerType old_state )
private
1409{
1410 // Reserve space for the new triangles upfront, so that the reference to this triangle will not change.
1411 {
1412 size_t num_triangles_new = m_triangles.size() + m_triangles[facet_idx].number_of_split_sides() + 1;
1413 if (m_triangles.capacity() < num_triangles_new)
1414 m_triangles.reserve(next_highest_power_of_2(num_triangles_new));
1415 }
1416
1417 Triangle &tr = m_triangles[facet_idx];
1418 assert(tr.is_split());
1419
1420 // indices of triangle vertices
1421#ifdef NDEBUG
1422 boost::container::small_vector<int, 6> verts_idxs;
1423#else // NDEBUG
1424 // For easier debugging.
1425 std::vector<int> verts_idxs;
1426 verts_idxs.reserve(6);
1427#endif // NDEBUG
1428 for (int j=0, idx = tr.special_side(); j<3; ++j, idx = next_idx_modulo(idx, 3))
1429 verts_idxs.push_back(tr.verts_idxs[idx]);
1430
1431 auto get_alloc_vertex = [this, &neighbors, &verts_idxs](int edge, int i1, int i2) -> int {
1432 return this->triangle_midpoint_or_allocate(neighbors(edge), verts_idxs[i1], verts_idxs[i2]);
1433 };
1434
1435 int ichild = 0;
1436 switch (tr.number_of_split_sides()) {
1437 case 1:
1438 verts_idxs.insert(verts_idxs.begin()+2, get_alloc_vertex(next_idx_modulo(tr.special_side(), 3), 2, 1));
1439 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[2], tr.source_triangle, old_state);
1440 tr.children[ichild ] = push_triangle(verts_idxs[2], verts_idxs[3], verts_idxs[0], tr.source_triangle, old_state);
1441 break;
1442
1443 case 2:
1444 verts_idxs.insert(verts_idxs.begin()+1, get_alloc_vertex(tr.special_side(), 1, 0));
1445 verts_idxs.insert(verts_idxs.begin()+4, get_alloc_vertex(prev_idx_modulo(tr.special_side(), 3), 0, 3));
1446 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[4], tr.source_triangle, old_state);
1447 tr.children[ichild ++] = push_triangle(verts_idxs[1], verts_idxs[2], verts_idxs[4], tr.source_triangle, old_state);
1448 tr.children[ichild ] = push_triangle(verts_idxs[2], verts_idxs[3], verts_idxs[4], tr.source_triangle, old_state);
1449 break;
1450
1451 case 3:
1452 assert(tr.special_side() == 0);
1453 verts_idxs.insert(verts_idxs.begin()+1, get_alloc_vertex(0, 1, 0));
1454 verts_idxs.insert(verts_idxs.begin()+3, get_alloc_vertex(1, 3, 2));
1455 verts_idxs.insert(verts_idxs.begin()+5, get_alloc_vertex(2, 0, 4));
1456 tr.children[ichild ++] = push_triangle(verts_idxs[0], verts_idxs[1], verts_idxs[5], tr.source_triangle, old_state);
1457 tr.children[ichild ++] = push_triangle(verts_idxs[1], verts_idxs[2], verts_idxs[3], tr.source_triangle, old_state);
1458 tr.children[ichild ++] = push_triangle(verts_idxs[3], verts_idxs[4], verts_idxs[5], tr.source_triangle, old_state);
1459 tr.children[ichild ] = push_triangle(verts_idxs[1], verts_idxs[3], verts_idxs[5], tr.source_triangle, old_state);
1460 break;
1461
1462 default:
1463 break;
1464 }
1465
1466#ifndef NDEBUG
1467 assert(this->verify_triangle_neighbors(tr, neighbors));
1468 for (int i = 0; i <= tr.number_of_split_sides(); ++i) {
1469 Vec3i32 n = this->child_neighbors(tr, neighbors, i);
1470 assert(this->verify_triangle_neighbors(m_triangles[tr.children[i]], n));
1471 }
1472#endif // NDEBUG
1473}
int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state=EnforcerBlockerType{0})
Definition TriangleSelector.cpp:1374
int triangle_midpoint_or_allocate(int itriangle, int vertexi, int vertexj)
Definition TriangleSelector.cpp:770
uint16_t next_highest_power_of_2(uint16_t v)
Definition Utils.hpp:376
INDEX_TYPE prev_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
Definition Utils.hpp:445

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< Vec3i32 >, std::vector< Vec3i32 > > Slic3r::TriangleSelector::precompute_all_neighbors ( ) const
472{
473 std::vector<Vec3i32> neighbors(m_triangles.size(), Vec3i32(-1, -1, -1));
474 std::vector<Vec3i32> neighbors_propagated(m_triangles.size(), Vec3i32(-1, -1, -1));
475 for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
476 neighbors[facet_idx] = m_neighbors[facet_idx];
477 neighbors_propagated[facet_idx] = neighbors[facet_idx];
478 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx]));
479 if (m_triangles[facet_idx].is_split())
480 this->precompute_all_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors_propagated[facet_idx], neighbors, neighbors_propagated);
481 }
482 return std::make_pair(std::move(neighbors), std::move(neighbors_propagated));
483}
void precompute_all_neighbors_recursive(int facet_idx, const Vec3i32 &neighbors, const Vec3i32 &neighbors_propagated, std::vector< Vec3i32 > &neighbors_out, std::vector< Vec3i32 > &neighbors_normal_out) const
Definition TriangleSelector.cpp:442

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

Referenced by bucket_fill_select_triangles(), and Slic3r::GUI::TriangleSelectorPatch::update_triangles_per_patch().

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 Vec3i32 & neighbors,
const Vec3i32 & neighbors_propagated,
std::vector< Vec3i32 > & neighbors_out,
std::vector< Vec3i32 > & neighbors_normal_out ) const
443{
444 assert(facet_idx < int(m_triangles.size()));
445
446 const Triangle *tr = &m_triangles[facet_idx];
447 if (!tr->valid())
448 return;
449
450 neighbors_out[facet_idx] = neighbors;
451 neighbors_propagated_out[facet_idx] = neighbors_propagated;
452 if (tr->is_split()) {
453 assert(this->verify_triangle_neighbors(*tr, neighbors));
454
455 int num_of_children = tr->number_of_split_sides() + 1;
456 if (num_of_children != 1) {
457 for (int i = 0; i < num_of_children; ++i) {
458 assert(i < int(tr->children.size()));
459 assert(tr->children[i] < int(m_triangles.size()));
460 // Recursion, deep first search over the children of this triangle.
461 // All children of this triangle were created by splitting a single source triangle of the original mesh.
462 const Vec3i32 child_neighbors = this->child_neighbors(*tr, neighbors, i);
464 this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), neighbors_out,
465 neighbors_propagated_out);
466 }
467 }
468 }
469}

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
1375{
1376 for (int i : {a, b, c}) {
1377 assert(i >= 0 && i < int(m_vertices.size()));
1378 ++m_vertices[i].ref_cnt;
1379 }
1380 int idx;
1381 if (m_free_triangles_head == -1) {
1382 // Allocate a new triangle.
1383 assert(m_invalid_triangles == 0);
1384 idx = int(m_triangles.size());
1385 m_triangles.emplace_back(a, b, c, source_triangle, state);
1386 } else {
1387 // Reuse triangle from the free list.
1388 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1389 assert(! m_triangles[m_free_triangles_head].valid());
1390 assert(m_invalid_triangles > 0);
1392 m_free_triangles_head = m_triangles[idx].children[0];
1394 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1395 assert(m_free_triangles_head == -1 || ! m_triangles[m_free_triangles_head].valid());
1396 assert(m_invalid_triangles >= 0);
1397 assert((m_invalid_triangles == 0) == (m_free_triangles_head == -1));
1398 m_triangles[idx] = {a, b, c, source_triangle, state};
1399 }
1400 assert(m_triangles[idx].valid());
1401 return idx;
1402}

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:

◆ remap_painting()

TriangleSelector::TriangleSplittingData Slic3r::TriangleSelector::remap_painting ( const indexed_triangle_set & source_its,
const TriangleSplittingData & source_painting,
const indexed_triangle_set & target_its,
const Transform3d & target_transform,
const std::optional< std::reference_wrapper< const TriangleSplittingData > > & existing_painting )
static
2504{
2505 TriangleSelector::TriangleSplittingData result;
2506 if (source_painting.bitstream.empty())
2507 return result;
2508
2509 // 1. Deserialize source painting
2510 TriangleMesh source_mesh(source_its);
2511 TriangleSelector source_selector(source_mesh);
2512 source_selector.deserialize(source_painting, false);
2513
2514 // 2. Extract painted geometry
2515 std::vector<std::reference_wrapper<const Triangle>> painted_triangles;
2516 painted_triangles.reserve(source_selector.m_triangles.size());
2517 for (const Triangle& tr : source_selector.m_triangles) {
2518 if (tr.valid() && !tr.is_split() && tr.get_state() != EnforcerBlockerType::NONE) {
2519 painted_triangles.push_back(std::ref(tr));
2520 }
2521 }
2522
2523 if (painted_triangles.empty())
2524 return result;
2525
2526 // 3. Build AABB tree of target mesh so we could find nearest face quickly
2527 TriangleMesh target_mesh(target_its);
2528 target_mesh.transform(target_transform);
2529 AABBTreeIndirect::Tree3f target_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(target_mesh.its.vertices, target_mesh.its.indices);
2530
2531 // Helper: check overlap between a paint triangle and a target triangle.
2532 // Uses 3D barycentric point-in-triangle tests and dominant-axis 2D projection
2533 // for edge-edge intersection to handle all triangle orientations correctly.
2534 auto check_overlap = [&](const Vec3f& pa, const Vec3f& pb, const Vec3f& pc,
2535 const Vec3f& ta, const Vec3f& tb, const Vec3f& tc) -> bool {
2536 // Check if any target vertex is inside the paint triangle
2537 if (is_point_inside_triangle(ta, pa, pb, pc)) return true;
2538 if (is_point_inside_triangle(tb, pa, pb, pc)) return true;
2539 if (is_point_inside_triangle(tc, pa, pb, pc)) return true;
2540
2541 // Check if any paint vertex is inside the target triangle
2542 if (is_point_inside_triangle(pa, ta, tb, tc)) return true;
2543 if (is_point_inside_triangle(pb, ta, tb, tc)) return true;
2544 if (is_point_inside_triangle(pc, ta, tb, tc)) return true;
2545
2546 // Check edge-edge intersections using dominant-axis 2D projection.
2547 // Project onto the plane (XY, XZ, or YZ) where the triangles have the
2548 // most area, avoiding degenerate projections for vertical/angled surfaces.
2549 Vec3f n1 = (pb - pa).cross(pc - pa);
2550 Vec3f n2 = (tb - ta).cross(tc - ta);
2551 Vec3f n_abs = (n1.cwiseAbs() + n2.cwiseAbs());
2552 int axis = (n_abs.x() >= n_abs.y() && n_abs.x() >= n_abs.z()) ? 0
2553 : (n_abs.y() >= n_abs.z()) ? 1 : 2;
2554 const int u_axis = (axis + 1) % 3;
2555 const int v_axis = (axis + 2) % 3;
2556 const std::pair<int, int> proj{u_axis, v_axis};
2557
2558 if (segments_intersect_proj(pa, pb, ta, tb, proj)) return true;
2559 if (segments_intersect_proj(pa, pb, tb, tc, proj)) return true;
2560 if (segments_intersect_proj(pa, pb, tc, ta, proj)) return true;
2561 if (segments_intersect_proj(pb, pc, ta, tb, proj)) return true;
2562 if (segments_intersect_proj(pb, pc, tb, tc, proj)) return true;
2563 if (segments_intersect_proj(pb, pc, tc, ta, proj)) return true;
2564 if (segments_intersect_proj(pc, pa, ta, tb, proj)) return true;
2565 if (segments_intersect_proj(pc, pa, tb, tc, proj)) return true;
2566 if (segments_intersect_proj(pc, pa, tc, ta, proj)) return true;
2567
2568 return false;
2569 };
2570
2571 // 4. For each painted face, we find the nearest target face, and apply the TriangleCursor to paint it
2572 TriangleSelector target_selector(target_mesh);
2573 if (existing_painting) {
2574 // Restore existing painting first, if given
2575 target_selector.deserialize(existing_painting->get(), false);
2576 }
2577 for (auto tri_ref : painted_triangles) {
2578 const Triangle& tri = tri_ref.get();
2579 const Vec3f& pv0 = source_selector.m_vertices[tri.verts_idxs[0]].v;
2580 const Vec3f& pv1 = source_selector.m_vertices[tri.verts_idxs[1]].v;
2581 const Vec3f& pv2 = source_selector.m_vertices[tri.verts_idxs[2]].v;
2582
2583 // Find ALL target faces whose bounding boxes overlap with the paint
2584 // triangle's bounding box, not just the nearest one.
2585 Eigen::AlignedBox3f pt_bbox;
2586 pt_bbox.extend(pv0);
2587 pt_bbox.extend(pv1);
2588 pt_bbox.extend(pv2);
2589 pt_bbox.min() -= Eigen::Vector3f::Constant(TriangleCursor::tolerance);
2590 pt_bbox.max() += Eigen::Vector3f::Constant(TriangleCursor::tolerance);
2591
2592 AABBTreeIndirect::traverse(target_tree, AABBTreeIndirect::intersecting(pt_bbox), [&](const AABBTreeIndirect::Tree3f::Node& node) -> bool {
2593 size_t face_idx = node.idx;
2594 if (face_idx >= target_mesh.its.indices.size())
2595 return true;
2596
2597 const Vec3f& norm_a = source_selector.m_face_normals[tri.source_triangle];
2598 const Vec3f& norm_b = target_selector.m_face_normals[face_idx];
2599
2600 const Vec3i32& face = target_mesh.its.indices[face_idx];
2601 const Vec3f& ta = target_mesh.its.vertices[face(0)];
2602 const Vec3f& tb = target_mesh.its.vertices[face(1)];
2603 const Vec3f& tc = target_mesh.its.vertices[face(2)];
2604
2605 if (TriangleCursor::check_normal(norm_b, -norm_a) && check_overlap(pv0, pv1, pv2, ta, tb, tc)) {
2606 // Paint this face
2607 target_selector.select_patch(face_idx, TriangleCursor::build_cursor(source_selector, tri), tri.get_state(),
2608 Transform3d::Identity(), true, 0.f, Vec3f::UnitZ(), true);
2609 }
2610 return true; // continue traversal
2611 });
2612 }
2613
2614 return target_selector.serialize();
2615}
static std::unique_ptr< Cursor > build_cursor(const TriangleSelector &source_selector, const TriangleSelector::Triangle &tri)
Definition TriangleSelector.cpp:2384
static constexpr float tolerance
Definition TriangleSelector.cpp:2482
static bool check_normal(const Vec3f &facet_norm, const Vec3f &camera_dir)
Definition TriangleSelector.cpp:2476
TriangleSelector(const TriangleMesh &mesh, float edge_limit=0.6f)
Definition TriangleSelector.cpp:1344
auto intersecting(const G &g)
Definition AABBTreeIndirect.hpp:925
void traverse(const Tree< Dims, T > &tree, Predicate &&pred, Fn &&callback)
Definition AABBTreeIndirect.hpp:986
Tree< 3, typename VertexType::Scalar > build_aabb_tree_over_indexed_triangle_set(const std::vector< VertexType > &vertices, const std::vector< IndexedFaceType > &faces, const typename VertexType::Scalar eps=0)
Definition AABBTreeIndirect.hpp:677
Tree< 3, float > Tree3f
Definition AABBTreeIndirect.hpp:222
static bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3)
Definition TriangleSelector.cpp:251
T cross(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:168
static bool segments_intersect_proj(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3, const Vec3f &p4, const std::pair< int, int > &proj)
Definition TriangleSelector.cpp:2350

References TriangleSelector(), Slic3r::TriangleSelector::TriangleSplittingData::bitstream, Slic3r::AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(), Slic3r::TriangleCursor::build_cursor(), Slic3r::TriangleCursor::check_normal(), Slic3r::cross(), deserialize(), Slic3r::TriangleSelector::Triangle::get_state(), Slic3r::AABBTreeIndirect::intersecting(), Slic3r::is_point_inside_triangle(), Slic3r::TriangleSelector::Triangle::is_split(), Slic3r::TriangleMesh::its, m_face_normals, m_triangles, m_vertices, Slic3r::NONE, Slic3r::segments_intersect_proj(), select_patch(), serialize(), Slic3r::TriangleSelector::Triangle::source_triangle, Slic3r::TriangleCursor::tolerance, Slic3r::TriangleMesh::transform(), Slic3r::AABBTreeIndirect::traverse(), Slic3r::TriangleSelector::Triangle::valid(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by Slic3r::ModelVolume::restore_painting().

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

◆ remap_triangle_state()

void Slic3r::TriangleSelector::remap_triangle_state ( const EnforcerBlockerStateMap & state_map)
1329{
1330 if (m_triangles.empty())
1331 return;
1332
1333 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_triangles.size()), [this, &state_map](const tbb::blocked_range<size_t>& range) {
1334 for (size_t i = range.begin(); i != range.end(); ++i) {
1335 Triangle& tr = m_triangles[i];
1336 if (tr.valid()) {
1337 const auto current_state = static_cast<size_t>(tr.get_state());
1338 tr.set_state(state_map[current_state]);
1339 }
1340 }
1341 });
1342}
auto range(Cont &&cont)
Definition libslic3r.h:405

References m_triangles, and Slic3r::range().

Referenced by Slic3r::GUI::GLGizmoMmuSegmentation::remap_filament_assignments(), and Slic3r::FacetsAnnotation::remap_states().

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

◆ remove_useless_children()

void Slic3r::TriangleSelector::remove_useless_children ( int facet_idx)
private
1237{
1238 // Check that all children are leafs of the same type. If not, try to
1239 // make them (recursive call). Remove them if sucessful.
1240
1241 assert(facet_idx < int(m_triangles.size()) && m_triangles[facet_idx].valid());
1242 Triangle& tr = m_triangles[facet_idx];
1243
1244 if (! tr.is_split()) {
1245 // This is a leaf, there nothing to do. This can happen during the
1246 // first (non-recursive call). Shouldn't otherwise.
1247 return;
1248 }
1249
1250 // Call this for all non-leaf children.
1251 for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
1252 assert(child_idx < int(m_triangles.size()) && m_triangles[child_idx].valid());
1253 if (m_triangles[tr.children[child_idx]].is_split())
1254 remove_useless_children(tr.children[child_idx]);
1255 }
1256
1257
1258 // Return if a child is not leaf or two children differ in type.
1260 for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
1261 if (m_triangles[tr.children[child_idx]].is_split())
1262 return;
1263 if (child_idx == 0)
1264 first_child_type = m_triangles[tr.children[0]].get_state();
1265 else if (m_triangles[tr.children[child_idx]].get_state() != first_child_type)
1266 return;
1267 }
1268
1269 // If we got here, the children can be removed.
1270 undivide_triangle(facet_idx);
1271 tr.set_state(first_child_type);
1272}
void remove_useless_children(int facet_idx)
Definition TriangleSelector.cpp:1236

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 ( )
1351{
1352 m_vertices.clear();
1353 m_triangles.clear();
1357 m_vertices.reserve(m_mesh.its.vertices.size());
1358 for (const stl_vertex& vert : m_mesh.its.vertices)
1359 m_vertices.emplace_back(vert);
1360 m_triangles.reserve(m_mesh.its.indices.size());
1361 for (size_t i = 0; i < m_mesh.its.indices.size(); ++i) {
1362 const stl_triangle_vertex_indices &ind = m_mesh.its.indices[i];
1363 push_triangle(ind[0], ind[1], ind[2], int(i));
1364 }
1365 m_orig_size_vertices = int(m_vertices.size());
1366 m_orig_size_indices = int(m_triangles.size());
1367}

References 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, and push_triangle().

Referenced by TriangleSelector(), deserialize(), and Slic3r::GUI::GLGizmoTextureDisplacement::select_visible_faces().

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)
2077{
2078 for (Triangle &triangle : m_triangles)
2079 if (!triangle.is_split() && triangle.is_selected_by_seed_fill())
2080 triangle.set_state(new_state);
2081
2082 for (Triangle &triangle : m_triangles)
2083 if (triangle.is_split() && triangle.valid()) {
2084 size_t facet_idx = &triangle - &m_triangles.front();
2085 remove_useless_children(int(facet_idx));
2086 }
2087}

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,
const Vec3f & up_direction = Vec3f::UnitZ(),
bool force_reselection = false )
389{
390 assert(facet_start < m_orig_size_indices);
391
392 // Recompute seed fill only if the cursor is pointing on facet unselected by seed fill or a clipping plane is active.
393 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())
394 return;
395
397
398 std::vector<bool> visited(m_triangles.size(), false);
399 std::queue<int> facet_queue;
400 facet_queue.push(facet_start);
401
402 const double facet_angle_limit = cos(Geometry::deg2rad(seed_fill_angle)) - EPSILON;
403 const float highlight_angle_limit = -cos(Geometry::deg2rad(highlight_by_angle_deg));
404
405 // Depth-first traversal of neighbors of the face hit by the ray thrown from the mouse cursor.
406 while (!facet_queue.empty()) {
407 int current_facet = facet_queue.front();
408 facet_queue.pop();
409
410 const Vec3f &facet_normal = m_face_normals[m_triangles[current_facet].source_triangle];
411 Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
412 float world_normal_dot = (normal_matrix * facet_normal).normalized().dot(up_direction);
413 if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || world_normal_dot < highlight_angle_limit)) {
414 if (m_triangles[current_facet].is_split()) {
415 for (int split_triangle_idx = 0; split_triangle_idx <= m_triangles[current_facet].number_of_split_sides(); ++split_triangle_idx) {
416 assert(split_triangle_idx < int(m_triangles[current_facet].children.size()));
417 assert(m_triangles[current_facet].children[split_triangle_idx] < int(m_triangles.size()));
418 if (int child = m_triangles[current_facet].children[split_triangle_idx]; !visited[child])
419 // Child triangle shares normal with its parent. Select it.
420 facet_queue.push(child);
421 }
422 } else
423 m_triangles[current_facet].select_by_seed_fill();
424
425 if (current_facet < m_orig_size_indices)
426 // Propagate over the original triangles.
427 for (int neighbor_idx : m_neighbors[current_facet]) {
428 assert(neighbor_idx >= -1);
429 if (neighbor_idx >= 0 && !visited[neighbor_idx] && !is_facet_clipped(neighbor_idx, clp)) {
430 // Check if neighbour_facet_idx is satisfies angle in seed_fill_angle and append it to facet_queue if it do.
431 const Vec3f &n1 = m_face_normals[m_triangles[neighbor_idx].source_triangle];
432 const Vec3f &n2 = m_face_normals[m_triangles[current_facet].source_triangle];
433 if (std::clamp(n1.dot(n2), 0.f, 1.f) >= facet_angle_limit)
434 facet_queue.push(neighbor_idx);
435 }
436 }
437 }
438 visited[current_facet] = true;
439 }
440}
Eigen::Matrix< float, 3, 3, Eigen::DontAlign > Matrix3f
Definition Point.hpp:85
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299

References Slic3r::cast(), Slic3r::Geometry::deg2rad(), EPSILON, 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 ( )
2056{
2057 for (Triangle &triangle : m_triangles)
2058 if (!triangle.is_split())
2059 triangle.unselect_by_seed_fill();
2060}

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,
const Vec3f & up_direction = Vec3f::UnitZ(),
bool select_partially = false )
302{
303 assert(facet_start < m_orig_size_indices);
304
305 // Save current cursor center, squared radius and camera direction, so we don't
306 // have to pass it around.
307 m_cursor = std::move(cursor);
308
309 // In case user changed cursor size since last time, update triangle edge limit.
310 // It is necessary to compare the internal radius in m_cursor! radius is in
311 // world coords and does not change after scaling.
312 if (m_old_cursor_radius_sqr != m_cursor->radius_sqr) {
313 // BBS: improve details for large cursor radius
314 TriangleSelector::HeightRange* hr_cursor = dynamic_cast<TriangleSelector::HeightRange*>(m_cursor.get());
315 if (hr_cursor == nullptr) {
316 set_edge_limit(std::min(std::sqrt(m_cursor->radius_sqr) / 5.f, 0.05f));
317 m_old_cursor_radius_sqr = m_cursor->radius_sqr;
318 }
319 else {
320 set_edge_limit(0.1);
322 }
323 }
324
325 const float highlight_angle_limit = -cos(Geometry::deg2rad(highlight_by_angle_deg));
326
327 // BBS
328 std::vector<int> start_facets;
329 HeightRange* hr_cursor = dynamic_cast<HeightRange*>(m_cursor.get());
330 if (hr_cursor) {
331 for (int facet_id = 0; facet_id < m_orig_size_indices; facet_id++) {
332 const Triangle& tr = m_triangles[facet_id];
333 if (m_cursor->is_edge_inside_cursor(tr, m_vertices)) {
334 start_facets.push_back(facet_id);
335 }
336 }
337 }
338 else {
339 start_facets.push_back(facet_start);
340 }
341
342 // Keep track of facets of the original mesh we already processed.
343 std::vector<bool> visited(m_orig_size_indices, false);
344
345 for (int i = 0; i < start_facets.size(); i++) {
346 int start_facet_id = start_facets[i];
347 if (visited[start_facet_id])
348 continue;
349
350 // Now start with the facet the pointer points to and check all adjacent facets.
351 std::vector<int> facets_to_check;
352 facets_to_check.reserve(16);
353 facets_to_check.emplace_back(start_facet_id);
354
355 // Breadth-first search around the hit point. facets_to_check may grow significantly large.
356 // Head of the bread-first facets_to_check FIFO.
357 int facet_idx = 0;
358 while (facet_idx < int(facets_to_check.size())) {
359 int facet = facets_to_check[facet_idx];
360 const Vec3f& facet_normal = m_face_normals[m_triangles[facet].source_triangle];
361 Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
362 float world_normal_dot = (normal_matrix * facet_normal).normalized().dot(up_direction);
363 if (!visited[facet] && (highlight_by_angle_deg == 0.f || world_normal_dot < highlight_angle_limit)) {
364 if (select_triangle(facet, new_state, triangle_splitting, select_partially)) {
365 // add neighboring facets to list to be processed later
366 for (int neighbor_idx : m_neighbors[facet])
367 if (neighbor_idx >= 0 && m_cursor->is_facet_visible(neighbor_idx, m_face_normals))
368 facets_to_check.push_back(neighbor_idx);
369 }
370 }
371 visited[facet] = true;
372 ++facet_idx;
373 }
374 }
375}
Definition TriangleSelector.hpp:218
bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting, bool select_partially)
Definition TriangleSelector.cpp:620
std::unique_ptr< Cursor > m_cursor
Definition TriangleSelector.hpp:547
float m_old_cursor_radius_sqr
Definition TriangleSelector.hpp:549
void set_edge_limit(float edge_limit)
Definition TriangleSelector.cpp:1369

References Slic3r::cast(), Slic3r::Geometry::deg2rad(), m_cursor, m_face_normals, m_neighbors, m_old_cursor_radius_sqr, m_orig_size_indices, m_triangles, m_vertices, select_triangle(), and set_edge_limit().

Referenced by remap_painting().

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,
bool select_partially )
private
621{
622 assert(facet_idx < int(m_triangles.size()));
623
624 if (! m_triangles[facet_idx].valid())
625 return false;
626
627 Vec3i32 neighbors = m_neighbors[facet_idx];
628 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
629
630 if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting, select_partially))
631 return false;
632
633 // In case that all children are leafs and have the same state now,
634 // they may be removed and substituted by the parent triangle.
635 remove_useless_children(facet_idx);
636
637#ifdef EXPENSIVE_DEBUG_CHECKS
638 // Make sure that we did not lose track of invalid triangles.
639 assert(m_invalid_triangles == std::count_if(m_triangles.begin(), m_triangles.end(),
640 [](const Triangle& tr) { return ! tr.valid(); }));
641#endif // EXPENSIVE_DEBUG_CHECKS
642
643 // Do garbage collection maybe?
644 if (2*m_invalid_triangles > int(m_triangles.size()))
646
647 return true;
648}
bool select_triangle_recursive(int facet_idx, const Vec3i32 &neighbors, EnforcerBlockerType type, bool triangle_splitting, bool select_partially)
Definition TriangleSelector.cpp:970
void garbage_collect()
Definition TriangleSelector.cpp:1274

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 Vec3i32 & neighbors,
EnforcerBlockerType type,
bool triangle_splitting,
bool select_partially )
private
971{
972 assert(facet_idx < int(m_triangles.size()));
973
974 Triangle* tr = &m_triangles[facet_idx];
975 if (! tr->valid())
976 return false;
977
978 assert(this->verify_triangle_neighbors(*tr, neighbors));
979
980 int num_of_inside_vertices = m_cursor->vertices_inside(*tr, m_vertices);
981
982 if (num_of_inside_vertices == 0
983 && ! m_cursor->is_pointer_in_triangle(*tr, m_vertices)
984 && ! m_cursor->is_edge_inside_cursor(*tr, m_vertices))
985 return false;
986
987 if (num_of_inside_vertices == 3) {
988 // dump any subdivision and select whole triangle
989 undivide_triangle(facet_idx);
990 tr->set_state(type);
991 } else {
992 // the triangle is partially inside, let's recursively divide it
993 // (if not already) and try selecting its children.
994
995 if (! tr->is_split() && tr->get_state() == type) {
996 // This is leaf triangle that is already of correct type as a whole.
997 // No need to split, all children would end up selected anyway.
998 return true;
999 }
1000
1001 if (triangle_splitting)
1002 split_triangle(facet_idx, neighbors);
1003 if ((!triangle_splitting || select_partially) && !m_triangles[facet_idx].is_split()) {
1004 m_triangles[facet_idx].set_state(type);
1005 return true;
1006 }
1007 tr = &m_triangles[facet_idx]; // might have been invalidated by split_triangle().
1008
1009 int num_of_children = tr->number_of_split_sides() + 1;
1010 if (num_of_children != 1) {
1011 for (int i=0; i<num_of_children; ++i) {
1012 assert(i < int(tr->children.size()));
1013 assert(tr->children[i] < int(m_triangles.size()));
1014 // Recursion, deep first search over the children of this triangle.
1015 // All children of this triangle were created by splitting a single source triangle of the original mesh.
1016 select_triangle_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), type, triangle_splitting, select_partially);
1017 tr = &m_triangles[facet_idx]; // might have been invalidated
1018 }
1019 }
1020 }
1021
1022 return true;
1023}
void split_triangle(int facet_idx, const Vec3i32 &neighbors)
Definition TriangleSelector.cpp:1035

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
nodiscard
291{
292 assert(facet_idx < int(m_triangles.size()));
293 if (!m_triangles[facet_idx].valid())
294 return -1;
295
296 Vec3i32 neighbors = m_neighbors[facet_idx];
297 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
298 return this->select_unsplit_triangle(hit, facet_idx, neighbors);
299}

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 Vec3i32 & neighbors ) const
nodiscard
258{
259 assert(facet_idx < int(m_triangles.size()));
260 const Triangle *tr = &m_triangles[facet_idx];
261 if (!tr->valid())
262 return -1;
263
264 if (!tr->is_split()) {
265 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))
266 return facet_idx;
267
268 return -1;
269 }
270
271 assert(this->verify_triangle_neighbors(*tr, neighbors));
272
273 int num_of_children = tr->number_of_split_sides() + 1;
274 if (num_of_children != 1) {
275 for (int i = 0; i < num_of_children; ++i) {
276 assert(i < int(tr->children.size()));
277 assert(tr->children[i] < int(m_triangles.size()));
278 // Recursion, deep first search over the children of this triangle.
279 // All children of this triangle were created by splitting a single source triangle of the original mesh.
280
281 const std::array<int, 3> &t_vert = m_triangles[tr->children[i]].verts_idxs;
282 if (is_point_inside_triangle(hit, m_vertices[t_vert[0]].v, m_vertices[t_vert[1]].v, m_vertices[t_vert[2]].v))
283 return this->select_unsplit_triangle(hit, tr->children[i], this->child_neighbors(*tr, neighbors, i));
284 }
285 }
286
287 return -1;
288}

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()

TriangleSelector::TriangleSplittingData Slic3r::TriangleSelector::serialize ( ) const
1717 {
1718 // Each original triangle of the mesh is assigned a number encoding its state
1719 // or how it is split. Each triangle is encoded by 4 bits (xxyy) or 8 bits (zzzzxxyy):
1720 // leaf triangle: xx = EnforcerBlockerType (Only values 0, 1, and 2. Value 3 is used as an indicator for additional 4 bits.), yy = 0
1721 // leaf triangle: xx = 0b11, yy = 0b00, zzzz = EnforcerBlockerType (subtracted by 3)
1722 // non-leaf: xx = special side, yy = number of split sides
1723 // These are bitwise appended and formed into one 64-bit integer.
1724
1725 // The function returns a map from original triangle indices to
1726 // stream of bits encoding state and offsprings.
1727
1728 // Using an explicit function object to support recursive call of Serializer::serialize().
1729 // This is cheaper than the previous implementation using a recursive call of type erased std::function.
1730 // (std::function calls using a pointer, while this implementation calls directly).
1731 struct Serializer {
1732 const TriangleSelector* triangle_selector;
1733 TriangleSplittingData data;
1734
1735 void serialize(int facet_idx) {
1736 const Triangle& tr = triangle_selector->m_triangles[facet_idx];
1737
1738 // Always save number of split sides. It is zero for unsplit triangles.
1739 int split_sides = tr.number_of_split_sides();
1740 assert(split_sides >= 0 && split_sides <= 3);
1741
1742 data.bitstream.push_back(split_sides & 0b01);
1743 data.bitstream.push_back(split_sides & 0b10);
1744
1745 if (split_sides) {
1746 // If this triangle is split, save which side is split (in case
1747 // of one split) or kept (in case of two splits). The value will
1748 // be ignored for 3-side split.
1749 assert(tr.is_split() && split_sides > 0);
1750 assert(tr.special_side() >= 0 && tr.special_side() <= 3);
1751 data.bitstream.push_back(tr.special_side() & 0b01);
1752 data.bitstream.push_back(tr.special_side() & 0b10);
1753 // Now save all children.
1754 // Serialized in reverse order for compatibility with PrusaSlicer 2.3.1.
1755 for (int child_idx = split_sides; child_idx >= 0; -- child_idx)
1756 this->serialize(tr.children[child_idx]);
1757 } else {
1758 // In case this is leaf, we better save information about its state.
1759 int n = int(tr.get_state());
1760 if (n <= static_cast<size_t>(EnforcerBlockerType::ExtruderMax))
1761 data.used_states[n] = true;
1762
1763 if (n >= 3) {
1764 assert(n <= int(EnforcerBlockerType::ExtruderMax));
1765 // Store "11" plus 4 bits of (n-3), which covers states 3..17. State 18 and
1766 // above set that nibble to 0b1111 and store (n-18) in a second nibble. This is
1767 // the encoding the CONST_FILAMENTS table in Model.cpp already writes for
1768 // colored mesh imports.
1769 data.bitstream.insert(data.bitstream.end(), { true, true });
1770 auto &bitstream = data.bitstream;
1771 auto push_nibble = [&bitstream](int value) {
1772 for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx)
1773 bitstream.push_back(value & (uint64_t(0b0001) << bit_idx));
1774 };
1775 if (n <= 17) {
1776 push_nibble(n - 3);
1777 } else {
1778 push_nibble(0b1111);
1779 push_nibble(n - 18);
1780 }
1781 } else {
1782 // Simple case, compatible with PrusaSlicer 2.3.1 and older for storing paint on supports and seams.
1783 // Store 2 bits of n.
1784 data.bitstream.push_back(n & 0b01);
1785 data.bitstream.push_back(n & 0b10);
1786 }
1787 }
1788 }
1789 } out { this };
1790
1791 out.data.triangles_to_split.reserve(m_orig_size_indices);
1792 for (int i=0; i<m_orig_size_indices; ++i)
1793 if (const Triangle& tr = m_triangles[i]; tr.is_split() || tr.get_state() != EnforcerBlockerType::NONE) {
1794 // Store index of the first bit assigned to ith triangle.
1795 out.data.triangles_to_split.emplace_back(i, int(out.data.bitstream.size()));
1796 // out the triangle bits.
1797 out.serialize(i);
1798 }
1799
1800 // May be stored onto Undo / Redo stack, thus conserve memory.
1801 out.data.triangles_to_split.shrink_to_fit();
1802 out.data.bitstream.shrink_to_fit();
1803 return out.data;
1804}
void serialize(Archive &ar, FacenamesSerializer &t, const std::uint32_t version)
Definition GLGizmoEmboss.cpp:3407
std::array< std::size_t, 3 > Triangle
Definition MeshRepair.cpp:87

References TriangleSelector(), Slic3r::TriangleSelector::TriangleSplittingData::bitstream, Slic3r::TriangleSelector::Triangle::children, Slic3r::ExtruderMax, 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(), Slic3r::TriangleSelector::Triangle::special_side(), and Slic3r::TriangleSelector::TriangleSplittingData::used_states.

Referenced by Slic3r::GUI::GLGizmoTextureDisplacement::masks_after_subdivision(), remap_painting(), and 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)
1370{
1371 m_edge_limit_sqr = std::pow(edge_limit, 2.f);
1372}
float m_edge_limit_sqr
Definition TriangleSelector.hpp:541

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 )
1026{
1027 assert(facet_idx < m_orig_size_indices);
1028 undivide_triangle(facet_idx);
1029 assert(! m_triangles[facet_idx].is_split());
1030 m_triangles[facet_idx].set_state(state);
1031}

References m_orig_size_indices, m_triangles, and undivide_triangle().

Referenced by Slic3r::apply_painted_mesh_to_volume(), Slic3r::GUI::GLGizmoTextureDisplacement::masks_after_subdivision(), and Slic3r::GUI::GLGizmoTextureDisplacement::select_visible_faces().

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

◆ shift_states_above()

void Slic3r::TriangleSelector::shift_states_above ( EnforcerBlockerType threshold,
int delta )
2063{
2064 for (Triangle &triangle : m_triangles) {
2065 if (triangle.is_split() || !triangle.valid())
2066 continue;
2067 EnforcerBlockerType s = triangle.get_state();
2068 if (s >= threshold && s != EnforcerBlockerType::NONE) {
2069 int new_val = (int)s + delta;
2070 if (new_val >= 0)
2071 triangle.set_state(EnforcerBlockerType(new_val));
2072 }
2073 }
2074}

References m_triangles, and Slic3r::NONE.

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

Here is the caller graph for this function:

◆ split_triangle()

void Slic3r::TriangleSelector::split_triangle ( int facet_idx,
const Vec3i32 & neighbors )
private
1036{
1037 if (m_triangles[facet_idx].is_split()) {
1038 // The triangle is divided already.
1039 return;
1040 }
1041
1042 Triangle* tr = &m_triangles[facet_idx];
1043 assert(this->verify_triangle_neighbors(*tr, neighbors));
1044
1045 EnforcerBlockerType old_type = tr->get_state();
1046
1047 // If we got here, we are about to actually split the triangle.
1048 const double limit_squared = m_edge_limit_sqr;
1049
1050 std::array<int, 3>& facet = tr->verts_idxs;
1051 std::array<const stl_vertex*, 3> pts = { &m_vertices[facet[0]].v,
1052 &m_vertices[facet[1]].v,
1053 &m_vertices[facet[2]].v};
1054 std::array<stl_vertex, 3> pts_transformed; // must stay in scope of pts !!!
1055
1056 // In case the object is non-uniformly scaled, transform the
1057 // points to world coords.
1058 if (! m_cursor->uniform_scaling) {
1059 for (size_t i=0; i<pts.size(); ++i) {
1060 pts_transformed[i] = m_cursor->trafo * (*pts[i]);
1061 pts[i] = &pts_transformed[i];
1062 }
1063 }
1064
1065 std::array<double, 3> sides = {(*pts[2] - *pts[1]).squaredNorm(),
1066 (*pts[0] - *pts[2]).squaredNorm(),
1067 (*pts[1] - *pts[0]).squaredNorm()};
1068
1069 boost::container::small_vector<int, 3> sides_to_split;
1070 int side_to_keep = -1;
1071 for (int pt_idx = 0; pt_idx<3; ++pt_idx) {
1072 if (sides[pt_idx] > limit_squared)
1073 sides_to_split.push_back(pt_idx);
1074 else
1075 side_to_keep = pt_idx;
1076 }
1077 if (sides_to_split.empty()) {
1078 // This shall be unselected.
1079 tr->set_division(0, 0);
1080 return;
1081 }
1082
1083 // Save how the triangle will be split. Second argument makes sense only for one
1084 // or two split sides, otherwise the value is ignored.
1085 tr->set_division(int(sides_to_split.size()),
1086 sides_to_split.size() == 2 ? side_to_keep : sides_to_split[0]);
1087
1088 perform_split(facet_idx, neighbors, old_type);
1089}

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
733{
734 if (tr.number_of_split_sides() == 0)
735 // If this triangle is not split, then there is no upper / lower subtriangle sharing the edge.
736 return -1;
737
738 // Find the triangle edge.
739 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
740 assert(tr.verts_idxs[edge] == vertexi);
741 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
742
743 if (tr.number_of_split_sides() == 1) {
744 return edge == next_idx_modulo(tr.special_side(), 3) ?
745 m_triangles[tr.children[0]].verts_idxs[2] :
746 this->triangle_midpoint(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj);
747 } else if (tr.number_of_split_sides() == 2) {
748 return edge == next_idx_modulo(tr.special_side(), 3) ?
749 this->triangle_midpoint(m_triangles[tr.children[2]], vertexi, vertexj) :
750 edge == tr.special_side() ?
751 m_triangles[tr.children[0]].verts_idxs[1] :
752 m_triangles[tr.children[1]].verts_idxs[2];
753 } else {
754 assert(tr.number_of_split_sides() == 3);
755 assert(tr.special_side() == 0);
756 return
757 (edge == 0) ? m_triangles[tr.children[0]].verts_idxs[1] :
758 (edge == 1) ? m_triangles[tr.children[1]].verts_idxs[2] :
759 m_triangles[tr.children[2]].verts_idxs[2];
760 }
761}

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
766{
767 return itriangle == -1 ? -1 : this->triangle_midpoint(m_triangles[itriangle], vertexi, vertexj);
768}

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
771{
772 int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj);
773 if (midpoint == -1) {
774 Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v);
775#ifdef EXPENSIVE_DEBUG_CHECKS
776 // Verify that the vertex is really a new one.
777 auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [c](const Vertex &v) {
778 return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; });
779 assert(it == m_vertices.end());
780#endif // EXPENSIVE_DEBUG_CHECKS
781 // Allocate a new vertex, possibly reusing the free list.
782 if (m_free_vertices_head == -1) {
783 // Allocate a new vertex.
784 midpoint = int(m_vertices.size());
785 m_vertices.emplace_back(c);
786 } else {
787 // Reuse a vertex from the free list.
788 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
789 midpoint = m_free_vertices_head;
790 memcpy(&m_free_vertices_head, &m_vertices[midpoint].v[0], sizeof(m_free_vertices_head));
791 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
792 m_vertices[midpoint].v = c;
793 }
794 assert(m_vertices[midpoint].ref_cnt == 0);
795 } else {
796#ifndef NDEBUG
797 Vec3f c1 = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v);
798 Vec3f c2 = m_vertices[midpoint].v;
799 float d = (c2 - c1).norm();
800 assert(std::abs(d) < EPSILON);
801#endif // NDEBUG
802 assert(m_vertices[midpoint].ref_cnt > 0);
803 }
804 return midpoint;
805}

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
702{
703 if (tr.number_of_split_sides() == 0)
704 // If this triangle is not split, then there is no subtriangles touching the edge.
705 return std::make_pair(-1, -1);
706
707 // Find the triangle edge.
708 int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2;
709 assert(tr.verts_idxs[edge] == vertexi);
710 assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
711
712 if (tr.number_of_split_sides() == 1) {
713 return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[0], tr.children[1]) :
714 std::make_pair(tr.children[edge == tr.special_side() ? 0 : 1], -1);
715 } else if (tr.number_of_split_sides() == 2) {
716 return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[2], -1) :
717 edge == tr.special_side() ? std::make_pair(tr.children[0], tr.children[1]) :
718 std::make_pair(tr.children[2], tr.children[0]);
719 } else {
720 assert(tr.number_of_split_sides() == 3);
721 assert(tr.special_side() == 0);
722 return edge == 0 ? std::make_pair(tr.children[0], tr.children[1]) :
723 edge == 1 ? std::make_pair(tr.children[1], tr.children[2]) :
724 std::make_pair(tr.children[2], tr.children[0]);
725 }
726
727 return std::make_pair(-1, -1);
728}

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
697{
698 return itriangle == -1 ? std::make_pair(-1, -1) : Slic3r::TriangleSelector::triangle_subtriangles(m_triangles[itriangle], vertexi, vertexj);
699}

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
1199{
1200 assert(facet_idx < int(m_triangles.size()));
1201 Triangle& tr = m_triangles[facet_idx];
1202
1203 if (tr.is_split()) {
1204 for (int i = 0; i <= tr.number_of_split_sides(); ++i) {
1205 int child = tr.children[i];
1206 Triangle &child_tr = m_triangles[child];
1207 assert(child_tr.valid());
1208 undivide_triangle(child);
1209 for (int j = 0; j < 3; ++j) {
1210 int iv = child_tr.verts_idxs[j];
1211 Vertex &v = m_vertices[iv];
1212 assert(v.ref_cnt > 0);
1213 if (-- v.ref_cnt == 0) {
1214 // Release this vertex.
1215 // Chain released vertices into a linked list through ref_cnt.
1216 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
1217 memcpy(&m_vertices[iv].v[0], &m_free_vertices_head, sizeof(m_free_vertices_head));
1219 assert(m_free_vertices_head >= -1 && m_free_vertices_head < int(m_vertices.size()));
1220 }
1221 }
1222 // Chain released triangles into a linked list through children[0].
1223 assert(child_tr.valid());
1224 child_tr.m_valid = false;
1225 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1226 assert(m_free_triangles_head == -1 || ! m_triangles[m_free_triangles_head].valid());
1227 child_tr.children[0] = m_free_triangles_head;
1228 m_free_triangles_head = child;
1229 assert(m_free_triangles_head >= -1 && m_free_triangles_head < int(m_triangles.size()));
1231 }
1232 tr.set_division(0, 0); // not split
1233 }
1234}

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 deserialize(), 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
143{
144 for (int i = 0; i < 3; ++ i) {
145 int v1 = tr.verts_idxs[i];
146 int v2 = tr.verts_idxs[next_idx_modulo(i, 3)];
147 int vmid = this->triangle_midpoint(tr, v1, v2);
148 assert(vmid >= -1);
149 if (vmid != -1) {
150 Vec3f c1 = 0.5f * (m_vertices[v1].v + m_vertices[v2].v);
151 Vec3f c2 = m_vertices[vmid].v;
152 float d = (c2 - c1).norm();
153 assert(std::abs(d) < EPSILON);
154 }
155 }
156 return true;
157}

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 Vec3i32 & neighbors ) const
protected
160{
161 assert(neighbors(0) >= -1);
162 assert(neighbors(1) >= -1);
163 assert(neighbors(2) >= -1);
164 assert(verify_triangle_midpoints(tr));
165
166 for (int i = 0; i < 3; ++i)
167 if (neighbors(i) != -1) {
168 const Triangle &tr2 = m_triangles[neighbors(i)];
169 assert(verify_triangle_midpoints(tr2));
170 int v1 = tr.verts_idxs[i];
171 int v2 = tr.verts_idxs[next_idx_modulo(i, 3)];
172 assert(tr2.verts_idxs[0] == v1 || tr2.verts_idxs[1] == v1 || tr2.verts_idxs[2] == v1);
173 int j = tr2.verts_idxs[0] == v1 ? 0 : tr2.verts_idxs[1] == v1 ? 1 : 2;
174 assert(tr2.verts_idxs[j] == v1);
175 assert(tr2.verts_idxs[prev_idx_modulo(j, 3)] == v2);
176 }
177 return true;
178}
bool verify_triangle_midpoints(const Triangle &tr) const
Definition TriangleSelector.cpp:142

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(), split_triangle(), and Slic3r::GUI::TriangleSelectorPatch::update_triangles_per_patch().

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

◆ TriangleCursor

friend class TriangleCursor
friend

References TriangleCursor.

Referenced by TriangleCursor.

Member Data Documentation

◆ m_cursor

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

◆ m_edge_limit

float Slic3r::TriangleSelector::m_edge_limit = 0.6f
protected

Referenced by TriangleSelector().

◆ 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

◆ 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: