mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-14 04:31:49 +08:00
Measuring: Initial plane detection
This commit is contained in:
parent
f0cf420a84
commit
5d8aaed18f
@ -127,6 +127,7 @@ void GLGizmoMeasure::on_render()
|
|||||||
|
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
glsafe(::glEnable(GL_BLEND));
|
glsafe(::glEnable(GL_BLEND));
|
||||||
|
glsafe(::glLineWidth(5.f));
|
||||||
|
|
||||||
if (selection.is_single_full_instance()) {
|
if (selection.is_single_full_instance()) {
|
||||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
||||||
@ -227,15 +228,14 @@ void GLGizmoMeasure::update_planes()
|
|||||||
|
|
||||||
// Now we'll go through all the facets and append Points of facets sharing the same normal.
|
// Now we'll go through all the facets and append Points of facets sharing the same normal.
|
||||||
// This part is still performed in mesh coordinate system.
|
// This part is still performed in mesh coordinate system.
|
||||||
const int num_of_facets = ch.facets_count();
|
const size_t num_of_facets = ch.facets_count();
|
||||||
std::vector<size_t> face_to_plane(num_of_facets, 0);
|
std::vector<size_t> face_to_plane(num_of_facets, size_t(-1));
|
||||||
const std::vector<Vec3f> face_normals = its_face_normals(ch.its);
|
const std::vector<Vec3f> face_normals = its_face_normals(ch.its);
|
||||||
const std::vector<Vec3i> face_neighbors = its_face_neighbors(ch.its);
|
const std::vector<Vec3i> face_neighbors = its_face_neighbors(ch.its);
|
||||||
std::vector<int> facet_queue(num_of_facets, 0);
|
std::vector<int> facet_queue(num_of_facets, 0);
|
||||||
std::vector<bool> facet_visited(num_of_facets, false);
|
|
||||||
int facet_queue_cnt = 0;
|
int facet_queue_cnt = 0;
|
||||||
const stl_normal* normal_ptr = nullptr;
|
const stl_normal* normal_ptr = nullptr;
|
||||||
int facet_idx = 0;
|
size_t seed_facet_idx = 0;
|
||||||
|
|
||||||
auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool {
|
auto is_same_normal = [](const stl_normal& a, const stl_normal& b) -> bool {
|
||||||
return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001);
|
return (std::abs(a(0) - b(0)) < 0.001 && std::abs(a(1) - b(1)) < 0.001 && std::abs(a(2) - b(2)) < 0.001);
|
||||||
@ -243,16 +243,15 @@ void GLGizmoMeasure::update_planes()
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// Find next unvisited triangle:
|
// Find next unvisited triangle:
|
||||||
for (; facet_idx < num_of_facets; ++ facet_idx)
|
for (; seed_facet_idx < num_of_facets; ++ seed_facet_idx)
|
||||||
if (!facet_visited[facet_idx]) {
|
if (face_to_plane[seed_facet_idx] == size_t(-1)) {
|
||||||
facet_queue[facet_queue_cnt ++] = facet_idx;
|
facet_queue[facet_queue_cnt ++] = seed_facet_idx;
|
||||||
facet_visited[facet_idx] = true;
|
normal_ptr = &face_normals[seed_facet_idx];
|
||||||
normal_ptr = &face_normals[facet_idx];
|
face_to_plane[seed_facet_idx] = m_planes.size();
|
||||||
face_to_plane[facet_idx] = m_planes.size();
|
|
||||||
m_planes.emplace_back();
|
m_planes.emplace_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (facet_idx == num_of_facets)
|
if (seed_facet_idx == num_of_facets)
|
||||||
break; // Everything was visited already
|
break; // Everything was visited already
|
||||||
|
|
||||||
while (facet_queue_cnt > 0) {
|
while (facet_queue_cnt > 0) {
|
||||||
@ -260,70 +259,69 @@ void GLGizmoMeasure::update_planes()
|
|||||||
const stl_normal& this_normal = face_normals[facet_idx];
|
const stl_normal& this_normal = face_normals[facet_idx];
|
||||||
if (is_same_normal(this_normal, *normal_ptr)) {
|
if (is_same_normal(this_normal, *normal_ptr)) {
|
||||||
const Vec3i& face = ch.its.indices[facet_idx];
|
const Vec3i& face = ch.its.indices[facet_idx];
|
||||||
for (int j=0; j<3; ++j)
|
|
||||||
m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast<double>());
|
|
||||||
|
|
||||||
facet_visited[facet_idx] = true;
|
|
||||||
face_to_plane[facet_idx] = m_planes.size() - 1;
|
face_to_plane[facet_idx] = m_planes.size() - 1;
|
||||||
|
m_planes.back().facets.emplace_back(facet_idx);
|
||||||
for (int j = 0; j < 3; ++ j)
|
for (int j = 0; j < 3; ++ j)
|
||||||
if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx])
|
if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && face_to_plane[neighbor_idx] == size_t(-1))
|
||||||
facet_queue[facet_queue_cnt ++] = neighbor_idx;
|
facet_queue[facet_queue_cnt ++] = neighbor_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_planes.back().normal = normal_ptr->cast<double>();
|
|
||||||
|
|
||||||
Pointf3s& verts = m_planes.back().vertices;
|
m_planes.back().normal = normal_ptr->cast<double>();
|
||||||
// Now we'll transform all the points into world coordinates, so that the areas, angles and distances
|
|
||||||
// make real sense.
|
|
||||||
verts = transform(verts, inst_matrix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(std::none_of(face_to_plane.begin(), face_to_plane.end(), [](size_t val) { return val == size_t(-1); }));
|
||||||
|
|
||||||
|
SurfaceMesh sm(ch.its);
|
||||||
|
for (int plane_id=0; plane_id < m_planes.size(); ++plane_id) {
|
||||||
|
//int plane_id = 5; {
|
||||||
|
const auto& facets = m_planes[plane_id].facets;
|
||||||
|
std::vector<stl_vertex> pts;
|
||||||
|
for (int face_id=0; face_id<facets.size(); ++face_id) {
|
||||||
|
assert(face_to_plane[facets[face_id]] == plane_id);
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (j=0; j<3; ++j)
|
||||||
|
if (face_to_plane[face_neighbors[facets[face_id]][j]] != plane_id)
|
||||||
|
break;
|
||||||
|
if (j == 3)
|
||||||
|
continue;
|
||||||
|
Halfedge_index he = sm.halfedge(Face_index(facets[face_id]));
|
||||||
|
for (int i=0; i<j; ++i)
|
||||||
|
he = sm.next(he);
|
||||||
|
|
||||||
|
// he is the first halfedge on the border. Now walk around and append the points.
|
||||||
|
const Halfedge_index he_orig = he;
|
||||||
|
m_planes[plane_id].borders.emplace_back(std::vector<Vec3d>{ sm.point(sm.source(he)).cast<double>() });
|
||||||
|
Vertex_index target = sm.target(he);
|
||||||
|
const Halfedge_index he_start = he;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const Halfedge_index he_orig = he;
|
||||||
|
he = sm.next_around_target(he);
|
||||||
|
while ( face_to_plane[sm.face(he)] == plane_id && he != he_orig)
|
||||||
|
he = sm.next_around_target(he);
|
||||||
|
he = sm.opposite(he);
|
||||||
|
m_planes[plane_id].borders.back().emplace_back(sm.point(sm.source(he)).cast<double>());
|
||||||
|
} while (he != he_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DEBUGGING:
|
||||||
|
//m_planes.erase(std::remove_if(m_planes.begin(), m_planes.end(), [](const PlaneData& p) { return p.borders.empty(); }), m_planes.end());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Let's prepare transformation of the normal vector from mesh to instance coordinates.
|
// Let's prepare transformation of the normal vector from mesh to instance coordinates.
|
||||||
Geometry::Transformation t(inst_matrix);
|
Geometry::Transformation t(inst_matrix);
|
||||||
Vec3d scaling = t.get_scaling_factor();
|
Vec3d scaling = t.get_scaling_factor();
|
||||||
t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2)));
|
t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2)));
|
||||||
|
|
||||||
// Now we'll go through all the polygons, transform the points into xy plane to process them:
|
|
||||||
for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) {
|
|
||||||
Pointf3s& polygon = m_planes[polygon_id].vertices;
|
|
||||||
const Vec3d& normal = m_planes[polygon_id].normal;
|
|
||||||
|
|
||||||
// transform the normal according to the instance matrix:
|
|
||||||
Vec3d normal_transformed = t.get_matrix() * normal;
|
|
||||||
|
|
||||||
// We are going to rotate about z and y to flatten the plane
|
|
||||||
Eigen::Quaterniond q;
|
|
||||||
Transform3d m = Transform3d::Identity();
|
|
||||||
m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix();
|
|
||||||
polygon = transform(polygon, m);
|
|
||||||
|
|
||||||
// Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since
|
|
||||||
// it works in fixed point representation, we will rescale the polygon to avoid overflows.
|
|
||||||
// And yes, it is a nasty thing to do. Whoever has time is free to refactor.
|
|
||||||
Vec3d bb_size = BoundingBoxf3(polygon).size();
|
|
||||||
float sf = std::min(1./bb_size(0), 1./bb_size(1));
|
|
||||||
Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f));
|
|
||||||
polygon = transform(polygon, tr);
|
|
||||||
polygon = Slic3r::Geometry::convex_hull(polygon);
|
|
||||||
polygon = transform(polygon, tr.inverse());
|
|
||||||
|
|
||||||
// We will shrink the polygon a little bit so it does not touch the object edges:
|
|
||||||
Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0));
|
|
||||||
centroid /= (double)polygon.size();
|
|
||||||
for (auto& vertex : polygon)
|
|
||||||
vertex = 0.95f*vertex + 0.05f*centroid;
|
|
||||||
|
|
||||||
// Raise a bit above the object surface to avoid flickering:
|
|
||||||
for (auto& b : polygon)
|
|
||||||
b(2) += 0.1f;
|
|
||||||
|
|
||||||
// Transform back to 3D (and also back to mesh coordinates)
|
|
||||||
polygon = transform(polygon, inst_matrix.inverse() * m.inverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations):
|
|
||||||
std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; });
|
|
||||||
m_planes.resize(std::min((int)m_planes.size(), 254));
|
|
||||||
|
|
||||||
// Planes are finished - let's save what we calculated it from:
|
// Planes are finished - let's save what we calculated it from:
|
||||||
m_volumes_matrices.clear();
|
m_volumes_matrices.clear();
|
||||||
@ -339,21 +337,23 @@ void GLGizmoMeasure::update_planes()
|
|||||||
// And finally create respective VBOs. The polygon is convex with
|
// And finally create respective VBOs. The polygon is convex with
|
||||||
// the vertices in order, so triangulation is trivial.
|
// the vertices in order, so triangulation is trivial.
|
||||||
for (auto& plane : m_planes) {
|
for (auto& plane : m_planes) {
|
||||||
|
for (auto& vertices : plane.borders) {
|
||||||
GLModel::Geometry init_data;
|
GLModel::Geometry init_data;
|
||||||
init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 };
|
init_data.format = { GLModel::Geometry::EPrimitiveType::LineStrip, GLModel::Geometry::EVertexLayout::P3N3 };
|
||||||
init_data.reserve_vertices(plane.vertices.size());
|
init_data.reserve_vertices(vertices.size());
|
||||||
init_data.reserve_indices(plane.vertices.size());
|
init_data.reserve_indices(vertices.size());
|
||||||
// vertices + indices
|
// vertices + indices
|
||||||
for (size_t i = 0; i < plane.vertices.size(); ++i) {
|
for (size_t i = 0; i < vertices.size(); ++i) {
|
||||||
init_data.add_vertex((Vec3f)plane.vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>());
|
init_data.add_vertex((Vec3f)vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>());
|
||||||
init_data.add_index((unsigned int)i);
|
init_data.add_index((unsigned int)i);
|
||||||
}
|
}
|
||||||
plane.vbo.init_from(std::move(init_data));
|
plane.vbo.init_from(std::move(init_data));
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: vertices should really be local, they need not
|
// FIXME: vertices should really be local, they need not
|
||||||
// persist now when we use VBOs
|
// persist now when we use VBOs
|
||||||
plane.vertices.clear();
|
plane.borders.clear();
|
||||||
plane.vertices.shrink_to_fit();
|
plane.borders.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_planes_valid = true;
|
m_planes_valid = true;
|
||||||
|
@ -24,8 +24,8 @@ class GLGizmoMeasure : public GLGizmoBase
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
struct PlaneData {
|
struct PlaneData {
|
||||||
std::vector<Vec3d> vertices; // should be in fact local in update_planes()
|
std::vector<std::vector<Vec3d>> borders; // should be in fact local in update_planes()
|
||||||
std::vector<int> borders_facets;
|
std::vector<int> facets;
|
||||||
GLModel vbo;
|
GLModel vbo;
|
||||||
Vec3d normal;
|
Vec3d normal;
|
||||||
float area;
|
float area;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user