Refactoring of Cursors in TriangleSelector as preparation for upcoming improvements of painting.

This commit is contained in:
Lukáš Hejl 2021-11-15 11:39:47 +01:00
parent fc089fd2c5
commit e898eda320
3 changed files with 175 additions and 127 deletions

View file

@ -124,24 +124,20 @@ int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx) c
return this->select_unsplit_triangle(hit, facet_idx, neighbors); return this->select_unsplit_triangle(hit, facet_idx, neighbors);
} }
void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, void 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)
const Vec3f& source, float radius,
CursorType cursor_type, EnforcerBlockerType new_state,
const Transform3d& trafo, const Transform3d& trafo_no_translate,
bool triangle_splitting, const ClippingPlane &clp, float highlight_by_angle_deg)
{ {
assert(facet_start < m_orig_size_indices); assert(facet_start < m_orig_size_indices);
// Save current cursor center, squared radius and camera direction, so we don't // Save current cursor center, squared radius and camera direction, so we don't
// have to pass it around. // have to pass it around.
m_cursor = Cursor(hit, source, radius, cursor_type, trafo, clp); m_cursor = std::move(cursor);
// In case user changed cursor size since last time, update triangle edge limit. // In case user changed cursor size since last time, update triangle edge limit.
// It is necessary to compare the internal radius in m_cursor! radius is in // It is necessary to compare the internal radius in m_cursor! radius is in
// world coords and does not change after scaling. // world coords and does not change after scaling.
if (m_old_cursor_radius_sqr != m_cursor.radius_sqr) { if (m_old_cursor_radius_sqr != m_cursor->radius_sqr) {
set_edge_limit(std::sqrt(m_cursor.radius_sqr) / 5.f); set_edge_limit(std::sqrt(m_cursor->radius_sqr) / 5.f);
m_old_cursor_radius_sqr = m_cursor.radius_sqr; m_old_cursor_radius_sqr = m_cursor->radius_sqr;
} }
const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg)); const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg));
@ -163,7 +159,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
if (select_triangle(facet, new_state, triangle_splitting)) { if (select_triangle(facet, new_state, triangle_splitting)) {
// add neighboring facets to list to be processed later // add neighboring facets to list to be processed later
for (int neighbor_idx : m_neighbors[facet]) for (int neighbor_idx : m_neighbors[facet])
if (neighbor_idx >= 0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx))) if (neighbor_idx >= 0 && m_cursor->is_facet_visible(neighbor_idx, m_face_normals))
facets_to_check.push_back(neighbor_idx); facets_to_check.push_back(neighbor_idx);
} }
} }
@ -788,11 +784,11 @@ bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i &nei
assert(this->verify_triangle_neighbors(*tr, neighbors)); assert(this->verify_triangle_neighbors(*tr, neighbors));
int num_of_inside_vertices = vertices_inside(facet_idx); int num_of_inside_vertices = m_cursor->vertices_inside(*tr, m_vertices);
if (num_of_inside_vertices == 0 if (num_of_inside_vertices == 0
&& ! is_pointer_in_triangle(facet_idx) && ! m_cursor->is_pointer_in_triangle(*tr, m_vertices)
&& ! is_edge_inside_cursor(facet_idx)) && ! m_cursor->is_edge_inside_cursor(*tr, m_vertices))
return false; return false;
if (num_of_inside_vertices == 3) { if (num_of_inside_vertices == 3) {
@ -840,7 +836,7 @@ void TriangleSelector::set_facet(int facet_idx, EnforcerBlockerType state)
} }
// called by select_patch()->select_triangle()...select_triangle() // called by select_patch()->select_triangle()...select_triangle()
// to decide which sides of the traingle to split and to actually split it calling set_division() and perform_split(). // to decide which sides of the triangle to split and to actually split it calling set_division() and perform_split().
void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors) void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors)
{ {
if (m_triangles[facet_idx].is_split()) { if (m_triangles[facet_idx].is_split()) {
@ -864,9 +860,9 @@ void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors)
// In case the object is non-uniformly scaled, transform the // In case the object is non-uniformly scaled, transform the
// points to world coords. // points to world coords.
if (! m_cursor.uniform_scaling) { if (! m_cursor->uniform_scaling) {
for (size_t i=0; i<pts.size(); ++i) { for (size_t i=0; i<pts.size(); ++i) {
pts_transformed[i] = m_cursor.trafo * (*pts[i]); pts_transformed[i] = m_cursor->trafo * (*pts[i]);
pts[i] = &pts_transformed[i]; pts[i] = &pts_transformed[i];
} }
} }
@ -897,72 +893,63 @@ void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors)
perform_split(facet_idx, neighbors, old_type); perform_split(facet_idx, neighbors, old_type);
} }
// Is pointer in a triangle? // Is pointer in a triangle?
bool TriangleSelector::is_pointer_in_triangle(int facet_idx) const bool TriangleSelector::Cursor::is_pointer_in_triangle(const Triangle &tr, const std::vector<Vertex> &vertices) const {
{ const Vec3f& p1 = vertices[tr.verts_idxs[0]].v;
const Vec3f& p1 = m_vertices[m_triangles[facet_idx].verts_idxs[0]].v; const Vec3f& p2 = vertices[tr.verts_idxs[1]].v;
const Vec3f& p2 = m_vertices[m_triangles[facet_idx].verts_idxs[1]].v; const Vec3f& p3 = vertices[tr.verts_idxs[2]].v;
const Vec3f& p3 = m_vertices[m_triangles[facet_idx].verts_idxs[2]].v; return this->is_pointer_in_triangle(p1, p2, p3);
return m_cursor.is_pointer_in_triangle(p1, p2, p3);
} }
// Determine whether this facet is potentially visible (still can be obscured). // Determine whether this facet is potentially visible (still can be obscured).
bool TriangleSelector::faces_camera(int facet) const bool TriangleSelector::Circle::is_facet_visible(int facet_idx, const std::vector<Vec3f> &face_normals) const
{ {
assert(facet < m_orig_size_indices); assert(facet_idx < int(face_normals.size()));
Vec3f n = m_face_normals[facet]; Vec3f n = face_normals[facet_idx];
if (! m_cursor.uniform_scaling) if (!this->uniform_scaling)
n = m_cursor.trafo_normal * n; n = this->trafo_normal * n;
return n.dot(m_cursor.dir) < 0.; return n.dot(this->dir) < 0.f;
} }
// How many vertices of a triangle are inside the circle? // How many vertices of a triangle are inside the circle?
int TriangleSelector::vertices_inside(int facet_idx) const int TriangleSelector::Cursor::vertices_inside(const Triangle &tr, const std::vector<Vertex> &vertices) const
{ {
int inside = 0; int inside = 0;
for (size_t i=0; i<3; ++i) { for (size_t i = 0; i < 3; ++i)
if (m_cursor.is_mesh_point_inside(m_vertices[m_triangles[facet_idx].verts_idxs[i]].v)) if (this->is_mesh_point_inside(vertices[tr.verts_idxs[i]].v))
++inside; ++inside;
}
return inside; return inside;
} }
// Is edge inside cursor? // Is edge inside cursor?
bool TriangleSelector::is_edge_inside_cursor(int facet_idx) const bool TriangleSelector::SinglePointCursor::is_edge_inside_cursor(const Triangle &tr, const std::vector<Vertex> &vertices) const
{ {
std::array<Vec3f, 3> pts; std::array<Vec3f, 3> pts;
for (int i=0; i<3; ++i) { for (int i = 0; i < 3; ++i) {
pts[i] = m_vertices[m_triangles[facet_idx].verts_idxs[i]].v; pts[i] = vertices[tr.verts_idxs[i]].v;
if (! m_cursor.uniform_scaling) if (!this->uniform_scaling)
pts[i] = m_cursor.trafo * pts[i]; pts[i] = this->trafo * pts[i];
} }
const Vec3f& p = m_cursor.center; const Vec3f &p = this->center;
for (int side = 0; side < 3; ++side) { for (int side = 0; side < 3; ++side) {
const Vec3f& a = pts[side]; const Vec3f &a = pts[side];
const Vec3f& b = pts[side<2 ? side+1 : 0]; const Vec3f &b = pts[side < 2 ? side + 1 : 0];
Vec3f s = (b-a).normalized(); Vec3f s = (b - a).normalized();
float t = (p-a).dot(s); float t = (p - a).dot(s);
Vec3f vector = a+t*s - p; Vec3f vector = a + t * s - p;
// vector is 3D vector from center to the intersection. What we want to // vector is 3D vector from center to the intersection. What we want to
// measure is length of its projection onto plane perpendicular to dir. // measure is length of its projection onto plane perpendicular to dir.
float dist_sqr = vector.squaredNorm() - std::pow(vector.dot(m_cursor.dir), 2.f); float dist_sqr = vector.squaredNorm() - std::pow(vector.dot(this->dir), 2.f);
if (dist_sqr < m_cursor.radius_sqr && t>=0.f && t<=(b-a).norm()) if (dist_sqr < this->radius_sqr && t >= 0.f && t <= (b - a).norm())
return true; return true;
} }
return false; return false;
} }
// Recursively remove all subtriangles. // Recursively remove all subtriangles.
void TriangleSelector::undivide_triangle(int facet_idx) void TriangleSelector::undivide_triangle(int facet_idx)
{ {
@ -1002,7 +989,6 @@ void TriangleSelector::undivide_triangle(int facet_idx)
} }
} }
void TriangleSelector::remove_useless_children(int facet_idx) void TriangleSelector::remove_useless_children(int facet_idx)
{ {
// Check that all children are leafs of the same type. If not, try to // Check that all children are leafs of the same type. If not, try to
@ -1041,8 +1027,6 @@ void TriangleSelector::remove_useless_children(int facet_idx)
tr.set_state(first_child_type); tr.set_state(first_child_type);
} }
void TriangleSelector::garbage_collect() void TriangleSelector::garbage_collect()
{ {
// First make a map from old to new triangle indices. // First make a map from old to new triangle indices.
@ -1103,7 +1087,6 @@ TriangleSelector::TriangleSelector(const TriangleMesh& mesh)
reset(); reset();
} }
void TriangleSelector::reset() void TriangleSelector::reset()
{ {
m_vertices.clear(); m_vertices.clear();
@ -1124,17 +1107,11 @@ void TriangleSelector::reset()
} }
void TriangleSelector::set_edge_limit(float edge_limit) void TriangleSelector::set_edge_limit(float edge_limit)
{ {
m_edge_limit_sqr = std::pow(edge_limit, 2.f); m_edge_limit_sqr = std::pow(edge_limit, 2.f);
} }
int TriangleSelector::push_triangle(int a, int b, int c, int source_triangle, const EnforcerBlockerType state) int TriangleSelector::push_triangle(int a, int b, int c, int source_triangle, const EnforcerBlockerType state)
{ {
for (int i : {a, b, c}) { for (int i : {a, b, c}) {
@ -1693,42 +1670,55 @@ void TriangleSelector::seed_fill_apply_on_triangles(EnforcerBlockerType new_stat
} }
} }
TriangleSelector::Cursor::Cursor( TriangleSelector::Cursor::Cursor(const Vec3f &source_, float radius_world, const Transform3d &trafo_, const ClippingPlane &clipping_plane_)
const Vec3f& center_, const Vec3f& source_, float radius_world, : source{source_}, trafo{trafo_.cast<float>()}, clipping_plane{clipping_plane_}
CursorType type_, const Transform3d& trafo_, const ClippingPlane &clipping_plane_)
: center{center_},
source{source_},
type{type_},
trafo{trafo_.cast<float>()},
clipping_plane(clipping_plane_)
{ {
Vec3d sf = Geometry::Transformation(trafo_).get_scaling_factor(); Vec3d sf = Geometry::Transformation(trafo_).get_scaling_factor();
if (is_approx(sf(0), sf(1)) && is_approx(sf(1), sf(2))) { if (is_approx(sf(0), sf(1)) && is_approx(sf(1), sf(2))) {
radius_sqr = float(std::pow(radius_world / sf(0), 2)); radius_sqr = float(std::pow(radius_world / sf(0), 2));
uniform_scaling = true; uniform_scaling = true;
} } else {
else {
// In case that the transformation is non-uniform, all checks whether // In case that the transformation is non-uniform, all checks whether
// something is inside the cursor should be done in world coords. // something is inside the cursor should be done in world coords.
// First transform center, source and dir in world coords and remember // First transform source in world coords and remember that we did this.
// that we did this.
center = trafo * center;
source = trafo * source; source = trafo * source;
uniform_scaling = false; uniform_scaling = false;
radius_sqr = radius_world * radius_world; radius_sqr = radius_world * radius_world;
trafo_normal = trafo.linear().inverse().transpose(); trafo_normal = trafo.linear().inverse().transpose();
} }
}
TriangleSelector::SinglePointCursor::SinglePointCursor(const Vec3f& center_, const Vec3f& source_, float radius_world, const Transform3d& trafo_, const ClippingPlane &clipping_plane_)
: center{center_}, Cursor(source_, radius_world, trafo_, clipping_plane_)
{
// In case that the transformation is non-uniform, all checks whether
// something is inside the cursor should be done in world coords.
// Because of the center is transformed.
if (!uniform_scaling)
center = trafo * center;
// Calculate dir, in whatever coords is appropriate. // Calculate dir, in whatever coords is appropriate.
dir = (center - source).normalized(); dir = (center - source).normalized();
} }
// Is a point (in mesh coords) inside a cursor? // Is a point (in mesh coords) inside a Sphere cursor?
bool TriangleSelector::Cursor::is_mesh_point_inside(const Vec3f &point) const bool TriangleSelector::Sphere::is_mesh_point_inside(const Vec3f &point) const
{
const Vec3f transformed_point = uniform_scaling ? point : Vec3f(trafo * point);
const bool is_point_inside = (center - point).squaredNorm() < radius_sqr;
if (is_point_inside && clipping_plane.is_active())
return !clipping_plane.is_mesh_point_clipped(point);
return is_point_inside;
}
// Is a point (in mesh coords) inside a Circle cursor?
bool TriangleSelector::Circle::is_mesh_point_inside(const Vec3f &point) const
{ {
const Vec3f transformed_point = uniform_scaling ? point : Vec3f(trafo * point); const Vec3f transformed_point = uniform_scaling ? point : Vec3f(trafo * point);
const Vec3f diff = center - transformed_point; const Vec3f diff = center - transformed_point;
const bool is_point_inside = (type == CIRCLE ? (diff - diff.dot(dir) * dir).squaredNorm() : diff.squaredNorm()) < radius_sqr; const bool is_point_inside = (diff - diff.dot(dir) * dir).squaredNorm() < radius_sqr;
if (is_point_inside && clipping_plane.is_active()) if (is_point_inside && clipping_plane.is_active())
return !clipping_plane.is_mesh_point_clipped(point); return !clipping_plane.is_mesh_point_clipped(point);
@ -1737,10 +1727,7 @@ bool TriangleSelector::Cursor::is_mesh_point_inside(const Vec3f &point) const
} }
// p1, p2, p3 are in mesh coords! // p1, p2, p3 are in mesh coords!
bool TriangleSelector::Cursor::is_pointer_in_triangle(const Vec3f& p1_, static bool is_circle_pointer_inside_triangle(const Vec3f &p1_, const Vec3f &p2_, const Vec3f &p3_, const Vec3f &center, const Vec3f &dir, const bool uniform_scaling, const Transform3f &trafo) {
const Vec3f& p2_,
const Vec3f& p3_) const
{
const Vec3f& q1 = center + dir; const Vec3f& q1 = center + dir;
const Vec3f& q2 = center - dir; const Vec3f& q2 = center - dir;
@ -1761,4 +1748,10 @@ bool TriangleSelector::Cursor::is_pointer_in_triangle(const Vec3f& p1_,
return signed_volume_sign(q1,q2,p2,p3) == pos && signed_volume_sign(q1,q2,p3,p1) == pos; return signed_volume_sign(q1,q2,p2,p3) == pos && signed_volume_sign(q1,q2,p3,p1) == pos;
} }
// p1, p2, p3 are in mesh coords!
bool TriangleSelector::SinglePointCursor::is_pointer_in_triangle(const Vec3f &p1_, const Vec3f &p2_, const Vec3f &p3_) const
{
return is_circle_pointer_inside_triangle(p1_, p2_, p3_, center, dir, uniform_scaling, trafo);
}
} // namespace Slic3r } // namespace Slic3r

View file

@ -15,7 +15,12 @@ enum class EnforcerBlockerType : int8_t;
// Following class holds information about selected triangles. It also has power // Following class holds information about selected triangles. It also has power
// to recursively subdivide the triangles and make the selection finer. // to recursively subdivide the triangles and make the selection finer.
class TriangleSelector { class TriangleSelector
{
protected:
class Triangle;
struct Vertex;
public: public:
enum CursorType { enum CursorType {
CIRCLE, CIRCLE,
@ -35,6 +40,83 @@ public:
bool is_mesh_point_clipped(const Vec3f &point) const { return normal.dot(point) - offset > 0.f; } bool is_mesh_point_clipped(const Vec3f &point) const { return normal.dot(point) - offset > 0.f; }
}; };
class Cursor
{
public:
Cursor() = delete;
virtual ~Cursor() = default;
bool is_pointer_in_triangle(const Triangle &tr, const std::vector<Vertex> &vertices) const;
virtual bool is_mesh_point_inside(const Vec3f &point) const = 0;
virtual bool is_pointer_in_triangle(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) const = 0;
virtual int vertices_inside(const Triangle &tr, const std::vector<Vertex> &vertices) const;
virtual bool is_edge_inside_cursor(const Triangle &tr, const std::vector<Vertex> &vertices) const = 0;
virtual bool is_facet_visible(int facet_idx, const std::vector<Vec3f> &face_normals) const { return true; }
protected:
explicit Cursor(const Vec3f &source_, float radius_world, const Transform3d &trafo_, const ClippingPlane &clipping_plane_);
Transform3f trafo;
Vec3f source;
bool uniform_scaling;
Transform3f trafo_normal;
float radius_sqr;
Vec3f dir = Vec3f(0.f, 0.f, 0.f);
ClippingPlane clipping_plane; // Clipping plane to limit painting to not clipped facets only
friend TriangleSelector;
};
class SinglePointCursor : public Cursor
{
public:
SinglePointCursor() = delete;
~SinglePointCursor() override = default;
bool is_edge_inside_cursor(const Triangle &tr, const std::vector<Vertex> &vertices) const override;
bool is_pointer_in_triangle(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) const override;
static std::unique_ptr<Cursor> cursor_factory(const Vec3f &center, const Vec3f &camera_pos, const float cursor_radius, const CursorType cursor_type, const Transform3d &trafo_matrix, const ClippingPlane &clipping_plane)
{
assert(cursor_type == TriangleSelector::CursorType::CIRCLE || cursor_type == TriangleSelector::CursorType::SPHERE);
if (cursor_type == TriangleSelector::CursorType::SPHERE)
return std::make_unique<TriangleSelector::Sphere>(center, camera_pos, cursor_radius, trafo_matrix, clipping_plane);
else
return std::make_unique<TriangleSelector::Circle>(center, camera_pos, cursor_radius, trafo_matrix, clipping_plane);
}
protected:
explicit SinglePointCursor(const Vec3f &center_, const Vec3f &source_, float radius_world, const Transform3d &trafo_, const ClippingPlane &clipping_plane_);
Vec3f center;
};
class Sphere : public SinglePointCursor
{
public:
Sphere() = delete;
explicit Sphere(const Vec3f &center_, const Vec3f &source_, float radius_world, const Transform3d &trafo_, const ClippingPlane &clipping_plane_)
: SinglePointCursor(center_, source_, radius_world, trafo_, clipping_plane_){};
~Sphere() override = default;
bool is_mesh_point_inside(const Vec3f &point) const override;
};
class Circle : public SinglePointCursor
{
public:
Circle() = delete;
explicit Circle(const Vec3f &center_, const Vec3f &source_, float radius_world, const Transform3d &trafo_, const ClippingPlane &clipping_plane_)
: SinglePointCursor(center_, source_, radius_world, trafo_, clipping_plane_){};
~Circle() override = default;
bool is_mesh_point_inside(const Vec3f &point) const override;
bool is_facet_visible(int facet_idx, const std::vector<Vec3f> &face_normals) const override;
};
std::pair<std::vector<Vec3i>, std::vector<Vec3i>> precompute_all_neighbors() const; std::pair<std::vector<Vec3i>, std::vector<Vec3i>> precompute_all_neighbors() const;
void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out, std::vector<Vec3i> &neighbors_normal_out) const; void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out, std::vector<Vec3i> &neighbors_normal_out) const;
@ -51,16 +133,11 @@ public:
[[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const; [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const;
// Select all triangles fully inside the circle, subdivide where needed. // Select all triangles fully inside the circle, subdivide where needed.
void select_patch(const Vec3f &hit, // point where to start void select_patch(int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to std::unique_ptr<Cursor> &&cursor, // Cursor containing information about the point where to start, camera position (mesh coords), matrix to get from mesh to world, and its shape and type.
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? EnforcerBlockerType new_state, // enforcer or blocker?
const Transform3d &trafo, // matrix to get from mesh to world
const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation
bool triangle_splitting, // If triangles will be split base on the cursor or not bool triangle_splitting, // If triangles will be split base on the cursor or not
const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only
float highlight_by_angle_deg = 0.f); // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees. float highlight_by_angle_deg = 0.f); // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees.
void seed_fill_select_triangles(const Vec3f &hit, // point where to start void seed_fill_select_triangles(const Vec3f &hit, // point where to start
@ -195,39 +272,16 @@ protected:
int m_orig_size_vertices = 0; int m_orig_size_vertices = 0;
int m_orig_size_indices = 0; int m_orig_size_indices = 0;
// Cache for cursor position, radius and direction. std::unique_ptr<Cursor> m_cursor;
struct Cursor {
Cursor() = default;
Cursor(const Vec3f& center_, const Vec3f& source_, float radius_world,
CursorType type_, const Transform3d& trafo_, const ClippingPlane &clipping_plane_);
bool is_mesh_point_inside(const 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;
ClippingPlane clipping_plane;
};
Cursor m_cursor;
float m_old_cursor_radius_sqr; float m_old_cursor_radius_sqr;
// Private functions: // Private functions:
private: private:
bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting); bool select_triangle(int facet_idx, EnforcerBlockerType type, bool triangle_splitting);
bool select_triangle_recursive(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType type, bool triangle_splitting); bool select_triangle_recursive(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType type, bool triangle_splitting);
int vertices_inside(int facet_idx) const;
bool faces_camera(int facet) const;
void undivide_triangle(int facet_idx); void undivide_triangle(int facet_idx);
void split_triangle(int facet_idx, const Vec3i &neighbors); void split_triangle(int facet_idx, const Vec3i &neighbors);
void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant. 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;
bool is_facet_clipped(int facet_idx, const ClippingPlane &clp) const; 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}); int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0});
void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state); void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state);

View file

@ -365,10 +365,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, true, true); m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, true, true);
m_seed_fill_last_mesh_id = -1; m_seed_fill_last_mesh_id = -1;
} else if (m_tool_type == ToolType::BRUSH) } else if (m_tool_type == ToolType::BRUSH) {
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type, auto cursor = TriangleSelector::SinglePointCursor::cursor_factory(m_rr.hit, camera_pos, m_cursor_radius, m_cursor_type, trafo_matrix, clp);
new_state, trafo_matrix, trafo_matrix_not_translate, m_triangle_splitting_enabled, clp, m_triangle_selectors[m_rr.mesh_id]->select_patch(int(m_rr.facet), std::move(cursor), new_state, trafo_matrix_not_translate, m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f); }
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
m_last_mouse_click = mouse_position; m_last_mouse_click = mouse_position;
} }