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>()) {
225 v->normal().setZero();
231 log.log(0,
"Clearing per-Vertex normals...");
234 ForEachType<typename MeshType::Containers>::apply(f);
236 log.log(100,
"Per-Vertex normals cleared.");
244template<LoggerConcept LogType = NullLogger>
245void clearPerFaceNormals(FaceMeshConcept
auto& mesh, LogType& log =
nullLogger)
247 clearPerElementNormals<ElemId::FACE>(mesh, log);
255template<LoggerConcept LogType = NullLogger>
256void normalizePerVertexNormals(
257 MeshConcept
auto& mesh,
260 normalizePerElementNormals<ElemId::VERTEX>(mesh, log);
279template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
280void normalizePerReferencedVertexNormals(
284 requirePerVertexNormal(mesh);
287 auto f = [&]<mesh::ElementContainerConcept Cont>() {
288 using Elem =
typename Cont::ElementType;
289 if constexpr (comp::HasVertexReferences<Elem>) {
290 for (
auto& e : mesh.template elements<Elem::ELEMENT_ID>()) {
292 detail::normalizeNoThrow<ElemId::VERTEX>(*v, log);
298 log.log(0,
"Normalizing per-Vertex normals...");
301 ForEachType<typename MeshType::Containers>::apply(f);
303 log.log(100,
"Per-Vertex normals normalized.");
311template<LoggerConcept LogType = NullLogger>
312void normalizePerFaceNormals(
313 FaceMeshConcept
auto& mesh,
316 normalizePerElementNormals<ElemId::FACE>(mesh, log);
327template<
typename Matrix, LoggerConcept LogType = NullLogger>
328void multiplyPerVertexNormalsByMatrix(
329 MeshConcept
auto& mesh,
334 multiplyPerElementNormalsByMatrix<ElemId::VERTEX>(
345template<
typename Matrix, LoggerConcept LogType = NullLogger>
346void multiplyPerFaceNormalsByMatrix(
347 FaceMeshConcept
auto& mesh,
352 multiplyPerElementNormalsByMatrix<ElemId::FACE>(
371template<LoggerConcept LogType = NullLogger>
372void updatePerFaceNormals(
373 FaceMeshConcept
auto& mesh,
374 bool normalize =
true,
379 using FaceType =
RemoveRef<
decltype(mesh)>::FaceType;
380 using ScalarType = FaceType::NormalType::ScalarType;
382 log.log(0,
"Updating per-Face normals...");
384 parallelFor(mesh.faces(), [](
auto& f) {
385 f.normal() = faceNormal(f).template cast<ScalarType>();
389 log.startNewTask(50, 100,
"Normalizing per-Face normals...");
390 normalizePerFaceNormals(mesh, log);
391 log.endTask(
"Normalizing per-Face normals...");
394 log.log(100,
"Per-Face normals updated.");
414template<LoggerConcept LogType = NullLogger>
415void updatePerVertexNormals(
416 FaceMeshConcept
auto& mesh,
417 bool normalize =
true,
420 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
421 using NScalar = VertexType::NormalType::ScalarType;
423 log.log(0,
"Updating per-Vertex normals...");
425 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
426 clearPerReferencedVertexNormals(mesh, log);
427 log.endTask(
"Clearing per-Vertex normals...");
429 log.log(20,
"Updating per-Vertex normals...");
431 for (
auto& f : mesh.
faces()) {
433 v->normal() +=
faceNormal(f).template cast<NScalar>();
438 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
439 normalizePerReferencedVertexNormals(mesh, log);
440 log.endTask(
"Normalizing per-Vertex normals...");
443 log.log(100,
"Per-Vertex normals updated.");
463template<LoggerConcept LogType = NullLogger>
464void updatePerVertexNormalsFromFaceNormals(
465 FaceMeshConcept
auto& mesh,
466 bool normalize =
true,
471 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
472 using ScalarType = VertexType::NormalType::ScalarType;
474 log.log(0,
"Updating per-Vertex normals...");
476 log.startNewTask(0, 20,
"Clearing per-Vertex normals...");
477 clearPerReferencedVertexNormals(mesh, log);
478 log.endTask(
"Clearing per-Vertex normals...");
480 log.log(20,
"Updating per-Vertex normals...");
482 for (
auto& f : mesh.
faces()) {
484 v->normal() += f.normal().template cast<ScalarType>();
489 log.startNewTask(80, 100,
"Normalizing per-Vertex normals...");
490 normalizePerReferencedVertexNormals(mesh, log);
491 log.endTask(
"Normalizing per-Vertex normals...");
494 log.log(100,
"Per-Vertex normals updated.");
517template<LoggerConcept LogType = NullLogger>
518void updatePerVertexAndFaceNormals(
519 FaceMeshConcept
auto& mesh,
520 bool normalize =
true,
523 log.log(0,
"Updating per-Vertex and per-Face normals...");
525 log.startNewTask(0, 40,
"Updating per-Face normals...");
526 updatePerFaceNormals(mesh,
false, log);
529 log.startNewTask(40, 80,
"Updating per-Vertex normals...");
530 updatePerVertexNormalsFromFaceNormals(mesh, normalize, log);
534 log.startNewTask(80, 100,
"Normalizing per-Face normals...");
535 normalizePerFaceNormals(mesh, log);
539 log.log(100,
"Per-Vertex normals updated.");
569template<LoggerConcept LogType = NullLogger>
570void updatePerVertexNormalsAngleWeighted(
571 FaceMeshConcept
auto& mesh,
572 bool normalize =
true,
575 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
576 using NormalType = VertexType::NormalType;
577 using NScalarType = NormalType::ScalarType;
579 log.log(0,
"Updating per-Vertex normals...");
581 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
582 clearPerReferencedVertexNormals(mesh, log);
583 log.endTask(
"Clearing per-Vertex normals...");
585 log.log(5,
"Updating per-Vertex normals...");
587 for (
auto& f : mesh.
faces()) {
588 auto n =
faceNormal(f).template cast<NScalarType>();
590 for (uint i = 0; i < f.vertexNumber(); ++i) {
592 (f.vertexMod(i - 1)->position() - f.vertexMod(i)->position())
594 .template cast<NScalarType>();
596 (f.vertexMod(i + 1)->position() - f.vertexMod(i)->position())
598 .template cast<NScalarType>();
600 f.vertex(i)->normal() += n * vec1.angle(vec2);
605 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
606 normalizePerReferencedVertexNormals(mesh, log);
607 log.endTask(
"Normalizing per-Vertex normals...");
610 log.log(100,
"Per-Vertex normals updated.");
643template<LoggerConcept LogType = NullLogger>
644void updatePerVertexNormalsNelsonMaxWeighted(
645 FaceMeshConcept
auto& mesh,
646 bool normalize =
true,
649 using VertexType =
RemoveRef<
decltype(mesh)>::VertexType;
650 using NScalarType = VertexType::NormalType::ScalarType;
652 log.log(0,
"Updating per-Vertex normals...");
654 log.startNewTask(0, 5,
"Clearing per-Vertex normals...");
655 clearPerReferencedVertexNormals(mesh, log);
656 log.endTask(
"Clearing per-Vertex normals...");
658 log.log(5,
"Updating per-Vertex normals...");
660 for (
auto& f : mesh.
faces()) {
661 auto n =
faceNormal(f).template cast<NScalarType>();
663 for (uint i = 0; i < f.vertexNumber(); ++i) {
665 (f.vertexMod(i - 1)->position() - f.vertexMod(i)->position())
668 (f.vertexMod(i + 1)->position() - f.vertexMod(i)->position())
671 f.vertex(i)->normal() += n / (e1 * e2);
676 log.startNewTask(95, 100,
"Normalizing per-Vertex normals...");
677 normalizePerReferencedVertexNormals(mesh, log);
678 log.endTask(
"Normalizing per-Vertex normals...");
681 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:1066
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