RINGMesh  Version 5.0.0
A programming library for geological model meshes
mesh_quality.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2017, Association Scientifique pour la Geologie et ses
3  * Applications (ASGA). 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  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of ASGA nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ASGA BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * http://www.ring-team.org
28  *
29  * RING Project
30  * Ecole Nationale Superieure de Geologie - GeoRessources
31  * 2 Rue du Doyen Marcel Roubault - TSA 70605
32  * 54518 VANDOEUVRE-LES-NANCY
33  * FRANCE
34  */
35 
37 
38 #include <geogram/basic/attributes.h>
39 
42 
49 namespace
50 {
51  using namespace RINGMesh;
52 
65  double tetra_insphere_radius(
66  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
67  {
68  double tet_volume = GEO::Geom::tetra_volume( v0, v1, v2, v3 );
69  double A1 = GEO::Geom::triangle_area( v0, v1, v2 );
70  double A2 = GEO::Geom::triangle_area( v1, v2, v3 );
71  double A3 = GEO::Geom::triangle_area( v2, v3, v0 );
72  double A4 = GEO::Geom::triangle_area( v3, v0, v1 );
73  ringmesh_assert( A1 + A2 + A3 + A4 > global_epsilon );
74  return ( 3 * tet_volume ) / ( A1 + A2 + A3 + A4 );
75  }
76 
93  double tet_quality_insphere_radius_by_circumsphere_radius(
94  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
95  {
96  const vec3 tetra_circum_center =
97  GEO::Geom::tetra_circum_center( v0, v1, v2, v3 );
98  const double tetra_circum_radius =
99  vec3( tetra_circum_center - v0 ).length();
100  ringmesh_assert( std::abs( tetra_circum_radius
101  - ( tetra_circum_center - v1 ).length() )
102  < global_epsilon );
103  ringmesh_assert( std::abs( tetra_circum_radius
104  - ( tetra_circum_center - v2 ).length() )
105  < global_epsilon );
106  ringmesh_assert( std::abs( tetra_circum_radius
107  - ( tetra_circum_center - v3 ).length() )
108  < global_epsilon );
109 
110  // insphere computation
111  double in_radius = tetra_insphere_radius( v0, v1, v2, v3 );
112  return 3. * in_radius / tetra_circum_radius;
113  }
114 
122  double max_tet_edge_length(
123  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
124  {
125  double l1 = ( v1 - v0 ).length();
126  double l2 = ( v2 - v0 ).length();
127  double l3 = ( v3 - v0 ).length();
128  double l4 = ( v2 - v1 ).length();
129  double l5 = ( v3 - v1 ).length();
130  double l6 = ( v3 - v2 ).length();
131  return GEO::geo_max(
132  GEO::geo_max(
133  GEO::geo_max( GEO::geo_max( GEO::geo_max( l1, l2 ), l3 ), l4 ),
134  l5 ),
135  l6 );
136  }
137 
161  double tet_quality_insphere_radius_by_max_edge_length(
162  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
163  {
164  double in_radius = tetra_insphere_radius( v0, v1, v2, v3 );
165  double edge_length = max_tet_edge_length( v0, v1, v2, v3 );
166 
167  return 2 * std::sqrt( 6. ) * in_radius / edge_length;
168  }
169 
177  double sum_square_edge_length(
178  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
179  {
180  double l1 = vec3( v1 - v0 ).length2();
181  double l2 = vec3( v2 - v0 ).length2();
182  double l3 = vec3( v3 - v0 ).length2();
183  double l4 = vec3( v2 - v1 ).length2();
184  double l5 = vec3( v3 - v1 ).length2();
185  double l6 = vec3( v3 - v2 ).length2();
186  return l1 + l2 + l3 + l4 + l5 + l6;
187  }
188 
207  double tet_quality_volume_by_sum_square_edges(
208  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
209  {
210  const double tet_volume = GEO::Geom::tetra_volume( v0, v1, v2, v3 );
211  double sum_square_edge = sum_square_edge_length( v0, v1, v2, v3 );
212  ringmesh_assert( sum_square_edge > global_epsilon );
213  return 12. * std::pow( 3. * tet_volume, 2. / 3. ) / sum_square_edge;
214  }
215 
227  double sin_half_solid_angle(
228  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
229  {
230  double tet_volume = GEO::Geom::tetra_volume( v0, v1, v2, v3 );
231  double l01 = ( v1 - v0 ).length();
232  double l02 = ( v2 - v0 ).length();
233  double l03 = ( v3 - v0 ).length();
234  double l12 = ( v2 - v1 ).length();
235  double l13 = ( v3 - v1 ).length();
236  double l23 = ( v3 - v2 ).length();
237  double denominator = ( l01 + l02 + l12 ) * ( l01 + l02 - l12 )
238  * ( l02 + l03 + l23 ) * ( l02 + l03 - l23 )
239  * ( l03 + l01 + l13 ) * ( l03 + l01 - l13 );
240 
241  ringmesh_assert( denominator > global_epsilon_sq );
242 
243  denominator = std::sqrt( denominator );
244  return 12 * tet_volume / denominator;
245  }
246 
276  double tet_quality_min_solid_angle(
277  const vec3& v0, const vec3& v1, const vec3& v2, const vec3& v3 )
278  {
279  double min_sin_half_solid_angle = std::min(
280  std::min( std::min( sin_half_solid_angle( v0, v1, v2, v3 ),
281  sin_half_solid_angle( v1, v0, v2, v3 ) ),
282  sin_half_solid_angle( v2, v0, v1, v3 ) ),
283  sin_half_solid_angle( v3, v0, v1, v2 ) );
284  return 1.5 * std::sqrt( 6. ) * min_sin_half_solid_angle;
285  }
286 
292  std::string mesh_qual_mode_to_prop_name( MeshQualityMode mesh_qual_mode )
293  {
294  std::string quality_name = "";
295  switch( mesh_qual_mode )
296  {
298  quality_name = "INSPHERE_RADIUS_BY_CIRCUMSPHERE_RADIUS";
299  break;
301  quality_name = "INSPHERE_RADIUS_BY_MAX_EDGE_LENGTH";
302  break;
304  quality_name = "VOLUME_BY_SUM_SQUARE_EDGE";
305  break;
306  case MIN_SOLID_ANGLE:
307  quality_name = "MIN_SOLID_ANGLE";
308  break;
309  default:
311  }
312  ringmesh_assert( !quality_name.empty() );
313  return quality_name;
314  }
315 
329  double get_tet_quality( const vec3& v0,
330  const vec3& v1,
331  const vec3& v2,
332  const vec3& v3,
333  MeshQualityMode mesh_qual_mode )
334  {
335  double quality = -1;
336  switch( mesh_qual_mode )
337  {
339  quality = tet_quality_insphere_radius_by_circumsphere_radius(
340  v0, v1, v2, v3 );
341  break;
343  quality = tet_quality_insphere_radius_by_max_edge_length(
344  v0, v1, v2, v3 );
345  break;
347  quality = tet_quality_volume_by_sum_square_edges( v0, v1, v2, v3 );
348  break;
349  case MIN_SOLID_ANGLE:
350  quality = tet_quality_min_solid_angle( v0, v1, v2, v3 );
351  break;
352  default:
354  }
356  quality > -1 * global_epsilon && quality < 1 + global_epsilon );
357  return quality;
358  }
359 } // namespace
360 
361 namespace RINGMesh
362 {
364  MeshQualityMode mesh_qual_mode, const GeoModel3D& geomodel )
365  {
366  ringmesh_assert( geomodel.nb_regions() != 0 );
367  for( const auto& region : geomodel.regions() )
368  {
369  ringmesh_assert( region.is_meshed() );
370  ringmesh_assert( region.is_simplicial() );
371  GEO::AttributesManager& reg_attr_mgr =
372  region.cell_attribute_manager();
373  GEO::Attribute< double > attr(
374  reg_attr_mgr, mesh_qual_mode_to_prop_name( mesh_qual_mode ) );
375  for( auto cell_itr : range( region.nb_mesh_elements() ) )
376  {
377  attr[cell_itr] =
378  get_tet_quality( region.mesh_element_vertex(
379  ElementLocalVertex( cell_itr, 0 ) ),
380  region.mesh_element_vertex(
381  ElementLocalVertex( cell_itr, 1 ) ),
382  region.mesh_element_vertex(
383  ElementLocalVertex( cell_itr, 2 ) ),
384  region.mesh_element_vertex(
385  ElementLocalVertex( cell_itr, 3 ) ),
386  mesh_qual_mode );
387  }
388  }
389  }
390 }
void RINGMESH_API compute_prop_tet_mesh_quality(MeshQualityMode mesh_qual_mode, const GeoModel3D &geomodel)
Computes and stores mesh quality in the GeoModel.
vecn< 3 > vec3
Definition: types.h:76
#define ringmesh_assert(x)
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
#define ringmesh_assert_not_reached