mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-22 06:04:01 -06:00
Added the bucket fill tool into the multi-material gizmo. Also, the multi-material gizmo was reworked to show only options applicable for a chosen painting tool.
This commit is contained in:
parent
977ffe556d
commit
51b94f4747
5 changed files with 519 additions and 107 deletions
|
@ -69,7 +69,70 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si
|
|||
this->special_side_idx = special_side_idx;
|
||||
}
|
||||
|
||||
inline bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3)
|
||||
{
|
||||
// Real-time collision detection, Ericson, Chapter 3.4
|
||||
auto barycentric = [&pt, &p1, &p2, &p3]() -> Vec3f {
|
||||
std::array<Vec3f, 3> v = {p2 - p1, p3 - p1, pt - p1};
|
||||
float d00 = v[0].dot(v[0]);
|
||||
float d01 = v[0].dot(v[1]);
|
||||
float d11 = v[1].dot(v[1]);
|
||||
float d20 = v[2].dot(v[0]);
|
||||
float d21 = v[2].dot(v[1]);
|
||||
float denom = d00 * d11 - d01 * d01;
|
||||
|
||||
Vec3f barycentric_cords(1.f, (d11 * d20 - d01 * d21) / denom, (d00 * d21 - d01 * d20) / denom);
|
||||
barycentric_cords.x() = barycentric_cords.x() - barycentric_cords.y() - barycentric_cords.z();
|
||||
return barycentric_cords;
|
||||
};
|
||||
|
||||
Vec3f barycentric_cords = barycentric();
|
||||
return std::all_of(begin(barycentric_cords), end(barycentric_cords), [](float cord) { return 0.f <= cord && cord <= 1.0; });
|
||||
}
|
||||
|
||||
int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const
|
||||
{
|
||||
assert(facet_idx < int(m_triangles.size()));
|
||||
const Triangle *tr = &m_triangles[facet_idx];
|
||||
if (!tr->valid())
|
||||
return -1;
|
||||
|
||||
if (!tr->is_split()) {
|
||||
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))
|
||||
return facet_idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(this->verify_triangle_neighbors(*tr, neighbors));
|
||||
|
||||
int num_of_children = tr->number_of_split_sides() + 1;
|
||||
if (num_of_children != 1) {
|
||||
for (int i = 0; i < num_of_children; ++i) {
|
||||
assert(i < int(tr->children.size()));
|
||||
assert(tr->children[i] < int(m_triangles.size()));
|
||||
// Recursion, deep first search over the children of this triangle.
|
||||
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
||||
|
||||
const std::array<int, 3> &t_vert = m_triangles[tr->children[i]].verts_idxs;
|
||||
if (is_point_inside_triangle(hit, m_vertices[t_vert[0]].v, m_vertices[t_vert[1]].v, m_vertices[t_vert[2]].v))
|
||||
return this->select_unsplit_triangle(hit, tr->children[i], this->child_neighbors(*tr, neighbors, i));
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx) const
|
||||
{
|
||||
assert(facet_idx < int(m_triangles.size()));
|
||||
if (!m_triangles[facet_idx].valid())
|
||||
return -1;
|
||||
|
||||
Vec3i neighbors = root_neighbors(*m_mesh, facet_idx);
|
||||
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
|
||||
return this->select_unsplit_triangle(hit, facet_idx, neighbors);
|
||||
}
|
||||
|
||||
void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
|
||||
const Vec3f& source, float radius,
|
||||
|
@ -116,19 +179,19 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
|
|||
}
|
||||
}
|
||||
|
||||
void TriangleSelector::seed_fill_select_triangles(const Vec3f& hit, int facet_start, float seed_fill_angle)
|
||||
void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, float seed_fill_angle)
|
||||
{
|
||||
assert(facet_start < m_orig_size_indices);
|
||||
this->seed_fill_unselect_all_triangles();
|
||||
|
||||
std::vector<bool> visited(m_triangles.size(), false);
|
||||
std::queue<int> facet_queue;
|
||||
std::queue<int> facet_queue;
|
||||
facet_queue.push(facet_start);
|
||||
|
||||
const double facet_angle_limit = cos(Geometry::deg2rad(seed_fill_angle)) - EPSILON;
|
||||
|
||||
// Depth-first traversal of neighbors of the face hit by the ray thrown from the mouse cursor.
|
||||
while(!facet_queue.empty()) {
|
||||
while (!facet_queue.empty()) {
|
||||
int current_facet = facet_queue.front();
|
||||
facet_queue.pop();
|
||||
|
||||
|
@ -161,6 +224,129 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f& hit, int facet_st
|
|||
}
|
||||
}
|
||||
|
||||
void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out) const
|
||||
{
|
||||
assert(facet_idx < int(m_triangles.size()));
|
||||
|
||||
const Triangle *tr = &m_triangles[facet_idx];
|
||||
if (!tr->valid())
|
||||
return;
|
||||
|
||||
neighbors_out[facet_idx] = neighbors_propagated;
|
||||
if (tr->is_split()) {
|
||||
assert(this->verify_triangle_neighbors(*tr, neighbors));
|
||||
|
||||
int num_of_children = tr->number_of_split_sides() + 1;
|
||||
if (num_of_children != 1) {
|
||||
for (int i = 0; i < num_of_children; ++i) {
|
||||
assert(i < int(tr->children.size()));
|
||||
assert(tr->children[i] < int(m_triangles.size()));
|
||||
// Recursion, deep first search over the children of this triangle.
|
||||
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
||||
this->precompute_all_level_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vec3i> TriangleSelector::precompute_all_level_neighbors() const
|
||||
{
|
||||
std::vector<Vec3i> neighbors(m_triangles.size(), Vec3i(-1, -1, -1));
|
||||
for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
|
||||
neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx);
|
||||
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx]));
|
||||
if (m_triangles[facet_idx].is_split())
|
||||
this->precompute_all_level_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors[facet_idx], neighbors);
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
bool TriangleSelector::are_triangles_touching(const int first_facet_idx, const int second_facet_idx) const
|
||||
{
|
||||
std::array<Linef3, 3> sides_facet = {Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast<double>()),
|
||||
Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast<double>()),
|
||||
Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast<double>())};
|
||||
|
||||
const Vec3d p0 = m_vertices[m_triangles[second_facet_idx].verts_idxs[0]].v.cast<double>();
|
||||
const Vec3d p1 = m_vertices[m_triangles[second_facet_idx].verts_idxs[1]].v.cast<double>();
|
||||
const Vec3d p2 = m_vertices[m_triangles[second_facet_idx].verts_idxs[2]].v.cast<double>();
|
||||
|
||||
for (size_t idx = 0; idx < 3; ++idx)
|
||||
if (line_alg::distance_to_squared(sides_facet[idx], p0) <= EPSILON && (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON || line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON))
|
||||
return true;
|
||||
else if (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON && line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<int> TriangleSelector::neighboring_triangles(const int first_facet_idx, const int second_facet_idx, EnforcerBlockerType second_facet_state) const
|
||||
{
|
||||
assert(first_facet_idx < int(m_triangles.size()));
|
||||
|
||||
const Triangle *tr = &m_triangles[first_facet_idx];
|
||||
if (!tr->valid())
|
||||
return {};
|
||||
|
||||
if (!tr->is_split() && tr->get_state() == second_facet_state && (are_triangles_touching(second_facet_idx, first_facet_idx) || are_triangles_touching(first_facet_idx, second_facet_idx)))
|
||||
return {first_facet_idx};
|
||||
|
||||
std::vector<int> neighbor_facets_out;
|
||||
int num_of_children = tr->number_of_split_sides() + 1;
|
||||
if (num_of_children != 1) {
|
||||
for (int i = 0; i < num_of_children; ++i) {
|
||||
assert(i < int(tr->children.size()));
|
||||
assert(tr->children[i] < int(m_triangles.size()));
|
||||
|
||||
if (std::vector<int> neighbor_facets = neighboring_triangles(tr->children[i], second_facet_idx, second_facet_state); !neighbor_facets.empty())
|
||||
Slic3r::append(neighbor_facets_out, std::move(neighbor_facets));
|
||||
}
|
||||
}
|
||||
|
||||
return neighbor_facets_out;
|
||||
}
|
||||
|
||||
void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate)
|
||||
{
|
||||
this->seed_fill_unselect_all_triangles();
|
||||
|
||||
int start_facet_idx = select_unsplit_triangle(hit, facet_start);
|
||||
EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state();
|
||||
if (start_facet_idx == -1)
|
||||
return;
|
||||
|
||||
if (!propagate) {
|
||||
m_triangles[start_facet_idx].select_by_seed_fill();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Vec3i> all_level_neighbors = this->precompute_all_level_neighbors();
|
||||
std::vector<bool> visited(m_triangles.size(), false);
|
||||
std::queue<int> facet_queue;
|
||||
|
||||
facet_queue.push(start_facet_idx);
|
||||
while (!facet_queue.empty()) {
|
||||
int current_facet = facet_queue.front();
|
||||
facet_queue.pop();
|
||||
assert(!m_triangles[current_facet].is_split());
|
||||
|
||||
if (!visited[current_facet]) {
|
||||
m_triangles[current_facet].select_by_seed_fill();
|
||||
for(int neighbor_idx : all_level_neighbors[current_facet]) {
|
||||
if(!m_triangles[neighbor_idx].is_split()) {
|
||||
if(m_triangles[neighbor_idx].get_state() == start_facet_state)
|
||||
facet_queue.push(neighbor_idx);
|
||||
} else {
|
||||
for(int neighbor_facet_idx : neighboring_triangles(neighbor_idx, current_facet, start_facet_state))
|
||||
facet_queue.push(neighbor_facet_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visited[current_facet] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Selects either the whole triangle (discarding any children it had), or divides
|
||||
// the triangle recursively, selecting just subtriangles truly inside the circle.
|
||||
// This is done by an actual recursive call. Returns false if the triangle is
|
||||
|
@ -412,6 +598,89 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo
|
|||
return out;
|
||||
}
|
||||
|
||||
// Return neighbors of the ith child of a triangle given neighbors of the triangle.
|
||||
// If such a neighbor doesn't exist, return the neighbor from the previous depth.
|
||||
Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const
|
||||
{
|
||||
int i = tr.special_side();
|
||||
int j = i + 1;
|
||||
if (j >= 3) j = 0;
|
||||
int k = j + 1;
|
||||
if (k >= 3) k = 0;
|
||||
|
||||
Vec3i out;
|
||||
switch (tr.number_of_split_sides()) {
|
||||
case 1:
|
||||
switch (child_idx) {
|
||||
case 0:
|
||||
out(0) = neighbors(i);
|
||||
out(1) = neighbors(j);
|
||||
out(2) = tr.children[1];
|
||||
break;
|
||||
default:
|
||||
assert(child_idx == 1);
|
||||
out(0) = neighbors(j);
|
||||
out(1) = neighbors(k);
|
||||
out(2) = tr.children[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch (child_idx) {
|
||||
case 0:
|
||||
out(0) = neighbors(i);
|
||||
out(1) = tr.children[1];
|
||||
out(2) = neighbors(k);
|
||||
break;
|
||||
case 1:
|
||||
assert(child_idx == 1);
|
||||
out(0) = neighbors(i);
|
||||
out(1) = tr.children[2];
|
||||
out(2) = tr.children[0];
|
||||
break;
|
||||
default:
|
||||
assert(child_idx == 2);
|
||||
out(0) = neighbors(j);
|
||||
out(1) = neighbors(k);
|
||||
out(2) = tr.children[1];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
assert(tr.special_side() == 0);
|
||||
switch (child_idx) {
|
||||
case 0:
|
||||
out(0) = neighbors(0);
|
||||
out(1) = tr.children[3];
|
||||
out(2) = neighbors(2);
|
||||
break;
|
||||
case 1:
|
||||
out(0) = neighbors(0);
|
||||
out(1) = neighbors(1);
|
||||
out(2) = tr.children[3];
|
||||
break;
|
||||
case 2:
|
||||
out(0) = neighbors(1);
|
||||
out(1) = neighbors(2);
|
||||
out(2) = tr.children[3];
|
||||
break;
|
||||
default:
|
||||
assert(child_idx == 3);
|
||||
out(0) = tr.children[1];
|
||||
out(1) = tr.children[2];
|
||||
out(2) = tr.children[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool TriangleSelector::select_triangle_recursive(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType type, bool triangle_splitting)
|
||||
{
|
||||
assert(facet_idx < int(m_triangles.size()));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue