Implementation of ShortEdgeCollapse

Replaced QEC by edge collapse in occlusion computation
This commit is contained in:
PavelMikus 2022-06-02 13:53:40 +02:00 committed by Lukas Matena
parent b5b39195f4
commit 1e7b4a6720
5 changed files with 197 additions and 13 deletions

View File

@ -205,6 +205,8 @@ add_library(libslic3r STATIC
QuadricEdgeCollapse.cpp
QuadricEdgeCollapse.hpp
Semver.cpp
ShortEdgeCollapse.cpp
ShortEdgeCollapse.hpp
ShortestPath.cpp
ShortestPath.hpp
SLAPrint.cpp

View File

@ -17,7 +17,7 @@
#include "libslic3r/Layer.hpp"
#include "libslic3r/Geometry/Curves.hpp"
#include "libslic3r/QuadricEdgeCollapse.hpp"
#include "libslic3r/ShortEdgeCollapse.hpp"
#include "libslic3r/TriangleSetSampling.hpp"
#include "libslic3r/Utils.hpp"
@ -585,7 +585,8 @@ std::pair<size_t, size_t> find_previous_and_next_perimeter_point(const std::vect
}
// Computes all global model info - transforms object, performs raycasting
void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po, std::function<void(void)> throw_if_canceled) {
void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po,
std::function<void(void)> throw_if_canceled) {
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: gather occlusion meshes: start";
auto obj_transform = po->trafo_centered();
@ -607,20 +608,19 @@ void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po, st
}
throw_if_canceled();
size_t negative_volumes_start_index = triangle_set.indices.size();
its_merge(triangle_set, negative_volumes_set);
its_transform(triangle_set, obj_transform);
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: gather occlusion meshes: end";
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: decimate: start";
float target_error = 1.0f;
its_quadric_edge_collapse(triangle_set, 0, &target_error, throw_if_canceled);
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: decimate: end";
<< "SeamPlacer: decimate: start";
its_short_edge_collpase(triangle_set, 25000);
its_short_edge_collpase(negative_volumes_set, 25000);
size_t negative_volumes_start_index = triangle_set.indices.size();
its_merge(triangle_set, negative_volumes_set);
its_transform(triangle_set, obj_transform);
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: decimate: end";
BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: Compute visibility sample points: start";

View File

@ -122,9 +122,9 @@ struct PrintObjectSeamData
class SeamPlacer {
public:
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
static constexpr size_t raycasting_visibility_samples_count = 25000;
static constexpr size_t raycasting_visibility_samples_count = 30000;
//square of number of rays per sample point
static constexpr size_t sqr_rays_per_sample_point = 8;
static constexpr size_t sqr_rays_per_sample_point = 5;
// arm length used during angles computation
static constexpr float polygon_local_angles_arm_distance = 0.3f;

View File

@ -0,0 +1,166 @@
#include "ShortEdgeCollapse.hpp"
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <algorithm>
namespace Slic3r {
void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_count) {
std::unordered_map<size_t, size_t> vertices_index_mapping; // this map has two usages:
// in the first step, it contains mapping from original vertex index to final vertex index (which is different from original only for removed vertices)
std::unordered_set<size_t> vertices_to_remove;
std::unordered_set<size_t> faces_to_remove;
std::vector<Vec3i> triangles_neighbors;
std::vector<Vec3f> face_normals;
std::vector<Vec3f> vertex_normals;
std::vector<size_t> face_indices;
std::random_device rd;
std::mt19937 generator(rd());
float decimation_ratio = 1.0f;
float edge_size = 0.2f;
size_t triangle_count = mesh.indices.size();
while (triangle_count > target_triangle_count) {
if (decimation_ratio < 0.4) {
edge_size *= 1.5f;
}
if (decimation_ratio < 0.05) {
edge_size *= 1.5f;
}
float max_edge_len_squared = edge_size * edge_size;
triangles_neighbors = its_face_neighbors_par(mesh);
face_normals = its_face_normals(mesh);
vertex_normals.resize(mesh.vertices.size());
face_indices.resize(mesh.indices.size());
for (size_t face_idx = 0; face_idx < mesh.indices.size(); ++face_idx) {
Vec3i t = mesh.indices[face_idx];
Vec3f n = face_normals[face_idx];
vertex_normals[t[0]] = n;
vertex_normals[t[1]] = n;
vertex_normals[t[2]] = n;
face_indices[face_idx] = face_idx;
}
std::vector<float> min_vertex_score(mesh.vertices.size(), 1);
for (size_t face_idx = 0; face_idx < mesh.indices.size(); ++face_idx) {
Vec3i t = mesh.indices[face_idx];
Vec3f n = face_normals[face_idx];
min_vertex_score[t[0]] = std::min(min_vertex_score[t[0]], n.dot(vertex_normals[t[0]]));
min_vertex_score[t[1]] = std::min(min_vertex_score[t[1]], n.dot(vertex_normals[t[1]]));
min_vertex_score[t[2]] = std::min(min_vertex_score[t[2]], n.dot(vertex_normals[t[2]]));
}
for (size_t vertex_index = 0; vertex_index < mesh.vertices.size(); ++vertex_index) {
vertices_index_mapping[vertex_index] = vertex_index;
}
std::shuffle(face_indices.begin(), face_indices.end(), generator);
for (const size_t &face_idx : face_indices) {
if (faces_to_remove.find(face_idx) != faces_to_remove.end()) {
continue;
}
for (size_t edge_idx = 0; edge_idx < 3; ++edge_idx) {
size_t vertex_index_keep = mesh.indices[face_idx][edge_idx];
size_t vertex_index_remove = mesh.indices[face_idx][(edge_idx + 1) % 3];
if ((mesh.vertices[vertex_index_keep] - mesh.vertices[vertex_index_remove]).squaredNorm()
> max_edge_len_squared) {
continue;
}
if (min_vertex_score[vertex_index_remove] < min_vertex_score[vertex_index_keep]) {
size_t tmp = vertex_index_keep;
vertex_index_keep = vertex_index_remove;
vertex_index_remove = tmp;
}
if (min_vertex_score[vertex_index_remove] < -1.0f) {
continue;
}
if (vertices_to_remove.find(vertex_index_keep) != vertices_to_remove.end()
|| vertices_to_remove.find(vertex_index_remove) != vertices_to_remove.end()) {
break;
}
int neighbor_face_idx = triangles_neighbors[face_idx][edge_idx];
if (neighbor_face_idx > 0 && faces_to_remove.find(neighbor_face_idx) != faces_to_remove.end()) {
continue;
}
faces_to_remove.insert(face_idx);
faces_to_remove.insert(neighbor_face_idx);
vertices_to_remove.insert(vertex_index_remove);
vertices_index_mapping[vertex_index_remove] = vertices_index_mapping[vertex_index_keep];
min_vertex_score[vertex_index_keep] = -2.0;
break;
}
}
//flatten the mapping
for (auto &pair : vertices_index_mapping) {
while (vertices_index_mapping[pair.second] != pair.second) {
pair.second = vertices_index_mapping[pair.second];
}
}
std::vector<Vec3f> new_vertices;
new_vertices.reserve(mesh.vertices.size() - vertices_to_remove.size());
for (size_t vertex_index = 0; vertex_index < mesh.vertices.size(); ++vertex_index) {
if (vertices_to_remove.find(vertex_index) == vertices_to_remove.end()) { //not removed
new_vertices.push_back(mesh.vertices[vertex_index]);
assert(vertices_index_mapping[vertex_index] == vertex_index);
vertices_index_mapping[vertex_index] = new_vertices.size() - 1;
}
}
std::vector<Vec3i> new_indices;
new_indices.reserve(mesh.indices.size() - faces_to_remove.size());
for (size_t face_idx = 0; face_idx < mesh.indices.size(); ++face_idx) {
if (faces_to_remove.find(face_idx) != faces_to_remove.end()) {
continue; //skip removed triangles
}
Vec3i new_triangle;
for (int t_vertex_idx = 0; t_vertex_idx < 3; ++t_vertex_idx) {
size_t orig_index = mesh.indices[face_idx][t_vertex_idx];
if (vertices_to_remove.find(orig_index) == vertices_to_remove.end()) { //this vertex was not removed
new_triangle[t_vertex_idx] = vertices_index_mapping[orig_index];
} else { // this vertex was removed, so use the vertex mapping points to
new_triangle[t_vertex_idx] = vertices_index_mapping[vertices_index_mapping[orig_index]];
}
}
if (new_triangle[0] == new_triangle[1] || new_triangle[1] == new_triangle[2]
|| new_triangle[2] == new_triangle[0]) {
continue; //skip degenerate
}
new_indices.push_back(new_triangle);
}
decimation_ratio = float(faces_to_remove.size()) / float(mesh.indices.size());
// std::cout << " DECIMATION RATIO: " << decimation_ratio << std::endl;
mesh.vertices = new_vertices;
mesh.indices = new_indices;
vertices_index_mapping.clear();
vertices_to_remove.clear();
faces_to_remove.clear();
triangles_neighbors.clear();
face_normals.clear();
vertex_normals.clear();
face_indices.clear();
triangle_count = mesh.indices.size();
}
}
}

View File

@ -0,0 +1,16 @@
#ifndef SRC_LIBSLIC3R_SHORTEDGECOLLAPSE_HPP_
#define SRC_LIBSLIC3R_SHORTEDGECOLLAPSE_HPP_
#include "libslic3r/TriangleMesh.hpp"
namespace Slic3r{
// Decimates the model by collapsing short edges. It starts with very small edges and gradually increases the collapsible length,
// until the target triangle count is reached (the algorithm will certainly undershoot the target count, result will have less triangles than target count)
// The algorithm does not check for triangle flipping, disconnections, self intersections or any other degeneration that can appear during mesh processing.
void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_count);
}
#endif /* SRC_LIBSLIC3R_SHORTEDGECOLLAPSE_HPP_ */