Refactoring of the short edge collpase, should greatly improve performance
integration of NormalsUitls from SDF branch
This commit is contained in:
parent
9b761d3a6f
commit
13ac7a24d8
@ -166,6 +166,8 @@ add_library(libslic3r STATIC
|
||||
MultiPoint.cpp
|
||||
MultiPoint.hpp
|
||||
MutablePriorityQueue.hpp
|
||||
NormalUtils.cpp
|
||||
NormalUtils.hpp
|
||||
ObjectID.cpp
|
||||
ObjectID.hpp
|
||||
PerimeterGenerator.cpp
|
||||
|
142
src/libslic3r/NormalUtils.cpp
Normal file
142
src/libslic3r/NormalUtils.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "NormalUtils.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
Vec3f NormalUtils::create_triangle_normal(
|
||||
const stl_triangle_vertex_indices &indices,
|
||||
const std::vector<stl_vertex> & vertices)
|
||||
{
|
||||
const stl_vertex &v0 = vertices[indices[0]];
|
||||
const stl_vertex &v1 = vertices[indices[1]];
|
||||
const stl_vertex &v2 = vertices[indices[2]];
|
||||
Vec3f direction = (v1 - v0).cross(v2 - v0);
|
||||
direction.normalize();
|
||||
return direction;
|
||||
}
|
||||
|
||||
std::vector<Vec3f> NormalUtils::create_triangle_normals(
|
||||
const indexed_triangle_set &its)
|
||||
{
|
||||
std::vector<Vec3f> normals;
|
||||
normals.reserve(its.indices.size());
|
||||
for (const Vec3crd &index : its.indices) {
|
||||
normals.push_back(create_triangle_normal(index, its.vertices));
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
NormalUtils::Normals NormalUtils::create_normals_average_neighbor(
|
||||
const indexed_triangle_set &its)
|
||||
{
|
||||
size_t count_vertices = its.vertices.size();
|
||||
std::vector<Vec3f> normals(count_vertices, Vec3f(.0f, .0f, .0f));
|
||||
std::vector<unsigned int> count(count_vertices, 0);
|
||||
for (const Vec3crd &indice : its.indices) {
|
||||
Vec3f normal = create_triangle_normal(indice, its.vertices);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
normals[indice[i]] += normal;
|
||||
++count[indice[i]];
|
||||
}
|
||||
}
|
||||
// normalize to size 1
|
||||
for (auto &normal : normals) {
|
||||
size_t index = &normal - &normals.front();
|
||||
normal /= static_cast<float>(count[index]);
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
// calc triangle angle of vertex defined by index to triangle indices
|
||||
float NormalUtils::indice_angle(int i,
|
||||
const Vec3crd & indice,
|
||||
const std::vector<stl_vertex> &vertices)
|
||||
{
|
||||
int i1 = (i == 0) ? 2 : (i - 1);
|
||||
int i2 = (i == 2) ? 0 : (i + 1);
|
||||
|
||||
Vec3f v1 = vertices[i1] - vertices[i];
|
||||
Vec3f v2 = vertices[i2] - vertices[i];
|
||||
|
||||
v1.normalize();
|
||||
v2.normalize();
|
||||
|
||||
float w = v1.dot(v2);
|
||||
if (w > 1.f)
|
||||
w = 1.f;
|
||||
else if (w < -1.f)
|
||||
w = -1.f;
|
||||
return acos(w);
|
||||
}
|
||||
|
||||
NormalUtils::Normals NormalUtils::create_normals_angle_weighted(
|
||||
const indexed_triangle_set &its)
|
||||
{
|
||||
size_t count_vertices = its.vertices.size();
|
||||
std::vector<Vec3f> normals(count_vertices, Vec3f(.0f, .0f, .0f));
|
||||
std::vector<float> count(count_vertices, 0.f);
|
||||
for (const Vec3crd &indice : its.indices) {
|
||||
Vec3f normal = create_triangle_normal(indice, its.vertices);
|
||||
Vec3f angles(indice_angle(0, indice, its.vertices),
|
||||
indice_angle(1, indice, its.vertices), 0.f);
|
||||
angles[2] = (M_PI - angles[0] - angles[1]);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const float &weight = angles[i];
|
||||
normals[indice[i]] += normal * weight;
|
||||
count[indice[i]] += weight;
|
||||
}
|
||||
}
|
||||
// normalize to size 1
|
||||
for (auto &normal : normals) {
|
||||
size_t index = &normal - &normals.front();
|
||||
normal /= count[index];
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
NormalUtils::Normals NormalUtils::create_normals_nelson_weighted(
|
||||
const indexed_triangle_set &its)
|
||||
{
|
||||
size_t count_vertices = its.vertices.size();
|
||||
std::vector<Vec3f> normals(count_vertices, Vec3f(.0f, .0f, .0f));
|
||||
std::vector<float> count(count_vertices, 0.f);
|
||||
const std::vector<stl_vertex> &vertices = its.vertices;
|
||||
for (const Vec3crd &indice : its.indices) {
|
||||
Vec3f normal = create_triangle_normal(indice, vertices);
|
||||
|
||||
const stl_vertex &v0 = vertices[indice[0]];
|
||||
const stl_vertex &v1 = vertices[indice[1]];
|
||||
const stl_vertex &v2 = vertices[indice[2]];
|
||||
|
||||
float e0 = (v0 - v1).norm();
|
||||
float e1 = (v1 - v2).norm();
|
||||
float e2 = (v2 - v0).norm();
|
||||
|
||||
Vec3f coefs(e0 * e2, e0 * e1, e1 * e2);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const float &weight = coefs[i];
|
||||
normals[indice[i]] += normal * weight;
|
||||
count[indice[i]] += weight;
|
||||
}
|
||||
}
|
||||
// normalize to size 1
|
||||
for (auto &normal : normals) {
|
||||
size_t index = &normal - &normals.front();
|
||||
normal /= count[index];
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
// calculate normals by averaging normals of neghbor triangles
|
||||
std::vector<Vec3f> NormalUtils::create_normals(
|
||||
const indexed_triangle_set &its, VertexNormalType type)
|
||||
{
|
||||
switch (type) {
|
||||
case VertexNormalType::AverageNeighbor:
|
||||
return create_normals_average_neighbor(its);
|
||||
case VertexNormalType::AngleWeighted:
|
||||
return create_normals_angle_weighted(its);
|
||||
case VertexNormalType::NelsonMaxWeighted:
|
||||
default:
|
||||
return create_normals_nelson_weighted(its);
|
||||
}
|
||||
}
|
69
src/libslic3r/NormalUtils.hpp
Normal file
69
src/libslic3r/NormalUtils.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef slic3r_NormalUtils_hpp_
|
||||
#define slic3r_NormalUtils_hpp_
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "Model.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/// <summary>
|
||||
/// Collection of static function
|
||||
/// to create normals
|
||||
/// </summary>
|
||||
class NormalUtils
|
||||
{
|
||||
public:
|
||||
using Normal = Vec3f;
|
||||
using Normals = std::vector<Normal>;
|
||||
NormalUtils() = delete; // only static functions
|
||||
|
||||
enum class VertexNormalType {
|
||||
AverageNeighbor,
|
||||
AngleWeighted,
|
||||
NelsonMaxWeighted
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create normal for triangle defined by indices from vertices
|
||||
/// </summary>
|
||||
/// <param name="indices">index into vertices</param>
|
||||
/// <param name="vertices">vector of vertices</param>
|
||||
/// <returns>normal to triangle(normalized to size 1)</returns>
|
||||
static Normal create_triangle_normal(
|
||||
const stl_triangle_vertex_indices &indices,
|
||||
const std::vector<stl_vertex> & vertices);
|
||||
|
||||
/// <summary>
|
||||
/// Create normals for each vertices
|
||||
/// </summary>
|
||||
/// <param name="its">indices and vertices</param>
|
||||
/// <returns>Vector of normals</returns>
|
||||
static Normals create_triangle_normals(const indexed_triangle_set &its);
|
||||
|
||||
/// <summary>
|
||||
/// Create normals for each vertex by averaging neighbor triangles normal
|
||||
/// </summary>
|
||||
/// <param name="its">Triangle indices and vertices</param>
|
||||
/// <param name="type">Type of calculation normals</param>
|
||||
/// <returns>Normal for each vertex</returns>
|
||||
static Normals create_normals(
|
||||
const indexed_triangle_set &its,
|
||||
VertexNormalType type = VertexNormalType::NelsonMaxWeighted);
|
||||
static Normals create_normals_average_neighbor(const indexed_triangle_set &its);
|
||||
static Normals create_normals_angle_weighted(const indexed_triangle_set &its);
|
||||
static Normals create_normals_nelson_weighted(const indexed_triangle_set &its);
|
||||
|
||||
/// <summary>
|
||||
/// Calculate angle of trinagle side.
|
||||
/// </summary>
|
||||
/// <param name="i">index to indices, define angle point</param>
|
||||
/// <param name="indice">address to vertices</param>
|
||||
/// <param name="vertices">vertices data</param>
|
||||
/// <returns>Angle [in radian]</returns>
|
||||
static float indice_angle(int i,
|
||||
const Vec3crd & indice,
|
||||
const std::vector<stl_vertex> &vertices);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
#endif // slic3r_NormalUtils_hpp_
|
@ -1,4 +1,5 @@
|
||||
#include "ShortEdgeCollapse.hpp"
|
||||
#include "libslic3r/NormalUtils.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@ -8,57 +9,42 @@
|
||||
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)
|
||||
// in the second step, it keeps the value for the removed vertices from the first step, but for those NOT removed, it contains mapping to the new position of the new vertices vector.
|
||||
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; // Vertex normal in this algorithm is normal of any! triangle that contains the vertex
|
||||
|
||||
std::vector<size_t> face_indices; //vector if indices, serves only the purpose of randomised traversal of the faces
|
||||
std::mt19937_64 generator { };
|
||||
|
||||
float decimation_ratio = 1.0f; // decimation ratio updated in each iteration. it is number of removed triangles / number of all
|
||||
float edge_size = 0.2f; // Allowed collapsible edge size. Starts low, but is gradually increased
|
||||
size_t triangle_count = mesh.indices.size();
|
||||
|
||||
std::vector<Vec3f> new_vertices;
|
||||
std::vector<Vec3i> new_indices;
|
||||
|
||||
|
||||
while (triangle_count > target_triangle_count) {
|
||||
// the following two switches try to keep the decimation ratio within 0.05 and 0.4 range (but nothing too clever :)
|
||||
if (decimation_ratio < 0.4) { // if decimation ratio is not too large, increase it
|
||||
edge_size *= 1.5f;
|
||||
// whenever vertex is removed, its mapping is update to the index of vertex with wich it merged
|
||||
std::vector<size_t> vertices_index_mapping(mesh.vertices.size());
|
||||
for (size_t idx = 0; idx < vertices_index_mapping.size(); ++idx) {
|
||||
vertices_index_mapping[idx] = idx;
|
||||
}
|
||||
// Algorithm uses get_final_index query to get the actual vertex index. The query also updates all mappings on the way, essentially flattening the mapping
|
||||
std::vector<size_t> flatten_queue;
|
||||
auto get_final_index = [&vertices_index_mapping, &flatten_queue](const size_t &orig_index) {
|
||||
flatten_queue.clear();
|
||||
size_t idx = orig_index;
|
||||
while (vertices_index_mapping[idx] != idx) {
|
||||
flatten_queue.push_back(idx);
|
||||
idx = vertices_index_mapping[idx];
|
||||
}
|
||||
if (decimation_ratio < 0.05) { // if decimation ratio is very low, increase it once more
|
||||
edge_size *= 1.5f;
|
||||
for (size_t i : flatten_queue) {
|
||||
vertices_index_mapping[i] = idx;
|
||||
}
|
||||
return idx;
|
||||
|
||||
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];
|
||||
//assign the normal of the current triangle to all its vertices. Do not care if its overridden, normal of any triangle will work
|
||||
// (so in the end, each vertex has assigned normal of one of its triangles with largest face index)
|
||||
vertex_normals[t[0]] = n;
|
||||
vertex_normals[t[1]] = n;
|
||||
vertex_normals[t[2]] = n;
|
||||
// if face is removed, mark it here
|
||||
std::vector<bool> face_removal_flags(mesh.indices.size(), false);
|
||||
|
||||
face_indices[face_idx] = face_idx; // just an index vector, will be later shuffled for randomized face traversal
|
||||
}
|
||||
std::vector<Vec3i> triangles_neighbors = its_face_neighbors_par(mesh);
|
||||
|
||||
// now compute vertices dot product - this is used during edge collapse,
|
||||
// to determine which vertex to remove and which to keep; We try to keep the one with larger angle, because it defines the shape "more".
|
||||
// The min vertex dot product is lowest dot product of its normal with the normals of faces around it.
|
||||
// the lower the dot product, the more we want to keep the vertex
|
||||
// NOTE: This score is not updated, even though the decimation does change the mesh. It saves computation time, and there are no strong reasons to update.
|
||||
std::vector<float> min_vertex_dot_product(mesh.vertices.size(), 1);
|
||||
{
|
||||
std::vector<Vec3f> face_normals = its_face_normals(mesh);
|
||||
std::vector<Vec3f> vertex_normals = NormalUtils::create_normals(mesh);
|
||||
|
||||
std::vector<float> min_vertex_dot_product(mesh.vertices.size(), 1); // now compute vertices dot product - this is used during edge collapse,
|
||||
// to determine which vertex to remove and which to keep; We try to keep the one with larger angle, because it defines the shape "more".
|
||||
// The min vertex dot product is lowest dot product of its normal (assigned in previous step) with the normals of faces around it.
|
||||
// the lower the dot product, the more we want to keep the vertex
|
||||
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];
|
||||
@ -66,24 +52,62 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
|
||||
min_vertex_dot_product[t[1]] = std::min(min_vertex_dot_product[t[1]], n.dot(vertex_normals[t[1]]));
|
||||
min_vertex_dot_product[t[2]] = std::min(min_vertex_dot_product[t[2]], n.dot(vertex_normals[t[2]]));
|
||||
}
|
||||
}
|
||||
|
||||
// prepare vertices mapping, intitalize with self index, no vertex has been removed yet
|
||||
for (size_t vertex_index = 0; vertex_index < mesh.vertices.size(); ++vertex_index) {
|
||||
vertices_index_mapping[vertex_index] = vertex_index;
|
||||
// lambda to remove face. It flags the face as removed, and updates neighbourhood info
|
||||
auto remove_face = [&triangles_neighbors, &face_removal_flags](int face_idx, int other_face_idx) {
|
||||
if (face_idx < 0) {
|
||||
return;
|
||||
}
|
||||
face_removal_flags[face_idx] = true;
|
||||
Vec3i neighbors = triangles_neighbors[face_idx];
|
||||
int n_a = neighbors[0] != other_face_idx ? neighbors[0] : neighbors[1];
|
||||
int n_b = neighbors[2] != other_face_idx ? neighbors[2] : neighbors[1];
|
||||
if (n_a > 0)
|
||||
for (int &n : triangles_neighbors[n_a]) {
|
||||
if (n == face_idx) {
|
||||
n = n_b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n_b > 0)
|
||||
for (int &n : triangles_neighbors[n_b]) {
|
||||
if (n == face_idx) {
|
||||
n = n_a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::mt19937_64 generator { }; // default constant seed! so that results are deterministic
|
||||
std::vector<size_t> face_indices(mesh.indices.size());
|
||||
for (size_t idx = 0; idx < face_indices.size(); ++idx) {
|
||||
face_indices[idx] = idx;
|
||||
}
|
||||
//tmp face indices used only for swapping
|
||||
std::vector<size_t> tmp_face_indices(mesh.indices.size());
|
||||
|
||||
float decimation_ratio = 1.0f; // decimation ratio updated in each iteration. it is number of removed triangles / number of all
|
||||
float edge_len = 0.2f; // Allowed collapsible edge size. Starts low, but is gradually increased
|
||||
|
||||
while (face_indices.size() > target_triangle_count) {
|
||||
// simpple func to increase the edge len - if decimation ratio is low, it increases the len up to twice, if decimation ratio is high, increments are low
|
||||
edge_len = edge_len * (1.0f + 1.0 - decimation_ratio);
|
||||
float max_edge_len_squared = edge_len * edge_len;
|
||||
|
||||
//shuffle the faces and traverse in random order, this MASSIVELY improves the quality of the result
|
||||
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()) {
|
||||
// if face already removed from previous collapses, skip (each collapse removes two triangles [at least] )
|
||||
if (face_removal_flags[face_idx]) {
|
||||
// if face already removed from previous collapses, skip (each collapse removes two triangles [at least] )
|
||||
continue;
|
||||
}
|
||||
// look at each edge if it is good candidate for collapse
|
||||
|
||||
// look at each edge if it is good candidate for collapse
|
||||
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];
|
||||
size_t vertex_index_keep = get_final_index(mesh.indices[face_idx][edge_idx]);
|
||||
size_t vertex_index_remove = get_final_index(mesh.indices[face_idx][(edge_idx + 1) % 3]);
|
||||
//check distance, skip long edges
|
||||
if ((mesh.vertices[vertex_index_keep] - mesh.vertices[vertex_index_remove]).squaredNorm()
|
||||
> max_edge_len_squared) {
|
||||
@ -96,91 +120,64 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
|
||||
vertex_index_remove = tmp;
|
||||
}
|
||||
|
||||
// If vertex has already been part of a collapse, skip it (mark value -2.0 is set after collapse)
|
||||
if (min_vertex_dot_product[vertex_index_remove] < -1.1f) {
|
||||
continue;
|
||||
}
|
||||
// if any of the collapsed vertices is already marked for removal, skip as well. (break, since no edge is collapsible in this case)
|
||||
if (vertices_to_remove.find(vertex_index_keep) != vertices_to_remove.end()
|
||||
|| vertices_to_remove.find(vertex_index_remove) != vertices_to_remove.end()) {
|
||||
break;
|
||||
//remove vertex
|
||||
{
|
||||
// map its index to the index of the kept vertex
|
||||
vertices_index_mapping[vertex_index_remove] = vertices_index_mapping[vertex_index_keep];
|
||||
}
|
||||
|
||||
// find neighbour triangle over this edge. if marked for removal, skip
|
||||
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;
|
||||
}
|
||||
int neighbor_to_remove_face_idx = triangles_neighbors[face_idx][edge_idx];
|
||||
// remove faces
|
||||
remove_face(face_idx, neighbor_to_remove_face_idx);
|
||||
remove_face(neighbor_to_remove_face_idx, face_idx);
|
||||
|
||||
//finaly do the collapse:
|
||||
//mark faces for removal
|
||||
faces_to_remove.insert(face_idx);
|
||||
faces_to_remove.insert(neighbor_face_idx);
|
||||
// mark one vertex for removal (with higher dot product)
|
||||
vertices_to_remove.insert(vertex_index_remove);
|
||||
// map its index to the index of the kept vertex
|
||||
vertices_index_mapping[vertex_index_remove] = vertices_index_mapping[vertex_index_keep];
|
||||
// mark the kept vertex, so that it cannot participate as a vertex for removal in any other collapse
|
||||
min_vertex_dot_product[vertex_index_keep] = -2.0f;
|
||||
// break, we are done with this triangle
|
||||
// break. this triangle is done
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new_vertices.clear();
|
||||
new_vertices.reserve(mesh.vertices.size() - vertices_to_remove.size());
|
||||
for (size_t vertex_index = 0; vertex_index < mesh.vertices.size(); ++vertex_index) {
|
||||
// filter out removed vertices, add those NOT removed to the new_vertices vector, and also store their new position in the index mapping
|
||||
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;
|
||||
// filter face_indices, remove those that have been collapsed
|
||||
size_t prev_size = face_indices.size();
|
||||
tmp_face_indices.clear();
|
||||
for (size_t face_idx : face_indices) {
|
||||
if (!face_removal_flags[face_idx]){
|
||||
tmp_face_indices.push_back(face_idx);
|
||||
}
|
||||
}
|
||||
face_indices.swap(tmp_face_indices);
|
||||
|
||||
new_indices.clear();
|
||||
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
|
||||
// NOT removed vertices point to their new position, so use directly the mapping
|
||||
new_triangle[t_vertex_idx] = vertices_index_mapping[orig_index];
|
||||
} else {
|
||||
// Removed vertices point to the index of the kept vertex to which they collapsed.
|
||||
// This vertex was surely not removed, so use the mapping twice (first to kept vertex, and then to its new position)
|
||||
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 triangles
|
||||
}
|
||||
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;
|
||||
|
||||
// finally update the mesh
|
||||
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();
|
||||
decimation_ratio = float(prev_size - face_indices.size()) / float(prev_size);
|
||||
//std::cout << " DECIMATION RATIO: " << decimation_ratio << std::endl;
|
||||
}
|
||||
|
||||
//Extract the result mesh
|
||||
std::unordered_map<size_t, size_t> final_vertices_mapping;
|
||||
std::vector<Vec3f> final_vertices;
|
||||
std::vector<Vec3i> final_indices;
|
||||
final_indices.reserve(face_indices.size());
|
||||
for (size_t idx : face_indices) {
|
||||
Vec3i final_face;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
final_face[i] = get_final_index(mesh.indices[idx][i]);
|
||||
}
|
||||
if (final_face[0] == final_face[1] || final_face[1] == final_face[2] || final_face[2] == final_face[0]) {
|
||||
continue; // discard degenerate triangles
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (final_vertices_mapping.find(final_face[i]) == final_vertices_mapping.end()) {
|
||||
final_vertices_mapping[final_face[i]] = final_vertices.size();
|
||||
final_vertices.push_back(mesh.vertices[final_face[i]]);
|
||||
}
|
||||
final_face[i] = final_vertices_mapping[final_face[i]];
|
||||
}
|
||||
|
||||
final_indices.push_back(final_face);
|
||||
}
|
||||
|
||||
mesh.vertices = final_vertices;
|
||||
mesh.indices = final_indices;
|
||||
}
|
||||
|
||||
}
|
||||
} //namespace Slic3r
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user