Lagrange
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/legacy/inline.h>
21#include <lagrange/utils/geometry3d.h>
22
23namespace lagrange {
24LAGRANGE_LEGACY_INLINE
25namespace legacy {
26/*
27Fills the edge attribute "dihedral_angle" with dihedral angles.
28Boundary edges will have value 0.
29
30Requires 3D mesh.
31
32Computes facet normals (mesh facet attribute "normal") and
33initializes the mesh edge data if needed.
34*/
35
36template <typename MeshType>
38{
39 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
40
41 if (mesh.get_dim() != 3) {
42 throw std::runtime_error("Input mesh is not 3D.");
43 }
44
45 using Index = typename MeshType::Index;
46 using Scalar = typename MeshType::Scalar;
47
48 mesh.initialize_edge_data();
49
50 if (!mesh.has_facet_attribute("normal")) {
51 compute_triangle_normal(mesh);
52 }
53
54 const auto& facet_normals = mesh.get_facet_attribute("normal");
55 bool non_manifold = false;
56 eval_as_edge_attribute_new(mesh, "dihedral_angle", [&](Index i) -> Scalar {
57 const auto num_adj_facets = mesh.get_num_facets_around_edge(i);
58 if (num_adj_facets > 2) {
59 non_manifold = true;
60 }
61
62 if (num_adj_facets <= 1) {
63 return 0;
64 } else if (num_adj_facets == 2) {
65 Eigen::Matrix<Scalar, 2, 3, Eigen::RowMajor> normals(num_adj_facets, 3);
66 Index index = 0;
67 mesh.foreach_facets_around_edge(i, [&](Index fid) {
68 normals.row(index) = facet_normals.row(fid);
69 index++;
70 });
71
72 const Eigen::Matrix<Scalar, 1, 3>& n1 = normals.row(0);
73 const Eigen::Matrix<Scalar, 1, 3>& n2 = normals.row(1);
74 return angle_between(n1, n2);
75 } else {
76 // Non-manifold edge encountered. Default to 2 * M_PI.
77 return 2 * M_PI;
78 }
79 });
80
81 if (non_manifold) {
82 lagrange::logger().warn("Computing dihedral angles on a non-manifold mesh!");
83 }
84}
85} // namespace legacy
86} // namespace lagrange
Definition: Mesh.h:48
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
AttributeId compute_dihedral_angles(SurfaceMesh< Scalar, Index > &mesh, const DihedralAngleOptions &options={})
Computes dihedral angles for each edge in the mesh.
Definition: compute_dihedral_angles.cpp:32
Main namespace for Lagrange.
Definition: AABBIGL.h:30
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:36