OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::TriangleSelectorGUI Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp>

Inheritance diagram for Slic3r::GUI::TriangleSelectorGUI:
Collaboration diagram for Slic3r::GUI::TriangleSelectorGUI:

Public Types

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

Public Member Functions

 TriangleSelectorGUI (const TriangleMesh &mesh, float edge_limit=0.6f)
virtual ~TriangleSelectorGUI ()=default
virtual void render (ImGuiWrapper *imgui, const Transform3d &matrix)
void render_paint_contour (const Transform3d &matrix)
void set_wireframe_needed (bool need_wireframe)
bool get_wireframe_needed ()
void request_update_render_data (bool paint_changed=false)
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)
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
void get_facets (std::vector< indexed_triangle_set > &facets_per_type) 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 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)

Static Public Attributes

static ColorRGBA enforcers_color = {0.5f, 1.f, 0.5f, 1.f}
static ColorRGBA blockers_color = {1.f, 0.5f, 0.5f, 1.f}

Protected Member Functions

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

Static Protected Member Functions

static ColorRGBA get_seed_fill_color (const ColorRGBA &base_color)

Protected Attributes

bool m_update_render_data = false
bool m_paint_changed = true
GLModel m_paint_contour
bool m_need_wireframe {false}
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

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

GLModel m_iva_enforcers
GLModel m_iva_blockers
std::array< GLModel, 3 > m_iva_seed_fills
int m_free_triangles_head { -1 }
int m_free_vertices_head { -1 }

Detailed Description

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
strongprivateinherited
Enumerator
First 
Second 
565 {
566 First,
567 Second,
568 };

Constructor & Destructor Documentation

◆ TriangleSelectorGUI()

Slic3r::GUI::TriangleSelectorGUI::TriangleSelectorGUI ( const TriangleMesh & mesh,
float edge_limit = 0.6f )
inlineexplicit
47 : TriangleSelector(mesh, edge_limit) {}
TriangleSelector(const TriangleMesh &mesh, float edge_limit=0.6f)
Definition TriangleSelector.cpp:1344

References Slic3r::TriangleSelector::TriangleSelector().

Referenced by Slic3r::GUI::TriangleSelectorPatch::TriangleSelectorPatch().

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

◆ ~TriangleSelectorGUI()

virtual Slic3r::GUI::TriangleSelectorGUI::~TriangleSelectorGUI ( )
virtualdefault

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
privateinherited
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
protectedinherited
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 )
inherited
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
const std::vector< Vec3f > m_face_normals
Definition TriangleSelector.hpp:532
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
privateinherited
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
privateinherited
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 )
inherited
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
const TriangleMesh & m_mesh
Definition TriangleSelector.hpp:530
void undivide_triangle(int facet_idx)
Definition TriangleSelector.cpp:1198
void reset()
Definition TriangleSelector.cpp:1350
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)
staticinherited
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 ( )
inherited
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
inherited
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
inherited
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
privateinherited
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
inherited
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}
const std::vector< Vec3i32 > m_neighbors
Definition TriangleSelector.hpp:531
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
privateinherited
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_color()

ColorRGBA Slic3r::GUI::TriangleSelectorGUI::get_seed_fill_color ( const ColorRGBA & base_color)
staticprotected
1266{
1267 // BBS
1268 return {
1269 base_color.r() * 1.25f < 1.f ? base_color.r() * 1.25f : 1.f,
1270 base_color.g() * 1.25f < 1.f ? base_color.g() * 1.25f : 1.f,
1271 base_color.b() * 1.25f < 1.f ? base_color.b() * 1.25f : 1.f,
1272 1.f};
1273}

References Slic3r::ColorRGBA::b(), Slic3r::ColorRGBA::g(), and Slic3r::ColorRGBA::r().

Referenced by render().

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
inherited
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
privateinherited
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:

◆ get_wireframe_needed()

bool Slic3r::GUI::TriangleSelectorGUI::get_wireframe_needed ( )
inline
56{ return m_need_wireframe; }
bool m_need_wireframe
Definition GLGizmoPainterBase.hpp:97

References m_need_wireframe.

◆ has_facets() [1/2]

bool Slic3r::TriangleSelector::has_facets ( const TriangleSplittingData & data,
EnforcerBlockerType test_state )
staticinherited
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
inherited
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
privateinherited
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
privateinherited
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
privateinherited
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
inherited
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 )
privateinherited
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
inherited
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
inherited
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} )
privateinherited
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 )
staticinherited
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
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)
inherited
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)
privateinherited
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:

◆ render()

void Slic3r::GUI::TriangleSelectorGUI::render ( ImGuiWrapper * imgui,
const Transform3d & matrix )
virtual

Reimplemented in Slic3r::GUI::TriangleSelectorPatch.

1276{
1279 m_update_render_data = false;
1280 }
1281
1282 auto* shader = wxGetApp().get_current_shader();
1283 if (! shader)
1284 return;
1285 assert(shader->get_name() == "gouraud" || shader->get_name() == "mm_gouraud");
1286
1287 for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color),
1288 std::make_pair(&m_iva_blockers, blockers_color)}) {
1289 iva.first->set_color(iva.second);
1290 iva.first->render();
1291 }
1292
1293 for (auto& iva : m_iva_seed_fills) {
1294 size_t color_idx = &iva - &m_iva_seed_fills.front();
1295 const ColorRGBA& color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color :
1296 color_idx == 2 ? blockers_color :
1298 iva.set_color(color);
1299 iva.render();
1300 }
1301
1302 render_paint_contour(matrix);
1303
1304#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
1305 if (imgui)
1306 render_debug(imgui);
1307 else
1308 assert(false); // If you want debug output, pass ptr to ImGuiWrapper.
1309#endif
1310}
static ColorRGBA NEUTRAL_COLOR
Definition 3DScene.hpp:97
static ColorRGBA get_seed_fill_color(const ColorRGBA &base_color)
Definition GLGizmoPainterBase.cpp:1265
static ColorRGBA blockers_color
Definition GLGizmoPainterBase.hpp:67
static ColorRGBA enforcers_color
Definition GLGizmoPainterBase.hpp:66
bool m_update_render_data
Definition GLGizmoPainterBase.hpp:76
GLModel m_iva_enforcers
Definition GLGizmoPainterBase.hpp:85
void update_render_data()
Definition GLGizmoPainterBase.cpp:1312
void render_paint_contour(const Transform3d &matrix)
Definition GLGizmoPainterBase.cpp:1944
std::array< GLModel, 3 > m_iva_seed_fills
Definition GLGizmoPainterBase.hpp:87
GLModel m_iva_blockers
Definition GLGizmoPainterBase.hpp:86

References blockers_color, enforcers_color, get_seed_fill_color(), m_iva_blockers, m_iva_enforcers, m_iva_seed_fills, m_update_render_data, Slic3r::GLVolume::NEUTRAL_COLOR, render_paint_contour(), and update_render_data().

Here is the call graph for this function:

◆ render_paint_contour()

void Slic3r::GUI::TriangleSelectorGUI::render_paint_contour ( const Transform3d & matrix)
1945{
1946 auto* curr_shader = wxGetApp().get_current_shader();
1947 if (curr_shader != nullptr)
1948 curr_shader->stop_using();
1949
1950 auto* contour_shader = wxGetApp().get_shader("mm_contour");
1951 if (contour_shader != nullptr) {
1952 contour_shader->start_using();
1953
1954 contour_shader->set_uniform("offset", OpenGLManager::get_gl_info().is_mesa() ? 0.0005 : 0.00001);
1955 const Camera& camera = wxGetApp().plater()->get_camera();
1956 contour_shader->set_uniform("view_model_matrix", camera.get_view_matrix() * matrix);
1957 contour_shader->set_uniform("projection_matrix", camera.get_projection_matrix());
1958
1959 m_paint_contour.render();
1960
1961 contour_shader->stop_using();
1962 }
1963
1964 if (curr_shader != nullptr)
1965 curr_shader->start_using();
1966}
static const GLInfo & get_gl_info()
Definition OpenGLManager.hpp:106
GLModel m_paint_contour
Definition GLGizmoPainterBase.hpp:93
@ Camera
Definition Shortcuts.hpp:72

References Slic3r::GUI::OpenGLManager::get_gl_info(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::Camera::get_view_matrix(), and m_paint_contour.

Referenced by render(), and Slic3r::GUI::TriangleSelectorPatch::render().

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

◆ request_update_render_data()

void Slic3r::GUI::TriangleSelectorGUI::request_update_render_data ( bool paint_changed = false)
inline
60 {
62 m_paint_changed |= paint_changed;
63 }
bool m_paint_changed
Definition GLGizmoPainterBase.hpp:78

References m_paint_changed, and m_update_render_data.

Referenced by Slic3r::GUI::GLGizmoFdmSupports::on_render_input_window(), Slic3r::GUI::GLGizmoMmuSegmentation::on_render_input_window(), Slic3r::GUI::GLGizmoMmuSegmentation::remap_filament_assignments(), and Slic3r::GUI::GLGizmoTextureDisplacement::select_visible_faces().

Here is the caller graph for this function:

◆ reset()

void Slic3r::TriangleSelector::reset ( )
inherited
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)
inherited
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 )
inherited
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 ( )
inherited
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 )
inherited
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 )
privateinherited
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 )
privateinherited
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
nodiscardinherited
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
nodiscardinherited
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
inherited
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)
inherited
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 )
inherited
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:

◆ set_wireframe_needed()

void Slic3r::GUI::TriangleSelectorGUI::set_wireframe_needed ( bool need_wireframe)
inline
55{ m_need_wireframe = need_wireframe; }

References m_need_wireframe.

◆ shift_states_above()

void Slic3r::TriangleSelector::shift_states_above ( EnforcerBlockerType threshold,
int delta )
inherited
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 )
privateinherited
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
privateinherited
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
privateinherited
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 )
privateinherited
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 )
staticprivateinherited
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
privateinherited
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)
privateinherited
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:

◆ update_paint_contour()

void Slic3r::GUI::TriangleSelectorGUI::update_paint_contour ( )
protected
1922{
1923 m_paint_contour.reset();
1924
1925 GLModel::Geometry init_data;
1926 const std::vector<Vec2i32> contour_edges = this->get_seed_fill_contour();
1928 init_data.reserve_vertices(2 * contour_edges.size());
1929 init_data.reserve_indices(2 * contour_edges.size());
1930 init_data.color = ColorRGBA::WHITE();
1931 // vertices + indices
1932 unsigned int vertices_count = 0;
1933 for (const Vec2i32& edge : contour_edges) {
1934 init_data.add_vertex(m_vertices[edge(0)].v);
1935 init_data.add_vertex(m_vertices[edge(1)].v);
1936 vertices_count += 2;
1937 init_data.add_line(vertices_count - 2, vertices_count - 1);
1938 }
1939
1940 if (!init_data.is_empty())
1941 m_paint_contour.init_from(std::move(init_data));
1942}
static const ColorRGBA WHITE()
Definition Color.hpp:142
std::vector< Vec2i32 > get_seed_fill_contour() const
Definition TriangleSelector.cpp:1673
Eigen::Matrix< int32_t, 2, 1, Eigen::DontAlign > Vec2i32
Definition Point.hpp:57

References Slic3r::GUI::GLModel::Geometry::add_line(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::GUI::GLModel::Geometry::color, Slic3r::GUI::GLModel::Geometry::format, Slic3r::TriangleSelector::get_seed_fill_contour(), Slic3r::GUI::GLModel::Geometry::is_empty(), Slic3r::GUI::GLModel::Geometry::Lines, m_paint_contour, Slic3r::TriangleSelector::m_vertices, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::Geometry::reserve_indices(), Slic3r::GUI::GLModel::Geometry::reserve_vertices(), and Slic3r::ColorRGBA::WHITE().

Referenced by update_render_data(), and Slic3r::GUI::TriangleSelectorPatch::update_render_data().

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

◆ update_render_data()

void Slic3r::GUI::TriangleSelectorGUI::update_render_data ( )
private
1313{
1314 int enf_cnt = 0;
1315 int blc_cnt = 0;
1316 std::vector<int> seed_fill_cnt(m_iva_seed_fills.size(), 0);
1317
1318 for (auto* iva : { &m_iva_enforcers, &m_iva_blockers }) {
1319 iva->reset();
1320 }
1321
1322 for (auto& iva : m_iva_seed_fills) {
1323 iva.reset();
1324 }
1325
1326 GLModel::Geometry iva_enforcers_data;
1328 GLModel::Geometry iva_blockers_data;
1330 std::array<GLModel::Geometry, 3> iva_seed_fills_data;
1331 for (auto& data : iva_seed_fills_data)
1333
1334 // small value used to offset triangles along their normal to avoid z-fighting
1335 static const float offset = 0.001f;
1336
1337 for (const Triangle &tr : m_triangles) {
1338 if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill()))
1339 continue;
1340
1341 int tr_state = int(tr.get_state());
1342 GLModel::Geometry &iva = tr.is_selected_by_seed_fill() ? iva_seed_fills_data[tr_state] :
1343 tr.get_state() == EnforcerBlockerType::ENFORCER ? iva_enforcers_data :
1344 iva_blockers_data;
1345 int &cnt = tr.is_selected_by_seed_fill() ? seed_fill_cnt[tr_state] :
1346 tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt :
1347 blc_cnt;
1348 const Vec3f &v0 = m_vertices[tr.verts_idxs[0]].v;
1349 const Vec3f &v1 = m_vertices[tr.verts_idxs[1]].v;
1350 const Vec3f &v2 = m_vertices[tr.verts_idxs[2]].v;
1351 //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort
1352 // or the current implementation may be more cache friendly.
1353 const Vec3f n = (v1 - v0).cross(v2 - v1).normalized();
1354 // small value used to offset triangles along their normal to avoid z-fighting
1355 const Vec3f offset_n = offset * n;
1356 iva.add_vertex(v0 + offset_n, n);
1357 iva.add_vertex(v1 + offset_n, n);
1358 iva.add_vertex(v2 + offset_n, n);
1359 iva.add_triangle((unsigned int)cnt, (unsigned int)cnt + 1, (unsigned int)cnt + 2);
1360 cnt += 3;
1361 }
1362
1363 if (!iva_enforcers_data.is_empty())
1364 m_iva_enforcers.init_from(std::move(iva_enforcers_data));
1365 if (!iva_blockers_data.is_empty())
1366 m_iva_blockers.init_from(std::move(iva_blockers_data));
1367 for (size_t i = 0; i < m_iva_seed_fills.size(); ++i) {
1368 if (!iva_seed_fills_data[i].is_empty())
1369 m_iva_seed_fills[i].init_from(std::move(iva_seed_fills_data[i]));
1370 }
1371
1373}
void update_paint_contour()
Definition GLGizmoPainterBase.cpp:1921
@ ENFORCER
Definition TriangleSelector.hpp:27
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cross(), Slic3r::ENFORCER, Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::Geometry::is_empty(), m_iva_blockers, m_iva_enforcers, m_iva_seed_fills, Slic3r::TriangleSelector::m_triangles, Slic3r::TriangleSelector::m_vertices, Slic3r::NONE, Slic3r::offset(), Slic3r::GUI::GLModel::Geometry::P3N3, Slic3r::GUI::GLModel::Geometry::Triangles, and update_paint_contour().

Referenced by render().

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
privateinherited
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
protectedinherited
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:

Member Data Documentation

◆ blockers_color

◆ enforcers_color

◆ m_cursor

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

◆ m_edge_limit

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

Referenced by TriangleSelector().

◆ m_edge_limit_sqr

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

Referenced by set_edge_limit(), and split_triangle().

◆ m_face_normals

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

◆ m_free_triangles_head

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

◆ m_free_vertices_head

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

◆ m_invalid_triangles

int Slic3r::TriangleSelector::m_invalid_triangles
protectedinherited

◆ m_iva_blockers

GLModel Slic3r::GUI::TriangleSelectorGUI::m_iva_blockers
private

Referenced by render(), and update_render_data().

◆ m_iva_enforcers

GLModel Slic3r::GUI::TriangleSelectorGUI::m_iva_enforcers
private

Referenced by render(), and update_render_data().

◆ m_iva_seed_fills

std::array<GLModel, 3> Slic3r::GUI::TriangleSelectorGUI::m_iva_seed_fills
private

Referenced by render(), and update_render_data().

◆ m_mesh

const TriangleMesh& Slic3r::TriangleSelector::m_mesh
protectedinherited

◆ m_need_wireframe

◆ m_neighbors

◆ m_old_cursor_radius_sqr

float Slic3r::TriangleSelector::m_old_cursor_radius_sqr = 0
protectedinherited

Referenced by select_patch().

◆ m_orig_size_indices

int Slic3r::TriangleSelector::m_orig_size_indices = 0
protectedinherited

◆ m_orig_size_vertices

int Slic3r::TriangleSelector::m_orig_size_vertices = 0
protectedinherited

Referenced by garbage_collect(), and reset().

◆ m_paint_changed

bool Slic3r::GUI::TriangleSelectorGUI::m_paint_changed = true
protected

◆ m_paint_contour

GLModel Slic3r::GUI::TriangleSelectorGUI::m_paint_contour
protected

◆ m_triangles

◆ m_update_render_data

bool Slic3r::GUI::TriangleSelectorGUI::m_update_render_data = false
protected

◆ m_vertices


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