23#ifndef VCL_ALGORITHMS_MESH_UPDATE_NORMAL_H
24#define VCL_ALGORITHMS_MESH_UPDATE_NORMAL_H
26#include <vclib/algorithms/core/polygon.h>
27#include <vclib/mesh/requirements.h>
28#include <vclib/misc/logger.h>
29#include <vclib/misc/parallel.h>
30#include <vclib/space/core/matrix.h>
36template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
37void normalizeNoThrow(
auto& elem, LogType& log =
nullLogger)
40 elem.normal().normalize();
42 catch (
const std::exception& e) {
45 elementEnumString<ELEM_ID>() +
" " + std::to_string(elem.index()) +
66template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
67void clearPerElementNormals(MeshConcept
auto& mesh, LogType& log =
nullLogger)
69 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
71 log.log(0,
"Clearing per-" + elementEnumString<ELEM_ID>() +
" normals...");
73 parallelFor(mesh.template elements<ELEM_ID>(), [](
auto& e) {
77 log.log(100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals cleared.");
93template<u
int ELEM_ID, LoggerConcept LogType = NullLogger>
94void normalizePerElementNormals(
95 MeshConcept
auto& mesh,
98 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
101 0,
"Normalizing per-" + elementEnumString<ELEM_ID>() +
" normals...");
104 auto normalize = [&](
auto& elem) {
105 detail::normalizeNoThrow<ELEM_ID>(elem, log);
108 parallelFor(mesh.template elements<ELEM_ID>(), normalize);
111 100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals normalized.");
132template<u
int ELEM_ID,
typename MScalar, LoggerConcept LogType = NullLogger>
133void multiplyPerElementNormalsByMatrix(
134 MeshConcept
auto& mesh,
135 Matrix33<MScalar> mat,
136 bool removeScalingFromMatrix =
true,
139 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
141 if (removeScalingFromMatrix) {
142 MScalar scaleX = std::sqrt(
143 mat(0, 0) * mat(0, 0) + mat(0, 1) * mat(0, 1) +
144 mat(0, 2) * mat(0, 2));
145 MScalar scaleY = std::sqrt(
146 mat(1, 0) * mat(1, 0) + mat(1, 1) * mat(1, 1) +
147 mat(1, 2) * mat(1, 2));
148 MScalar scaleZ = std::sqrt(
149 mat(2, 0) * mat(2, 0) + mat(2, 1) * mat(2, 1) +
150 mat(2, 2) * mat(2, 2));
151 for (
int i = 0; i < 3; ++i) {
160 "Multiplying per-" + elementEnumString<ELEM_ID>() +
161 " normals by matrix...");
163 parallelFor(mesh.template elements<ELEM_ID>(), [&](
auto& e) {
164 e.normal() = mat * e.normal();
168 100,
"Per-" + elementEnumString<ELEM_ID>() +
" normals multiplied.");
190template<u
int ELEM_ID,
typename MScalar, LoggerConcept LogType = NullLogger>
191void multiplyPerElementNormalsByMatrix(
192 MeshConcept
auto& mesh,
193 const Matrix44<MScalar>& mat,
194 bool removeScalingFromMatrix =
true,
197 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
199 Matrix33<MScalar> m33 = mat.block(0, 0, 3, 3);
200 multiplyPerElementNormalsByMatrix<ELEM_ID>(
201 mesh, m33, removeScalingFromMatrix, log);
209template<LoggerConcept LogType = NullLogger>
210void clearPerVertexNormals(MeshConcept
auto& mesh, LogType& log =
nullLogger)
212 clearPerElementNormals<ElemId::VERTEX>(mesh, log);
232template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
233void clearPerReferencedVertexNormals(MeshType& mesh, LogType& log =
nullLogger)
235 requirePerVertexNormal(mesh);
238 auto f = [&]<mesh::ElementContainerConcept Cont>() {
239 using Elem =
typename Cont::ElementType;
240 if constexpr (comp::HasVertexReferences<Elem>) {
241 for (
auto& e : mesh.template elements<Elem::ELEMENT_ID>()) {
243 v->normal().setZero();
249 log.log(0,
"Clearing per-Vertex normals...");
252 ForEachType<typename MeshType::Containers>::apply(f);
254 log.log(100,
"Per-Vertex normals cleared.");
262template<LoggerConcept LogType = NullLogger>
263void clearPerFaceNormals(FaceMeshConcept
auto& mesh, LogType& log =
nullLogger)
265 clearPerElementNormals<ElemId::FACE>(mesh, log);
273template<LoggerConcept LogType = NullLogger>
274void normalizePerVertexNormals(
275 MeshConcept
auto& mesh,
278 normalizePerElementNormals<ElemId::VERTEX>(mesh, log);
297template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
298void normalizePerReferencedVertexNormals(
302 requirePerVertexNormal(mesh);
305 auto f = [&]<mesh::ElementContainerConcept Cont>() {
306 using Elem =
typename Cont::ElementType;
307 if constexpr (comp::HasVertexReferences<Elem>) {
308 for (
auto& e : mesh.template elements<Elem::ELEMENT_ID>()) {
310 detail::normalizeNoThrow<ElemId::VERTEX>(*v, log);
316 log.log(0,
"Normalizing per-Vertex normals...");
319 ForEachType<typename MeshType::Containers>::apply(f);
321 log.log(100,
"Per-Vertex normals normalized.");
329template<LoggerConcept LogType = NullLogger>
330void normalizePerFaceNormals(
331 FaceMeshConcept
auto& mesh,
334 normalizePerElementNormals<ElemId::FACE>(mesh, log);
345template<
typename Matrix, LoggerConcept LogType = NullLogger>
346void multiplyPerVertexNormalsByMatrix(
347 MeshConcept
auto& mesh,
349 bool removeScalingFromMatrix =
true,
352 multiplyPerElementNormalsByMatrix<ElemId::VERTEX>(
353 mesh, mat, removeScalingFromMatrix, log);
363template<
typename Matrix, LoggerConcept LogType = NullLogger>
364void multiplyPerFaceNormalsByMatrix(
365 FaceMeshConcept
auto& mesh,
367 bool removeScalingFromMatrix =
true,
370 multiplyPerElementNormalsByMatrix<ElemId::FACE>(
371 mesh, mat, removeScalingFromMatrix, log);
389template<LoggerConcept LogType = NullLogger>
390void updatePerFaceNormals(
391 FaceMeshConcept
auto& mesh,
392 bool normalize =
true,
397 using FaceType =
RemoveRef<
decltype(mesh)>::FaceType;
398 using ScalarType = FaceType::NormalType::ScalarType;
400 log.log(0,
"Updating per-Face normals...");
402 parallelFor(mesh.faces(), [](
auto& f) {
403 f.normal() = faceNormal(f).template cast<ScalarType>();
407 log.startNewTask(50, 100,
"Normalizing per-Face normals...");
408 normalizePerFaceNormals(mesh, log);
409 log.endTask(
"Normalizing per-Face normals...");
412 log.log(100,
"Per-Face normals updated.");
432template<LoggerConcept LogType = NullLogger>
433void updatePerVertexNormals(
434 FaceMeshConcept
auto& mesh,
435 bool normalize =
true,
438 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
439 using NScalar = VertexType::NormalType::ScalarType;
441 log.log(0,
"Updating per-Vertex normals...");
443 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
444 clearPerReferencedVertexNormals(mesh, log);
445 log.endTask(
"Clearing per-Vertex normals...");
447 log.log(20,
"Updating per-Vertex normals...");
449 for (
auto& f : mesh.
faces()) {
451 v->normal() +=
faceNormal(f).template cast<NScalar>();
456 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
457 normalizePerReferencedVertexNormals(mesh, log);
458 log.endTask(
"Normalizing per-Vertex normals...");
461 log.log(100,
"Per-Vertex normals updated.");
481template<LoggerConcept LogType = NullLogger>
482void updatePerVertexNormalsFromFaceNormals(
483 FaceMeshConcept
auto& mesh,
484 bool normalize =
true,
489 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
490 using ScalarType = VertexType::NormalType::ScalarType;
492 log.log(0,
"Updating per-Vertex normals...");
494 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
495 clearPerReferencedVertexNormals(mesh, log);
496 log.endTask(
"Clearing per-Vertex normals...");
498 log.log(20,
"Updating per-Vertex normals...");
500 for (
auto& f : mesh.
faces()) {
502 v->normal() += f.normal().template cast<ScalarType>();
507 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
508 normalizePerReferencedVertexNormals(mesh, log);
509 log.endTask(
"Normalizing per-Vertex normals...");
512 log.log(100,
"Per-Vertex normals updated.");
535template<LoggerConcept LogType = NullLogger>
536void updatePerVertexAndFaceNormals(
537 FaceMeshConcept
auto& mesh,
538 bool normalize =
true,
541 log.log(0,
"Updating per-Vertex and per-Face normals...");
543 log.startNewTask(0, 40,
"Updating per-Face normals...");
544 updatePerFaceNormals(mesh,
false, log);
547 log.startNewTask(40, 80,
"Updating per-Vertex normals...");
548 updatePerVertexNormalsFromFaceNormals(mesh, normalize, log);
552 log.startNewTask(80, 100,
"Normalizing per-Face normals...");
553 normalizePerFaceNormals(mesh, log);
557 log.log(100,
"Per-Vertex normals updated.");
587template<LoggerConcept LogType = NullLogger>
588void updatePerVertexNormalsAngleWeighted(
589 FaceMeshConcept
auto& mesh,
590 bool normalize =
true,
593 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
594 using NormalType = VertexType::NormalType;
595 using NScalarType = NormalType::ScalarType;
597 log.log(0,
"Updating per-Vertex normals...");
599 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
600 clearPerReferencedVertexNormals(mesh, log);
601 log.endTask(
"Clearing per-Vertex normals...");
603 log.log(5,
"Updating per-Vertex normals...");
605 for (
auto& f : mesh.
faces()) {
606 auto n =
faceNormal(f).template cast<NScalarType>();
608 for (uint i = 0; i < f.vertexNumber(); ++i) {
610 (f.vertexMod(i - 1)->coord() - f.vertexMod(i)->coord())
612 .template cast<NScalarType>();
614 (f.vertexMod(i + 1)->coord() - f.vertexMod(i)->coord())
616 .template cast<NScalarType>();
618 f.vertex(i)->normal() += n * vec1.angle(vec2);
623 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
624 normalizePerReferencedVertexNormals(mesh, log);
625 log.endTask(
"Normalizing per-Vertex normals...");
628 log.log(100,
"Per-Vertex normals updated.");
661template<LoggerConcept LogType = NullLogger>
662void updatePerVertexNormalsNelsonMaxWeighted(
663 FaceMeshConcept
auto& mesh,
664 bool normalize =
true,
667 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
668 using NScalarType = VertexType::NormalType::ScalarType;
670 log.log(0,
"Updating per-Vertex normals...");
672 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
673 clearPerReferencedVertexNormals(mesh, log);
674 log.endTask(
"Clearing per-Vertex normals...");
676 log.log(5,
"Updating per-Vertex normals...");
678 for (
auto& f : mesh.
faces()) {
679 auto n =
faceNormal(f).template cast<NScalarType>();
681 for (uint i = 0; i < f.vertexNumber(); ++i) {
683 (f.vertexMod(i - 1)->coord() - f.vertexMod(i)->coord())
686 (f.vertexMod(i + 1)->coord() - f.vertexMod(i)->coord())
689 f.vertex(i)->normal() += n / (e1 * e2);
694 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
695 normalizePerReferencedVertexNormals(mesh, log);
696 log.endTask(
"Normalizing per-Vertex normals...");
699 log.log(100,
"Per-Vertex normals updated.");
FaceType::VertexType::CoordType faceNormal(const FaceType &f)
Computes the normal of a face, without modifying the face. Works both for triangle and polygonal face...
Definition geometry.h:45
void requirePerFaceNormal(const MeshType &m)
This function asserts that a Mesh has a FaceContainer, the Face has a Normal Component,...
Definition face_requirements.h:804
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:125
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
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60