GCC Code Coverage Report


Directory: ./
File: lib/geogram/mesh/mesh_geometry.h
Date: 2026-09-07 02:25:23
Exec Total Coverage
Lines: 10 20 50.0%
Functions: 1 4 25.0%
Branches: 4 14 28.6%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_MESH_MESH_GEOMETRY
41 #define GEOGRAM_MESH_MESH_GEOMETRY
42
43 #include <geogram/basic/common.h>
44 #include <geogram/mesh/mesh.h>
45 #include <geogram/basic/geometry.h>
46 #include <geogram/basic/geometry_nd.h>
47
48 /**
49 * \file geogram/mesh/mesh_geometry.h
50 * \brief Functions for accessing the geometry in a mesh
51 */
52
53 namespace GEO {
54
55 namespace Geom {
56
57 /**
58 * \brief Gets a mesh vertex by its index.
59 * \param[in] M the mesh
60 * \param[in] v the index of the vertex
61 * \return a const reference to the \p v%th vertex of a mesh
62 * \pre M.vertices.dimension() >= 3
63 * \deprecated use M.vertices.point(v) instead
64 */
65 [[deprecated("use M.vertices.point(v) instead")]]
66 inline const vec3& mesh_vertex(const Mesh& M, index_t v) {
67 return M.vertices.point(v);
68 }
69
70 /**
71 * \brief Gets a mesh vertex by its index.
72 * \param[in] M the mesh
73 * \param[in] v the index of the vertex
74 * \return a const reference to the \p v%th vertex of a mesh
75 * \pre M.vertices.dimension() >= 3
76 * \deprecated use M.vertices.point(v) instead
77 */
78 [[deprecated("use M.vertices.point(v) instead")]]
79 inline const vec3& mesh_vertex_ref(const Mesh& M, index_t v) {
80 return M.vertices.point(v);
81 }
82
83 /**
84 * \brief Gets a mesh vertex by its index.
85 * \param[in] M the mesh
86 * \param[in] v the index of the vertex
87 * \return a reference to the \p v%th vertex of a mesh
88 * \pre M.vertices.dimension() >= 3
89 * \deprecated use M.vertices.point(v) instead
90 */
91 [[deprecated("use M.vertices.point(v) instead")]]
92 inline vec3& mesh_vertex_ref(Mesh& M, index_t v) {
93 return M.vertices.point(v);
94 }
95
96 /**
97 * \brief Gets a mesh vertex by an incident corner index.
98 * \param[in] M the mesh
99 * \param[in] c the index of a corner incident to the vertex
100 * \return a reference to the \p v%th vertex of a mesh
101 * \pre M.vertices.dimension() >= 3
102 * \deprecated use M.facet_corners.point(c) instead
103 */
104 [[deprecated("use M.facet_corners.point(c) instead")]]
105 inline const vec3& mesh_corner_vertex(const Mesh& M, index_t c) {
106 return M.facet_corners.point(c);
107 }
108
109 /**
110 * \brief Gets a mesh vertex by an incident corner index.
111 * \param[in] M the mesh
112 * \param[in] c the index of a corner incident to the vertex
113 * \return a const reference to the \p v%th vertex of a mesh
114 * \pre M.vertices.dimension() >= 3
115 * \deprecated use M.facet_corners.point(c) instead
116 */
117 [[deprecated("use M.facet_corners.point(c) instead")]]
118 inline vec3& mesh_corner_vertex_ref(Mesh& M, index_t c) {
119 return M.facet_corners.point(c);
120 }
121
122 /**
123 * \brief Gets a mesh vertex normal by vertex index.
124 * \param[in] M the mesh
125 * \param[in] v the index of the vertex
126 * \return a const reference to the stored normal of vertex \p v
127 * \pre M.vertices.dimension() >= 6
128 */
129 inline const vec3& mesh_vertex_normal(const Mesh& M, index_t v) {
130 geo_debug_assert(M.vertices.dimension() >= 6);
131 40664 return *(const vec3*) (M.vertices.point_ptr(v) + 3);
132 }
133
134 /**
135 * \brief Gets a mesh vertex normal by vertex index.
136 * \param[in] M the mesh
137 * \param[in] v the index of the vertex
138 * \return a reference to the stored normal of vertex \p v
139 * \pre M.vertices.dimension() >= 6
140 */
141 inline vec3& mesh_vertex_normal_ref(Mesh& M, index_t v) {
142 geo_debug_assert(M.vertices.dimension() >= 6);
143 33396 return *(vec3*) (M.vertices.point_ptr(v) + 3);
144 }
145
146 /**
147 * \brief Gets a mesh vertex normal by vertex index.
148 * \param[in] M the mesh
149 * \param[in] v the index of the vertex
150 * \return a const reference to the stored normal of vertex \p v
151 * \pre M.vertices.dimension() >= 6
152 */
153 inline const vec3& mesh_vertex_normal_ref(const Mesh& M, index_t v) {
154 geo_debug_assert(M.vertices.dimension() >= 6);
155 return *(vec3 const *) (M.vertices.point_ptr(v) + 3);
156 }
157
158 /**
159 * \brief Computes the area of a facet.
160 * \param[in] M a const reference to the mesh
161 * \param[in] f index of the facet
162 * \param[in] dim dimension that will be used to compute the area
163 * \return the area of the facet, obtained by considering the
164 * \p dim first coordinates of the vertices only
165 */
166 695790 inline double mesh_facet_area(const Mesh& M, index_t f, index_t dim=0) {
167 geo_debug_assert(dim <= M.vertices.dimension());
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 695790 times.
695790 if(dim == 0) {
169 dim = M.vertices.dimension();
170 }
171 double result = 0.0;
172 // Check for empty facet, should not happen.
173
1/2
✓ Branch 0 taken 695790 times.
✗ Branch 1 not taken.
695790 if(M.facets.corners_end(f) == M.facets.corners_begin(f)) {
174 return result;
175 }
176 const double* p0 = M.vertices.point_ptr(
177 M.facet_corners.vertex(M.facets.corners_begin(f))
178 );
179 695790 for(
180 695790 index_t i = M.facets.corners_begin(f) + 1;
181
2/2
✓ Branch 0 taken 695796 times.
✓ Branch 1 taken 695790 times.
1391586 i + 1 < M.facets.corners_end(f); i++
182 ) {
183 695796 result += GEO::Geom::triangle_area(
184 p0,
185 M.vertices.point_ptr(M.facet_corners.vertex(i)),
186 M.vertices.point_ptr(M.facet_corners.vertex(i + 1)),
187 coord_index_t(dim)
188 );
189 }
190 return result;
191 }
192
193 /**
194 * \brief Computes the normal to a mesh facet.
195 * \param[in] M the mesh
196 * \param[in] f the facet index in \p M
197 * \return the normal to facet \p f
198 * \pre dimension >= 3
199 * \note the computed vector is not normalized.
200 */
201 vec3 GEOGRAM_API mesh_facet_normal(const Mesh& M, index_t f);
202
203 /**
204 * \brief Gets the centroid of the vertices of a facet in a mesh.
205 * \param[in] M the mesh
206 * \param[in] f the index of the facet
207 * \return the 3d centroid of facet \p f in \p M
208 */
209 inline vec3 mesh_facet_center(const Mesh& M, index_t f) {
210 vec3 result(0.0, 0.0, 0.0);
211 double count = 0.0;
212 for(index_t c = M.facets.corners_begin(f);
213 c < M.facets.corners_end(f); ++c) {
214 result += M.facet_corners.point(c);
215 count += 1.0;
216 }
217 return (1.0 / count) * result;
218 }
219
220 /**
221 * \brief Gets the centroid of the vertices of a cell in a mesh.
222 * \param[in] M the mesh
223 * \param[in] c the index of the facet
224 * \return the 3d centroid of facet \p f in \p M
225 */
226 inline vec3 mesh_cell_center(const Mesh& M, index_t c) {
227 vec3 result(0.0, 0.0, 0.0);
228 for(index_t lv=0; lv<M.cells.nb_vertices(c); ++lv) {
229 index_t v = M.cells.vertex(c,lv);
230 result += M.vertices.point(v);
231 }
232 return (1.0 / double(M.cells.nb_vertices(c))) * result;
233 }
234
235
236 /**
237 * \brief Gets the centroid of a tetrahedron in a mesh.
238 * \param[in] M the mesh
239 * \param[in] t the index of the tetrahedron
240 * \return the 3d centroid of tetrahedron \p t in \p M
241 */
242 inline vec3 mesh_tet_center(const Mesh& M, index_t t) {
243 const vec3& v1 = M.cells.point(t,0);
244 const vec3& v2 = M.cells.point(t,1);
245 const vec3& v3 = M.cells.point(t,2);
246 const vec3& v4 = M.cells.point(t,3);
247 return 0.25 * (v1 + v2 + v3 + v4);
248 }
249
250 /**
251 * \brief Gets a vector by a mesh corner.
252 * \param[in] M a const reference to the mesh
253 * \param[in] c1 a corner index in \p M
254 * \return a vector originating at \p c1 and
255 * pointing at the next corner around the facet
256 * incident to \p c1
257 * \pre M.facets.are_simplices()
258 */
259 inline vec3 mesh_corner_vector(const Mesh& M, index_t c1) {
260 geo_debug_assert(M.facets.are_simplices());
261 index_t c2 = M.facets.next_corner_around_facet(c1/3, c1);
262 return M.facet_corners.point(c2) - M.facet_corners.point(c1);
263 }
264
265 /**
266 * \brief Computes the angle between the normal vectors
267 * of two mesh facets sharing an edge.
268 * \param[in] M a const reference to the mesh
269 * \param[in] c a corner index in \p M
270 * \return the angle between the facet that contains c and
271 * the facet adjacent to c
272 * \pre M.facets.are_simplices() && M.corner_adjacent_facet(c) != -1
273 */
274 double GEOGRAM_API mesh_normal_angle(const Mesh& M, index_t c);
275
276 /**
277 * \brief Computes the angle between the normal vectors
278 * of two mesh facets sharing an edge.
279 * \param[in] M a const reference to the mesh
280 * \param[in] f1 , f2 two facets of the mesh
281 * \return the angle between \p f1 and \p f2 in radians
282 */
283 double GEOGRAM_API mesh_unsigned_normal_angle(
284 const Mesh& M, index_t f1, index_t f2
285 );
286
287 /**
288 * \brief Computes the total surface area of a mesh in arbitrary
289 * dimension.
290 * \param[in] M the mesh
291 * \param[in] dim the dimension to be used for the computation
292 * \return the area of the mesh \p M computed in dim \p d.
293 * \pre dim <= M.vertices.dimension()
294 */
295 double GEOGRAM_API mesh_area(const Mesh& M, index_t dim);
296
297 /**
298 * \brief Computes the total surface area of a mesh.
299 * \param[in] M the mesh
300 * \return the area of the mesh computed in M.vertices.dimension() dim.
301 */
302 inline double mesh_area(const Mesh& M) {
303 14 return mesh_area(M, M.vertices.dimension());
304 }
305
306 /**
307 * \brief Computes the volume enclosed by a surfacic mesh.
308 * \param[in] M a closed surfacic mesh.
309 * \return the volume enclosed by \p M.
310 */
311 double GEOGRAM_API mesh_enclosed_volume(const Mesh& M);
312 }
313
314 /**
315 * \brief Computes the normals to the vertices, and stores
316 * them as additional coordinates.
317 * \param[in,out] M the mesh
318 */
319 void GEOGRAM_API compute_normals(Mesh& M);
320
321 /**
322 * \brief Smoothes a mesh.
323 * \details Moves each point of mesh \p M to the barycenter of its
324 * neighbors. This operation is repeated the specified number of times \p
325 * nb_iter.
326 * \param[in,out] M the mesh to smooth
327 * \param[in] nb_iter number of smoothing iterations
328 * \param[in] normals_only if set, only stored normals are smoothed.
329 */
330 void GEOGRAM_API simple_Laplacian_smooth(
331 Mesh& M, index_t nb_iter, bool normals_only
332 );
333
334 /**
335 * \brief Gets the bounding box of a mesh.
336 * \param[in] M The mesh
337 * \param[out] xyzmin the lower corner of the bounding box
338 * \param[out] xyzmax the upper corner of the bounding box
339 */
340 void GEOGRAM_API get_bbox(const Mesh& M, double* xyzmin, double* xyzmax);
341
342 /**
343 * \brief Computes the length of the bounding box diagonal of a mesh.
344 * \param[in] M the mesh
345 * \return The length of \p M%'s bounding box diagonal
346 */
347 double GEOGRAM_API bbox_diagonal(const Mesh& M);
348
349 /**
350 * \brief Normalizes and scales the stored vertex normals by a factor.
351 * \details If no normal are stored, then they are created and
352 * computed. Normals are stored in coordinates 3,4,5 of the vertices.
353 * \param[in,out] M the mesh
354 * \param[in] s the factor used to scale the normals
355 */
356 void GEOGRAM_API set_anisotropy(Mesh& M, double s);
357
358 /**
359 * \brief Normalizes the stored vertex normals.
360 * \param[in,out] M the mesh
361 */
362 void GEOGRAM_API unset_anisotropy(Mesh& M);
363
364 /**
365 * \brief Computes a sizing field using an estimate of lfs
366 * (local feature size).
367 * \details The sizing field is stored in \p M%'s vertices weights.
368 * \param[in,out] M the mesh
369 * \param[in] gradation the exponent to be applied to the sizing field
370 * \param[in] nb_lfs_samples if set to 0, the vertices of \p M are used,
371 * else \p M is resampled (needed if \p M's facets density is
372 * highly irregular).
373 */
374 void GEOGRAM_API compute_sizing_field(
375 Mesh& M, double gradation = 1.0, index_t nb_lfs_samples = 0
376 );
377
378 /**
379 * \brief Computes vertices weights in such a way that triangle
380 * areas are normalized.
381 * \details If this function is used, then
382 * CentroidalVoronoiTesselation generates Voronoi cells of
383 * equal areas.
384 * \param[in,out] M the mesh
385 */
386 void GEOGRAM_API normalize_embedding_area(Mesh& M);
387
388 /**
389 * \brief Computes the volume of a cell in a mesh.
390 * \param[in] M a const reference to the mesh
391 * \param[in] c the index of the cell
392 * \return the volume of the cell
393 * \pre c < M.cells.nb()
394 */
395 double GEOGRAM_API mesh_cell_volume(
396 const Mesh& M, index_t c
397 );
398
399 /**
400 * \brief Computes the volume of the cells of a mesh.
401 * \param[in] M a const reference to the mesh
402 * \return the volume of the cells of the mesh
403 */
404 double GEOGRAM_API mesh_cells_volume(const Mesh& M);
405
406
407 /**
408 * \brief Computes the normal of a cell facet.
409 * \param[in] M a const reference to the mesh
410 * \param[in] c the index of the cell
411 * \param[in] lf the local index of the facet within cell \p c
412 * \return the vector normal to facet \p lf in cell \p c
413 * \pre c < M.cells.nb() && lf < M.cells
414 * \note the computed vector is not normalized
415 */
416 vec3 GEOGRAM_API mesh_cell_facet_normal(
417 const Mesh& M, index_t c, index_t lf
418 );
419
420 /**
421 * \brief Computes the average edge length in a surface.
422 * \param[in] M a const reference to a surface mesh
423 * \return the average edge length
424 */
425 double GEOGRAM_API surface_average_edge_length(
426 const Mesh& M
427 );
428
429 }
430
431 #endif
432