mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 23:15:54 +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());
|
||||
TriangleStateType start_facet_state = m_triangles[start_facet_idx].get_state();
|
||||
this->seed_fill_unselect_all_triangles();
|
||||
|
||||
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_triangle_selected_by_seed_fill = start_facet_idx;
|
||||
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;
|
||||
@ -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
|
||||
// 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());
|
||||
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
|
||||
// first (non-recursive call). Shouldn't otherwise.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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());
|
||||
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.
|
||||
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())
|
||||
return;
|
||||
return children_removed;
|
||||
if (child_idx == 0)
|
||||
first_child_type = m_triangles[tr.children[0]].get_state();
|
||||
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.
|
||||
undivide_triangle(facet_idx);
|
||||
tr.set_state(first_child_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TriangleSelector::garbage_collect()
|
||||
@ -2050,7 +2057,22 @@ void TriangleSelector::seed_fill_unselect_all_triangles()
|
||||
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) {
|
||||
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)
|
||||
if (!triangle.is_split() && triangle.is_selected_by_seed_fill())
|
||||
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 {
|
||||
const stl_vertex &v0 = m_vertices[triangle.verts_idxs[0]].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.
|
||||
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.
|
||||
// The operation may merge split triangles if they are being assigned the same color.
|
||||
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.
|
||||
double get_triangle_area(const Triangle &triangle) const;
|
||||
|
||||
@ -495,13 +502,16 @@ protected:
|
||||
|
||||
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:
|
||||
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);
|
||||
void undivide_triangle(int facet_idx);
|
||||
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;
|
||||
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);
|
||||
|
@ -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)) {
|
||||
for (const ProjectedMousePosition &projected_mouse_position: projected_mouse_positions) {
|
||||
assert(projected_mouse_position.mesh_idx == mesh_idx);
|
||||
const Vec3f mesh_hit = projected_mouse_position.mesh_hit;
|
||||
const int facet_idx = int(projected_mouse_position.facet_idx);
|
||||
const Vec3f mesh_hit = projected_mouse_position.mesh_hit;
|
||||
const int facet_idx = int(projected_mouse_position.facet_idx);
|
||||
|
||||
m_triangle_selectors[mesh_idx]->seed_fill_apply_on_triangles(new_state);
|
||||
|
||||
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_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f), TriangleSelector::ForceReselection::YES);
|
||||
|
Loading…
x
Reference in New Issue
Block a user