mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 08:56:02 +08:00
Optimize painting using single triangle brush.
Especially on the detail models, painting using the single triangle brush is noticeably faster.
This commit is contained in:
parent
8cd2e8264a
commit
72f47f7963
@ -583,11 +583,17 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f &hit, int facet_
|
|||||||
|
|
||||||
assert(!m_triangles[start_facet_idx].is_split());
|
assert(!m_triangles[start_facet_idx].is_split());
|
||||||
TriangleStateType start_facet_state = m_triangles[start_facet_idx].get_state();
|
TriangleStateType start_facet_state = m_triangles[start_facet_idx].get_state();
|
||||||
this->seed_fill_unselect_all_triangles();
|
|
||||||
|
|
||||||
if (propagate == BucketFillPropagate::NO) {
|
if (propagate == BucketFillPropagate::NO) {
|
||||||
|
if (m_triangle_selected_by_seed_fill != -1)
|
||||||
|
this->seed_fill_unselect_triangle(m_triangle_selected_by_seed_fill);
|
||||||
|
|
||||||
m_triangles[start_facet_idx].select_by_seed_fill();
|
m_triangles[start_facet_idx].select_by_seed_fill();
|
||||||
|
m_triangle_selected_by_seed_fill = start_facet_idx;
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
m_triangle_selected_by_seed_fill = -1;
|
||||||
|
this->seed_fill_unselect_all_triangles();
|
||||||
}
|
}
|
||||||
|
|
||||||
const float facet_angle_limit = std::cos(Geometry::deg2rad(bucket_fill_angle)) - EPSILON;
|
const float facet_angle_limit = std::cos(Geometry::deg2rad(bucket_fill_angle)) - EPSILON;
|
||||||
@ -1286,42 +1292,43 @@ void TriangleSelector::undivide_triangle(int facet_idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleSelector::remove_useless_children(int facet_idx)
|
// Returns true when some triangle during recursive descending was removed (undivided).
|
||||||
{
|
bool 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
|
||||||
// make them (recursive call). Remove them if sucessful.
|
// make them (recursive call). Remove them if successful.
|
||||||
|
|
||||||
assert(facet_idx < int(m_triangles.size()) && m_triangles[facet_idx].valid());
|
assert(facet_idx < int(m_triangles.size()) && m_triangles[facet_idx].valid());
|
||||||
Triangle& tr = m_triangles[facet_idx];
|
Triangle &tr = m_triangles[facet_idx];
|
||||||
|
|
||||||
if (! tr.is_split()) {
|
if (!tr.is_split()) {
|
||||||
// This is a leaf, there nothing to do. This can happen during the
|
// This is a leaf, there nothing to do. This can happen during the
|
||||||
// first (non-recursive call). Shouldn't otherwise.
|
// first (non-recursive call). Shouldn't otherwise.
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this for all non-leaf children.
|
// Call this for all non-leaf children.
|
||||||
for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
|
bool children_removed = false;
|
||||||
|
for (int child_idx = 0; child_idx <= tr.number_of_split_sides(); ++child_idx) {
|
||||||
assert(child_idx < int(m_triangles.size()) && m_triangles[child_idx].valid());
|
assert(child_idx < int(m_triangles.size()) && m_triangles[child_idx].valid());
|
||||||
if (m_triangles[tr.children[child_idx]].is_split())
|
if (m_triangles[tr.children[child_idx]].is_split())
|
||||||
remove_useless_children(tr.children[child_idx]);
|
children_removed |= remove_useless_children(tr.children[child_idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return if a child is not leaf or two children differ in type.
|
// Return if a child is not leaf or two children differ in type.
|
||||||
TriangleStateType first_child_type = TriangleStateType::NONE;
|
TriangleStateType first_child_type = TriangleStateType::NONE;
|
||||||
for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
|
for (int child_idx = 0; child_idx <= tr.number_of_split_sides(); ++child_idx) {
|
||||||
if (m_triangles[tr.children[child_idx]].is_split())
|
if (m_triangles[tr.children[child_idx]].is_split())
|
||||||
return;
|
return children_removed;
|
||||||
if (child_idx == 0)
|
if (child_idx == 0)
|
||||||
first_child_type = m_triangles[tr.children[0]].get_state();
|
first_child_type = m_triangles[tr.children[0]].get_state();
|
||||||
else if (m_triangles[tr.children[child_idx]].get_state() != first_child_type)
|
else if (m_triangles[tr.children[child_idx]].get_state() != first_child_type)
|
||||||
return;
|
return children_removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got here, the children can be removed.
|
// If we got here, the children can be removed.
|
||||||
undivide_triangle(facet_idx);
|
undivide_triangle(facet_idx);
|
||||||
tr.set_state(first_child_type);
|
tr.set_state(first_child_type);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleSelector::garbage_collect()
|
void TriangleSelector::garbage_collect()
|
||||||
@ -2050,7 +2057,22 @@ void TriangleSelector::seed_fill_unselect_all_triangles()
|
|||||||
triangle.unselect_by_seed_fill();
|
triangle.unselect_by_seed_fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriangleSelector::seed_fill_unselect_triangle(const int facet_idx) {
|
||||||
|
assert(facet_idx > 0 && facet_idx < m_triangles.size());
|
||||||
|
Triangle &triangle = m_triangles[facet_idx];
|
||||||
|
|
||||||
|
assert(!triangle.is_split());
|
||||||
|
if (!triangle.is_split())
|
||||||
|
triangle.unselect_by_seed_fill();
|
||||||
|
}
|
||||||
|
|
||||||
void TriangleSelector::seed_fill_apply_on_triangles(TriangleStateType new_state) {
|
void TriangleSelector::seed_fill_apply_on_triangles(TriangleStateType new_state) {
|
||||||
|
if (m_triangle_selected_by_seed_fill != -1) {
|
||||||
|
this->seed_fill_apply_on_single_triangle(new_state, m_triangle_selected_by_seed_fill);
|
||||||
|
m_triangle_selected_by_seed_fill = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Triangle &triangle : m_triangles)
|
for (Triangle &triangle : m_triangles)
|
||||||
if (!triangle.is_split() && triangle.is_selected_by_seed_fill())
|
if (!triangle.is_split() && triangle.is_selected_by_seed_fill())
|
||||||
triangle.set_state(new_state);
|
triangle.set_state(new_state);
|
||||||
@ -2062,6 +2084,15 @@ void TriangleSelector::seed_fill_apply_on_triangles(TriangleStateType new_state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriangleSelector::seed_fill_apply_on_single_triangle(TriangleStateType new_state, const int facet_idx) {
|
||||||
|
assert(facet_idx > 0 && facet_idx < m_triangles.size());
|
||||||
|
|
||||||
|
if (Triangle &triangle = m_triangles[facet_idx]; !triangle.is_split() && triangle.is_selected_by_seed_fill()) {
|
||||||
|
triangle.set_state(new_state);
|
||||||
|
remove_useless_children(triangle.source_triangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double TriangleSelector::get_triangle_area(const Triangle &triangle) const {
|
double TriangleSelector::get_triangle_area(const Triangle &triangle) const {
|
||||||
const stl_vertex &v0 = m_vertices[triangle.verts_idxs[0]].v;
|
const stl_vertex &v0 = m_vertices[triangle.verts_idxs[0]].v;
|
||||||
const stl_vertex &v1 = m_vertices[triangle.verts_idxs[1]].v;
|
const stl_vertex &v1 = m_vertices[triangle.verts_idxs[1]].v;
|
||||||
|
@ -401,10 +401,17 @@ public:
|
|||||||
// For all triangles, remove the flag indicating that the triangle was selected by seed fill.
|
// For all triangles, remove the flag indicating that the triangle was selected by seed fill.
|
||||||
void seed_fill_unselect_all_triangles();
|
void seed_fill_unselect_all_triangles();
|
||||||
|
|
||||||
|
// Remove the flag indicating that the triangle was selected by seed fill.
|
||||||
|
void seed_fill_unselect_triangle(int facet_idx);
|
||||||
|
|
||||||
// For all triangles selected by seed fill, set new TriangleStateType and remove flag indicating that triangle was selected by seed fill.
|
// For all triangles selected by seed fill, set new TriangleStateType and remove flag indicating that triangle was selected by seed fill.
|
||||||
// The operation may merge split triangles if they are being assigned the same color.
|
// The operation may merge split triangles if they are being assigned the same color.
|
||||||
void seed_fill_apply_on_triangles(TriangleStateType new_state);
|
void seed_fill_apply_on_triangles(TriangleStateType new_state);
|
||||||
|
|
||||||
|
// For the triangle selected by seed fill, set a new TriangleStateType and remove the flag indicating that the triangle was selected by seed fill.
|
||||||
|
// The operation may merge a split triangle if it is being assigned the same color.
|
||||||
|
void seed_fill_apply_on_single_triangle(TriangleStateType new_state, const int facet_idx);
|
||||||
|
|
||||||
// Compute total area of the triangle.
|
// Compute total area of the triangle.
|
||||||
double get_triangle_area(const Triangle &triangle) const;
|
double get_triangle_area(const Triangle &triangle) const;
|
||||||
|
|
||||||
@ -495,13 +502,16 @@ protected:
|
|||||||
|
|
||||||
std::unique_ptr<Cursor> m_cursor;
|
std::unique_ptr<Cursor> m_cursor;
|
||||||
|
|
||||||
|
// Single triangle selected by seed fill. It is used to optimize painting using a single triangle brush.
|
||||||
|
int m_triangle_selected_by_seed_fill = -1;
|
||||||
|
|
||||||
// Private functions:
|
// Private functions:
|
||||||
private:
|
private:
|
||||||
bool select_triangle(int facet_idx, TriangleStateType type, bool triangle_splitting);
|
bool select_triangle(int facet_idx, TriangleStateType type, bool triangle_splitting);
|
||||||
bool select_triangle_recursive(int facet_idx, const Vec3i &neighbors, TriangleStateType type, bool triangle_splitting);
|
bool select_triangle_recursive(int facet_idx, const Vec3i &neighbors, TriangleStateType type, bool triangle_splitting);
|
||||||
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.
|
bool remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant.
|
||||||
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, TriangleStateType state = TriangleStateType::NONE);
|
int push_triangle(int a, int b, int c, int source_triangle, TriangleStateType state = TriangleStateType::NONE);
|
||||||
void perform_split(int facet_idx, const Vec3i &neighbors, TriangleStateType old_state);
|
void perform_split(int facet_idx, const Vec3i &neighbors, TriangleStateType old_state);
|
||||||
|
@ -643,9 +643,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
if (m_tool_type == ToolType::SMART_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
|
if (m_tool_type == ToolType::SMART_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
|
||||||
for (const ProjectedMousePosition &projected_mouse_position: projected_mouse_positions) {
|
for (const ProjectedMousePosition &projected_mouse_position: projected_mouse_positions) {
|
||||||
assert(projected_mouse_position.mesh_idx == mesh_idx);
|
assert(projected_mouse_position.mesh_idx == mesh_idx);
|
||||||
const Vec3f mesh_hit = projected_mouse_position.mesh_hit;
|
const Vec3f mesh_hit = projected_mouse_position.mesh_hit;
|
||||||
const int facet_idx = int(projected_mouse_position.facet_idx);
|
const int facet_idx = int(projected_mouse_position.facet_idx);
|
||||||
|
|
||||||
m_triangle_selectors[mesh_idx]->seed_fill_apply_on_triangles(new_state);
|
m_triangle_selectors[mesh_idx]->seed_fill_apply_on_triangles(new_state);
|
||||||
|
|
||||||
if (m_tool_type == ToolType::SMART_FILL) {
|
if (m_tool_type == ToolType::SMART_FILL) {
|
||||||
m_triangle_selectors[mesh_idx]->seed_fill_select_triangles(mesh_hit, facet_idx, trafo_matrix_not_translate, clp, m_smart_fill_angle, m_smart_fill_gap_area,
|
m_triangle_selectors[mesh_idx]->seed_fill_select_triangles(mesh_hit, facet_idx, trafo_matrix_not_translate, clp, m_smart_fill_angle, m_smart_fill_gap_area,
|
||||||
(m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f), TriangleSelector::ForceReselection::YES);
|
(m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f), TriangleSelector::ForceReselection::YES);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user