RINGMesh  Version 5.0.0
A programming library for geological model meshes
geomodel_mesh_entity.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 
42 
43 #include <stack>
44 
49 
50 namespace
51 {
52  using namespace RINGMesh;
53 
58  template < index_t DIMENSION >
59  bool check_range_model_vertex_ids(
61  {
62  const auto& geomodel_vertices = E.geomodel().mesh.vertices;
64  auto id = E.gmme();
65  for( auto i : range( E.nb_vertices() ) )
66  {
67  if( geomodel_vertices.geomodel_vertex_id( id, i ) == NO_ID
68  && geomodel_vertices.geomodel_vertex_id( id, i )
69  >= E.geomodel().mesh.vertices.nb() )
70  {
72  "GeoModelEntity", "Invalid geomodel vertex index in ", id );
73  return false;
74  }
75  }
76  return true;
77  }
78 
82  template < index_t DIMENSION >
83  index_t compute_nb_surface_connected_components(
84  const SurfaceBase< DIMENSION >& surface )
85  {
86  index_t nb_connected_components;
87  std::tie( nb_connected_components, std::ignore ) =
88  surface.mesh().connected_components();
89  return nb_connected_components;
90  }
91 
95  template < index_t DIMENSION >
96  index_t compute_nb_volume_connected_components(
97  const Region< DIMENSION >& region )
98  {
99  index_t nb_connected_components;
100  std::tie( nb_connected_components, std::ignore ) =
101  region.mesh().connected_components();
102  return nb_connected_components;
103  }
104 
113  template < index_t DIMENSION >
114  std::vector< index_t > count_vertex_occurences(
116  {
117  std::vector< index_t > nb( E.nb_vertices(), 0 );
118  for( auto mesh_element_index : range( E.nb_mesh_elements() ) )
119  {
120  for( auto vertex :
121  range( E.nb_mesh_element_vertices( mesh_element_index ) ) )
122  {
124  { mesh_element_index, vertex } )];
125  }
126  }
127  return nb;
128  }
129 
130  bool check_mesh_entity_vertices_are_different(
131  std::vector< index_t >& vertices,
132  std::vector< index_t >& vertices_global )
133  {
135  std::count( vertices.begin(), vertices.end(), NO_ID ) == 0 );
137  std::count( vertices_global.begin(), vertices_global.end(), NO_ID )
138  == 0 );
139  // 0 is the default value of the geomodel_vertex_id
140  // If we have only 0 either this is a degenerate polygons, but most
141  // certainly
142  // geomodel vertex ids are not good
144  static_cast< index_t >( std::count(
145  vertices_global.begin(), vertices_global.end(), 0 ) )
146  != vertices_global.size() );
147 
148  std::sort( vertices.begin(), vertices.end() );
149  std::sort( vertices_global.begin(), vertices_global.end() );
150  return std::unique( vertices.begin(), vertices.end() ) != vertices.end()
151  || std::unique( vertices_global.begin(), vertices_global.end() )
152  != vertices_global.end();
153  }
154 
159  template < index_t DIMENSION >
160  bool polygon_is_degenerate(
161  const SurfaceBase< DIMENSION >& S, const gmme_id& id, index_t p )
162  {
163  index_t nb_polygon_vertices{ S.nb_mesh_element_vertices( p ) };
164  std::vector< index_t > corners( nb_polygon_vertices, NO_ID );
165  std::vector< index_t > corners_global( nb_polygon_vertices, NO_ID );
166  index_t v{ 0 };
167  const auto& geomodel_vertices = S.geomodel().mesh.vertices;
168  for( auto c : range( S.nb_mesh_element_vertices( p ) ) )
169  {
170  index_t polygon_vertex_index{ S.mesh_element_vertex_index(
171  { p, c } ) };
172  corners[v] = polygon_vertex_index;
173  corners_global[v] =
174  geomodel_vertices.geomodel_vertex_id( id, { p, v } );
175  v++;
176  }
177  double area{ S.mesh_element_size( p ) };
178  return check_mesh_entity_vertices_are_different(
179  corners, corners_global )
180  || area < S.geomodel().epsilon2();
181  }
182 
188  template < index_t DIMENSION >
189  bool cell_is_degenerate(
190  const Region< DIMENSION >& region, index_t cell_index )
191  {
192  index_t nb_vertices_in_cell{ region.nb_mesh_element_vertices(
193  cell_index ) };
194  std::vector< index_t > vertices( nb_vertices_in_cell, NO_ID );
195  std::vector< index_t > vertices_global( nb_vertices_in_cell, NO_ID );
196  auto id = region.gmme();
197  const auto& geomodel_vertices = region.geomodel().mesh.vertices;
198  for( auto v : range( nb_vertices_in_cell ) )
199  {
200  vertices[v] = region.mesh_element_vertex_index( { cell_index, v } );
201  vertices_global[v] =
202  geomodel_vertices.geomodel_vertex_id( id, { cell_index, v } );
203  }
204  double volume{ region.mesh_element_size( cell_index ) };
205  return check_mesh_entity_vertices_are_different(
206  vertices, vertices_global )
207  || volume < region.geomodel().epsilon3();
208  }
209 } // namespace
210 
211 namespace RINGMesh
212 {
213  template < index_t DIMENSION >
215  const GeoModelMeshEntity& rhs ) const
216  {
217  // Find out if this surface is twice in the incident_entity vector
218  auto rhs_id = rhs.gmme();
219  const auto& manager =
220  this->geomodel().entity_type_manager().relationship_manager;
221  return std::count_if( incident_entities_.begin(),
222  incident_entities_.end(),
223  [&rhs_id, &manager]( index_t i ) {
224  return manager.incident_entity_gmme( i ) == rhs_id;
225  } )
226  > 1;
227  }
228 
229  template < index_t DIMENSION >
231  {
232  for( auto i : range( nb_boundaries() ) )
233  {
234  if( boundary( i ).is_inside_border( *this ) )
235  {
236  return true;
237  }
238  }
239  return false;
240  }
241 
242  template < index_t DIMENSION >
244  {
245 #ifdef RINGMESH_DEBUG
246  ringmesh_assert( mesh_ != nullptr );
247  mesh_->print_mesh_bounded_attributes();
248 #endif
249  }
250 
251  template < index_t DIMENSION >
252  void
254  {
255  auto& modifiable_model =
256  const_cast< GeoModel< DIMENSION >& >( this->geomodel() );
257  modifiable_model.mesh.vertices.unbind_geomodel_vertex_map( gmme() );
258  }
259 
260  template < index_t DIMENSION >
262  {
263  auto& modifiable_model =
264  const_cast< GeoModel< DIMENSION >& >( this->geomodel() );
265  modifiable_model.mesh.vertices.bind_geomodel_vertex_map( gmme() );
266  }
267 
268  template < index_t DIMENSION >
270  const
271  {
272  bool valid{ true };
273  // For all vertices
274  // Check that the global vertex has an index backward to
275  // the vertex of this entity
276  const auto& geomodel_vertices = this->geomodel().mesh.vertices;
277  auto id = gmme();
278  for( auto v : range( nb_vertices() ) )
279  {
280  index_t geomodel_v{ geomodel_vertices.geomodel_vertex_id( id, v ) };
281 
282  if( geomodel_v == NO_ID )
283  {
284  Logger::warn( "GeoModelEntity", id, " vertex ", v,
285  " is not mapped to the related global geomodel vertex "
286  "indices." );
287  valid = false;
288  }
289 
290  auto backward_vertices =
291  geomodel_vertices.mesh_entity_vertex_id( id, geomodel_v );
292  bool found_in_backward{ false };
293  for( auto bv : backward_vertices )
294  {
295  if( bv == v )
296  {
297  found_in_backward = true;
298  }
299  }
300  if( !found_in_backward )
301  {
302  Logger::warn( "GeoModelEntity", "Error in mapping of ", id,
303  " vertex ", v,
304  " to the related global geomodel vertex indices." );
305  valid = false;
306  }
307  }
308  return valid;
309  }
310 
311  template < index_t DIMENSION >
313  {
314  return this->index() < this->geomodel().nb_mesh_entities( type_name() );
315  }
316 
317  template < index_t DIMENSION >
319  {
320  const auto& family =
321  this->geomodel().entity_type_manager().mesh_entity_manager;
322  const auto entity_type = type_name();
323  const auto& boundary_type = family.boundary_entity_type( entity_type );
324 
325  bool valid{ true };
326  auto id = gmme();
327  if( family.is_valid_type( boundary_type ) )
328  {
329  for( auto i : range( nb_boundaries() ) )
330  {
331  const auto& E = boundary( i );
332  bool found{ false };
333  index_t j{ 0 };
334  while( !found && j < E.nb_incident_entities() )
335  {
336  if( E.incident_entity_gmme( j ) == id )
337  {
338  found = true;
339  }
340  j++;
341  }
342  if( !found )
343  {
344  Logger::warn( "GeoModelEntity",
345  "Inconsistency boundary-incident_entity between ", id,
346  " and ", E.gmme() );
347  valid = false;
348  }
349  }
350  }
351  return valid;
352  }
353 
354  template < index_t DIMENSION >
355  bool
357  const
358  {
359  const auto& family =
360  this->geomodel().entity_type_manager().mesh_entity_manager;
361  const auto entity_type = type_name();
362  const auto& incident_entity_type =
363  family.incident_entity_type( entity_type );
364 
365  bool valid{ true };
366  auto id = gmme();
367  if( family.is_valid_type( incident_entity_type ) )
368  {
369  if( nb_incident_entities() == 0 )
370  {
371  Logger::warn(
372  "GeoModelEntity", id, " is in the boundary of no entity " );
373  valid = false;
374  }
375  for( auto i : range( nb_incident_entities() ) )
376  {
377  const auto& E = incident_entity( i );
378  bool found{ false };
379  index_t j{ 0 };
380  while( !found && j < E.nb_boundaries() )
381  {
382  if( E.boundary_gmme( j ) == id )
383  {
384  found = true;
385  }
386  j++;
387  }
388  if( !found )
389  {
390  Logger::warn( "GeoModelEntity",
391  "Inconsistency incident_entity-boundary between ", id,
392  " and ", E.gmme() );
393  valid = false;
394  }
395  }
396  }
397  return valid;
398  }
399 
400  template < index_t DIMENSION >
402  {
403  const auto& family =
404  this->geomodel().entity_type_manager().relationship_manager;
405  const auto entity_type = type_name();
406 
407  bool valid{ true };
408  const auto parent_types = family.parent_types( entity_type );
409  auto id = gmme();
410  for( const auto& parent_type : parent_types )
411  {
412  index_t nb_parent_entities_in_geomodel{
413  this->geomodel_.nb_geological_entities( parent_type )
414  };
415  if( nb_parent_entities_in_geomodel == 0 )
416  {
417  continue;
418  }
419  // There must be one and only one parent of that type in this entity
420  // And this parent must have this entity in its children
421  index_t nb_found_parents{ 0 };
422  for( auto i : range( nb_parents() ) )
423  {
424  const auto& E = parent( i );
425  if( E.type_name() == parent_type )
426  {
427  nb_found_parents++;
428 
429  // The parent must have this entity in its children
430  bool found{ false };
431  index_t j{ 0 };
432  while( !found && j < E.nb_children() )
433  {
434  if( E.child_gmme( j ) == id )
435  {
436  found = true;
437  }
438  j++;
439  }
440  if( !found )
441  {
442  Logger::warn( "GeoModelEntity",
443  "Inconsistency parent-child between ", id, " and ",
444  E.gmge() );
445  valid = false;
446  }
447  }
448  }
449  if( nb_found_parents != 1 )
450  {
451  Logger::warn( "GeoModelEntity", id, " has ", nb_found_parents,
452  " geological parent entity of type ", parent_type,
453  " (expected one)" );
454  valid = false;
455  }
456  }
457  return valid;
458  }
459 
460  template < index_t DIMENSION >
462  {
463  return is_boundary_connectivity_valid()
464  && is_incident_entity_connectivity_valid();
465  }
466 
467  template < index_t DIMENSION >
469  GeoModelMeshEntity< DIMENSION >::parent( index_t parent_index ) const
470  {
471  auto parent = parent_gmge( parent_index );
472  ringmesh_assert( parent.is_defined() );
473  return this->geomodel().geological_entity( parent );
474  }
475 
476  template < index_t DIMENSION >
479  const GeologicalEntityType& parent_type ) const
480  {
481  auto id = parent_gmge( parent_type );
482  ringmesh_assert( id.is_defined() );
483  return this->geomodel().geological_entity( id );
484  }
485 
486  template < index_t DIMENSION >
488  const GeologicalEntityType& parent_type ) const
489  {
490  return defined_parent_gmge( parent_type );
491  }
492 
493  template < index_t DIMENSION >
495  const GeologicalEntityType& parent_type ) const
496  {
497  for( auto i : range( nb_parents() ) )
498  {
499  if( parent_gmge( i ).type() == parent_type )
500  {
501  return parent_gmge( i );
502  }
503  }
504  return gmge_id(
506  }
507 
508  template < index_t DIMENSION >
510  const GeologicalEntityType& parent_type ) const
511  {
512  const auto parent_gmge = could_be_undefined_parent_gmge( parent_type );
513  ringmesh_assert( parent_gmge.is_defined() );
514  return parent_gmge;
515  }
516 
517  template < index_t DIMENSION >
519  index_t x ) const
520  {
521  ringmesh_assert( x < nb_boundaries() );
522  return this->geomodel()
523  .entity_type_manager()
524  .relationship_manager.boundary_gmme( boundaries_[x] );
525  }
526 
527  template < index_t DIMENSION >
530  {
531  return this->geomodel().mesh_entity( boundary_gmme( x ) );
532  }
533 
534  template < index_t DIMENSION >
537  {
538  return this->geomodel().mesh_entity( incident_entity_gmme( x ) );
539  }
540 
541  template < index_t DIMENSION >
543  index_t x ) const
544  {
545  ringmesh_assert( x < this->nb_incident_entities() );
546  return this->geomodel()
547  .entity_type_manager()
548  .relationship_manager.incident_entity_gmme( incident_entities_[x] );
549  }
550 
551  template < index_t DIMENSION >
553  index_t id ) const
554  {
555  ringmesh_assert( id < nb_parents() );
556  return this->geomodel()
557  .entity_type_manager()
558  .relationship_manager.parent_of_gmme( parents_[id] );
559  }
560  /**************************************************************/
561 
562  template < index_t DIMENSION >
564  {
565  // True if one of the incident lines defines the universe
566  for( auto i : range( this->nb_incident_entities() ) )
567  {
568  if( incident_entity( i ).is_on_voi() )
569  {
570  return true;
571  }
572  }
573  return false;
574  }
575 
576  template < index_t DIMENSION >
578  {
579  bool valid{ true };
580  if( this->nb_vertices() != 1 )
581  {
582  Logger::err( "GeoModelEntity", this->gmme(), " mesh has ",
583  point_set_mesh_->nb_vertices(), " vertices " );
584  valid = false;
585  }
586  if( !point_set_mesh_->is_mesh_valid() )
587  {
588  Logger::err( "GeoModelEntity", this->gmme(), " mesh is invalid" );
589  valid = false;
590  }
591  return valid;
592  }
593 
594  template < index_t DIMENSION >
596  index_t x ) const
597  {
598  return static_cast< const Line< DIMENSION >& >(
600  }
601 
602  /***************************************************************/
603 
604  template < index_t DIMENSION >
606  {
607  bool valid{ true };
608 
609  if( !line_mesh_->is_mesh_valid() )
610  {
611  Logger::err( "GeoModelEntity", this->gmme(), " mesh is invalid" );
612  valid = false;
613  }
614 
615  // Model indices must be valid
616  valid = check_range_model_vertex_ids( *this ) && valid;
617 
618  if( this->nb_vertices() > 1 )
619  {
620  // Count the number of edges in which each vertex is
621  auto nb = count_vertex_occurences( *this );
622  index_t nb0{ 0 };
623  index_t nb1{ 0 };
624  index_t nb2{ 0 };
625  for( auto i : nb )
626  {
627  if( i == 0 )
628  {
629  ++nb0;
630  }
631  else if( i == 1 )
632  {
633  ++nb1;
634  }
635  else if( i == 2 )
636  {
637  ++nb2;
638  }
639  }
640 
641  // Vertices at extremitites must be in only one edge
642  if( nb.front() != 1 || nb.back() != 1 )
643  {
644  Logger::err( "GeoModelEntity", "Invalid extremity points in ",
645  this->gmme() );
646  valid = false;
647  }
648  // No isolated vertices are allowed
649  if( nb0 > 0 )
650  {
651  Logger::warn( "GeoModelEntity", nb0, " isolated vertices in ",
652  this->gmme() );
653  valid = false;
654  }
655  // Only the two extremities are in only 1 edge
656  // One connected component condition
657  if( nb1 != 2 )
658  {
659  Logger::warn( "GeoModelEntity",
660  "More than one connected component for ", this->gmme() );
661  valid = false;
662  }
663  // All the others must be in 2 edges and 2 edges only
664  // Manifold condition
665  if( nb2 != nb.size() - 2 )
666  {
667  Logger::warn(
668  "GeoModelEntity", "Non-manifold entity", this->gmme() );
669  valid = false;
670  }
671  }
672 
673  // No zero edge length
674  index_t nb_degenerated{ 0 };
675  for( auto e : range( nb_mesh_elements() ) )
676  {
677  double l = ( this->mesh_element_vertex( { e, 1 } )
678  - this->mesh_element_vertex( { e, 0 } ) )
679  .length();
680  if( l < this->geomodel().epsilon() )
681  {
682  nb_degenerated++;
683  }
684  }
685  if( nb_degenerated > 0 )
686  {
687  Logger::warn( "GeoModelEntity", nb_degenerated,
688  " degenerated edges in ", this->gmme() );
689  valid = false;
690  }
691  if( !is_first_corner_first_vertex() )
692  {
693  Logger::warn( "GeoModelEntity", "First and last vertex of Line",
694  this->index(),
695  " do not match first and second Corner respectively" );
696  valid = false;
697  }
698  return valid;
699  }
700 
701  template < index_t DIMENSION >
703  {
704  bool line_valid{
706  };
707 
708  // A Line must have 2 corners - they are identical if the Line is closed
709  if( this->nb_boundaries() != 2 )
710  {
711  Logger::warn(
712  "Connectivity", this->gmme(), " does not have 2 corners" );
713  line_valid = false;
714  }
715  return line_valid;
716  }
717 
718  template < index_t DIMENSION >
720  {
721  if( this->nb_boundaries() != 2 || this->nb_vertices() < 2 )
722  {
723  return false;
724  }
725  // Geometric comparison - not great at all
726  return this->boundary( 0 ).vertex( 0 ) == this->vertex( 0 )
727  && this->boundary( 1 ).vertex( 0 )
728  == this->vertex( this->nb_vertices() - 1 );
729  }
730 
731  template < index_t DIMENSION >
733  {
734  return static_cast< const Corner< DIMENSION >& >(
736  }
737 
738  template <>
739  bool Line< 2 >::is_on_voi() const
740  {
741  ringmesh_assert( this->nb_incident_entities() == 1
742  || this->nb_incident_entities() == 2 );
743  return this->nb_incident_entities() == 1;
744  }
745 
746  template <>
747  bool Line< 3 >::is_on_voi() const
748  {
749  // True if one of the incident surfaces defines the universe
750  for( auto i : range( this->nb_incident_entities() ) )
751  {
752  if( this->incident_entity( i ).is_on_voi() )
753  {
754  return true;
755  }
756  }
757  return false;
758  }
759 
760  /********************************************************************/
761 
762  template < index_t DIMENSION >
764  {
765  bool valid{ true };
766  auto id = this->gmme();
767 
768  if( !surface_mesh_->is_mesh_valid() )
769  {
770  Logger::err( "GeoModelEntity", this->gmme(), " mesh is invalid" );
771  valid = false;
772  }
773 
774  // No zero area polygon
775  // No polygon incident to the same vertex check local and global indices
776  index_t nb_degenerate{ 0 };
777  for( auto p : range( surface_mesh_->nb_polygons() ) )
778  {
779  if( polygon_is_degenerate( *this, id, p ) )
780  {
781  nb_degenerate++;
782  }
783  }
784  if( nb_degenerate != 0 )
785  {
786  Logger::warn( "GeoModelEntity", id, " mesh has ", nb_degenerate,
787  " degenerate polygons " );
788  valid = false;
789  }
790 
791  // One connected component
792  index_t cc{ compute_nb_surface_connected_components( *this ) };
793  if( cc != 1 )
794  {
795  Logger::warn( "GeoModelEntity", id, " mesh has ", cc,
796  " connected components " );
797  valid = false;
798  }
799  return valid;
800  }
801 
802  template < index_t DIMENSION >
804  index_t x ) const
805  {
806  return static_cast< const Line< DIMENSION >& >(
808  }
809 
811  {
812  return false;
813  }
814 
816  {
818  || this->nb_incident_entities() == 2 );
819  return this->nb_incident_entities() == 1;
820  }
821 
822  const Region3D& Surface< 3 >::incident_entity( index_t x ) const
823  {
824  return static_cast< const Region3D& >(
825  GeoModelMeshEntity3D::incident_entity( x ) );
826  }
827 
828  /********************************************************************/
829 
830  template < index_t DIMENSION >
832  {
833  return static_cast< const Surface< DIMENSION >& >(
835  }
836 
837  template < index_t DIMENSION >
839  {
840  return false;
841  }
842 
843  template < index_t DIMENSION >
845  {
846  if( this->nb_boundaries() != sides_.size() )
847  {
848  Logger::err( "GeoModelEntity", this->gmme(),
849  " boundary sides are invalid " );
850  return false;
851  }
852  bool region_valid{
854  };
855  if( this->nb_boundaries() == 0 )
856  {
857  Logger::warn( "Connectivity", this->gmme(), " has no boundaries " );
858  region_valid = false;
859  }
860  return region_valid;
861  }
862 
863  template < index_t DIMENSION >
865  {
866  if( !is_meshed() )
867  {
868  return true;
869  }
870  bool valid{ true };
871 
872  if( !volume_mesh_->is_mesh_valid() )
873  {
874  Logger::err( "GeoModelEntity", this->gmme(), " mesh is invalid" );
875  valid = false;
876  }
877 
878  // No cell with negative volume
879  // No cell incident to the same vertex check local and global indices
880  index_t nb_degenerate{ 0 };
881  for( auto c : range( volume_mesh_->nb_cells() ) )
882  {
883  if( cell_is_degenerate( *this, c ) )
884  {
885  nb_degenerate++;
886  }
887  }
888  if( nb_degenerate != 0 )
889  {
890  Logger::warn( "GeoModelEntity", this->gmme(), " mesh has ",
891  nb_degenerate, " degenerate cells " );
892  valid = false;
893  }
894 
895  // One connected component
896  index_t cc{ compute_nb_volume_connected_components( *this ) };
897  if( cc != 1 )
898  {
899  Logger::warn( "GeoModelEntity", this->gmme(), " mesh has ", cc,
900  " connected components " );
901  valid = false;
902  }
903  return valid;
904  }
905 
906  template < index_t DIMENSION >
908  const MeshType& type )
909  {
910  if( gmme_.mesh_->type_name() != type )
911  {
912  gmme_.unbind_vertex_mapping_attribute();
913  gmme_.change_mesh_data_structure( type );
914  gmme_.bind_vertex_mapping_attribute();
915  }
916  }
917 
918  template < index_t DIMENSION >
920  {
921  auto new_mesh = PointSetMesh< DIMENSION >::create_mesh( type );
922  auto builder =
924  builder->copy( *point_set_mesh_, true );
925  update_mesh_storage_type( std::move( new_mesh ) );
926  }
927 
928  template < index_t DIMENSION >
930  {
931  auto new_mesh = LineMesh< DIMENSION >::create_mesh( type );
932  auto builder =
934  builder->copy( *line_mesh_, true );
935  update_mesh_storage_type( std::move( new_mesh ) );
936  }
937 
938  template < index_t DIMENSION >
940  const MeshType& type )
941  {
942  auto new_mesh = SurfaceMesh< DIMENSION >::create_mesh( type );
943  auto builder =
945  builder->copy( *surface_mesh_, true );
946  update_mesh_storage_type( std::move( new_mesh ) );
947  }
948 
949  template < index_t DIMENSION >
952  const vecn< DIMENSION >& vertex_vec ) const
953  {
954  ElementLocalVertex cell_local_vertex;
955  volume_mesh_->find_cell_from_colocated_vertex_within_distance_if_any(
956  vertex_vec, this->geomodel_.epsilon(),
957  cell_local_vertex.element_id_, cell_local_vertex.local_vertex_id_ );
958  return cell_local_vertex;
959  }
960 
961  template < index_t DIMENSION >
963  {
964  auto new_mesh = VolumeMesh< DIMENSION >::create_mesh( type );
965  auto builder =
967  builder->copy( *volume_mesh_, true );
968  update_mesh_storage_type( std::move( new_mesh ) );
969  }
970  template <>
972  {
973  ringmesh_assert( gmme_.type_name() == Surface2D::type_name_static() );
974  return dynamic_cast< Surface2D& >( gmme_ ).sides_;
975  }
976 
977  template <>
979  {
980  ringmesh_assert( gmme_.type_name() == Region3D::type_name_static() );
981  return dynamic_cast< Region3D& >( gmme_ ).sides_;
982  }
983 
984  template class RINGMESH_API GeoModelMeshEntity< 2 >;
985  template class RINGMESH_API GeoModelMeshEntityAccess< 2 >;
986  template class RINGMESH_API Corner< 2 >;
987  template class RINGMESH_API Line< 2 >;
988  template class RINGMESH_API SurfaceBase< 2 >;
989 
990  template class RINGMESH_API GeoModelMeshEntity< 3 >;
991  template class RINGMESH_API GeoModelMeshEntityAccess< 3 >;
992  template class RINGMESH_API Corner< 3 >;
993  template class RINGMESH_API Line< 3 >;
994  template class RINGMESH_API SurfaceBase< 3 >;
995  template class RINGMESH_API Region< 3 >;
996 } // namespace RINGMesh
void change_mesh_data_structure(const MeshType &type) final
std::vector< bool > & modifiable_sides()
void change_mesh_data_structure(const MeshType &type) final
static std::unique_ptr< PointSetMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:70
const GeoModel< DIMENSION > & geomodel() const
virtual MeshEntityType type_name() const =0
const VolumeMesh< DIMENSION > & mesh() const
Get the low level mesh data structure.
GeoModelMesh< DIMENSION > mesh
Definition: geomodel.h:241
Abstract base class for GeoModelMeshEntity.
GEO::vecng< DIMENSION, double > vecn
Definition: types.h:74
static std::unique_ptr< LineMeshBuilder > create_builder(LineMesh< DIMENSION > &mesh)
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.
static std::unique_ptr< LineMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:101
bool is_inside_border(const GeoModelMeshEntity &rhs) const
Check if this entity is an inside border of rhs.
double mesh_element_size(index_t polygon_index) const final
index_t nb_mesh_element_vertices(index_t polygon_index) const final
The GeologicalEntityType described the type of the Geological entities User can defined there own Geo...
Definition: entity_type.h:137
static std::unique_ptr< PointSetMeshBuilder< DIMENSION > > create_builder(PointSetMesh< DIMENSION > &mesh)
static ForbiddenGeologicalEntityType & type_name_static()
Definition: entity_type.h:172
virtual bool is_connectivity_valid() const
index_t mesh_element_vertex_index(const ElementLocalVertex &element_local_vertex) const final
Index of a vertex in the Region from its index in a cell.
const Region< DIMENSION > & incident_entity(index_t x) const
bool is_first_corner_first_vertex() const
A GeoModelEntity of type CORNER.
ElementLocalVertex find_cell_from_colocated_vertex_if_any(const vecn< DIMENSION > &vertex_vec) const
virtual bool is_on_voi() const =0
virtual index_t nb_mesh_element_vertices(index_t mesh_element_index) const =0
Number of vertices of a constitutive element of the mesh.
const GeoModelGeologicalEntity< DIMENSION > & parent(index_t parent_index) const
static void warn(const std::string &feature, const Args &... args)
Definition: logger.h:75
std::shared_ptr< SurfaceMesh< DIMENSION > > surface_mesh_
const Surface< DIMENSION > & boundary(index_t x) const
const gmme_id & boundary_gmme(index_t x) const
gmge_id defined_parent_gmge(const GeologicalEntityType &parent_type) const
bool is_on_voi() const final
Checks if this entity define the geomodel external boundary.
const SurfaceMesh< DIMENSION > & mesh() const
Get the low level mesh data structure.
void change_mesh_data_structure(const MeshType &type)
const gmge_id & parent_gmge(index_t id) const
static std::unique_ptr< VolumeMeshBuilder< DIMENSION > > create_builder(VolumeMesh< DIMENSION > &mesh)
A GeoModelEntity of type SURFACE.
index_t nb_mesh_element_vertices(index_t cell_index) const final
bool is_mesh_valid() const final
static void err(const std::string &feature, const Args &... args)
Definition: logger.h:68
gmge_id could_be_undefined_parent_gmge(const GeologicalEntityType &parent_type) const
std::string MeshType
Definition: mesh.h:69
const Corner< DIMENSION > & boundary(index_t x) const
void update_mesh_storage_type(std::unique_ptr< SurfaceMesh< DIMENSION > > mesh)
bool is_mesh_valid() const final
Check that the mesh of the Surface is valid.
const gmme_id & incident_entity_gmme(index_t x) const
bool has_inside_border() const
Check if one entity is twice in the boundary.
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.
bool is_on_voi() const final
const GeoModel< DIMENSION > & geomodel_
Reference to the GeoModel owning this entity.
virtual bool is_index_valid() const final
bool is_mesh_valid() const final
Check that the Corner mesh is a unique point.
#define ringmesh_assert(x)
const GeoModelMeshEntity< DIMENSION > & incident_entity(index_t x) const
virtual index_t nb_mesh_elements() const =0
Get the number constitutive elements of the mesh.
static std::unique_ptr< SurfaceMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:244
A GeoModelEntity of type REGION.
const Line< DIMENSION > & boundary(index_t x) const
const Line< DIMENSION > & incident_entity(index_t x) const
This template is a specialization of a gme_id to the GeoModelGeologicalEntity.
Definition: entity_type.h:262
void change_mesh_data_structure(const MeshType &type) final
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
bool is_connectivity_valid() const final
void change_mesh_data_structure(const MeshType &type) final
A GeoModelEntity of type LINE.
bool is_on_voi() const final
bool are_geomodel_vertex_indices_valid() const
Check that geomodel vertex indices are consistent with what is stored at the GeoModel level...
bool is_mesh_valid() const final
Check that the mesh of the Line is valid.
static std::unique_ptr< VolumeMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:582
static std::unique_ptr< SurfaceMeshBuilder< DIMENSION > > create_builder(SurfaceMesh< DIMENSION > &mesh)
This template is a specialization of a gme_id to the GeoModelMeshEntity.
Definition: entity_type.h:285
bool is_connectivity_valid() const final
double mesh_element_size(index_t cell_index) const final
Volume of a cell.
const GeoModelMeshEntity< DIMENSION > & boundary(index_t x) const