RINGMesh  Version 5.0.0
A programming library for geological model meshes
geomodel_builder_repair.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 <array>
39 
40 #include <geogram/basic/algorithm.h>
42 
49 namespace RINGMesh
50 {
51  template < index_t DIMENSION >
54  : builder_( builder ),
55  geomodel_( geomodel ),
56  geomodel_access_( geomodel )
57  {
58  }
59 
60  template < index_t DIMENSION >
62  {
63  switch( repair_mode )
64  {
65  case ALL:
67  break;
68  case BASIC:
69  builder_.end_geomodel();
70  break;
71  case COLOCATED_VERTICES:
73  break;
76  break;
79  break;
80  case CONTACTS:
82  break;
83  case ISOLATED_VERTICES:
85  break;
86  default:
88  }
89  }
90 
91  template < index_t DIMENSION >
93  {
94  // Remove colocated vertices in each entity
96 
97  // Basic mesh repair for surfaces and lines
99 
100  // Proper reordering of line boundaries
102 
103  // This is basic requirement ! no_colocated geomodel vertices !
104  // So remove them if there are any
105  geomodel_.mesh.remove_colocated_vertices();
106 
107  // Builds the contacts
108  build_contacts();
109 
110  // Remove isolated vertices on mesh entities
112 
113  builder_.end_geomodel();
114  }
115 
116  template < index_t DIMENSION >
119  {
120  std::set< gmme_id > empty_mesh_entities;
121  std::set< gmge_id > empty_geological_entities;
122 
123  remove_colocated_entity_vertices( empty_mesh_entities );
124  if( !empty_mesh_entities.empty() )
125  {
126  builder_.topology.get_dependent_entities(
127  empty_mesh_entities, empty_geological_entities );
128  builder_.removal.remove_mesh_entities( empty_mesh_entities );
129  }
130  }
131 
132  template < index_t DIMENSION >
135  {
136  std::set< gmme_id > empty_mesh_entities;
137  remove_degenerate_polygons_and_edges( empty_mesh_entities );
140  if( !empty_mesh_entities.empty() )
141  {
142  builder_.removal.remove_mesh_entities( empty_mesh_entities );
143  }
144 
145  // This is basic requirement ! no_colocated geomodel vertices !
146  // So remove them if there are any
147  geomodel_.mesh.remove_colocated_vertices();
148 
149  builder_.end_geomodel();
150  }
151 
152  template < index_t DIMENSION >
154  {
155  for( const auto& line : geomodel_.lines() )
156  {
157  if( !line.is_first_corner_first_vertex() )
158  {
159  const auto first_boundary_index = line.boundary( 0 ).index();
160  builder_.topology.set_mesh_entity_boundary(
161  line.gmme(), 0, line.boundary_gmme( 1 ).index() );
162  builder_.topology.set_mesh_entity_boundary(
163  line.gmme(), 1, first_boundary_index );
164  }
165  }
166  }
167 
168  template <>
170  {
172  for( const auto& surface : geomodel_.surfaces() )
173  {
175  }
176  for( const auto& region : geomodel_.regions() )
177  {
178  if( region.is_meshed() )
179  {
181  }
182  }
183  }
184 
185  template <>
187  {
189  for( const auto& surface : geomodel_.surfaces() )
190  {
191  if( surface.is_meshed() )
192  {
194  }
195  }
196  }
197 
198  template < index_t DIMENSION >
200  {
201  for( const auto& line : geomodel_.lines() )
202  {
204  }
205  }
206 
207  template < index_t DIMENSION >
210  const GeoModelMeshEntity< DIMENSION >& geomodel_mesh_entity )
211  {
212  std::vector< bool > vertices_to_delete(
213  geomodel_mesh_entity.nb_vertices(), true );
214  for( auto mesh_element_index :
215  range( geomodel_mesh_entity.nb_mesh_elements() ) )
216  {
217  for( auto vertex :
218  range( geomodel_mesh_entity.nb_mesh_element_vertices(
219  mesh_element_index ) ) )
220  {
221  vertices_to_delete[geomodel_mesh_entity
223  { mesh_element_index, vertex } )] =
224  false;
225  }
226  }
227  builder_.geometry.delete_mesh_entity_vertices(
228  geomodel_mesh_entity.gmme(), vertices_to_delete );
229  }
230 
231  template < index_t DIMENSION >
233  const Surface< DIMENSION >& surface,
234  index_t polygon_id,
235  std::vector< index_t >& colocated_vertices )
236  {
237  auto nb_vertices = surface.nb_mesh_element_vertices( polygon_id );
238  if( nb_vertices != 3 )
239  {
240  std::vector< index_t > vertices( nb_vertices );
241  for( auto v : range( nb_vertices ) )
242  {
243  vertices[v] =
244  colocated_vertices[surface.mesh_element_vertex_index(
245  ElementLocalVertex( polygon_id, v ) )];
246  }
247  GEO::sort_unique( vertices );
248  return vertices.size() != nb_vertices;
249  }
250  auto v1 = colocated_vertices[surface.mesh_element_vertex_index(
251  { polygon_id, 0 } )];
252  auto v2 = colocated_vertices[surface.mesh_element_vertex_index(
253  { polygon_id, 1 } )];
254  auto v3 = colocated_vertices[surface.mesh_element_vertex_index(
255  { polygon_id, 2 } )];
256  return v1 == v2 || v2 == v3 || v3 == v1;
257  }
258 
259  template < index_t DIMENSION >
260  std::vector< index_t >
262  const Surface< DIMENSION >& surface,
263  std::vector< index_t >& colocated_vertices )
264  {
265  std::vector< index_t > f_is_degenerate( surface.nb_mesh_elements() );
266  for( auto p : range( surface.nb_mesh_elements() ) )
267  {
268  f_is_degenerate[p] =
269  polygon_is_degenerate( surface, p, colocated_vertices );
270  }
271  return f_is_degenerate;
272  }
273 
274  template < index_t DIMENSION >
276  const Surface< DIMENSION >& surface )
277  {
278  std::vector< index_t > colocated;
279  const auto& nn_search = surface.vertex_nn_search();
280  std::tie( std::ignore, colocated ) =
281  nn_search.get_colocated_index_mapping( geomodel_.epsilon() );
282 
283  auto degenerate =
284  surface_detect_degenerate_polygons( surface, colocated );
285  return static_cast< index_t >(
286  std::count( degenerate.begin(), degenerate.end(), 1 ) );
287  }
288 
289  template < index_t DIMENSION >
290  std::vector< bool >
292  const Line< DIMENSION >& line,
293  std::vector< index_t >& colocated_vertices )
294  {
295  std::vector< bool > e_is_degenerate( line.nb_mesh_elements() );
296  for( auto e : range( line.nb_mesh_elements() ) )
297  {
298  e_is_degenerate[e] =
299  edge_is_degenerate( line, e, colocated_vertices );
300  }
301  return e_is_degenerate;
302  }
303 
304  template < index_t DIMENSION >
306  const Line< DIMENSION >& line )
307  {
308  std::vector< index_t > colocated;
309  const auto& nn_search = line.vertex_nn_search();
310  std::tie( std::ignore, colocated ) =
311  nn_search.get_colocated_index_mapping( geomodel_.epsilon() );
312 
313  auto degenerate = line_detect_degenerate_edges( line, colocated );
314  auto nb = static_cast< index_t >(
315  std::count( degenerate.begin(), degenerate.end(), 1 ) );
318  builder_.geometry.delete_line_edges( line.index(), degenerate, false );
319  return nb;
320  }
321 
322  template < index_t DIMENSION >
324  remove_degenerate_polygons_and_edges( std::set< gmme_id >& to_remove )
325  {
326  to_remove.clear();
327  for( const auto& line : geomodel_.lines() )
328  {
329  auto nb = repair_line_mesh( line );
330  if( nb > 0 )
331  {
332  Logger::out( "GeoModel", nb,
333  " degenerated edges removed in LINE ", line.index() );
334  // If the Line is set it to remove
335  if( line.nb_mesh_elements() == 0 )
336  {
337  to_remove.insert( line.gmme() );
338  }
339  }
340  }
341  // The builder might be needed
342 
343  double epsilon_sq = geomodel_.epsilon() * geomodel_.epsilon();
344  for( const auto& surface : geomodel_.surfaces() )
345  {
346  auto nb = detect_degenerate_polygons( surface );
348  if( nb > 0 )
349  {
350  // If there are some degenerated polygons
351  // Using repair function of geogram
352  // Warning - This triangulates the mesh
353  if( surface.nb_vertices() > 0 )
354  {
355  // Colocated vertices must be processed before
356  // MESH_REPAIR_DUP_F 2 ;
357  auto mode = static_cast< GEO::MeshRepairMode >( 2 );
358  auto builder = builder_.geometry.create_surface_builder(
359  surface.index() );
360  builder->repair( mode, 0.0 );
361 
362  // This might create some small components - remove them
363  builder->remove_small_connected_components( epsilon_sq, 3 );
364 
365  // Alright, this is a bit of an overkill [JP]
366  if( surface.nb_vertices() > 0 )
367  {
368  builder->repair( mode, 0.0 );
369  }
370  }
371  if( surface.nb_vertices() == 0
372  || surface.nb_mesh_elements() == 0 )
373  {
374  to_remove.insert( surface.gmme() );
375  }
376  }
377  }
378  }
379 
380  template < index_t DIMENSION >
381  std::set< index_t >
383  const gmme_id& E_id )
384  {
385  std::set< index_t > vertices;
387  {
388  return vertices;
389  }
390  const auto& mesh_entity = geomodel_.mesh_entity( E_id );
391  if( E_id.type() == Line< DIMENSION >::type_name_static() )
392  {
393  if( mesh_entity.boundary( 0 ).is_inside_border( mesh_entity ) )
394  {
395  vertices.insert( mesh_entity.nb_vertices() - 1 );
396  }
397  return vertices;
398  }
399  std::vector< const GeoModelMeshEntity< DIMENSION >* > inside_border;
400  for( auto i : range( mesh_entity.nb_boundaries() ) )
401  {
402  if( mesh_entity.boundary( i ).is_inside_border( mesh_entity ) )
403  {
404  inside_border.push_back(
405  dynamic_cast< const GeoModelMeshEntity< DIMENSION >* >(
406  &mesh_entity.boundary( i ) ) );
407  }
408  }
409  if( !inside_border.empty() )
410  {
411  // We want to get the indices of the vertices in E
412  // that are colocated with those of the inside boundary
413  // We assume that the geomodel vertices are not computed
414  const auto& nn_search = mesh_entity.vertex_nn_search();
415 
416  for( const auto& entity : inside_border )
417  {
418  for( auto v : range( entity->nb_vertices() ) )
419  {
420  auto colocated_indices = nn_search.get_neighbors(
421  entity->vertex( v ), geomodel_.epsilon() );
422  if( colocated_indices.size() > 1 )
423  {
424  std::sort( colocated_indices.begin(),
425  colocated_indices.end() );
426  // Add colocated vertices except one to the duplicated
427  // vertices set
428  vertices.insert( colocated_indices.begin() + 1,
429  colocated_indices.end() );
430  }
431  }
432  }
433  }
434  return vertices;
435  }
436 
437  template < index_t DIMENSION >
439  std::set< gmme_id >& to_remove )
440  {
441  to_remove.clear();
442  // For all Lines and Surfaces
443  std::array< const MeshEntityType, 2 > types{
446  };
447  for( const auto& type : types )
448  {
449  for( auto e : range( geomodel_.nb_mesh_entities( type ) ) )
450  {
451  gmme_id entity_id{ type, e };
452  const auto& E = geomodel_.mesh_entity( entity_id );
453 
454  const auto& kdtree = E.vertex_nn_search();
455  std::vector< index_t > colocated;
456  std::tie( std::ignore, colocated ) =
457  kdtree.get_colocated_index_mapping( geomodel_.epsilon() );
458 
459  // Get the vertices to delete
460  auto inside_border = vertices_on_inside_boundary( entity_id );
461 
462  std::vector< bool > to_delete( colocated.size(), false );
463  index_t nb_todelete{ 0 };
464  for( auto v : range( colocated.size() ) )
465  {
466  if( colocated[v] == v
467  || inside_border.find( v ) != inside_border.end() )
468  {
469  // This point is kept
470  // No colocated or on an inside boundary
471  }
472  else
473  {
474  // The point is to remove
475  to_delete[v] = true;
476  nb_todelete++;
477  }
478  }
479 
480  if( nb_todelete == 0 )
481  {
482  // Nothing to do there
483  continue;
484  }
485  if( nb_todelete == E.nb_vertices() )
486  {
487  // The complete entity should be removed
488  to_remove.insert( E.gmme() );
489  continue;
490  }
492  {
493  auto builder =
494  builder_.geometry.create_surface_builder( e );
495  for( auto p_itr : range( E.nb_mesh_elements() ) )
496  {
497  for( auto fpv_itr :
498  range( E.nb_mesh_element_vertices( p_itr ) ) )
499  {
500  builder->set_polygon_vertex( { p_itr, fpv_itr },
501  colocated[E.mesh_element_vertex_index(
502  { p_itr, fpv_itr } )] );
503  }
504  }
505  builder->delete_vertices( to_delete );
506  Logger::out( "Repair", nb_todelete,
507  " colocated vertices deleted in ", entity_id );
508  }
509  else if( type == Line< DIMENSION >::type_name_static() )
510  {
511  auto builder = builder_.geometry.create_line_builder( e );
512  for( auto e_itr : range( E.nb_mesh_elements() ) )
513  {
514  builder->set_edge_vertex(
515  { e_itr, 0 }, colocated[E.mesh_element_vertex_index(
516  { e_itr, 0 } )] );
517  builder->set_edge_vertex(
518  { e_itr, 1 }, colocated[E.mesh_element_vertex_index(
519  { e_itr, 1 } )] );
520  }
521  builder->delete_vertices( to_delete );
522  Logger::out( "Repair", nb_todelete,
523  " colocated vertices deleted in ", entity_id );
524  }
525  else
526  {
528  }
529  }
530  }
531  }
532 
533  template < index_t DIMENSION >
535  const Line< DIMENSION >& line,
536  index_t edge,
537  const std::vector< index_t >& colocated_vertices )
538  {
539  auto v1 =
540  colocated_vertices[line.mesh_element_vertex_index( { edge, 0 } )];
541  auto v2 =
542  colocated_vertices[line.mesh_element_vertex_index( { edge, 1 } )];
543  return v1 == v2;
544  }
545 
546  template < index_t DIMENSION >
548  {
549  builder_.geology.build_contacts();
550  }
551  template class RINGMESH_API GeoModelBuilderRepair< 2 >;
552  template class RINGMESH_API GeoModelBuilderRepair< 3 >;
553 } // namespace RINGMesh
bool edge_is_degenerate(const Line< DIMENSION > &line, index_t edge, const std::vector< index_t > &colocated_vertices)
Checks if an edge is degenerate.
std::vector< bool > line_detect_degenerate_edges(const Line< DIMENSION > &line, std::vector< index_t > &colocated_vertices)
Abstract base class for GeoModelMeshEntity.
index_t mesh_element_vertex_index(const ElementLocalVertex &element_local_vertex) const final
Index of the vertex in the Surface from its index in a polygon of the mesh.
index_t nb_mesh_element_vertices(index_t polygon_index) const final
bool polygon_is_degenerate(const Surface< DIMENSION > &surface, index_t polygon_id, std::vector< index_t > &colocated_vertices)
Tests whether a polygon is degenerate.
void remove_degenerate_polygons_and_edges(std::set< gmme_id > &to_remove)
Remove degenerate polygons and edges from the Surface and Line of the geomodel.
std::set< index_t > vertices_on_inside_boundary(const gmme_id &E_id)
const NNSearch< DIMENSION > & vertex_nn_search() const
Return the NNSearch for the Entity vertices.
virtual index_t nb_mesh_element_vertices(index_t mesh_element_index) const =0
Number of vertices of a constitutive element of the mesh.
static MeshEntityType type_name_static()
GeoModelBuilderRepair(GeoModelBuilder< DIMENSION > &builder, GeoModel< DIMENSION > &geomodel)
Entity_type_template type() const
Definition: entity_type.h:202
index_t detect_degenerate_polygons(const Surface< DIMENSION > &surface)
Detect and remove degenerated polygons in a Surface.
std::vector< index_t > surface_detect_degenerate_polygons(const Surface< DIMENSION > &surface, std::vector< index_t > &colocated_vertices)
static MeshEntityType type_name_static()
void sort_unique(CONTAINER &container, const CMP &cmp)
Sorts a container and suppresses all duplicated entities.
Definition: algorithm.h:135
index_t nb_mesh_elements() const final
index_t mesh_element_vertex_index(const ElementLocalVertex &element_local_vertex) const final
Get the index of a vertex in the Line from the.
static void out(const std::string &feature, const Args &... args)
Definition: logger.h:61
static MeshEntityType type_name_static()
virtual index_t mesh_element_vertex_index(const ElementLocalVertex &element_local_vertex) const =0
Convert the index in a mesh element to an index in the Entity.
void repair(RepairMode repair_mode)
Repair a GeoModel according a repair mode.
void remove_isolated_vertices_on_mesh_entity(const GeoModelMeshEntity< DIMENSION > &geomodel_mesh_entity)
remove isolated vertices on a GeoModelMeshEntity
index_t repair_line_mesh(const Line< DIMENSION > &line)
Detect and remove degenerate edges in a.
virtual index_t nb_mesh_elements() const =0
Get the number constitutive elements of the mesh.
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
Try repairing a supposedly invalid GeoModel.
A GeoModelEntity of type LINE.
index_t nb_mesh_elements() const final
GeoModelBuilder< DIMENSION > & builder_
This template is a specialization of a gme_id to the GeoModelMeshEntity.
Definition: entity_type.h:285
void remove_isolated_vertices()
remove isolated vertices on GeoModelMeshEntities
void remove_colocated_entity_vertices(std::set< gmme_id > &to_remove)
Remove colocated vertices of the geomodel.
void repair_line_boundary_vertex_order()
For all the lines in the geomodel, switch line boundaries if the way of their indices does not follow...
#define ringmesh_assert_not_reached