23#ifndef VCL_ALGORITHMS_MESH_UPDATE_NORMAL_H
24#define VCL_ALGORITHMS_MESH_UPDATE_NORMAL_H
26#include <vclib/algorithms/core.h>
27#include <vclib/mesh.h>
28#include <vclib/space/core.h>
34template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
35void normalizeNoThrow(
auto& elem, LogType& log =
nullLogger)
38 elem.normal().normalize();
40 catch (
const std::exception& e) {
43 elementEnumString<ELEM_ID>() +
" " + std::to_string(elem.index()) +
64template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
65void clearPerElementNormals(MeshConcept
auto& mesh, LogType& log =
nullLogger)
67 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
69 log.log(0,
"Clearing per-" + elementEnumString<ELEM_ID>() +
" normals...");
71 parallelFor(mesh.template elements<ELEM_ID>(), [](
auto& e) {
75 log.log(100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals cleared.");
91template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
92void normalizePerElementNormals(
93 MeshConcept
auto& mesh,
96 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
99 0,
"Normalizing per-" + elementEnumString<ELEM_ID>() +
" normals...");
102 auto normalize = [&](
auto& elem) {
103 detail::normalizeNoThrow<ELEM_ID>(elem, log);
106 parallelFor(mesh.template elements<ELEM_ID>(), normalize);
109 100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals normalized.");
130template<u
int ELEM_ID,
typename MScalar, LoggerConcept LogType = NullLogger>
131void multiplyPerElementNormalsByMatrix(
132 MeshConcept
auto& mesh,
133 Matrix33<MScalar> mat,
137 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
141 "Multiplying per-" + elementEnumString<ELEM_ID>() +
142 " normals by matrix...");
144 multiplyNormalsByMatrix(
145 mesh.template elements<ELEM_ID>() | vcl::views::normals,
150 100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals multiplied.");
172template<u
int ELEM_ID,
typename MScalar, LoggerConcept LogType = NullLogger>
173void multiplyPerElementNormalsByMatrix(
174 MeshConcept
auto& mesh,
175 const Matrix44<MScalar>& mat,
179 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
181 Matrix33<MScalar> m33 = mat.block(0, 0, 3, 3);
182 multiplyPerElementNormalsByMatrix<ELEM_ID>(
191template<LoggerConcept LogType = NullLogger>
192void clearPerVertexNormals(MeshConcept
auto& mesh, LogType& log =
nullLogger)
194 clearPerElementNormals<ElemId::VERTEX>(mesh, log);
214template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
215void clearPerReferencedVertexNormals(MeshType& mesh, LogType& log =
nullLogger)
217 requirePerVertexNormal(mesh);
220 auto f = [&]<mesh::ElementContainerConcept Cont>() {
221 using Elem =
typename Cont::ElementType;
222 if constexpr (comp::HasVertexReferences<Elem>) {
223 for (
auto& e : mesh.template elements<Elem::ELEMENT_ID>()) {
227 v->normal() = {0., 0., 0.};
233 log.log(0,
"Clearing per-Vertex normals...");
236 ForEachType<typename MeshType::Containers>::apply(f);
238 log.log(100,
"Per-Vertex normals cleared.");
246template<LoggerConcept LogType = NullLogger>
247void clearPerFaceNormals(FaceMeshConcept
auto& mesh, LogType& log =
nullLogger)
249 clearPerElementNormals<ElemId::FACE>(mesh, log);
257template<LoggerConcept LogType = NullLogger>
258void normalizePerVertexNormals(
259 MeshConcept
auto& mesh,
262 normalizePerElementNormals<ElemId::VERTEX>(mesh, log);
281template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
282void normalizePerReferencedVertexNormals(
286 requirePerVertexNormal(mesh);
289 auto f = [&]<mesh::ElementContainerConcept Cont>() {
290 using Elem =
typename Cont::ElementType;
291 if constexpr (comp::HasVertexReferences<Elem>) {
292 for (
auto& e : mesh.template elements<Elem::ELEMENT_ID>()) {
294 detail::normalizeNoThrow<ElemId::VERTEX>(*v, log);
300 log.log(0,
"Normalizing per-Vertex normals...");
303 ForEachType<typename MeshType::Containers>::apply(f);
305 log.log(100,
"Per-Vertex normals normalized.");
313template<LoggerConcept LogType = NullLogger>
314void normalizePerFaceNormals(
315 FaceMeshConcept
auto& mesh,
318 normalizePerElementNormals<ElemId::FACE>(mesh, log);
329template<
typename Matrix, LoggerConcept LogType = NullLogger>
330void multiplyPerVertexNormalsByMatrix(
331 MeshConcept
auto& mesh,
336 multiplyPerElementNormalsByMatrix<ElemId::VERTEX>(
347template<
typename Matrix, LoggerConcept LogType = NullLogger>
348void multiplyPerFaceNormalsByMatrix(
349 FaceMeshConcept
auto& mesh,
354 multiplyPerElementNormalsByMatrix<ElemId::FACE>(
373template<LoggerConcept LogType = NullLogger>
374void updatePerFaceNormals(
375 FaceMeshConcept
auto& mesh,
376 bool normalize =
true,
381 using FaceType =
RemoveRef<
decltype(mesh)>::FaceType;
382 using ScalarType = FaceType::NormalType::ScalarType;
384 log.log(0,
"Updating per-Face normals...");
386 parallelFor(mesh.faces(), [](
auto& f) {
387 f.normal() = faceNormal(f).template cast<ScalarType>();
391 log.startNewTask(50, 100,
"Normalizing per-Face normals...");
392 normalizePerFaceNormals(mesh, log);
393 log.endTask(
"Normalizing per-Face normals...");
396 log.log(100,
"Per-Face normals updated.");
416template<LoggerConcept LogType = NullLogger>
417void updatePerVertexNormals(
418 FaceMeshConcept
auto& mesh,
419 bool normalize =
true,
422 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
423 using NScalar = VertexType::NormalType::ScalarType;
425 log.log(0,
"Updating per-Vertex normals...");
427 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
428 clearPerReferencedVertexNormals(mesh, log);
429 log.endTask(
"Clearing per-Vertex normals...");
431 log.log(20,
"Updating per-Vertex normals...");
433 for (
auto& f : mesh.
faces()) {
435 v->normal() +=
faceNormal(f).template cast<NScalar>();
440 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
441 normalizePerReferencedVertexNormals(mesh, log);
442 log.endTask(
"Normalizing per-Vertex normals...");
445 log.log(100,
"Per-Vertex normals updated.");
465template<LoggerConcept LogType = NullLogger>
466void updatePerVertexNormalsFromFaceNormals(
467 FaceMeshConcept
auto& mesh,
468 bool normalize =
true,
473 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
474 using ScalarType = VertexType::NormalType::ScalarType;
476 log.log(0,
"Updating per-Vertex normals...");
478 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
479 clearPerReferencedVertexNormals(mesh, log);
480 log.endTask(
"Clearing per-Vertex normals...");
482 log.log(20,
"Updating per-Vertex normals...");
484 for (
auto& f : mesh.
faces()) {
486 v->normal() += f.normal().template cast<ScalarType>();
491 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
492 normalizePerReferencedVertexNormals(mesh, log);
493 log.endTask(
"Normalizing per-Vertex normals...");
496 log.log(100,
"Per-Vertex normals updated.");
519template<LoggerConcept LogType = NullLogger>
520void updatePerVertexAndFaceNormals(
521 FaceMeshConcept
auto& mesh,
522 bool normalize =
true,
525 log.log(0,
"Updating per-Vertex and per-Face normals...");
527 log.startNewTask(0, 40,
"Updating per-Face normals...");
528 updatePerFaceNormals(mesh,
false, log);
531 log.startNewTask(40, 80,
"Updating per-Vertex normals...");
532 updatePerVertexNormalsFromFaceNormals(mesh, normalize, log);
536 log.startNewTask(80, 100,
"Normalizing per-Face normals...");
537 normalizePerFaceNormals(mesh, log);
541 log.log(100,
"Per-Vertex normals updated.");
571template<LoggerConcept LogType = NullLogger>
572void updatePerVertexNormalsAngleWeighted(
573 FaceMeshConcept
auto& mesh,
574 bool normalize =
true,
577 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
578 using NormalType = VertexType::NormalType;
579 using NScalarType = NormalType::ScalarType;
581 log.log(0,
"Updating per-Vertex normals...");
583 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
584 clearPerReferencedVertexNormals(mesh, log);
585 log.endTask(
"Clearing per-Vertex normals...");
587 log.log(5,
"Updating per-Vertex normals...");
589 for (
auto& f : mesh.
faces()) {
590 auto n =
faceNormal(f).template cast<NScalarType>();
592 for (uint i = 0; i < f.vertexNumber(); ++i) {
594 (f.vertexMod(i - 1)->position() - f.vertexMod(i)->position())
596 .template cast<NScalarType>();
598 (f.vertexMod(i + 1)->position() - f.vertexMod(i)->position())
600 .template cast<NScalarType>();
602 f.vertex(i)->normal() += n * vec1.angle(vec2);
607 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
608 normalizePerReferencedVertexNormals(mesh, log);
609 log.endTask(
"Normalizing per-Vertex normals...");
612 log.log(100,
"Per-Vertex normals updated.");
645template<LoggerConcept LogType = NullLogger>
646void updatePerVertexNormalsNelsonMaxWeighted(
647 FaceMeshConcept
auto& mesh,
648 bool normalize =
true,
651 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
652 using NScalarType = VertexType::NormalType::ScalarType;
654 log.log(0,
"Updating per-Vertex normals...");
656 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
657 clearPerReferencedVertexNormals(mesh, log);
658 log.endTask(
"Clearing per-Vertex normals...");
660 log.log(5,
"Updating per-Vertex normals...");
662 for (
auto& f : mesh.
faces()) {
663 auto n =
faceNormal(f).template cast<NScalarType>();
665 for (uint i = 0; i < f.vertexNumber(); ++i) {
667 (f.vertexMod(i - 1)->position() - f.vertexMod(i)->position())
670 (f.vertexMod(i + 1)->position() - f.vertexMod(i)->position())
673 f.vertex(i)->normal() += n / (e1 * e2);
678 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
679 normalizePerReferencedVertexNormals(mesh, log);
680 log.endTask(
"Normalizing per-Vertex normals...");
683 log.log(100,
"Per-Vertex normals updated.");
MatrixType removeScalingFromMatrix(const MatrixType &matrix)
Returns a matrix with the scaling factors removed.
Definition transform.h:274
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:123
std::remove_reference_t< T > RemoveRef
Utility alias to get a type type without the reference. e.g. If T is int&, the resulting type is int.
Definition pointers.h:55
FaceType::VertexType::PositionType faceNormal(const FaceType &f)
Computes the normal of a face, without modifying the face. Works both for triangle and polygonal face...
Definition geometry.h:46
void requirePerFaceNormal(const MeshType &m)
This function asserts that a Mesh has a FaceContainer, the Face has a Normal Component,...
Definition face_requirements.h:1179
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92