RINGMesh  Version 5.0.0
A programming library for geological model meshes
geomodel_builder_gocad.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 
53  gmme_id find_corner( const GeoModel3D& geomodel, const vec3& point )
54  {
55  for( const auto& corner : geomodel.corners() )
56  {
57  if( corner.vertex( 0 ) == point )
58  {
59  return corner.gmme();
60  }
61  }
62  return gmme_id();
63  }
64 
65  std::string read_name_with_spaces(
66  index_t field_id, const GEO::LineInput& line )
67  {
68  std::ostringstream oss;
69  do
70  {
71  oss << line.field( field_id++ );
72  } while( field_id < line.nb_fields() );
73  return oss.str();
74  }
75 
76  vec3 read_vertex_coordinates(
77  GEO::LineInput& in, index_t start_field, int z_sign )
78  {
79  vec3 vertex;
80  vertex.x = in.field_as_double( start_field++ );
81  vertex.y = in.field_as_double( start_field++ );
82  vertex.z = z_sign * in.field_as_double( start_field );
83  return vertex;
84  }
85 
86  std::vector< double > read_vertex_attributes(
87  GEO::LineInput& in, index_t start_field, index_t nb_attribute_fields )
88  {
89  std::vector< double > vertex( nb_attribute_fields );
90  for( auto& cur_attribute : vertex )
91  {
92  ringmesh_assert( !in.field_matches( start_field, "CNXYZ" ) );
93  ringmesh_assert( !in.field_matches( start_field, "XYZ" ) );
94  cur_attribute = in.field_as_double( start_field++ );
95  }
96  return vertex;
97  }
98 
110  template < index_t DIMENSION >
111  gmge_id find_geological_entity( const GeoModel< DIMENSION >& geomodel,
112  const GeologicalEntityType& geol_entity_type,
113  const std::string& geol_entity_name )
114  {
115  for( auto& geol_entity : geomodel.geol_entities( geol_entity_type ) )
116  {
117  if( geol_entity.name() == geol_entity_name )
118  {
119  return geol_entity.gmge();
120  }
121  }
122  return gmge_id();
123  }
124 
128  struct Border
129  {
130  Border( index_t part, index_t corner, index_t p0, index_t p1 )
131  : part_id_( part ), corner_id_( corner ), p0_( p0 ), p1_( p1 )
132  {
133  }
134 
135  // Id of the Surface owning this Border
136  index_t part_id_;
137 
138  // Id of p0 in the GeoModel corner vector
139  index_t corner_id_;
140 
141  // Ids of the starting corner and second vertex on the border in the
142  // Surface
143  // to which this Border belong
144  index_t p0_;
145  index_t p1_;
146  };
147 
155  vec3 get_point_from_gocad_id( const GeoModel3D& geomodel,
156  const VertexMap& vertex_map,
157  index_t point_gocad_id )
158  {
159  index_t point_local_id = vertex_map.local_id( point_gocad_id );
160  index_t point_region = vertex_map.region( point_gocad_id );
161 
162  return geomodel.region( point_region ).vertex( point_local_id );
163  }
164 
179  void get_surface_point_and_polygon_from_gocad_index(
180  index_t vertex_gocad_id,
181  const GeoModel3D& geomodel,
182  const TSolidLoadingStorage& load_storage,
183  std::vector< index_t >& gocad_vertices2cur_surf_points,
184  std::vector< vec3 >& cur_surf_points,
185  std::vector< index_t >& cur_surf_polygons )
186  {
187  if( vertex_gocad_id >= gocad_vertices2cur_surf_points.size() )
188  {
189  gocad_vertices2cur_surf_points.resize( vertex_gocad_id + 1, NO_ID );
190  }
191 
192  if( gocad_vertices2cur_surf_points[vertex_gocad_id] == NO_ID )
193  {
194  // First time this polygon corner is met in polygon_corners
195  vec3 point = get_point_from_gocad_id(
196  geomodel, load_storage.vertex_map_, vertex_gocad_id );
197  auto index = static_cast< index_t >( cur_surf_points.size() );
198  cur_surf_polygons.push_back( index );
199  gocad_vertices2cur_surf_points[vertex_gocad_id] = index;
200  cur_surf_points.push_back( point );
201  }
202  else
203  {
204  // If this polygon corner has already been met in polygon_corners
205  cur_surf_polygons.push_back(
206  gocad_vertices2cur_surf_points[vertex_gocad_id] );
207  }
208  }
209 
220  void get_surface_points_and_polygons_from_gocad_indices(
221  const GeoModel3D& geomodel,
222  const TSolidLoadingStorage& load_storage,
223  std::vector< vec3 >& cur_surf_points,
224  std::vector< index_t >& cur_surf_polygons )
225  {
226  std::vector< index_t > gocad_vertices2cur_surf_points;
227  for( auto corner_gocad_id :
229  {
230  get_surface_point_and_polygon_from_gocad_index( corner_gocad_id,
231  geomodel, load_storage, gocad_vertices2cur_surf_points,
232  cur_surf_points, cur_surf_polygons );
233  }
234  }
235 
241  void build_surface( GeoModelBuilderGocad& builder,
242  GeoModel3D& geomodel,
243  TSolidLoadingStorage& load_storage )
244  {
245  std::vector< vec3 > cur_surf_points;
246  std::vector< index_t > cur_surf_polygons;
247  get_surface_points_and_polygons_from_gocad_indices(
248  geomodel, load_storage, cur_surf_points, cur_surf_polygons );
249  builder.geometry.set_surface_geometry( load_storage.cur_surface_,
250  cur_surf_points, cur_surf_polygons,
251  load_storage.cur_surf_polygon_ptr_ );
252  load_storage.cur_surf_polygon_corners_gocad_id_.clear();
253  load_storage.cur_surf_polygon_ptr_.clear();
254  load_storage.cur_surf_polygon_ptr_.push_back( 0 );
255  }
256 
269  void compute_region_cell_facet_centers( const GeoModel3D& geomodel,
270  index_t region_id,
271  std::vector< vec3 >& cell_facet_centers )
272  {
273  const Region3D& region = geomodel.region( region_id );
274  const VolumeMesh3D& mesh = region.mesh();
275  const index_t nb_cells = region.nb_mesh_elements();
276  cell_facet_centers.reserve( 4 * nb_cells );
277  for( auto c : range( nb_cells ) )
278  {
279  for( auto f : range( region.nb_cell_facets( c ) ) )
280  {
281  cell_facet_centers.push_back(
282  mesh.cell_facet_barycenter( CellLocalFacet( c, f ) ) );
283  }
284  }
285  }
286 
293  std::vector< std::unique_ptr< NNSearch3D > >
294  compute_cell_facet_centers_region_nn_searchs(
295  const GeoModel3D& geomodel )
296  {
297  std::vector< std::unique_ptr< NNSearch3D > > region_nn_searchs(
298  geomodel.nb_regions() );
299  for( auto r : range( geomodel.nb_regions() ) )
300  {
301  std::vector< vec3 > cell_facet_centers;
302  compute_region_cell_facet_centers(
303  geomodel, r, cell_facet_centers );
304  region_nn_searchs[r].reset(
305  new NNSearch3D( cell_facet_centers, true ) );
306  }
307  return region_nn_searchs;
308  }
309 
320  std::tuple< index_t, std::vector< index_t > >
321  are_surface_sides_region_boundaries(
322  const Surface3D& surface, const NNSearch3D& region_nn_search )
323  {
324  vec3 first_polygon_center = surface.mesh_element_barycenter( 0 );
325  std::vector< index_t > colocated_cell_facet_centers;
326  colocated_cell_facet_centers = region_nn_search.get_neighbors(
327  first_polygon_center, surface.geomodel().epsilon() );
328  return std::make_tuple(
329  static_cast< index_t >( colocated_cell_facet_centers.size() ),
330  colocated_cell_facet_centers );
331  }
332 
345  bool determine_surface_side_to_add( const GeoModel3D& geomodel,
346  index_t region_id,
347  index_t surface_id,
348  index_t cell_facet_center_id )
349  {
350  index_t local_facet_id = cell_facet_center_id % 4;
351  index_t cell_id = ( cell_facet_center_id - local_facet_id ) / 4;
352  vec3 cell_facet_normal =
353  geomodel.region( region_id )
354  .mesh()
355  .cell_facet_normal( CellLocalFacet( cell_id, local_facet_id ) );
356  vec3 first_polygon_normal =
357  geomodel.surface( surface_id ).mesh().polygon_normal( 0 );
358  return dot( first_polygon_normal, cell_facet_normal ) > 0;
359  }
360 
369  void fill_region_and_surface_boundaries_links( index_t region_id,
370  index_t surface_id,
371  bool surf_side,
372  GeoModelBuilderTSolid& geomodel_builder )
373  {
374  geomodel_builder.topology.add_mesh_entity_boundary_relation(
375  gmme_id( Region3D::type_name_static(), region_id ),
376  gmme_id( Surface3D::type_name_static(), surface_id ), surf_side );
377  }
378 
387  void add_both_surface_sides_to_region_boundaries( index_t region_id,
388  index_t surface_id,
389  GeoModelBuilderTSolid& geomodel_builder )
390 
391  {
392  fill_region_and_surface_boundaries_links(
393  region_id, surface_id, true, geomodel_builder );
394  fill_region_and_surface_boundaries_links(
395  region_id, surface_id, false, geomodel_builder );
396  }
397 
409  void add_one_surface_side_to_region_boundaries( index_t region_id,
410  index_t surface_id,
411  index_t cell_facet_center_id,
412  GeoModelBuilderTSolid& geomodel_builder,
413  const GeoModel3D& geomodel )
414  {
415  bool side = determine_surface_side_to_add(
416  geomodel, region_id, surface_id, cell_facet_center_id );
417  fill_region_and_surface_boundaries_links(
418  region_id, surface_id, side, geomodel_builder );
419  }
420 
431  void add_surface_sides_to_region_boundaries( index_t surface_id,
432  index_t region_id,
433  const std::vector< index_t >& colocated_cell_facet_centers,
434  const GeoModel3D& geomodel,
435  GeoModelBuilderTSolid& geomodel_builder )
436  {
437  switch( colocated_cell_facet_centers.size() )
438  {
439  case 1:
440  add_one_surface_side_to_region_boundaries( region_id, surface_id,
441  colocated_cell_facet_centers[0], geomodel_builder, geomodel );
442  break;
443  case 2:
444  add_both_surface_sides_to_region_boundaries(
445  region_id, surface_id, geomodel_builder );
446  break;
447  default:
449  }
450  }
451 
461  void add_surface_to_region_boundaries( index_t surface_id,
462  const std::vector< std::unique_ptr< NNSearch3D > >& region_nn_searchs,
463  const GeoModel3D& geomodel,
464  GeoModelBuilderTSolid& geomodel_builder )
465  {
466  index_t cur_region{ 0 };
467  index_t nb_added_surf_sides{ 0 };
468  // Maximum 2 regions could be bounded by a single surface
469  while( cur_region < geomodel.nb_regions() && nb_added_surf_sides < 2 )
470  {
471  index_t nb_surf_sides_are_boundary = NO_ID;
472  std::vector< index_t > colocated_cell_facet_centers;
473  std::tie(
474  nb_surf_sides_are_boundary, colocated_cell_facet_centers ) =
475  are_surface_sides_region_boundaries(
476  geomodel.surface( surface_id ),
477  *region_nn_searchs[cur_region] );
478  if( nb_surf_sides_are_boundary > 0 )
479  {
480  add_surface_sides_to_region_boundaries( surface_id, cur_region,
481  colocated_cell_facet_centers, geomodel, geomodel_builder );
482  nb_added_surf_sides += nb_surf_sides_are_boundary;
483  }
484  ++cur_region;
485  }
486  if( nb_added_surf_sides == 0 )
487  {
489  }
490  }
491 
496  void compute_boundaries_of_geomodel_regions(
497  GeoModelBuilderTSolid& geomodel_builder, const GeoModel3D& geomodel )
498  {
499  std::vector< std::unique_ptr< NNSearch3D > > reg_nn_searchs =
500  compute_cell_facet_centers_region_nn_searchs( geomodel );
501  for( const auto& surface : geomodel.surfaces() )
502  {
503  add_surface_to_region_boundaries(
504  surface.index(), reg_nn_searchs, geomodel, geomodel_builder );
505  }
506  }
507 
508  /*
509  * @brief Determines if each side of the surfaces are
510  * in the boundaries of geomodel regions
511  * @param[in] geomodel GeoModel to consider
512  * @param[out] surf_side_minus Vector indicating if the '-' side of
513  * surfaces are in the boundaries of geomodel regions
514  * @return Vector indicating if the '+' side of
515  * surfaces are in the boundaries of geomodel regions
516  */
517  std::vector< bool > determine_if_surface_sides_bound_regions(
518  const GeoModel3D& geomodel )
519  {
520  std::vector< bool > surface_sides( 2 * geomodel.nb_surfaces(), false );
521  for( const auto& region : geomodel.regions() )
522  {
523  for( auto s : range( region.nb_boundaries() ) )
524  {
525  if( region.side( s ) )
526  {
527  surface_sides[2 * region.boundary( s ).index() + 1] = true;
528  }
529  else if( !region.side( s ) )
530  {
531  surface_sides[2 * region.boundary( s ).index()] = true;
532  }
533  else
534  {
536  }
537  }
538  }
539  return surface_sides;
540  }
541 
558  bool is_edge_in_several_surfaces( const GeoModel3D& geomodel,
559  index_t surface_id,
560  index_t polygon,
561  index_t edge,
562  const std::vector< std::unique_ptr< NNSearch3D > >& surface_nns,
563  const std::vector< Box3D >& surface_boxes )
564  {
565  const Surface3D& surface = geomodel.surface( surface_id );
566  const SurfaceMesh3D& mesh = surface.mesh();
567  const vec3 barycenter =
568  mesh.polygon_edge_barycenter( PolygonLocalEdge( polygon, edge ) );
569  std::vector< index_t > result;
570  index_t tested_surf{ 0 };
571  while( result.empty() && tested_surf < surface_nns.size() )
572  {
573  if( surface_boxes[tested_surf].contains( barycenter ) )
574  {
575  result = surface_nns[tested_surf]->get_neighbors(
576  barycenter, geomodel.epsilon() );
577  }
578  ++tested_surf;
579  }
580  return !result.empty();
581  }
582 
590  std::vector< vec3 > get_surface_border_edge_barycenters(
591  const GeoModel3D& geomodel, index_t surface_id )
592  {
593  std::vector< vec3 > border_edge_barycenters;
594  const Surface3D& surface = geomodel.surface( surface_id );
595  const SurfaceMesh3D& mesh = surface.mesh();
596  for( auto p : range( surface.nb_mesh_elements() ) )
597  {
598  for( auto e : range( surface.nb_mesh_element_vertices( p ) ) )
599  {
600  if( mesh.is_edge_on_border( PolygonLocalEdge( p, e ) ) )
601  {
602  border_edge_barycenters.push_back(
603  mesh.polygon_edge_barycenter(
604  PolygonLocalEdge( p, e ) ) );
605  }
606  }
607  }
608  return border_edge_barycenters;
609  }
610 
611  void assign_mesh_surface(
612  GeoModelBuilderGocad& builder, MLLoadingStorage& load_storage )
613  {
614  std::vector< vec3 > vertices(
615  load_storage.vertices_.begin() + load_storage.tface_vertex_ptr_,
616  load_storage.vertices_.end() );
617  for( index_t& id : load_storage.cur_surf_polygon_corners_gocad_id_ )
618  {
619  id -= load_storage.tface_vertex_ptr_;
620  }
621  builder.geometry.set_surface_geometry( load_storage.cur_surface_,
622  vertices, load_storage.cur_surf_polygon_corners_gocad_id_,
623  load_storage.cur_surf_polygon_ptr_ );
624  load_storage.cur_surf_polygon_corners_gocad_id_.clear();
625  load_storage.cur_surf_polygon_ptr_.clear();
626  load_storage.cur_surf_polygon_ptr_.push_back( 0 );
627  load_storage.cur_surface_++;
628  }
629 
630  void assign_attributes_to_mesh( const Region3D& region,
631  TSolidLoadingStorage& load_storage,
632  const std::vector< std::vector< double > >& region_attributes )
633  {
634  index_t read_fields{ 0 };
635  for( auto attrib_itr :
636  range( load_storage.vertex_attribute_names_.size() ) )
637  {
638  std::string name = load_storage.vertex_attribute_names_[attrib_itr];
639 
640  if( region.vertex_attribute_manager().is_defined( name ) )
641  {
642  Logger::warn( "Transfer attribute", "The attribute ", name,
643  " already exists on the ", region.gmme() );
644  continue;
645  }
646  GEO::Attribute< double > attr;
647  index_t nb_dimensions =
648  load_storage.vertex_attribute_dims_[attrib_itr];
649  attr.create_vector_attribute( region.vertex_attribute_manager(),
650  load_storage.vertex_attribute_names_[attrib_itr],
651  nb_dimensions );
652  // Does it resize all the past attributes to the size of the current
653  // attribute?
654  // Problematic, isn't it?
655  region.vertex_attribute_manager().resize(
656  static_cast< index_t >( region_attributes.size() )
657  * nb_dimensions
658  + nb_dimensions );
659  for( auto v_itr : range( region_attributes.size() ) )
660  {
661  for( auto attrib_dim_itr : range( nb_dimensions ) )
662  {
663  attr[v_itr * nb_dimensions + attrib_dim_itr] =
664  region_attributes[v_itr][read_fields + attrib_dim_itr];
665  }
666  }
667  read_fields += nb_dimensions;
668  }
669  }
670 
671  // Indices begin to 1 in Gocad
672  index_t GOCAD_OFFSET{ 1 };
673 
674  class LoadZSign final : public GocadLineParser
675  {
676  public:
677  LoadZSign( GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
678  : GocadLineParser( gm_builder, geomodel )
679  {
680  }
681 
682  private:
683  void execute(
684  GEO::LineInput& line, GocadLoadingStorage& load_storage ) final
685  {
686  if( line.field_matches( 1, "Elevation" ) )
687  {
688  load_storage.z_sign_ = 1;
689  }
690  else if( line.field_matches( 1, "Depth" ) )
691  {
692  load_storage.z_sign_ = -1;
693  }
694  else
695  {
697  }
698  }
699  };
700 
701  class LoadTSurf final : public MLLineParser
702  {
703  public:
704  LoadTSurf( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
705  : MLLineParser( gm_builder, geomodel )
706  {
707  }
708 
709  private:
710  void execute(
711  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
712  {
713  ringmesh_unused( load_storage );
714  std::string interface_name = read_name_with_spaces( 1, line );
715  // Create an interface and set its name
716  gmge_id interface_id = builder_.geology.create_geological_entity(
717  Interface3D::type_name_static() );
718  builder_.info.set_geological_entity_name(
719  interface_id, interface_name );
720  }
721  };
722 
723  class LoadMLSurface final : public MLLineParser
724  {
725  public:
726  LoadMLSurface( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
727  : MLLineParser( gm_builder, geomodel )
728  {
729  }
730 
731  private:
732  void execute(
733  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
734  {
735  if( !load_storage.is_header_read_ )
736  {
739  std::string geol = line.field( 2 );
740  std::string interface_name = read_name_with_spaces( 3, line );
741  create_surface( interface_name, geol );
742  }
743  else
744  {
745  if( !load_storage.vertices_.empty() )
746  {
747  assign_mesh_surface( builder_, load_storage );
748  auto nb_vertices =
749  static_cast< index_t >( load_storage.vertices_.size() );
750  load_storage.tface_vertex_ptr_ = nb_vertices;
751  }
752  }
753  }
754 
755  void create_surface(
756  const std::string& interface_name, const std::string& type )
757  {
758  gmge_id parent = find_geological_entity(
759  geomodel_, Interface3D::type_name_static(), interface_name );
760  if( !interface_name.empty() )
761  {
762  ringmesh_assert( parent.is_defined() );
763  }
764 
765  gmme_id children = builder_.topology.create_mesh_entity(
766  Surface3D::type_name_static() );
767  builder_.geology.add_parent_children_relation( parent, children );
768  builder_.geology.set_geological_entity_geol_feature( parent,
769  GeoModelGeologicalEntity3D::determine_geological_type( type ) );
770  }
771  };
772 
773  class LoadLayer final : public MLLineParser
774  {
775  public:
776  LoadLayer( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
777  : MLLineParser( gm_builder, geomodel )
778  {
779  }
780 
781  private:
782  void execute(
783  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
784  {
785  ringmesh_unused( load_storage );
788  gmge_id layer_id = builder_.geology.create_geological_entity(
789  Layer3D::type_name_static() );
790  builder_.info.set_geological_entity_name(
791  layer_id, line.field( 1 ) );
792  bool end_layer = false;
793  while( !end_layer )
794  {
795  line.get_line();
796  line.get_fields();
797  for( auto i : range( 5 ) )
798  {
799  index_t region_id = line.field_as_uint( i );
800  if( region_id == 0 )
801  {
802  end_layer = true;
803  break;
804  }
805  // Remove Universe region
806  region_id -= geomodel_.nb_surfaces() + 1;
807  // Correction because ids begin at 1 in the file
808  builder_.geology.add_parent_children_relation(
809  layer_id, gmme_id( Region3D::type_name_static(),
810  region_id - GOCAD_OFFSET ) );
811  }
812  }
813  }
814  };
815 
816  class MLEndSection final : public MLLineParser
817  {
818  public:
819  MLEndSection( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
820  : MLLineParser( gm_builder, geomodel )
821  {
822  }
823 
824  private:
825  void execute(
826  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
827  {
828  ringmesh_unused( line );
829  if( !load_storage.is_header_read_ )
830  {
831  load_storage.is_header_read_ = true;
832  }
833  else
834  {
835  assign_mesh_surface( builder_, load_storage );
836  load_storage.vertices_.clear();
837  load_storage.tface_vertex_ptr_ = 0;
838  }
839  }
840  };
841 
842  class LoadCorner final : public MLLineParser
843  {
844  public:
845  LoadCorner( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
846  : MLLineParser( gm_builder, geomodel )
847  {
848  }
849 
850  private:
851  void execute(
852  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
853  {
854  index_t v_id = line.field_as_uint( 1 ) - GOCAD_OFFSET;
855  if( !find_corner( geomodel_, load_storage.vertices_[v_id] )
856  .is_defined() )
857  {
858  // Create the corner
859  gmme_id corner_gme = builder_.topology.create_mesh_entity(
860  Corner3D::type_name_static() );
861  builder_.geometry.set_corner(
862  corner_gme.index(), load_storage.vertices_[v_id] );
863  }
864  }
865  };
866 
867  class LoadMLRegion final : public MLLineParser
868  {
869  public:
870  LoadMLRegion( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
871  : MLLineParser( gm_builder, geomodel )
872  {
873  }
874 
875  private:
876  void execute(
877  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
878  {
879  ringmesh_unused( load_storage );
882  std::string name = read_name_with_spaces( 2, line );
883 
884  std::vector< std::pair< index_t, bool > > region_boundaries =
885  get_region_boundaries( line );
886 
887  // Create the entity if it is not the universe
888  // Set the region name and boundaries
889  if( name != "Universe" )
890  {
891  gmme_id region_id = builder_.topology.create_mesh_entity(
892  Region3D::type_name_static() );
893  builder_.info.set_mesh_entity_name( region_id, name );
894  for( const std::pair< index_t, bool >& info :
895  region_boundaries )
896  {
897  gmme_id surface_id(
898  Surface3D::type_name_static(), info.first );
899  builder_.topology.add_mesh_entity_boundary_relation(
900  region_id, surface_id, info.second );
901  }
902  }
903  }
904 
905  std::vector< std::pair< index_t, bool > > get_region_boundaries(
906  GEO::LineInput& line )
907  {
908  std::vector< std::pair< index_t, bool > > region_boundaries;
909  bool end_region = false;
910  while( !end_region )
911  {
912  line.get_line();
913  line.get_fields();
914  for( auto i : range( 5 ) )
915  {
916  signed_index_t signed_id = line.field_as_int( i );
917  if( signed_id == 0 )
918  {
919  end_region = true;
920  break;
921  }
922  bool side = signed_id > 0;
923  auto id = static_cast< index_t >( std::abs( signed_id ) )
924  - GOCAD_OFFSET;
925  region_boundaries.emplace_back( id, side );
926  }
927  }
928  return region_boundaries;
929  }
930  };
931 
932  class LoadRegion : public TSolidLineParser
933  {
934  public:
935  LoadRegion( GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
936  : TSolidLineParser( gm_builder, geomodel )
937  {
938  }
939 
940  protected:
949  index_t initialize_region( const std::string& region_name,
950  GeoModelBuilderGocad& geomodel_builder ) const
951  {
952  gmme_id cur_region = geomodel_builder.topology.create_mesh_entity(
953  Region3D::type_name_static() );
954  geomodel_builder.info.set_mesh_entity_name(
955  cur_region, region_name );
956  return cur_region.index();
957  }
958  };
959 
960  class LoadTSolidRegion final : public LoadRegion
961  {
962  public:
963  LoadTSolidRegion(
964  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
965  : LoadRegion( gm_builder, geomodel )
966  {
967  }
968 
969  private:
970  void execute(
971  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
972  {
973  if( !load_storage.vertices_.empty() )
974  {
975  builder_.geometry.set_region_geometry( load_storage.cur_region_,
976  load_storage.vertices_, load_storage.tetra_corners_ );
977  assign_attributes_to_mesh(
978  geomodel_.region( load_storage.cur_region_ ), load_storage,
979  load_storage.attributes_ );
980  }
981 
982  std::string region_name;
983  if( line.nb_fields() == 1 )
984  {
985  region_name = "Unnamed";
986  }
987  else
988  {
989  region_name = line.field( 1 );
990  }
991 
992  load_storage.attributes_.clear();
993  load_storage.cur_region_ =
994  initialize_region( region_name, builder_ );
995  load_storage.vertices_.clear();
996  load_storage.tetra_corners_.clear();
997  }
998  void execute_light(
999  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1000  {
1001  ringmesh_unused( line );
1002  ringmesh_unused( load_storage );
1003  // Nothing
1004  }
1005  };
1006 
1007  class LoadLightTSolidRegion final : public LoadRegion
1008  {
1009  public:
1010  LoadLightTSolidRegion(
1011  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1012  : LoadRegion( gm_builder, geomodel )
1013  {
1014  }
1015 
1016  private:
1017  void execute(
1018  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1019  {
1020  ringmesh_unused( line );
1021  ringmesh_unused( load_storage );
1022  // Nothing
1023  }
1024  void execute_light(
1025  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1026  {
1027  std::string region_name = line.field( 2 );
1028 
1029  // Record new regions
1030  bool found;
1031  index_t region_id;
1032  std::tie( found, region_id ) =
1034  region_name );
1035  if( !found )
1036  {
1037  region_id = initialize_region( region_name, builder_ );
1038  load_storage.vertex_map_.add_new_region(
1039  region_id, region_name );
1040  }
1041 
1043  load_storage.cur_gocad_vrtx_id1_, region_id );
1045  load_storage.cur_gocad_vrtx_id2_, region_id );
1047  load_storage.cur_gocad_vrtx_id3_, region_id );
1049  load_storage.cur_gocad_vrtx_id4_, region_id );
1050  }
1051  };
1052 
1053  class LoadVertex final : public GocadLineParser
1054  {
1055  public:
1056  LoadVertex( GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
1057  : GocadLineParser( gm_builder, geomodel )
1058  {
1059  }
1060 
1061  private:
1062  void execute(
1063  GEO::LineInput& line, GocadLoadingStorage& load_storage ) final
1064  {
1065  vec3 vertex =
1066  read_vertex_coordinates( line, 2, load_storage.z_sign_ );
1067  load_storage.vertices_.push_back( vertex );
1068  if( load_storage.nb_attribute_fields_ > 0 )
1069  {
1070  std::vector< double > attribute = read_vertex_attributes(
1071  line, 5, load_storage.nb_attribute_fields_ );
1072  load_storage.attributes_.push_back( attribute );
1073  }
1074  }
1075  };
1076 
1077  class LoadMLAtom final : public MLLineParser
1078  {
1079  public:
1080  LoadMLAtom( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
1081  : MLLineParser( gm_builder, geomodel )
1082  {
1083  }
1084 
1085  private:
1086  void execute(
1087  GEO::LineInput& line, MLLoadingStorage& load_storage ) final
1088  {
1089  index_t vertex_id = line.field_as_uint( 2 ) - GOCAD_OFFSET;
1090  const vec3& vertex = load_storage.vertices_[vertex_id];
1091  load_storage.vertices_.push_back( vertex );
1092  }
1093  };
1094 
1095  class LoadAttributeTSolid final : public TSolidLineParser
1096  {
1097  public:
1098  LoadAttributeTSolid(
1099  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1100  : TSolidLineParser( gm_builder, geomodel )
1101  {
1102  }
1103 
1104  private:
1105  void execute(
1106  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1107  {
1108  load_storage.vertex_attribute_names_.reserve(
1109  line.nb_fields() - 1 );
1110  for( auto attrib_name_itr : range( 1, line.nb_fields() ) )
1111  {
1112  load_storage.vertex_attribute_names_.emplace_back(
1113  line.field( attrib_name_itr ) );
1114  }
1115  }
1116  void execute_light(
1117  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1118  {
1119  execute( line, load_storage );
1120  }
1121  };
1122 
1123  class LoadAttributeDimensionTSolid final : public TSolidLineParser
1124  {
1125  public:
1126  LoadAttributeDimensionTSolid(
1127  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1128  : TSolidLineParser( gm_builder, geomodel )
1129  {
1130  }
1131 
1132  private:
1133  void execute(
1134  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1135  {
1136  load_storage.vertex_attribute_dims_.reserve( line.nb_fields() - 1 );
1137  for( auto attrib_size_itr : range( 1, line.nb_fields() ) )
1138  {
1139  load_storage.vertex_attribute_dims_.push_back(
1140  line.field_as_uint( attrib_size_itr ) );
1141  load_storage.nb_attribute_fields_ +=
1142  line.field_as_uint( attrib_size_itr );
1143  }
1144  }
1145  void execute_light(
1146  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1147  {
1148  execute( line, load_storage );
1149  }
1150  };
1151 
1152  class LoadTSolidVertex final : public TSolidLineParser
1153  {
1154  public:
1155  LoadTSolidVertex(
1156  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1157  : TSolidLineParser( gm_builder, geomodel )
1158  {
1159  }
1160 
1161  private:
1162  void execute(
1163  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1164  {
1165  auto vertex_id =
1166  static_cast< index_t >( load_storage.vertices_.size() );
1167  load_storage.vertex_map_.add_vertex(
1168  vertex_id, load_storage.cur_region_ );
1169  GocadLineFactory::create( "VRTX", builder_, geomodel_ )
1170  ->execute( line, load_storage );
1171  }
1172  void execute_light(
1173  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1174  {
1175  load_storage.vertex_map_.add_vertex(
1176  line.field_as_uint( 1 ) - GOCAD_OFFSET,
1177  load_storage.cur_region_ );
1178  GocadLineFactory::create( "VRTX", builder_, geomodel_ )
1179  ->execute( line, load_storage );
1180  }
1181  };
1182 
1183  class LoadTSAtomic final : public TSolidLineParser
1184  {
1185  public:
1186  LoadTSAtomic( GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1187  : TSolidLineParser( gm_builder, geomodel )
1188  {
1189  }
1190 
1191  private:
1192  void execute(
1193  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1194  {
1195  read_and_add_atom_to_region_vertices( geomodel_, line, load_storage,
1196  load_storage.vertices_, load_storage.attributes_,
1197  load_storage.vertex_map_ );
1198  }
1199  void execute_light(
1200  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1201  {
1202  load_storage.lighttsolid_atom_map_.emplace(
1203  line.field_as_uint( 1 ) - GOCAD_OFFSET,
1204  line.field_as_uint( 2 ) - GOCAD_OFFSET );
1205  load_storage.vertex_map_.add_vertex(
1206  line.field_as_uint( 1 ) - GOCAD_OFFSET,
1207  load_storage.cur_region_ );
1208  load_storage.vertices_.emplace_back( vec3{} );
1209  if( load_storage.nb_attribute_fields_ > 0 )
1210  {
1211  std::vector< double > null_attrib(
1212  load_storage.nb_attribute_fields_, 0 );
1213  load_storage.attributes_.push_back( null_attrib );
1214  }
1215  }
1216 
1230  void read_and_add_atom_to_region_vertices( const GeoModel3D& geomodel,
1231  const GEO::LineInput& line,
1232  const TSolidLoadingStorage& load_storage,
1233  std::vector< vec3 >& region_vertices,
1234  std::vector< std::vector< double > >& region_attributes,
1235  VertexMap& vertex_map )
1236  {
1237  const index_t referring_vertex =
1238  line.field_as_uint( 2 ) - GOCAD_OFFSET;
1239  const index_t referred_vertex_local_id =
1240  vertex_map.local_id( referring_vertex );
1241  const index_t referred_vertex_region_id =
1242  vertex_map.region( referring_vertex );
1243  if( referred_vertex_region_id < load_storage.cur_region_ )
1244  {
1245  // If the atom referred to a vertex of another region,
1246  // acting like for a vertex
1247  auto index = static_cast< index_t >( region_vertices.size() );
1248  vertex_map.add_vertex( index, load_storage.cur_region_ );
1249 
1250  region_vertices.push_back(
1251  geomodel.region( referred_vertex_region_id )
1252  .vertex( referred_vertex_local_id ) );
1253 
1254  std::vector< double > attribute_v;
1255  for( auto attrib_itr :
1256  range( load_storage.vertex_attribute_names_.size() ) )
1257  {
1258  std::string name =
1259  load_storage.vertex_attribute_names_[attrib_itr];
1260  index_t dim =
1261  load_storage.vertex_attribute_dims_[attrib_itr];
1262  GEO::Attribute< double > attr(
1263  geomodel.region( referred_vertex_region_id )
1264  .vertex_attribute_manager(),
1265  name );
1266  for( auto dim_itr : range( dim ) )
1267  {
1268  attribute_v.push_back(
1269  attr[referred_vertex_local_id * dim + dim_itr] );
1270  }
1271  }
1272  region_attributes.push_back( attribute_v );
1273  }
1274  else
1275  {
1276  // If the atom referred to an atom of the same region
1277  vertex_map.add_vertex(
1278  referred_vertex_local_id, referred_vertex_region_id );
1279  }
1280  }
1281  };
1282 
1283  class LoadTetra final : public TSolidLineParser
1284  {
1285  public:
1286  LoadTetra( GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1287  : TSolidLineParser( gm_builder, geomodel )
1288  {
1289  }
1290 
1291  private:
1292  void execute(
1293  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1294  {
1295  std::vector< index_t > corners =
1296  read_tetraedra( line, load_storage.vertex_map_ );
1297  load_storage.tetra_corners_.insert(
1298  load_storage.tetra_corners_.end(), corners.begin(),
1299  corners.end() );
1300  }
1301  void execute_light(
1302  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1303  {
1304  load_storage.cur_gocad_vrtx_id1_ =
1305  line.field_as_uint( 1 ) - GOCAD_OFFSET;
1306  load_storage.cur_gocad_vrtx_id2_ =
1307  line.field_as_uint( 2 ) - GOCAD_OFFSET;
1308  load_storage.cur_gocad_vrtx_id3_ =
1309  line.field_as_uint( 3 ) - GOCAD_OFFSET;
1310  load_storage.cur_gocad_vrtx_id4_ =
1311  line.field_as_uint( 4 ) - GOCAD_OFFSET;
1312  }
1313 
1325  std::vector< index_t > read_tetraedra(
1326  const GEO::LineInput& in, const VertexMap& vertex_map )
1327  {
1328  std::vector< index_t > corners_id( 4 );
1329  ringmesh_assert( corners_id.size() == 4 );
1330  corners_id[0] =
1331  vertex_map.local_id( in.field_as_uint( 1 ) - GOCAD_OFFSET );
1332  corners_id[1] =
1333  vertex_map.local_id( in.field_as_uint( 2 ) - GOCAD_OFFSET );
1334  corners_id[2] =
1335  vertex_map.local_id( in.field_as_uint( 3 ) - GOCAD_OFFSET );
1336  corners_id[3] =
1337  vertex_map.local_id( in.field_as_uint( 4 ) - GOCAD_OFFSET );
1338  return corners_id;
1339  }
1340  };
1341 
1342  class LoadName final : public GocadLineParser
1343  {
1344  public:
1345  LoadName( GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
1346  : GocadLineParser( gm_builder, geomodel )
1347  {
1348  }
1349 
1350  private:
1351  void execute(
1352  GEO::LineInput& line, GocadLoadingStorage& load_storage ) final
1353  {
1354  ringmesh_unused( load_storage );
1355  // Set to the GeoModel name if empty
1356  if( geomodel_.name().empty() )
1357  {
1358  builder_.info.set_geomodel_name(
1359  read_name_with_spaces( 1, line ) );
1360  }
1361  }
1362  };
1363 
1364  class LoadLastRegion final : public TSolidLineParser
1365  {
1366  public:
1367  LoadLastRegion(
1368  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1369  : TSolidLineParser( gm_builder, geomodel )
1370  {
1371  }
1372 
1373  private:
1374  void execute(
1375  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1376  {
1377  ringmesh_unused( line );
1378  if( !load_storage.vertices_.empty() )
1379  {
1380  builder_.geometry.set_region_geometry( load_storage.cur_region_,
1381  load_storage.vertices_, load_storage.tetra_corners_ );
1382  assign_attributes_to_mesh(
1383  geomodel_.region( load_storage.cur_region_ ), load_storage,
1384  load_storage.attributes_ );
1385 
1386  load_storage.attributes_.clear();
1387  load_storage.vertices_.clear();
1388  load_storage.tetra_corners_.clear();
1389  }
1390  }
1391  void execute_light(
1392  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1393  {
1394  ringmesh_unused( line );
1395  get_light_tsolid_workflow_to_catch_up_with_tsolid_workflow(
1396  load_storage );
1397  // End of LightTSolid peculiar processing
1398  }
1399 
1400  std::vector< index_t > get_region_local_indices(
1401  const std::vector< VertexMap::RegionLocalVertex >&
1402  region_local_vertices )
1403  {
1404  std::vector< index_t > result;
1405  result.reserve( region_local_vertices.size() );
1406  for( auto& vertex : region_local_vertices )
1407  {
1408  result.push_back( vertex.local_id );
1409  }
1410  return result;
1411  }
1412  std::vector< vec3 > get_region_vertices(
1413  const std::vector< VertexMap::RegionLocalVertex >&
1414  region_local_vertices )
1415  {
1416  std::vector< vec3 > result;
1417  result.reserve( region_local_vertices.size() );
1418  for( auto& vertex : region_local_vertices )
1419  {
1420  result.push_back( vertex.tetra_vertex );
1421  }
1422  return result;
1423  }
1424 
1425  void get_light_tsolid_workflow_to_catch_up_with_tsolid_workflow(
1426  TSolidLoadingStorage& load_storage )
1427  {
1429 
1430  std::vector< std::vector< index_t > > region_tetra_corners_local;
1431  std::vector< std::vector< vec3 > > region_vertices;
1432  std::vector< std::vector< std::vector< double > > >
1433  region_attributes;
1434 
1435  region_tetra_corners_local.resize(
1436  load_storage.vertex_map_.nb_regions() );
1437  region_vertices.resize( load_storage.vertex_map_.nb_regions() );
1438  region_attributes.resize( load_storage.vertex_map_.nb_regions() );
1439  load_storage.vertex_map_.local_ids_.resize(
1440  load_storage.vertex_map_.nb_regions() );
1441 
1442  for( auto region_id : load_storage.vertex_map_.get_regions() )
1443  {
1444  ringmesh_assert( !load_storage.vertices_.empty() );
1446  std::vector< VertexMap::RegionLocalVertex >
1447  region_local_indices =
1448  load_storage.vertex_map_
1450  load_storage.vertices_, region_id,
1451  load_storage.lighttsolid_atom_map_ );
1452  region_vertices[region_id] =
1453  get_region_vertices( region_local_indices );
1454  load_storage.vertex_map_.local_ids_[region_id] =
1455  get_region_local_indices( region_local_indices );
1456  if( load_storage.nb_attribute_fields_ > 0 )
1457  {
1458  load_storage.vertex_map_
1460  load_storage.attributes_, region_id,
1461  load_storage.lighttsolid_atom_map_,
1462  region_attributes[region_id] );
1463  }
1464  }
1465 
1468  load_storage.lighttsolid_atom_map_ );
1469 
1470  for( auto region_id : load_storage.vertex_map_.get_regions() )
1471  {
1474  region_id, region_tetra_corners_local[region_id] );
1475 
1476  builder_.geometry.set_region_geometry( region_id,
1477  region_vertices[region_id],
1478  region_tetra_corners_local[region_id] );
1479 
1480  assign_attributes_to_mesh( geomodel_.region( region_id ),
1481  load_storage, region_attributes[region_id] );
1482  }
1483  load_storage.tetra_corners_.clear();
1484  load_storage.attributes_.clear();
1485  load_storage.vertices_.clear();
1486  load_storage.lighttsolid_atom_map_.clear();
1487  }
1488  };
1489 
1490  class LoadInterface final : public TSolidLineParser
1491  {
1492  public:
1493  LoadInterface( GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1494  : TSolidLineParser( gm_builder, geomodel )
1495  {
1496  }
1497 
1498  private:
1499  void execute(
1500  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1501  {
1502  gmge_id created_interface =
1503  builder_.geology.create_geological_entity(
1504  Interface3D::type_name_static() );
1505  load_storage.cur_interface_ = created_interface.index();
1506  builder_.info.set_geological_entity_name(
1507  created_interface, line.field( 1 ) );
1508  }
1509  void execute_light(
1510  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1511  {
1512  // LightTSolid Interface processing : same as TSolid processing
1513  execute( line, load_storage );
1514  }
1515  };
1516 
1517  class LoadSurface final : public TSolidLineParser
1518  {
1519  public:
1520  LoadSurface( GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1521  : TSolidLineParser( gm_builder, geomodel )
1522  {
1523  }
1524 
1525  private:
1526  void execute(
1527  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1528  {
1529  ringmesh_unused( line );
1530  // Compute the surface
1531  if( !load_storage.cur_surf_polygon_corners_gocad_id_.empty() )
1532  {
1533  build_surface( builder_, geomodel_, load_storage );
1534  }
1535  // Create a new surface
1536  gmme_id new_surface = builder_.topology.create_mesh_entity(
1537  Surface3D::type_name_static() );
1538  load_storage.cur_surface_ = new_surface.index();
1539  builder_.geology.add_parent_children_relation(
1540  gmge_id( Interface3D::type_name_static(),
1541  load_storage.cur_interface_ ),
1542  new_surface );
1543  }
1544  void execute_light(
1545  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1546  {
1547  // LightTSolid Surface processing : same as TSolid processing
1548  execute( line, load_storage );
1549  }
1550  };
1551 
1552  class LoadLastSurface final : public TSolidLineParser
1553  {
1554  public:
1555  LoadLastSurface(
1556  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1557  : TSolidLineParser( gm_builder, geomodel )
1558  {
1559  }
1560 
1561  private:
1562  void execute(
1563  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1564  {
1565  ringmesh_unused( line );
1566  // Compute the last surface
1567  if( !load_storage.cur_surf_polygon_corners_gocad_id_.empty() )
1568  {
1569  build_surface( builder_, geomodel_, load_storage );
1570  }
1571  }
1572  void execute_light(
1573  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) final
1574  {
1575  // LightTSolid LastSurface processing : same as TSolid processing
1576  execute( line, load_storage );
1577  }
1578  };
1579 
1580  class LoadTriangle final : public GocadLineParser
1581  {
1582  public:
1583  LoadTriangle( GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
1584  : GocadLineParser( gm_builder, geomodel )
1585  {
1586  }
1587 
1588  private:
1589  void execute(
1590  GEO::LineInput& line, GocadLoadingStorage& load_storage ) final
1591  {
1592  read_triangle(
1593  line, load_storage.cur_surf_polygon_corners_gocad_id_ );
1594  load_storage.end_polygon();
1595  }
1596 
1605  void read_triangle( const GEO::LineInput& in,
1606  std::vector< index_t >& cur_surf_polygons )
1607  {
1608  cur_surf_polygons.push_back( in.field_as_uint( 1 ) - GOCAD_OFFSET );
1609  cur_surf_polygons.push_back( in.field_as_uint( 2 ) - GOCAD_OFFSET );
1610  cur_surf_polygons.push_back( in.field_as_uint( 3 ) - GOCAD_OFFSET );
1611  }
1612  };
1613 
1614  void tsolid_import_factory_initialize()
1615  {
1616  TSolidLineFactory::register_creator< LoadTSolidRegion >( "TVOLUME" );
1617  TSolidLineFactory::register_creator< LoadLightTSolidRegion >( "#" );
1618  TSolidLineFactory::register_creator< LoadAttributeTSolid >(
1619  "PROPERTIES" );
1620  TSolidLineFactory::register_creator< LoadAttributeDimensionTSolid >(
1621  "ESIZES" );
1622  TSolidLineFactory::register_creator< LoadTSolidVertex >( "VRTX" );
1623  TSolidLineFactory::register_creator< LoadTSolidVertex >( "PVRTX" );
1624  TSolidLineFactory::register_creator< LoadTSAtomic >( "SHAREDVRTX" );
1625  TSolidLineFactory::register_creator< LoadTSAtomic >( "SHAREDPVRTX" );
1626  TSolidLineFactory::register_creator< LoadTSAtomic >( "ATOM" );
1627  TSolidLineFactory::register_creator< LoadTSAtomic >( "PATOM" );
1628  TSolidLineFactory::register_creator< LoadTetra >( "TETRA" );
1629  TSolidLineFactory::register_creator< LoadLastRegion >( "MODEL" );
1630  TSolidLineFactory::register_creator< LoadInterface >( "SURFACE" );
1631  TSolidLineFactory::register_creator< LoadSurface >( "TFACE" );
1632  TSolidLineFactory::register_creator< LoadLastSurface >( "END" );
1633  }
1634 
1635  void ml_import_factory_initialize()
1636  {
1637  MLLineFactory::register_creator< LoadTSurf >( "TSURF" );
1638  MLLineFactory::register_creator< LoadMLSurface >( "TFACE" );
1639  MLLineFactory::register_creator< LoadMLRegion >( "REGION" );
1640  MLLineFactory::register_creator< LoadLayer >( "LAYER" );
1641  MLLineFactory::register_creator< MLEndSection >( "END" );
1642  MLLineFactory::register_creator< LoadMLAtom >( "ATOM" );
1643  MLLineFactory::register_creator< LoadMLAtom >( "PATOM" );
1644  }
1645 
1646 } // namespace
1647 namespace RINGMesh
1648 {
1651  Factory< std::string,
1654  GeoModel3D& >
1656 
1658  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel )
1659  : GocadBaseParser( gm_builder, geomodel )
1660  {
1661  }
1663  GeoModelBuilderML& gm_builder, GeoModel3D& geomodel )
1664  : GocadBaseParser( gm_builder, geomodel )
1665  {
1666  }
1667 
1669  {
1670  while( !file_line_.eof() && file_line_.get_line() )
1671  {
1672  file_line_.get_fields();
1673  if( file_line_.nb_fields() > 0 )
1674  {
1675  read_line();
1676  }
1677  }
1678  }
1679 
1681  {
1682  cur_surf_polygon_ptr_.push_back( 0 );
1683  }
1684 
1686  GeoModel3D& geomodel, std::string filename )
1687  : GeoModelBuilderGocad( geomodel, std::move( filename ) )
1688  {
1690  *this, geomodel, file_line_, tsolid_load_storage_ ) );
1692  *this, geomodel, file_line_, tsolid_load_storage_ ) );
1693  }
1694 
1696  {
1697  GEO::LineInput line( filename_ );
1699  while( !line.eof() && line.get_line() )
1700  {
1701  line.get_fields();
1702  if( line.nb_fields() > 0 )
1703  {
1704  if( line.field_matches( 0, "VRTX" )
1705  || line.field_matches( 0, "PVRTX" )
1706  || line.field_matches( 0, "PATOM" )
1707  || line.field_matches( 0, "ATOM" )
1708  || line.field_matches( 0, "SHAREDPVRTX" )
1709  || line.field_matches( 0, "SHAREDVRTX" ) )
1710  {
1712  }
1713  }
1714  }
1717  }
1718 
1720  {
1721  read_file();
1722  // Compute internal borders (by removing adjacencies on
1723  // triangle edges common to at least two surfaces)
1726  compute_boundaries_of_geomodel_regions( *this, ( *this ).geomodel_ );
1727  geology.build_contacts();
1728  }
1729 
1731  {
1732  GEO::LineInput line( filename_ );
1733  while( !line.eof() && line.get_line() )
1734  {
1735  line.get_fields();
1736  if( line.nb_fields() > 0 )
1737  {
1738  if( line.field_matches( 0, "GOCAD" ) )
1739  {
1740  if( line.field_matches( 1, "TSolid" ) )
1741  {
1743  }
1744  else
1745  {
1747  line.field_matches( 1, "LightTSolid" ) );
1749  }
1750  break;
1751  }
1752  }
1753  }
1754  }
1755 
1757  {
1758  read_type();
1761  }
1762 
1764  {
1766  tsolid_load_storage_.nb_vertices_ ); // Exactly
1768  tsolid_load_storage_.nb_vertices_ ); // At least
1769  type_impl_[static_cast< index_t >( file_type_ )]->read_line();
1770  }
1771 
1773  index_t surface_id,
1774  const std::vector< std::unique_ptr< NNSearch3D > >& surface_nns,
1775  const std::vector< Box3D >& surface_boxes )
1776  {
1777  const Surface3D& surface = geomodel_.surface( surface_id );
1778  const SurfaceMesh3D& mesh = surface.mesh();
1779 
1780  for( index_t p : range( surface.nb_mesh_elements() ) )
1781  {
1782  std::vector< index_t > adjacent_polygons_id( 3 );
1783  for( index_t e : range( 3 ) )
1784  {
1785  adjacent_polygons_id[e] =
1786  surface.polygon_adjacent_index( PolygonLocalEdge( p, e ) );
1787  if( !mesh.is_edge_on_border( PolygonLocalEdge( p, e ) ) )
1788  {
1789  bool internal_border =
1790  is_edge_in_several_surfaces( geomodel_, surface_id, p,
1791  e, surface_nns, surface_boxes );
1792  if( internal_border )
1793  {
1794  adjacent_polygons_id[e] = NO_ID;
1795  }
1796  }
1797  }
1798  geometry.set_surface_element_adjacency(
1799  surface_id, p, adjacent_polygons_id );
1800  }
1801  }
1802 
1805  std::vector< std::unique_ptr< NNSearch3D > >& surface_nns,
1806  std::vector< Box3D >& surface_boxes ) const
1807  {
1808  surface_nns.resize( geomodel_.nb_surfaces() );
1809  surface_boxes.resize( geomodel_.nb_surfaces() );
1810 
1811  for( const auto& surface : geomodel_.surfaces() )
1812  {
1813  for( index_t v : range( surface.nb_vertices() ) )
1814  {
1815  surface_boxes[surface.index()].add_point( surface.vertex( v ) );
1816  }
1817  std::vector< vec3 > border_edge_barycenters =
1818  get_surface_border_edge_barycenters(
1819  geomodel_, surface.index() );
1820  surface_nns[surface.index()].reset(
1821  new NNSearch3D( border_edge_barycenters, true ) );
1822  }
1823  }
1824 
1826  {
1827  std::vector< std::unique_ptr< NNSearch3D > > nn_searchs;
1828  std::vector< Box3D > boxes;
1830  for( const auto& surface : geomodel_.surfaces() )
1831  {
1833  surface.index(), nn_searchs, boxes );
1834  }
1835  }
1836 
1837  /*************************************************************************/
1838 
1840  {
1841  cur_surface_ = 0;
1842  }
1843 
1845  {
1846  read_file();
1847  geomodel_.mesh.vertices.test_and_initialize();
1849  geology.build_contacts();
1850  }
1851 
1853  {
1854  std::string keyword = file_line_.field( 0 );
1855  std::unique_ptr< MLLineParser > tsolid_parser(
1856  MLLineFactory::create( keyword, *this, geomodel_ ) );
1857  if( tsolid_parser )
1858  {
1859  tsolid_parser->execute( file_line_, ml_load_storage_ );
1860  }
1861  else
1862  {
1863  std::unique_ptr< GocadLineParser > gocad_parser =
1864  GocadLineFactory::create( keyword, *this, geomodel_ );
1865  if( gocad_parser )
1866  {
1867  gocad_parser->execute( file_line_, ml_load_storage_ );
1868  }
1869  }
1870  }
1871 
1873  {
1874  GocadLineFactory::register_creator< LoadZSign >( "ZPOSITIVE" );
1875  GocadLineFactory::register_creator< LoadVertex >( "VRTX" );
1876  GocadLineFactory::register_creator< LoadVertex >( "PVRTX" );
1877  GocadLineFactory::register_creator< LoadName >( "name:" );
1878  GocadLineFactory::register_creator< LoadTriangle >( "TRGL" );
1879  tsolid_import_factory_initialize();
1880  ml_import_factory_initialize();
1881  }
1882 } // namespace RINGMesh
void end_polygon()
Ends a polygon (by adding the size of list of polygon corners at the end of the vector) ...
Factory< std::string, MLLineParser, GeoModelBuilderML &, GeoModel3D &> ml_factory
static std::unique_ptr< BaseClass > create(const Key &key, const Args &... args)
Definition: factory.h:85
std::vector< std::vector< double > > attributes_
GeoModel< DIMENSION > & geomodel_
GeoModelBuilderGeometry< DIMENSION > geometry
The GeologicalEntityType described the type of the Geological entities User can defined there own Geo...
Definition: entity_type.h:137
vecn< 3 > vec3
Definition: types.h:76
Structure used to load a GeoModel by GeoModelBuilderTSolid.
void reserve(index_t capacity)
index_t local_id(index_t gocad_vertex_id) const
void get_vertices_attributes_list_from_gocad_ids(const std::vector< std::vector< double > > &stored_attributes, index_t region_id, const std::map< index_t, index_t > &lighttsolid_atom_map, std::vector< std::vector< double > > &region_tetra_attributes) const
void get_tetra_corners_with_this_region_id(index_t region_id, std::vector< index_t > &region_tetra_corners_local) const
void ringmesh_unused(const T &)
Definition: common.h:105
GeoModelBuilderTopology< DIMENSION > topology
index_t tface_vertex_ptr_
Offset to read in the tface vertices in the tsurf vertices.
static void warn(const std::string &feature, const Args &... args)
Definition: logger.h:75
void RINGMESH_API initialize_gocad_import_factories()
const std::vector< index_t > & get_regions() const
std::tuple< bool, index_t > find_region_id_from_name(const std::string &region_name)
GeoModelBuilderTSolid(GeoModel3D &geomodel, std::string filename)
geol_entity_range< DIMENSION > geol_entities(const GeologicalEntityType &geol_type) const
Definition: geomodel.h:341
void load_file() final
Loads and builds a GeoModel from a Gocad .ml file.
std::map< index_t, index_t > lighttsolid_atom_map_
Build a GeoModel from a Gocad Model3D (file_model.ml)
void record_vertex_with_its_region(index_t gocad_vertex_id, index_t region_id)
index_t region(index_t gocad_vertex_id) const
Factory< std::string, TSolidLineParser, GeoModelBuilderTSolid &, GeoModel3D &> tsolid_factory
std::vector< index_t > vertex_attribute_dims_
void compute_polygon_edge_centers_nn_and_surface_boxes(std::vector< std::unique_ptr< NNSearch3D > > &surface_nns, std::vector< Box3D > &surface_boxes) const
Computes the NNSearchs of the centers of polygon edges for each surface and their Box3d...
MLLineParser(GeoModelBuilderML &gm_builder, GeoModel3D &geomodel)
std::array< std::unique_ptr< GeoModelBuilderTSolidImpl >, NB_TYPE > type_impl_
Builds a meshed GeoModel from a Gocad TSolid (file.so)
GeoModelBuilderGeology< DIMENSION > geology
bool is_defined() const
Definition: entity_type.h:275
#define ringmesh_assert(x)
void add_vertex(index_t local_vertex_id, index_t region_id)
void compute_surfaces_internal_borders()
Computes internal borders of the geomodel surfaces.
bool contains(const container &in, const T &value)
Definition: algorithm.h:87
TSolidLineParser(GeoModelBuilderTSolid &gm_builder, GeoModel3D &geomodel)
GeoModelBuilderInfo< DIMENSION > info
vecn< DIMENSION > cell_facet_barycenter(const CellLocalFacet &cell_local_facet) const
Definition: mesh.h:1010
void add_new_region(index_t region_id, const std::string &region_name)
void reserve_nb_vertices(index_t capacity)
std::vector< std::string > vertex_attribute_names_
void read_file()
Parses the file and loads the GeoModel.
This template is a specialization of a gme_id to the GeoModelGeologicalEntity.
Definition: entity_type.h:262
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
void deal_with_same_region_atoms(const std::map< index_t, index_t > &lighttsolid_atom_map)
void compute_surface_internal_borders(index_t surface_id, const std::vector< std::unique_ptr< NNSearch3D > > &surface_nns, const std::vector< Box3D > &surface_boxes)
Computes internal borders of a given surface.
void read_line() final
Reads the first word of the current line (keyword) and executes the good action with the information ...
index_t index() const
Definition: entity_type.h:197
Structure which maps the vertex indices in Gocad::TSolid to the pair (region, index in region) in the...
std::vector< RegionLocalVertex > get_vertices_list_and_local_ids_from_gocad_ids(const std::vector< vec3 > &stored_vertices, const index_t region_id, const std::map< index_t, index_t > &lighttsolid_atom_map) const
This template is a specialization of a gme_id to the GeoModelMeshEntity.
Definition: entity_type.h:285
std::vector< std::vector< index_t > > local_ids_
std::vector< index_t > cur_surf_polygon_ptr_
void read_line() final
Reads the first word of the current line (keyword) and executes the good action with the information ...
std::vector< index_t > cur_surf_polygon_corners_gocad_id_
#define ringmesh_assert_not_reached