18#include <lagrange/Mesh.h>
19#include <lagrange/MeshTrait.h>
20#include <lagrange/common.h>
21#include <lagrange/compute_dihedral_angles.h>
22#include <lagrange/compute_facet_area.h>
23#include <lagrange/compute_triangle_normal.h>
24#include <lagrange/internal/internal_angles.h>
25#include <lagrange/legacy/inline.h>
31template <
typename MeshType>
32void compute_corner_normal(
34 std::function<
bool(
typename MeshType::Index,
typename MeshType::Index)> is_sharp,
35 std::function<
bool(
typename MeshType::Index)> is_cone_vertex)
37 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
39 using AttributeArray =
typename MeshType::AttributeArray;
40 using Index =
typename MeshType::Index;
41 using Scalar =
typename MeshType::Scalar;
43 if (!mesh.has_facet_attribute(
"normal")) {
44 compute_triangle_normal(mesh);
46 if (!mesh.is_connectivity_initialized()) {
47 mesh.initialize_connectivity();
49 mesh.initialize_edge_data();
51 const Index dim = mesh.get_dim();
52 const Index num_vertices = mesh.get_num_vertices();
53 const Index num_facets = mesh.get_num_facets();
54 const Index vertex_per_facet = mesh.get_vertex_per_facet();
55 const auto& facets = mesh.get_facets();
56 const AttributeArray& facet_normals = mesh.get_facet_attribute(
"normal");
58 AttributeArray corner_angles;
61 assert(corner_angles.rows() == facets.rows());
62 assert(corner_angles.cols() == facets.cols());
66 AttributeArray corner_normals = AttributeArray::Zero(num_facets * vertex_per_facet, dim);
68 auto index_of = [](
const auto& data,
const auto item) -> Index {
69 auto itr = std::find(data.begin(), data.end(), item);
70 assert(itr != data.end());
71 return safe_cast<Index>(itr - data.begin());
74 auto get_root = [](
const auto& data, Index i) -> Index {
75 while (data[i] != i) {
82 auto get_corner_index = [vertex_per_facet, &facets](
const Index fid,
const Index vid) -> Index {
83 for (
auto i :
range(vertex_per_facet)) {
84 if (facets(fid, i) == vid) {
85 return fid * vertex_per_facet + i;
92 auto compute_corner_normal_around_cone_vertex =
93 [&mesh, &get_corner_index, &corner_normals, &facet_normals](Index vi) {
94 const auto& adj_facets = mesh.get_facets_adjacent_to_vertex(vi);
95 for (
const auto fi : adj_facets) {
96 const auto ci = get_corner_index(fi, vi);
97 corner_normals.row(ci) = facet_normals.row(fi);
101 std::vector<Index> facet_ids;
102 std::vector<Index> e_fids;
103 auto compute_corner_normal_around_regular_vertex = [&](Index vi) {
104 const auto& adj_facets = mesh.get_facets_adjacent_to_vertex(vi);
105 const auto num_adj_facets = adj_facets.size();
106 const auto& adj_vertices = mesh.get_vertices_adjacent_to_vertex(vi);
109 facet_ids.resize(num_adj_facets);
110 std::iota(facet_ids.begin(), facet_ids.end(), 0);
111 auto get_1_ring_root = [&get_root, &facet_ids](Index idx) {
112 return get_root(facet_ids, idx);
115 for (
auto vj : adj_vertices) {
116 if (!is_sharp(vi, vj)) {
117 auto ei = mesh.find_edge_from_vertices(vi, vj);
119 e_fids.reserve(mesh.get_num_facets_around_edge(ei));
120 mesh.foreach_facets_around_edge(ei, [&](Index fid) {
121 e_fids.push_back(index_of(adj_facets, fid));
124 std::transform(e_fids.begin(), e_fids.end(), e_fids.begin(), get_1_ring_root);
125 const auto root_id = *std::min_element(e_fids.begin(), e_fids.end());
126 std::for_each(e_fids.begin(), e_fids.end(), [&facet_ids, root_id](
const Index fid) {
127 facet_ids[fid] = root_id;
132 std::transform(facet_ids.begin(), facet_ids.end(), facet_ids.begin(), get_1_ring_root);
135 for (
auto i :
range(num_adj_facets)) {
136 const Index fid = adj_facets[i];
137 const Index corner_id = get_corner_index(fid, vi);
138 const Index root_fid = adj_facets[facet_ids[i]];
139 const Index root_corner_id = get_corner_index(root_fid, vi);
140 const Scalar corner_angle =
141 corner_angles(corner_id / vertex_per_facet, corner_id % vertex_per_facet);
142 if (corner_angle >= 0.f &&
143 corner_angle <= 3.14f) {
144 corner_normals.row(root_corner_id) += facet_normals.row(fid) * corner_angle;
148 for (
auto i :
range(num_adj_facets)) {
149 const Index fid = adj_facets[i];
150 const Index root_fid = adj_facets[facet_ids[i]];
151 const Index curr_corner_id = get_corner_index(fid, vi);
152 const Index root_corner_id = get_corner_index(root_fid, vi);
154 corner_normals.row(curr_corner_id) = corner_normals.row(root_corner_id);
156 if (corner_normals.row(curr_corner_id).template lpNorm<Eigen::Infinity>() > 1.e-4) {
157 corner_normals.row(curr_corner_id).normalize();
159 corner_normals.row(curr_corner_id).setZero();
164 for (
auto vi :
range(num_vertices)) {
165 if (is_cone_vertex(vi)) {
166 compute_corner_normal_around_cone_vertex(vi);
168 compute_corner_normal_around_regular_vertex(vi);
172 mesh.add_corner_attribute(
"normal");
173 mesh.import_corner_attribute(
"normal", corner_normals);
180template <
typename MeshType>
181void compute_corner_normal(
183 const typename MeshType::Scalar feature_angle_threshold,
184 const std::vector<typename MeshType::Index>& cone_vertices = {})
186 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
187 la_runtime_assert(feature_angle_threshold < 4,
"This angle is in degrees, must be in radians");
188 using Index =
typename MeshType::Index;
190 mesh.initialize_edge_data();
191 if (!mesh.has_edge_attribute(
"dihedral_angle")) {
195 auto is_sharp = [&mesh, feature_angle_threshold](Index vi, Index vj) {
196 assert(mesh.has_edge_attribute(
"dihedral_angle"));
197 const auto& dihedral_angles = mesh.get_edge_attribute(
"dihedral_angle");
198 Index eid = mesh.find_edge_from_vertices(vi, vj);
199 return std::abs(dihedral_angles(eid, 0)) > feature_angle_threshold;
202 if (cone_vertices.empty()) {
203 compute_corner_normal(mesh, is_sharp, [](Index) {
return false; });
205 std::vector<bool> is_cone(mesh.get_num_vertices(),
false);
206 std::for_each(cone_vertices.begin(), cone_vertices.end(), [&is_cone](Index vi) {
209 compute_corner_normal(mesh, is_sharp, [&is_cone](Index vi) {
return is_cone[vi]; });
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
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
void internal_angles(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets, Eigen::PlainObjectBase< DerivedK > &angles)
Compute internal angles for a triangle mesh.
Definition: internal_angles.h:39
Main namespace for Lagrange.
Definition: AABBIGL.h:30