PrusaSlicer-NonPlainar/src/libslic3r/NormalUtils.cpp
PavelMikus 13ac7a24d8 Refactoring of the short edge collpase, should greatly improve performance
integration of NormalsUitls from SDF branch
2022-06-07 11:12:48 +02:00

143 lines
4.6 KiB
C++

#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);
}
}