RINGMesh  Version 5.0.0
A programming library for geological model meshes
geomodel_builder_gocad.h
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 
36 #pragma once
37 
38 #include <ringmesh/basic/common.h>
39 
40 #include <array>
41 #include <memory>
42 
43 #include <geogram/basic/line_stream.h>
44 
45 #include <ringmesh/basic/factory.h>
46 
48 
49 namespace RINGMesh
50 {
51  class GeoModelBuilderTSolid;
52  class GeoModelBuilderTSolidImpl;
53  class GeoModelBuilderML;
54  struct VertexMap;
55  struct TSolidLoadingStorage;
56 } // namespace RINGMesh
57 
58 namespace RINGMesh
59 {
60  void RINGMESH_API initialize_gocad_import_factories();
61 
62  class RINGMESH_API GeoModelBuilderGocad : public GeoModelBuilderFile< 3 >
63  {
64  public:
65  GeoModelBuilderGocad( GeoModel3D& geomodel, std::string filename )
66  : GeoModelBuilderFile( geomodel, std::move( filename ) ),
67  file_line_( filename_ )
68  {
69  if( !file_line_.OK() )
70  {
71  throw RINGMeshException(
72  "I/O", "Failed to open file ", filename_ );
73  }
74  }
75 
83  void read_file();
84 
85  protected:
86  virtual void read_line() = 0;
87 
88  protected:
89  GEO::LineInput file_line_{ filename_ };
90  };
91 
93  {
95 
96  public:
97  virtual ~GocadBaseParser() = default;
98 
99  protected:
101  GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
102  : builder_( gm_builder ), geomodel_( geomodel )
103  {
104  }
105 
106  protected:
108  GeoModel3D& geomodel_;
109  };
110 
111  struct RINGMESH_API GocadLoadingStorage
112  {
114 
120  void end_polygon()
121  {
122  index_t nb_polygon_corners = static_cast< index_t >(
123  cur_surf_polygon_corners_gocad_id_.size() );
124  cur_surf_polygon_ptr_.push_back( nb_polygon_corners );
125  }
126 
127  // The orientation of positive Z
128  int z_sign_{ 1 };
129 
130  std::vector< vec3 > vertices_;
131 
132  std::vector< std::vector< double > > attributes_;
133 
134  // The vertices and the atoms
135  index_t nb_attribute_fields_{ 0 };
136 
137  // Current interface index
138  index_t cur_interface_{ NO_ID };
139 
140  // Current surface index
141  index_t cur_surface_{ NO_ID };
142 
143  // List of polygon corners for the current surface (gocad indices)
144  std::vector< index_t > cur_surf_polygon_corners_gocad_id_;
145 
146  // Starting indices (in cur_surf_polygons_corner_gocad_id_) of each
147  // polygon of the current surface
148  std::vector< index_t > cur_surf_polygon_ptr_;
149  };
150 
151  class RINGMESH_API GocadLineParser : public GocadBaseParser
152  {
153  public:
154  virtual void execute(
155  GEO::LineInput& line, GocadLoadingStorage& load_storage ) = 0;
156 
157  protected:
159  GeoModelBuilderGocad& gm_builder, GeoModel3D& geomodel )
160  : GocadBaseParser( gm_builder, geomodel )
161  {
162  }
163  };
164  using GocadLineFactory = Factory< std::string,
167  GeoModel3D& >;
168 
173  struct VertexMap
174  {
175  index_t gocad_vertex_id( index_t id ) const
176  {
177  ringmesh_assert( id < vertices_gocad_id_.size() );
178  return vertices_gocad_id_[id];
179  }
180 
181  index_t region_id( index_t id ) const
182  {
183  ringmesh_assert( id < vertices_region_id_.size() );
184  return vertices_region_id_[id];
185  }
186 
187  void add_new_region( index_t region_id, const std::string& region_name )
188  {
189  region_ids_.push_back( region_id );
190  region_names_.push_back( region_name );
191  }
192 
194  index_t gocad_vertex_id, index_t region_id )
195  {
196  vertices_gocad_id_.push_back( gocad_vertex_id );
197  vertices_region_id_.push_back( region_id );
198  }
199 
200  index_t nb_regions() const
201  {
202  ringmesh_assert( region_names_.size() == region_ids_.size() );
203  return static_cast< index_t >( region_ids_.size() );
204  }
205 
206  std::tuple< bool, index_t > find_region_id_from_name(
207  const std::string& region_name )
208  {
209  index_t region_id{ NO_ID };
210  for( auto i : range( region_names_.size() ) )
211  {
212  if( region_name.compare( region_names_[i] ) == 0 )
213  {
214  region_id = region_ids_[i];
215  ringmesh_assert( region_id != NO_ID );
216  return std::make_tuple( true, region_id );
217  }
218  }
219  return std::make_tuple( false, region_id );
220  }
221 
222  const std::vector< index_t >& get_regions() const
223  {
224  return region_ids_;
225  }
226 
227  void get_tetra_corners_with_this_region_id( index_t region_id,
228  std::vector< index_t >& region_tetra_corners_local ) const
229  {
230  index_t counter{ 0 };
231  for( auto tetra_region_id : vertices_region_id_ )
232  {
233  if( tetra_region_id == region_id )
234  {
235  region_tetra_corners_local.push_back(
236  local_id( vertices_gocad_id_[counter] ) );
237  }
238  counter++;
239  }
240  }
241 
243  const std::vector< std::vector< double > >& stored_attributes,
244  index_t region_id,
245  const std::map< index_t, index_t >& lighttsolid_atom_map,
246  std::vector< std::vector< double > >& region_tetra_attributes )
247  const
248  {
250  stored_attributes.size() == gocad_ids2region_ids_.size() );
251  for( auto gocad_id : range( stored_attributes.size() ) )
252  {
253  if( gocad_ids2region_ids_[gocad_id] == region_id )
254  {
255  if( lighttsolid_atom_map.find( gocad_id )
256  == lighttsolid_atom_map.end() )
257  {
258  region_tetra_attributes.push_back(
259  stored_attributes[gocad_id] );
260  }
261  else
262  {
263  index_t corresponding_gocad_id{
264  lighttsolid_atom_map.find( gocad_id )->second
265  };
266  if( region( corresponding_gocad_id )
267  != region( gocad_id ) )
268  {
269  region_tetra_attributes.push_back(
270  stored_attributes[corresponding_gocad_id] );
271  }
272  }
273  }
274  gocad_id++;
275  }
276  }
277 
279  {
280  RegionLocalVertex( vec3 vertex, index_t local_id )
281  : tetra_vertex( std::move( vertex ) ), local_id( local_id )
282  {
283  }
284  vec3 tetra_vertex{};
285  index_t local_id{ NO_ID };
286  };
287 
288  std::vector< RegionLocalVertex >
290  const std::vector< vec3 >& stored_vertices,
291  const index_t region_id,
292  const std::map< index_t, index_t >& lighttsolid_atom_map /*,
293  std::vector< vec3 >& region_tetra_vertices,
294  std::vector< index_t >& local_ids */ ) const
295  {
297  stored_vertices.size() == gocad_ids2region_ids_.size() );
298  std::vector< RegionLocalVertex > region_tetra_vertices;
299  for( auto gocad_id : range( stored_vertices.size() ) )
300  {
301  if( gocad_ids2region_ids_[gocad_id] == region_id )
302  {
303  if( lighttsolid_atom_map.find( gocad_id )
304  == lighttsolid_atom_map.end() )
305  {
306  region_tetra_vertices.emplace_back(
307  stored_vertices[gocad_id], gocad_id );
308  }
309  else
310  {
311  index_t corresponding_gocad_id{
312  lighttsolid_atom_map.find( gocad_id )->second
313  };
314  if( region( corresponding_gocad_id )
315  != region( gocad_id ) )
316  {
317  region_tetra_vertices.emplace_back(
318  stored_vertices[corresponding_gocad_id],
319  gocad_id );
320  }
321  }
322  }
323  gocad_id++;
324  }
325  return region_tetra_vertices;
326  }
327 
328  index_t local_id( index_t gocad_vertex_id ) const
329  {
330  ringmesh_assert( gocad_vertex_id < gocad_ids2local_ids_.size() );
331  return gocad_ids2local_ids_[gocad_vertex_id];
332  }
333 
334  index_t region( index_t gocad_vertex_id ) const
335  {
336  ringmesh_assert( gocad_vertex_id < gocad_ids2region_ids_.size() );
337  return gocad_ids2region_ids_[gocad_vertex_id];
338  }
339 
340  void add_vertex( index_t local_vertex_id, index_t region_id )
341  {
342  gocad_ids2local_ids_.push_back( local_vertex_id );
343  gocad_ids2region_ids_.push_back( region_id );
344  }
345 
346  void reserve( index_t capacity )
347  {
348  gocad_ids2local_ids_.reserve( capacity );
349  gocad_ids2region_ids_.reserve( capacity );
350  }
351 
352  void reserve_nb_vertices( index_t capacity )
353  {
354  vertices_gocad_id_.reserve( capacity );
355  vertices_region_id_.reserve( capacity );
356  }
357 
359  {
361  vertices_gocad_id_.size() == vertices_region_id_.size() );
362  size_t lighttsolid_vertices_nb = vertices_gocad_id_.size();
363  size_t lighttsolid_region_nb = nb_regions();
364 
365  // For every region ...
366  for( auto region_index : range( lighttsolid_region_nb ) )
367  {
368  // we want to record the region ids of the LightTSolid vertices
369  // ...
370  for( auto lighttsolid_vertices_id :
371  range( lighttsolid_vertices_nb ) )
372  {
373  // that are in this region.
374  if( region_id( lighttsolid_vertices_id ) == region_index )
375  {
376  index_t gocad_vertex_i{ gocad_vertex_id(
377  lighttsolid_vertices_id ) };
378 
379  gocad_ids2region_ids_[gocad_vertex_i] =
380  region_id( lighttsolid_vertices_id );
381  }
382  }
383  }
384  }
385 
387  {
389  vertices_gocad_id_.size() == vertices_region_id_.size() );
390  size_t lighttsolid_vertices_nb = vertices_gocad_id_.size();
391  size_t lighttsolid_region_nb = nb_regions();
392 
393  // For every region ...
394  for( auto rgion_id : range( lighttsolid_region_nb ) )
395  {
396  // we want to record the local ids of the LightTSolid vertices
397  // ...
398  const auto& local_ids = local_ids_[rgion_id];
399  for( auto lighttsolid_vertices_id :
400  range( lighttsolid_vertices_nb ) )
401  {
402  // that are in this region.
403  if( region_id( lighttsolid_vertices_id ) == rgion_id )
404  {
405  index_t gocad_vertex_i{ gocad_vertex_id(
406  lighttsolid_vertices_id ) };
407  for( auto local_id : range( local_ids.size() ) )
408  {
409  index_t gocad_id{ local_ids[local_id] };
410  if( gocad_id == gocad_vertex_i )
411  {
412  gocad_ids2local_ids_[gocad_vertex_i] = local_id;
413  }
414  }
415  }
416  }
417  }
418  }
419 
421  const std::map< index_t, index_t >& lighttsolid_atom_map )
422  {
423  for( const std::pair< index_t, index_t >& pair :
424  lighttsolid_atom_map )
425  {
426  if( region( pair.first ) == region( pair.second ) )
427  {
428  gocad_ids2local_ids_[pair.first] =
429  gocad_ids2local_ids_[pair.second];
430  }
431  }
432  }
433 
434  public:
444  std::vector< std::vector< index_t > > local_ids_;
445 
446  private:
454  std::vector< index_t > vertices_gocad_id_;
462  std::vector< index_t > vertices_region_id_;
463 
469  std::vector< index_t > region_ids_;
475  std::vector< std::string > region_names_;
476 
477  private:
483  std::vector< index_t > gocad_ids2local_ids_;
489  std::vector< index_t > gocad_ids2region_ids_;
490  };
491 
496  {
497  // Current region index
498  index_t cur_region_{ NO_ID };
499 
500  // Map between gocad and GeoModel vertex indices
502 
503  // Region tetrahedron corners
504  std::vector< index_t > tetra_corners_{};
505 
506  // Names of the attributes for the TSolid
507  std::vector< std::string > vertex_attribute_names_{};
508 
509  // Dimensions of the attributes for the TSolid
510  std::vector< index_t > vertex_attribute_dims_{};
511 
513  index_t cur_gocad_vrtx_id1_{ NO_ID };
514  index_t cur_gocad_vrtx_id2_{ NO_ID };
515  index_t cur_gocad_vrtx_id3_{ NO_ID };
516  index_t cur_gocad_vrtx_id4_{ NO_ID };
517 
519  std::map< index_t, index_t > lighttsolid_atom_map_{};
520 
521  // The vertices and the atoms
522  index_t nb_vertices_{ 0 };
523  };
524 
526  {
527  public:
528  virtual void execute(
529  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) = 0;
530  virtual void execute_light(
531  GEO::LineInput& line, TSolidLoadingStorage& load_storage ) = 0;
532 
533  protected:
535  GeoModelBuilderTSolid& gm_builder, GeoModel3D& geomodel );
536  };
537  using TSolidLineFactory = Factory< std::string,
540  GeoModel3D& >;
541 
545  class RINGMESH_API GeoModelBuilderTSolid final : public GeoModelBuilderGocad
546  {
547  public:
548  static const index_t NB_TYPE = 2;
549  enum struct TSolidType
550  {
551  TSOLID,
552  LIGHT_TSOLID
553  };
554  GeoModelBuilderTSolid( GeoModel3D& geomodel, std::string filename );
555 
556  private:
557  void read_number_of_vertices();
558  void read_type();
559  void load_file() final;
560  void read_file();
561 
567  void read_line() final;
568 
578  void compute_surface_internal_borders( index_t surface_id,
579  const std::vector< std::unique_ptr< NNSearch3D > >& surface_nns,
580  const std::vector< Box3D >& surface_boxes );
581 
589  void compute_polygon_edge_centers_nn_and_surface_boxes(
590  std::vector< std::unique_ptr< NNSearch3D > >& surface_nns,
591  std::vector< Box3D >& surface_boxes ) const;
592 
601  void compute_surfaces_internal_borders();
602 
603  protected:
605 
606  private:
607  TSolidType file_type_{ TSolidType::TSOLID };
608  std::array< std::unique_ptr< GeoModelBuilderTSolidImpl >, NB_TYPE >
610 
612  };
613 
615  {
617 
618  public:
619  GeoModelBuilderTSolidImpl( GeoModelBuilderTSolid& builder,
620  GeoModel3D& geomodel,
621  GEO::LineInput& file_line,
622  TSolidLoadingStorage& tsolid_load_storage )
623  : builder_( builder ),
624  geomodel_( geomodel ),
625  file_line_( file_line ),
626  tsolid_load_storage_( tsolid_load_storage )
627  {
628  }
629  virtual ~GeoModelBuilderTSolidImpl() = default;
630 
631  virtual void read_line() = 0;
632 
633  protected:
634  GeoModelBuilderTSolid& builder_;
635  GeoModel3D& geomodel_;
636  GEO::LineInput& file_line_;
638  };
639 
642  {
643  public:
644  GeoModelBuilderTSolidImpl_TSolid( GeoModelBuilderTSolid& builder,
645  GeoModel3D& geomodel,
646  GEO::LineInput& file_line,
647  TSolidLoadingStorage& tsolid_load_storage )
649  builder, geomodel, file_line, tsolid_load_storage )
650  {
651  }
652 
653  void read_line() override
654  {
655  std::string keyword = file_line_.field( 0 );
656  std::unique_ptr< TSolidLineParser > tsolid_parser =
657  TSolidLineFactory::create( keyword, this->builder_, geomodel_ );
658  if( tsolid_parser )
659  {
660  tsolid_parser->execute( file_line_, tsolid_load_storage_ );
661  }
662  else
663  {
664  std::unique_ptr< GocadLineParser > gocad_parser =
666  keyword, this->builder_, geomodel_ );
667  if( gocad_parser )
668  {
669  gocad_parser->execute( file_line_, tsolid_load_storage_ );
670  }
671  }
672  }
673  };
674 
677  {
678  public:
679  GeoModelBuilderTSolidImpl_LightTSolid( GeoModelBuilderTSolid& builder,
680  GeoModel3D& geomodel,
681  GEO::LineInput& file_line,
682  TSolidLoadingStorage& tsolid_load_storage )
684  builder, geomodel, file_line, tsolid_load_storage )
685  {
686  }
687 
688  void read_line() override
689  {
690  std::string keyword = file_line_.field( 0 );
691  std::unique_ptr< TSolidLineParser > tsolid_parser =
692  TSolidLineFactory::create( keyword, this->builder_, geomodel_ );
693  if( tsolid_parser )
694  {
695  tsolid_parser->execute_light(
696  file_line_, tsolid_load_storage_ );
697  }
698  else
699  {
700  std::unique_ptr< GocadLineParser > gocad_parser =
702  keyword, this->builder_, geomodel_ );
703  if( gocad_parser )
704  {
705  gocad_parser->execute( file_line_, tsolid_load_storage_ );
706  }
707  }
708  }
709  };
710 
712  {
714 
715  bool is_header_read_{ false };
716 
718  index_t tface_vertex_ptr_{ 0 };
719  };
721  {
722  public:
723  virtual void execute(
724  GEO::LineInput& line, MLLoadingStorage& load_storage ) = 0;
725 
726  protected:
727  MLLineParser( GeoModelBuilderML& gm_builder, GeoModel3D& geomodel );
728  };
729  using MLLineFactory =
731 
735  class RINGMESH_API GeoModelBuilderML final : public GeoModelBuilderGocad
736  {
737  public:
738  GeoModelBuilderML( GeoModel3D& geomodel, std::string filename )
739  : GeoModelBuilderGocad( geomodel, std::move( filename ) )
740  {
741  }
742 
743  private:
761  void load_file() final;
762 
768  void read_line() final;
769 
770  private:
772  };
773 
774 } // namespace RINGMesh
#define ringmesh_disable_copy_and_move(Class)
Definition: common.h:76
void end_polygon()
Ends a polygon (by adding the size of list of polygon corners at the end of the vector) ...
GeoModelBuilderML(GeoModel3D &geomodel, std::string filename)
static std::unique_ptr< BaseClass > create(const Key &key, const Args &... args)
Definition: factory.h:85
std::vector< index_t > region_ids_
std::vector< std::vector< double > > attributes_
GeoModelBuilderTSolidImpl_TSolid(GeoModelBuilderTSolid &builder, GeoModel3D &geomodel, GEO::LineInput &file_line, TSolidLoadingStorage &tsolid_load_storage)
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
std::vector< index_t > gocad_ids2local_ids_
void RINGMESH_API initialize_gocad_import_factories()
Abstract interface class to load and build GeoModels from files.
const std::vector< index_t > & get_regions() const
RegionLocalVertex(vec3 vertex, index_t local_id)
std::vector< std::string > region_names_
std::vector< index_t > vertices_gocad_id_
GocadLineParser(GeoModelBuilderGocad &gm_builder, GeoModel3D &geomodel)
std::tuple< bool, index_t > find_region_id_from_name(const std::string &region_name)
GeoModelBuilderGocad & builder_
GeoModelBuilderTSolidImpl(GeoModelBuilderTSolid &builder, GeoModel3D &geomodel, GEO::LineInput &file_line, TSolidLoadingStorage &tsolid_load_storage)
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
std::array< std::unique_ptr< GeoModelBuilderTSolidImpl >, NB_TYPE > type_impl_
Builds a meshed GeoModel from a Gocad TSolid (file.so)
#define ringmesh_assert(x)
std::vector< index_t > vertices_region_id_
void add_vertex(index_t local_vertex_id, index_t region_id)
void add_new_region(index_t region_id, const std::string &region_name)
void reserve_nb_vertices(index_t capacity)
std::vector< index_t > gocad_ids2region_ids_
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)
index_t gocad_vertex_id(index_t id) const
GeoModelBuilderGocad(GeoModel3D &geomodel, std::string filename)
GeoModelBuilderTSolidImpl_LightTSolid(GeoModelBuilderTSolid &builder, GeoModel3D &geomodel, GEO::LineInput &file_line, TSolidLoadingStorage &tsolid_load_storage)
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
std::vector< std::vector< index_t > > local_ids_
std::vector< index_t > cur_surf_polygon_ptr_
std::vector< index_t > cur_surf_polygon_corners_gocad_id_
index_t region_id(index_t id) const
GocadBaseParser(GeoModelBuilderGocad &gm_builder, GeoModel3D &geomodel)