Lagrange
Loading...
Searching...
No Matches
compute_dihedral_angles.h
1/*
2 * Copyright 2019 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/Edge.h>
15#include <lagrange/Logger.h>
16#include <lagrange/Mesh.h>
17#include <lagrange/MeshTrait.h>
18#include <lagrange/attributes/eval_as_attribute.h>
19#include <lagrange/compute_triangle_normal.h>
20#include <lagrange/internal/constants.h>
21#include <lagrange/legacy/inline.h>
22#include <lagrange/utils/geometry3d.h>
23
24namespace lagrange {
25LAGRANGE_LEGACY_INLINE
26namespace legacy {
27/*
28Fills the edge attribute "dihedral_angle" with dihedral angles.
29Boundary edges will have value 0.
30
31Requires 3D mesh.
32
33Computes facet normals (mesh facet attribute "normal") and
34initializes the mesh edge data if needed.
35*/
36
37template <typename MeshType>
38void compute_dihedral_angles(MeshType& mesh)
39{
40 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
41
42 if (mesh.get_dim() != 3) {
43 throw std::runtime_error("Input mesh is not 3D.");
44 }
45
46 using Index = typename MeshType::Index;
47 using Scalar = typename MeshType::Scalar;
48
49 mesh.initialize_edge_data();
50
51 if (!mesh.has_facet_attribute("normal")) {
52 compute_triangle_normal(mesh);
53 }
54
55 const auto& facet_normals = mesh.get_facet_attribute("normal");
56 bool non_manifold = false;
57 eval_as_edge_attribute_new(mesh, "dihedral_angle", [&](Index i) -> Scalar {
58 const auto num_adj_facets = mesh.get_num_facets_around_edge(i);
59 if (num_adj_facets > 2) {
60 non_manifold = true;
61 }
62
63 if (num_adj_facets <= 1) {
64 return 0;
65 } else if (num_adj_facets == 2) {
66 Eigen::Matrix<Scalar, 2, 3, Eigen::RowMajor> normals(num_adj_facets, 3);
67 Index index = 0;
68 mesh.foreach_facets_around_edge(i, [&](Index fid) {
69 normals.row(index) = facet_normals.row(fid);
70 index++;
71 });
72
73 const Eigen::Matrix<Scalar, 1, 3>& n1 = normals.row(0);
74 const Eigen::Matrix<Scalar, 1, 3>& n2 = normals.row(1);
75 return angle_between(n1, n2);
76 } else {
77 // Non-manifold edge encountered. Default to 2 * lagrange::internal::pi.
78 return 2 * lagrange::internal::pi;
79 }
80 });
81
82 if (non_manifold) {
83 lagrange::logger().warn("Computing dihedral angles on a non-manifold mesh!");
84 }
85}
86} // namespace legacy
87} // namespace lagrange
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
Main namespace for Lagrange.
Scalar angle_between(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2)
Returns the angle between two 3d vectors.
Definition geometry3d.h:38