Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TriangleSelector.hpp « libslic3r « src - github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 11387c766ce28e195acaf299ab7f0914ed6b1124 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#ifndef libslic3r_TriangleSelector_hpp_
#define libslic3r_TriangleSelector_hpp_

// #define PRUSASLICER_TRIANGLE_SELECTOR_DEBUG


#include "Point.hpp"
#include "TriangleMesh.hpp"

namespace Slic3r {

enum class EnforcerBlockerType : int8_t;



// Following class holds information about selected triangles. It also has power
// to recursively subdivide the triangles and make the selection finer.
class TriangleSelector {
public:
    enum CursorType {
        CIRCLE,
        SPHERE
    };

    void set_edge_limit(float edge_limit);

    // Create new object on a TriangleMesh. The referenced mesh must
    // stay valid, a ptr to it is saved and used.
    explicit TriangleSelector(const TriangleMesh& mesh);

    // Select all triangles fully inside the circle, subdivide where needed.
    void select_patch(const Vec3f& hit,    // point where to start
                      int facet_start,     // facet that point belongs to
                      const Vec3f& source, // camera position (mesh coords)
                      float radius,        // radius of the cursor
                      CursorType type,     // current type of cursor
                      EnforcerBlockerType new_state,   // enforcer or blocker?
                      const Transform3d& trafo); // matrix to get from mesh to world

    // Get facets currently in the given state.
    indexed_triangle_set get_facets(EnforcerBlockerType state) const;

    // Set facet of the mesh to a given state. Only works for original triangles.
    void set_facet(int facet_idx, EnforcerBlockerType state);

    // Clear everything and make the tree empty.
    void reset();

    // Remove all unnecessary data.
    void garbage_collect();

    // Store the division trees in compact form (a long stream of
    // bits for each triangle of the original mesh).
    std::map<int, std::vector<bool>> serialize() const;

    // Load serialized data. Assumes that correct mesh is loaded.
    void deserialize(const std::map<int, std::vector<bool>> data);


protected:
    // Triangle and info about how it's split.
    class Triangle {
    public:
        // Use TriangleSelector::push_triangle to create a new triangle.
        // It increments/decrements reference counter on vertices.
        Triangle(int a, int b, int c)
            : verts_idxs{a, b, c},
              state{EnforcerBlockerType(0)},
              number_of_splits{0},
              special_side_idx{0},
              old_number_of_splits{0}
        {}
        // Indices into m_vertices.
        std::array<int, 3> verts_idxs;

        // Is this triangle valid or marked to be removed?
        bool valid{true};

        // Children triangles.
        std::array<int, 4> children;

        // Set the division type.
        void set_division(int sides_to_split, int special_side_idx = -1);

        // Get/set current state.
        void set_state(EnforcerBlockerType type) { assert(! is_split()); state = type; }
        EnforcerBlockerType get_state() const { assert(! is_split()); return state; }

        // Get info on how it's split.
        bool is_split() const { return number_of_split_sides() != 0; }
        int number_of_split_sides() const { return number_of_splits; }
        int special_side() const  { assert(is_split()); return special_side_idx; }
        bool was_split_before() const { return old_number_of_splits != 0; }
        void forget_history() { old_number_of_splits = 0; }

    private:
        int number_of_splits;
        int special_side_idx;
        EnforcerBlockerType state;

        // How many children were spawned during last split?
        // Is not reset on remerging the triangle.
        int old_number_of_splits;
    };

    struct Vertex {
        explicit Vertex(const stl_vertex& vert)
            : v{vert},
              ref_cnt{0}
        {}
        stl_vertex v;
        int ref_cnt;
    };

    // Lists of vertices and triangles, both original and new
    std::vector<Vertex> m_vertices;
    std::vector<Triangle> m_triangles;
    const TriangleMesh* m_mesh;

    // Number of invalid triangles (to trigger garbage collection).
    int m_invalid_triangles;

    // Limiting length of triangle side (squared).
    float m_edge_limit_sqr = 1.f;

    // Number of original vertices and triangles.
    int m_orig_size_vertices = 0;
    int m_orig_size_indices = 0;

    // Cache for cursor position, radius and direction.
    struct Cursor {
        Cursor() = default;
        Cursor(const Vec3f& center_, const Vec3f& source_, float radius_world,
               CursorType type_, const Transform3d& trafo_);
        bool is_mesh_point_inside(Vec3f pt) const;
        bool is_pointer_in_triangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) const;

        Vec3f center;
        Vec3f source;
        Vec3f dir;
        float radius_sqr;
        CursorType type;
        Transform3f trafo;
        Transform3f trafo_normal;
        bool uniform_scaling;
    };

    Cursor m_cursor;
    float m_old_cursor_radius_sqr;

    // Private functions:
    bool select_triangle(int facet_idx, EnforcerBlockerType type,
                         bool recursive_call = false);
    int  vertices_inside(int facet_idx) const;
    bool faces_camera(int facet) const;
    void undivide_triangle(int facet_idx);
    void split_triangle(int facet_idx);
    void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant.
    bool is_pointer_in_triangle(int facet_idx) const;
    bool is_edge_inside_cursor(int facet_idx) const;
    void push_triangle(int a, int b, int c);
    void perform_split(int facet_idx, EnforcerBlockerType old_state);
};




} // namespace Slic3r

#endif // libslic3r_TriangleSelector_hpp_