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

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

Inheritance diagram for Slic3r::GUI::TriangleSelectorPatch:
Collaboration diagram for Slic3r::GUI::TriangleSelectorPatch:

Public Types

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

Public Member Functions

 TriangleSelectorPatch (const TriangleMesh &mesh, const std::vector< ColorRGBA > ebt_colors, float edge_limit=0.6f)
virtual ~TriangleSelectorPatch ()=default
void render (ImGuiWrapper *imgui, const Transform3d &matrix) override
void update_triangles_per_type ()
void update_selector_triangles ()
void update_triangles_per_patch ()
void set_ebt_colors (const std::vector< ColorRGBA > ebt_colors)
void set_filter_state (bool is_filter_state)
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 constexpr float GapAreaMin = 0.f
static constexpr float GapAreaMax = 5.f
static constexpr float GapAreaStep = 0.2f
static float gap_area = TriangleSelectorPatch::GapAreaMin
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 release_geometry ()
void finalize_vertices ()
void finalize_triangle_indices ()
void clear ()
bool has_VBOs (size_t triangle_indices_idx) const
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

std::vector< TrianglePatch > m_triangle_patches
std::vector< size_t > m_triangle_indices_sizes
unsigned int m_vertices_VAO_id { 0 }
std::vector< unsigned int > m_vertices_VBO_ids
std::vector< unsigned int > m_triangle_indices_VBO_ids
std::vector< ColorRGBA > m_ebt_colors
bool m_filter_state = false
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 ()
void render (int buffer_idx, bool show_wireframe=false)
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

◆ TriangleSelectorPatch()

Slic3r::GUI::TriangleSelectorPatch::TriangleSelectorPatch ( const TriangleMesh & mesh,
const std::vector< ColorRGBA > ebt_colors,
float edge_limit = 0.6f )
inlineexplicit
116 : TriangleSelectorGUI(mesh, edge_limit), m_ebt_colors(ebt_colors) {}
TriangleSelectorGUI(const TriangleMesh &mesh, float edge_limit=0.6f)
Definition GLGizmoPainterBase.hpp:46
std::vector< ColorRGBA > m_ebt_colors
Definition GLGizmoPainterBase.hpp:183

References Slic3r::GUI::TriangleSelectorGUI::TriangleSelectorGUI(), and m_ebt_colors.

Here is the call graph for this function:

◆ ~TriangleSelectorPatch()

virtual Slic3r::GUI::TriangleSelectorPatch::~TriangleSelectorPatch ( )
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:

◆ clear()

void Slic3r::GUI::TriangleSelectorPatch::clear ( )
inlineprotected
149 {
150 // BBS
151 this->m_vertices_VBO_ids.clear();
152 this->m_triangle_indices_VBO_ids.clear();
153 this->m_triangle_indices_sizes.clear();
154
155 for (TrianglePatch& patch : this->m_triangle_patches)
156 {
157 patch.patch_vertices.clear();
158 patch.triangle_indices.clear();
159 }
160 this->m_triangle_patches.clear();
161 }
std::vector< size_t > m_triangle_indices_sizes
Definition GLGizmoPainterBase.hpp:174
std::vector< unsigned int > m_triangle_indices_VBO_ids
Definition GLGizmoPainterBase.hpp:181
std::vector< TrianglePatch > m_triangle_patches
Definition GLGizmoPainterBase.hpp:170
std::vector< unsigned int > m_vertices_VBO_ids
Definition GLGizmoPainterBase.hpp:180

References m_triangle_indices_sizes, m_triangle_indices_VBO_ids, m_triangle_patches, and m_vertices_VBO_ids.

Referenced by release_geometry().

Here is the caller 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:

◆ finalize_triangle_indices()

void Slic3r::GUI::TriangleSelectorPatch::finalize_triangle_indices ( )
protected
1766{
1767#if !SLIC3R_OPENGL_ES
1768 if (OpenGLManager::get_gl_info().is_core_profile()) {
1769#endif // !SLIC3R_OPENGL_ES
1770 assert(this->m_vertices_VAO_id == 0);
1771#if !SLIC3R_OPENGL_ES
1772 }
1773#endif // !SLIC3R_OPENGL_ES
1777 assert(std::all_of(m_triangle_indices_VBO_ids.cbegin(), m_triangle_indices_VBO_ids.cend(), [](const auto& ti_VBO_id) { return ti_VBO_id == 0; }));
1778
1779 for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) {
1780 std::vector<float>& patch_vertices = m_triangle_patches[buffer_idx].patch_vertices;
1781 if (!patch_vertices.empty()) {
1782 glsafe(::glGenBuffers(1, &m_vertices_VBO_ids[buffer_idx]));
1784 glsafe(::glBufferData(GL_ARRAY_BUFFER, patch_vertices.size() * sizeof(float), patch_vertices.data(), GL_STATIC_DRAW));
1786 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%patch_vertices.size()%m_vertices_VBO_ids[buffer_idx];
1787 patch_vertices.clear();
1788 }
1789
1790 std::vector<int>& triangle_indices = m_triangle_patches[buffer_idx].triangle_indices;
1791 m_triangle_indices_sizes[buffer_idx] = triangle_indices.size();
1792 if (!triangle_indices.empty()) {
1795 glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangle_indices.size() * sizeof(int), triangle_indices.data(), GL_STATIC_DRAW));
1797 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%triangle_indices.size()%m_triangle_indices_VBO_ids[buffer_idx];
1798 triangle_indices.clear();
1799 }
1800 }
1801
1802#if !SLIC3R_OPENGL_ES
1803 if (OpenGLManager::get_gl_info().is_core_profile()) {
1804#endif // !SLIC3R_OPENGL_ES
1807#if !SLIC3R_OPENGL_ES
1808 }
1809#endif // !SLIC3R_OPENGL_ES
1810}
#define glsafe(cmd)
Definition OpenGLUtils.hpp:25
static const GLInfo & get_gl_info()
Definition OpenGLManager.hpp:106
unsigned int m_vertices_VAO_id
Definition GLGizmoPainterBase.hpp:178
#define glGenBuffers
Definition gl.h:3769
#define glBindBuffer
Definition gl.h:3267
#define glBindVertexArray
Definition gl.h:3307
#define GL_ARRAY_BUFFER
Definition gl.h:238
#define glGenVertexArrays
Definition gl.h:3791
#define glBufferData
Definition gl.h:3339
#define GL_STATIC_DRAW
Definition gl.h:1633
#define GL_ELEMENT_ARRAY_BUFFER
Definition gl.h:636

References Slic3r::GUI::OpenGLManager::get_gl_info(), GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, glBindBuffer, glBindVertexArray, glBufferData, glGenBuffers, glGenVertexArrays, glsafe, m_triangle_indices_sizes, m_triangle_indices_VBO_ids, m_triangle_patches, m_vertices_VAO_id, and m_vertices_VBO_ids.

Referenced by update_render_data().

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

◆ finalize_vertices()

void Slic3r::GUI::TriangleSelectorPatch::finalize_vertices ( )
protected
1754{
1755 /*assert(m_vertices_VBO_id == 0);
1756 if (!this->m_patch_vertices.empty()) {
1757 glsafe(::glGenBuffers(1, &this->m_vertices_VBO_id));
1758 glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_id));
1759 glsafe(::glBufferData(GL_ARRAY_BUFFER, this->m_patch_vertices.size() * sizeof(float), this->m_patch_vertices.data(), GL_STATIC_DRAW));
1760 glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
1761 this->m_patch_vertices.clear();
1762 }*/
1763}

◆ 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)
staticprotectedinherited
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 ( )
inlineinherited
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:

◆ has_VBOs()

bool Slic3r::GUI::TriangleSelectorPatch::has_VBOs ( size_t triangle_indices_idx) const
inlinenodiscardprotected
164 {
165 assert(triangle_indices_idx < this->m_triangle_patches.size());
166 return this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0;
167 }

References m_triangle_indices_VBO_ids, and m_triangle_patches.

Referenced by render().

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:

◆ release_geometry()

void Slic3r::GUI::TriangleSelectorPatch::release_geometry ( )
protected
1725{
1726 /*if (m_vertices_VBO_id) {
1727 glsafe(::glDeleteBuffers(1, &m_vertices_VBO_id));
1728 m_vertices_VBO_id = 0;
1729 }*/
1730#if !SLIC3R_OPENGL_ES
1731 if (OpenGLManager::get_gl_info().is_core_profile()) {
1732#endif // !SLIC3R_OPENGL_ES
1733 if (this->m_vertices_VAO_id > 0) {
1735 this->m_vertices_VAO_id = 0;
1736 }
1737#if !SLIC3R_OPENGL_ES
1738 }
1739#endif // !SLIC3R_OPENGL_ES
1740 for (auto& vertice_VBO_id : m_vertices_VBO_ids) {
1741 glsafe(::glDeleteBuffers(1, &vertice_VBO_id));
1742 vertice_VBO_id = 0;
1743 }
1744 for (auto& triangle_indices_VBO_id : m_triangle_indices_VBO_ids) {
1745 glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
1746 triangle_indices_VBO_id = 0;
1747 }
1748 this->clear();
1749
1750 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: released geometry")%__LINE__;
1751}
void clear()
Definition GLGizmoPainterBase.hpp:148
#define glDeleteVertexArrays
Definition gl.h:3591
#define glDeleteBuffers
Definition gl.h:3563

References clear(), Slic3r::GUI::OpenGLManager::get_gl_info(), glDeleteBuffers, glDeleteVertexArrays, glsafe, m_triangle_indices_VBO_ids, m_vertices_VAO_id, and m_vertices_VBO_ids.

Referenced by set_filter_state(), and update_render_data().

Here is the call graph for this function:
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
TriangleSelector(const TriangleMesh &mesh, float edge_limit=0.6f)
Definition TriangleSelector.cpp:1344
auto intersecting(const G &g)
Definition AABBTreeIndirect.hpp:925
void traverse(const Tree< Dims, T > &tree, Predicate &&pred, Fn &&callback)
Definition AABBTreeIndirect.hpp:986
Tree< 3, typename VertexType::Scalar > build_aabb_tree_over_indexed_triangle_set(const std::vector< VertexType > &vertices, const std::vector< IndexedFaceType > &faces, const typename VertexType::Scalar eps=0)
Definition AABBTreeIndirect.hpp:677
Tree< 3, float > Tree3f
Definition AABBTreeIndirect.hpp:222
static bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3)
Definition TriangleSelector.cpp:251
T cross(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:168
static bool segments_intersect_proj(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3, const Vec3f &p4, const std::pair< int, int > &proj)
Definition TriangleSelector.cpp:2350

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

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

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

◆ remap_triangle_state()

void Slic3r::TriangleSelector::remap_triangle_state ( const EnforcerBlockerStateMap & state_map)
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() [1/2]

void Slic3r::GUI::TriangleSelectorPatch::render ( ImGuiWrapper * imgui,
const Transform3d & matrix )
overridevirtual

Reimplemented from Slic3r::GUI::TriangleSelectorGUI.

1384{
1385 static bool last_show_wireframe = false;
1386 if (last_show_wireframe != wxGetApp().plater()->is_show_wireframe()) {
1387 last_show_wireframe = wxGetApp().plater()->is_show_wireframe();
1388 m_update_render_data = true;
1389 m_paint_changed = true;
1390 }
1393 m_update_render_data = false;
1394 }
1395
1396 auto* shader = wxGetApp().get_current_shader();
1397 if (!shader)
1398 return;
1399 assert(shader->get_name() == "gouraud" || shader->get_name() == "mm_gouraud");
1400 bool show_wireframe = false;
1401 if (wxGetApp().plater()->is_wireframe_enabled()) {
1402 if (m_need_wireframe && wxGetApp().plater()->is_show_wireframe()) {
1403 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe on");
1404 shader->set_uniform("show_wireframe", true);
1405 show_wireframe = true;
1406 }
1407 else {
1408 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe off");
1409 shader->set_uniform("show_wireframe", false);
1410 }
1411 }
1412
1413 for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) {
1414 if (this->has_VBOs(buffer_idx)) {
1415 const TrianglePatch& patch = m_triangle_patches[buffer_idx];
1416 ColorRGBA color;
1417 if (patch.is_fragment() && !patch.neighbor_types.empty()) {
1418 size_t color_idx = (size_t)*patch.neighbor_types.begin();
1419 color = m_ebt_colors[color_idx];
1420 color.a(0.85);
1421 }
1422 else {
1423 size_t color_idx = (size_t)patch.type;
1424 color = m_ebt_colors[color_idx];
1425 }
1426 //to make black not too hard too see
1427 ColorRGBA new_color = adjust_color_for_rendering(color);
1428 shader->set_uniform("uniform_color", new_color);
1429 this->render(buffer_idx, show_wireframe);
1430 }
1431 }
1432
1433 render_paint_contour(matrix);
1434}
Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors)
Definition 3DScene.cpp:112
bool m_update_render_data
Definition GLGizmoPainterBase.hpp:76
void render_paint_contour(const Transform3d &matrix)
Definition GLGizmoPainterBase.cpp:1944
bool m_paint_changed
Definition GLGizmoPainterBase.hpp:78
bool has_VBOs(size_t triangle_indices_idx) const
Definition GLGizmoPainterBase.hpp:163
void update_render_data()
Definition GLGizmoPainterBase.cpp:1632
void render(ImGuiWrapper *imgui, const Transform3d &matrix) override
Definition GLGizmoPainterBase.cpp:1383
static Plater * plater()
Definition GUI_Factories.cpp:400

References Slic3r::ColorRGBA::a(), adjust_color_for_rendering(), has_VBOs(), Slic3r::GUI::TrianglePatch::is_fragment(), m_ebt_colors, Slic3r::GUI::TriangleSelectorGUI::m_need_wireframe, Slic3r::GUI::TriangleSelectorGUI::m_paint_changed, m_triangle_patches, Slic3r::GUI::TriangleSelectorGUI::m_update_render_data, Slic3r::GUI::TrianglePatch::neighbor_types, Slic3r::GUI::plater(), render(), Slic3r::GUI::TriangleSelectorGUI::render_paint_contour(), Slic3r::GUI::TrianglePatch::type, and update_render_data().

Referenced by render().

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

◆ render() [2/2]

void Slic3r::GUI::TriangleSelectorPatch::render ( int buffer_idx,
bool show_wireframe = false )
private
1661{
1662 assert(triangle_indices_idx < this->m_triangle_indices_VBO_ids.size());
1663 assert(this->m_triangle_patches.size() == this->m_triangle_indices_VBO_ids.size());
1664#if !SLIC3R_OPENGL_ES
1665 if (OpenGLManager::get_gl_info().is_core_profile()) {
1666#endif // !SLIC3R_OPENGL_ES
1667 assert(this->m_vertices_VAO_id != 0);
1668#if !SLIC3R_OPENGL_ES
1669 }
1670#endif // !SLIC3R_OPENGL_ES
1671 //assert(this->m_vertices_VBO_id != 0);
1672 assert(this->m_triangle_patches.size() == this->m_vertices_VBO_ids.size());
1673 assert(this->m_vertices_VBO_ids[triangle_indices_idx] != 0);
1674 assert(this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0);
1675
1676 GLShaderProgram *shader = wxGetApp().get_current_shader();
1677 if (shader == nullptr)
1678 return;
1679
1680#if !SLIC3R_OPENGL_ES
1681 if (OpenGLManager::get_gl_info().is_core_profile()) {
1682#endif // !SLIC3R_OPENGL_ES
1684#if !SLIC3R_OPENGL_ES
1685 }
1686#endif // !SLIC3R_OPENGL_ES
1687 // the following binding is needed to set the vertex attributes
1688 glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx]));
1689 const GLint position_id = shader->get_attrib_location("v_position");
1690 if (position_id != -1) {
1691 if (show_wireframe) {
1692 glsafe(::glVertexAttribPointer((GLint) position_id, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void *) 0));
1693 } else {
1694 glsafe(::glVertexAttribPointer((GLint) position_id, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr));
1695 }
1697 }
1698 GLint barycentric_id = -1;
1699 // Orca: This is required even if wireframe is not displayed, otherwise on AMD Vega GPUs the painter gizmo won't render properly
1700 /*if (show_wireframe)*/ {
1701 barycentric_id = shader->get_attrib_location("v_barycentric");
1702 if (barycentric_id != -1) {
1703 glsafe(::glVertexAttribPointer((GLint) barycentric_id, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (const void *) (3 * sizeof(float))));
1704 glsafe(::glEnableVertexAttribArray((GLint) barycentric_id));
1705 }
1706 }
1707
1708 // Render using the Vertex Buffer Objects.
1709 if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) {
1711 glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->m_triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr));
1713 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: triangle_indices_idx %2%, bind indices vbo, buffer id %3%")%__LINE__%triangle_indices_idx%this->m_triangle_indices_VBO_ids[triangle_indices_idx];
1714 }
1715
1716 if (position_id != -1)
1718 if (barycentric_id != -1)
1719 glsafe(::glDisableVertexAttribArray(barycentric_id));
1720
1722}
#define glDisableVertexAttribArray
Definition gl.h:3613
int GLint
Definition gl.h:2062
#define GL_TRIANGLES
Definition gl.h:1887
#define GL_UNSIGNED_INT
Definition gl.h:1940
#define GL_FLOAT
Definition gl.h:660
#define glEnableVertexAttribArray
Definition gl.h:3673
#define glDrawElements
Definition gl.h:3633
#define glVertexAttribPointer
Definition gl.h:5315
int GLsizei
Definition gl.h:2065
#define GL_FALSE
Definition gl.h:648

References Slic3r::GLShaderProgram::get_attrib_location(), Slic3r::GUI::OpenGLManager::get_gl_info(), GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_FALSE, GL_FLOAT, GL_TRIANGLES, GL_UNSIGNED_INT, glBindBuffer, glBindVertexArray, glDisableVertexAttribArray, glDrawElements, glEnableVertexAttribArray, glsafe, glVertexAttribPointer, m_triangle_indices_sizes, m_triangle_indices_VBO_ids, m_triangle_patches, m_vertices_VAO_id, and m_vertices_VBO_ids.

Here is the call graph for this function:

◆ render_paint_contour()

void Slic3r::GUI::TriangleSelectorGUI::render_paint_contour ( const Transform3d & matrix)
inherited
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}
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)
inlineinherited
60 {
62 m_paint_changed |= paint_changed;
63 }

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

void Slic3r::GUI::TriangleSelectorPatch::set_ebt_colors ( const std::vector< ColorRGBA > ebt_colors)
inline
128{ m_ebt_colors = ebt_colors; }

References m_ebt_colors.

Referenced by Slic3r::GUI::GLGizmoMmuSegmentation::update_triangle_selectors_colors().

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

void Slic3r::GUI::TriangleSelectorPatch::set_filter_state ( bool is_filter_state)
1622{
1623 if (!m_filter_state && is_filter_state) {
1624 m_filter_state = is_filter_state;
1625 this->release_geometry();
1627 }
1628
1629 m_filter_state = is_filter_state;
1630}
bool m_filter_state
Definition GLGizmoPainterBase.hpp:185
void release_geometry()
Definition GLGizmoPainterBase.cpp:1724

References m_filter_state, release_geometry(), and update_render_data().

Referenced by Slic3r::GUI::GLGizmoFdmSupports::tool_changed(), Slic3r::GUI::GLGizmoMmuSegmentation::tool_changed(), and Slic3r::GUI::GLGizmoSeam::tool_changed().

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)
inlineinherited
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 ( )
protectedinherited
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::TriangleSelectorPatch::update_render_data ( )
private
1633{
1634 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", m_paint_changed=%1%, m_triangle_patches.size %2%")%m_paint_changed%m_triangle_patches.size();
1635 if (m_paint_changed || (m_triangle_patches.size() == 0)) {
1636 this->release_geometry();
1637
1638 /*m_patch_vertices.reserve(m_vertices.size() * 3);
1639 for (const Vertex& vr : m_vertices) {
1640 m_patch_vertices.emplace_back(vr.v.x());
1641 m_patch_vertices.emplace_back(vr.v.y());
1642 m_patch_vertices.emplace_back(vr.v.z());
1643 }
1644 this->finalize_vertices();*/
1645
1646 if (m_filter_state)
1648 else
1651
1652 m_paint_changed = false;
1653 }
1654
1655 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", before paint_contour");
1657 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", exit");
1658}
void update_paint_contour()
Definition GLGizmoPainterBase.cpp:1921
void update_triangles_per_type()
Definition GLGizmoPainterBase.cpp:1436
void finalize_triangle_indices()
Definition GLGizmoPainterBase.cpp:1765
void update_triangles_per_patch()
Definition GLGizmoPainterBase.cpp:1499

References finalize_triangle_indices(), m_filter_state, Slic3r::GUI::TriangleSelectorGUI::m_paint_changed, m_triangle_patches, release_geometry(), Slic3r::GUI::TriangleSelectorGUI::update_paint_contour(), update_triangles_per_patch(), and update_triangles_per_type().

Referenced by render(), and set_filter_state().

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

◆ update_selector_triangles()

void Slic3r::GUI::TriangleSelectorPatch::update_selector_triangles ( )
1487{
1488 for (TrianglePatch& patch : m_triangle_patches) {
1489 if (!patch.is_fragment() || patch.neighbor_types.empty())
1490 continue;
1491
1492 EnforcerBlockerType type = *patch.neighbor_types.begin();
1493 for (int facet_idx : patch.facet_indices) {
1494 m_triangles[facet_idx].set_state(type);
1495 }
1496 }
1497}

References m_triangle_patches, and Slic3r::TriangleSelector::m_triangles.

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

Here is the caller graph for this function:

◆ update_triangles_per_patch()

void Slic3r::GUI::TriangleSelectorPatch::update_triangles_per_patch ( )
1500{
1501 auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors();
1502 std::vector<bool> visited(m_triangles.size(), false);
1503
1504 bool using_wireframe = (m_need_wireframe && wxGetApp().plater()->is_wireframe_enabled() && wxGetApp().plater()->is_show_wireframe()) ? true : false;
1505
1506 auto get_all_touching_triangles = [this](int facet_idx, const Vec3i32& neighbors, const Vec3i32& neighbors_propagated) -> std::vector<int> {
1507 assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
1508 assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
1509 std::vector<int> touching_triangles;
1510 Vec3i32 vertices = { m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2] };
1511 append_touching_subtriangles(neighbors(0), vertices(1), vertices(0), touching_triangles);
1512 append_touching_subtriangles(neighbors(1), vertices(2), vertices(1), touching_triangles);
1513 append_touching_subtriangles(neighbors(2), vertices(0), vertices(2), touching_triangles);
1514
1515 for (int neighbor_idx : neighbors_propagated)
1516 if (neighbor_idx != -1 && !m_triangles[neighbor_idx].is_split())
1517 touching_triangles.emplace_back(neighbor_idx);
1518
1519 return touching_triangles;
1520 };
1521
1522 auto calc_fragment_area = [](const TrianglePatch& patch, float max_limit_area, int stride) {
1523 double total_area = 0.f;
1524 const std::vector<int>& ti = patch.triangle_indices;
1525 /*for (int i = 0; i < ti.size() / 3; i++) {
1526 total_area += std::abs((m_vertices[ti[i]].v - m_vertices[ti[i + 1]].v)
1527 .cross(m_vertices[ti[i]].v - m_vertices[ti[i + 2]].v).norm()) / 2;
1528 if (total_area >= max_limit_area)
1529 break;
1530 }*/
1531 const std::vector<float>& vertices = patch.patch_vertices;
1532 for (int i = 0; i < ti.size(); i+=3) {
1533 stl_vertex v0(vertices[ti[i] * stride], vertices[ti[i] * stride + 1], vertices[ti[i] * stride + 2]);
1534 stl_vertex v1(vertices[ti[i + 1] * stride], vertices[ti[i + 1] * stride + 1], vertices[ti[i + 1] * stride + 2]);
1535 stl_vertex v2(vertices[ti[i + 2] * stride], vertices[ti[i + 2] * stride + 1], vertices[ti[i + 2] * stride + 2]);
1536 total_area += std::abs((v0 - v1).cross(v0 - v2).norm()) / 2;
1537 if (total_area >= max_limit_area)
1538 break;
1539 }
1540
1541 return total_area;
1542 };
1543
1544 int start_facet_idx = 0;
1545 while (1) {
1546 for (; start_facet_idx < visited.size(); start_facet_idx++) {
1547 if (!visited[start_facet_idx] && m_triangles[start_facet_idx].valid() && !m_triangles[start_facet_idx].is_split())
1548 break;
1549 }
1550
1551 if (start_facet_idx >= m_triangles.size())
1552 break;
1553
1554 EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state();
1555 TrianglePatch patch;
1556 std::queue<int> facet_queue;
1557 facet_queue.push(start_facet_idx);
1558 while (!facet_queue.empty()) {
1559 int current_facet = facet_queue.front();
1560 facet_queue.pop();
1561 assert(!m_triangles[current_facet].is_split());
1562
1563 if (!visited[current_facet]) {
1564 Triangle& triangle = m_triangles[current_facet];
1565 for (int i = 0; i < 3; ++i) {
1566 int j = triangle.verts_idxs[i];
1567 int index = using_wireframe?int(patch.patch_vertices.size()/6) : int(patch.patch_vertices.size()/3);
1568 patch.patch_vertices.emplace_back(m_vertices[j].v(0));
1569 patch.patch_vertices.emplace_back(m_vertices[j].v(1));
1570 patch.patch_vertices.emplace_back(m_vertices[j].v(2));
1571 if (using_wireframe) {
1572 if (i == 0) {
1573 patch.patch_vertices.emplace_back(1.0);
1574 patch.patch_vertices.emplace_back(0.0);
1575 patch.patch_vertices.emplace_back(0.0);
1576 }
1577 else if (i == 1) {
1578 patch.patch_vertices.emplace_back(0.0);
1579 patch.patch_vertices.emplace_back(1.0);
1580 patch.patch_vertices.emplace_back(0.0);
1581 }
1582 else {
1583 patch.patch_vertices.emplace_back(0.0);
1584 patch.patch_vertices.emplace_back(0.0);
1585 patch.patch_vertices.emplace_back(1.0);
1586 }
1587 }
1588 patch.triangle_indices.emplace_back( index);
1589 }
1590 //patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end());
1591 patch.facet_indices.push_back(current_facet);
1592
1593 std::vector<int> touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]);
1594 for (const int tr_idx : touching_triangles) {
1595 if (tr_idx < 0)
1596 continue;
1597
1598 if (m_triangles[tr_idx].get_state() != start_facet_state) {
1599 patch.neighbor_types.insert(m_triangles[tr_idx].get_state());
1600 continue;
1601 }
1602
1603 // should check visited state after color for neight types
1604 if (visited[tr_idx])
1605 continue;
1606
1607 assert(!m_triangles[tr_idx].is_split());
1608 facet_queue.push(tr_idx);
1609 }
1610 }
1611
1612 visited[current_facet] = true;
1613 }
1614
1615 patch.area = calc_fragment_area(patch, GapAreaMax, using_wireframe?6:3);
1616 patch.type = start_facet_state;
1617 m_triangle_patches.emplace_back(std::move(patch));
1618 }
1619}
static constexpr float GapAreaMax
Definition GLGizmoPainterBase.hpp:132

References Slic3r::TriangleSelector::append_touching_subtriangles(), Slic3r::GUI::TrianglePatch::area, Slic3r::cross(), Slic3r::GUI::TrianglePatch::facet_indices, GapAreaMax, Slic3r::GUI::TriangleSelectorGUI::m_need_wireframe, m_triangle_patches, Slic3r::TriangleSelector::m_triangles, Slic3r::TriangleSelector::m_vertices, Slic3r::GUI::TrianglePatch::neighbor_types, Slic3r::GUI::TrianglePatch::patch_vertices, Slic3r::TriangleSelector::precompute_all_neighbors(), Slic3r::GUI::TrianglePatch::triangle_indices, Slic3r::GUI::TrianglePatch::type, Slic3r::TriangleSelector::verify_triangle_neighbors(), and Slic3r::TriangleSelector::Triangle::verts_idxs.

Referenced by update_render_data().

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

◆ update_triangles_per_type()

void Slic3r::GUI::TriangleSelectorPatch::update_triangles_per_type ( )
1437{
1438 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", enter");
1440 for (int i = 0; i < m_triangle_patches.size(); i++) {
1441 auto& patch = m_triangle_patches[i];
1442 patch.type = (EnforcerBlockerType)i;
1443 patch.triangle_indices.reserve(m_triangles.size() / 3);
1444 }
1445
1446 bool using_wireframe = (m_need_wireframe && wxGetApp().plater()->is_wireframe_enabled() && wxGetApp().plater()->is_show_wireframe()) ? true : false;
1447
1448 for (auto& triangle : m_triangles) {
1449 if (!triangle.valid() || triangle.is_split())
1450 continue;
1451
1452 int state = (int)triangle.get_state();
1453 auto& patch = m_triangle_patches[state];
1454 //patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end());
1455 for (int i = 0; i < 3; ++i) {
1456 int j = triangle.verts_idxs[i];
1457 int index = using_wireframe?int(patch.patch_vertices.size()/6) : int(patch.patch_vertices.size()/3);
1458 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: i=%2%, j=%3%, index=%4%, v[%5%,%6%,%7%]")%__LINE__%i%j%index%m_vertices[j].v(0)%m_vertices[j].v(1)%m_vertices[j].v(2);
1459 patch.patch_vertices.emplace_back(m_vertices[j].v(0));
1460 patch.patch_vertices.emplace_back(m_vertices[j].v(1));
1461 patch.patch_vertices.emplace_back(m_vertices[j].v(2));
1462 if (using_wireframe) {
1463 if (i == 0) {
1464 patch.patch_vertices.emplace_back(1.0);
1465 patch.patch_vertices.emplace_back(0.0);
1466 patch.patch_vertices.emplace_back(0.0);
1467 }
1468 else if (i == 1) {
1469 patch.patch_vertices.emplace_back(0.0);
1470 patch.patch_vertices.emplace_back(1.0);
1471 patch.patch_vertices.emplace_back(0.0);
1472 }
1473 else {
1474 patch.patch_vertices.emplace_back(0.0);
1475 patch.patch_vertices.emplace_back(0.0);
1476 patch.patch_vertices.emplace_back(1.0);
1477 }
1478 }
1479 patch.triangle_indices.emplace_back( index);
1480 }
1481 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: state=%2%, vertice size=%3%, triangle size %4%")%__LINE__%state%patch.patch_vertices.size()%patch.triangle_indices.size();
1482 }
1483 //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("exit");
1484}

References Slic3r::ExtruderMax, Slic3r::GUI::TriangleSelectorGUI::m_need_wireframe, m_triangle_patches, Slic3r::TriangleSelector::m_triangles, and Slic3r::TriangleSelector::m_vertices.

Referenced by update_render_data().

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

◆ gap_area

◆ GapAreaMax

◆ GapAreaMin

◆ GapAreaStep

float Slic3r::GUI::TriangleSelectorPatch::GapAreaStep = 0.2f
staticconstexpr

◆ m_cursor

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

◆ m_ebt_colors

std::vector<ColorRGBA> Slic3r::GUI::TriangleSelectorPatch::m_ebt_colors
protected

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

bool Slic3r::GUI::TriangleSelectorPatch::m_filter_state = false
protected

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

Referenced by render(), and update_render_data().

◆ m_iva_enforcers

GLModel Slic3r::GUI::TriangleSelectorGUI::m_iva_enforcers
privateinherited

Referenced by render(), and update_render_data().

◆ m_iva_seed_fills

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

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
protectedinherited

◆ m_paint_contour

GLModel Slic3r::GUI::TriangleSelectorGUI::m_paint_contour
protectedinherited

◆ m_triangle_indices_sizes

std::vector<size_t> Slic3r::GUI::TriangleSelectorPatch::m_triangle_indices_sizes
protected

◆ m_triangle_indices_VBO_ids

std::vector<unsigned int> Slic3r::GUI::TriangleSelectorPatch::m_triangle_indices_VBO_ids
protected

◆ m_triangle_patches

◆ m_triangles

◆ m_update_render_data

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

◆ m_vertices

◆ m_vertices_VAO_id

unsigned int Slic3r::GUI::TriangleSelectorPatch::m_vertices_VAO_id { 0 }
protected

◆ m_vertices_VBO_ids

std::vector<unsigned int> Slic3r::GUI::TriangleSelectorPatch::m_vertices_VBO_ids
protected

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