45                 numeric_like_vertex_attribute_names_(),
    46                 vertex_attribute_dimensions_(),
    47                 numeric_like_cell_attribute_names_(),
    48                 cell_attribute_dimensions_(),
    51                 vertex_exported_id_(),
    55         void load( 
const std::string& filename, GeoModel3D& geomodel ) 
final    57             std::ifstream input( filename.c_str() );
    63             builder.build_geomodel();
    65         void save( 
const GeoModel3D& geomodel, 
const std::string& filename ) 
final    68             out_.open( filename.c_str() );
    72             fill_top_header( geomodel );
    74             const GeoModelMesh3D& mesh = geomodel.mesh;
    77             fill_vertex_attribute_header( geomodel );
    78             fill_cell_attribute_header( geomodel );
    80             vertex_exported_.resize( mesh.vertices.nb(), false );
    81             atom_exported_.resize( mesh.cells.nb_duplicated_vertices(), false );
    82             vertex_exported_id_.resize( mesh.vertices.nb(), NO_ID );
    83             atom_exported_id_.resize( mesh.cells.nb_duplicated_vertices(), NO_ID );
    84             for( index_t r = 0; r < geomodel.nb_regions(); r++ ) {
    85                 const auto& region = geomodel.region( r );
    86                 export_one_region( region );
    89             export_model( geomodel );
    90             export_model_region( geomodel );
    92             out_ << 
"END" << std::endl;
    95         const GeoModelMesh3D& geomodel_mesh( 
const Region3D& region )
 const    97             return region.geomodel().mesh;
    99         void fill_top_header( 
const GeoModel3D& geomodel )
   103             out_ << 
"GOCAD TSolid 1" << 
EOL << 
"HEADER {" << 
EOL << 
"name:"   104                 << geomodel.name() << 
EOL << 
"}" << 
EOL;
   106             out_ << 
"GOCAD_ORIGINAL_COORDINATE_SYSTEM" << EOL << 
"NAME Default"   107                 << EOL << 
"AXIS_NAME \"X\" \"Y\" \"Z\"" << EOL
   108                 << 
"AXIS_UNIT \"m\" \"m\" \"m\"" << EOL << 
"ZPOSITIVE Elevation"   109                 << EOL << 
"END_ORIGINAL_COORDINATE_SYSTEM" << 
EOL;
   111         void fill_vertex_attribute_header( 
const GeoModel3D& geomodel )
   114             std::vector< bool > is_integer_like_attribute;
   115             for( index_t reg_i = 0; reg_i < geomodel.nb_regions(); ++reg_i ) {
   116                 const Region3D& cur_reg = geomodel.region( reg_i );
   117                 GEO::AttributesManager& reg_vertex_attr_mgr =
   118                     cur_reg.vertex_attribute_manager();
   119                 GEO::vector< std::string > att_v_names;
   120                 reg_vertex_attr_mgr.list_attribute_names( att_v_names );
   122                 for( 
const std::string& cur_att_v_name : att_v_names ) {
   124                     if( cur_att_v_name == 
"point" ) {
   128                     if( 
contains( numeric_like_vertex_attribute_names_,
   133                     const GEO::AttributeStore* attr_store =
   134                         reg_vertex_attr_mgr.find_attribute_store( cur_att_v_name );
   137                     if( !GEO::ReadOnlyScalarAttributeAdapter::can_be_bound_to(
   142                     numeric_like_vertex_attribute_names_.push_back( cur_att_v_name );
   143                     index_t cur_dim = attr_store->dimension();
   144                     vertex_attribute_dimensions_.push_back( cur_dim );
   146                     const GEO::ReadOnlyScalarAttributeAdapter adapter(
   147                         reg_vertex_attr_mgr, cur_att_v_name );
   149                         adapter.element_type()
   150                             != GEO::ReadOnlyScalarAttributeAdapter::ET_NONE );
   151                     is_integer_like_attribute.push_back(
   152                         adapter.element_type()
   153                             < GEO::ReadOnlyScalarAttributeAdapter::ET_FLOAT32 );
   157             const auto nb_numeric_like_vertex_attribute_names =
   158                 static_cast< index_t 
>( numeric_like_vertex_attribute_names_.size() );
   159             if( !numeric_like_vertex_attribute_names_.empty() ) {
   161                 out_ << 
"PROPERTIES";
   162                 for( 
const std::string& cur_num_like_v_att_name : numeric_like_vertex_attribute_names_ ) {
   163                     out_ << 
" " << cur_num_like_v_att_name;
   166                 out_ << 
"PROP_LEGAL_RANGES";
   167                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   169                     out_ << 
" **none**  **none**";
   172                 out_ << 
"NO_DATA_VALUES";
   173                 write_no_data_value( nb_numeric_like_vertex_attribute_names );
   176                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   181                 out_ << 
"PROPERTY_CLASSES";
   182                 for( 
const std::string& cur_num_like_v_att_name : numeric_like_vertex_attribute_names_ ) {
   183                     out_ << 
" " << cur_num_like_v_att_name;
   186                 out_ << 
"PROPERTY_KINDS";
   187                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   188                     if( is_integer_like_attribute[i] ) {
   189                         out_ << 
" \"Number\"";
   191                         out_ << 
" \"Real Number\"";
   195                 out_ << 
"PROPERTY_SUBCLASSES";
   196                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   198                     out_ << 
" QUANTITY Float";
   202                 for( 
const auto& cur_v_att_dim : vertex_attribute_dimensions_ ) {
   203                     out_ << 
" " << GEO::String::to_string( cur_v_att_dim );
   207                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   212                 for( 
auto i : 
range( nb_numeric_like_vertex_attribute_names ) ) {
   213                     out_ << 
"PROPERTY_CLASS_HEADER "   214                         << numeric_like_vertex_attribute_names_[i] << 
" {" << 
EOL;
   215                     if( is_integer_like_attribute[i] ) {
   216                         out_ << 
"kind: Number" << 
EOL;
   218                         out_ << 
"kind: Real Number" << 
EOL;
   220                     out_ << 
"unit: unitless" << 
EOL;
   226         void fill_cell_attribute_header( 
const GeoModel3D& geomodel )
   229             std::vector< bool > is_integer_like_attribute;
   231                 auto& reg_cell_attr_mgr =
   232                     cur_reg.cell_attribute_manager();
   233                 GEO::vector< std::string > att_c_names;
   234                 reg_cell_attr_mgr.list_attribute_names( att_c_names );
   236                 for( 
const auto& cur_att_c_name : att_c_names ) {
   238                     if( 
contains( numeric_like_cell_attribute_names_,
   243                     const auto* attr_store =
   244                         reg_cell_attr_mgr.find_attribute_store( cur_att_c_name );
   247                     if( !GEO::ReadOnlyScalarAttributeAdapter::can_be_bound_to(
   252                     numeric_like_cell_attribute_names_.push_back( cur_att_c_name );
   253                     auto cur_dim = attr_store->dimension();
   254                     cell_attribute_dimensions_.push_back( cur_dim );
   256                     const GEO::ReadOnlyScalarAttributeAdapter adapter(
   257                         reg_cell_attr_mgr, cur_att_c_name );
   259                         adapter.element_type()
   260                             != GEO::ReadOnlyScalarAttributeAdapter::ET_NONE );
   261                     is_integer_like_attribute.push_back(
   262                         adapter.element_type()
   263                             < GEO::ReadOnlyScalarAttributeAdapter::ET_FLOAT32 );
   267             const auto nb_numeric_like_cell_attribute_names =
   268                 static_cast< index_t 
> ( numeric_like_cell_attribute_names_.size() );
   269             if( !numeric_like_cell_attribute_names_.empty() ) {
   270                 out_ << 
"TETRA_PROPERTIES";
   271                 for( 
const auto& cur_num_like_c_att_name : numeric_like_cell_attribute_names_ ) {
   272                     out_ << 
" " << cur_num_like_c_att_name;
   275                 out_ << 
"TETRA_PROP_LEGAL_RANGES";
   276                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   278                     out_ << 
" **none**  **none**";
   281                 out_ << 
"TETRA_NO_DATA_VALUES";
   282                 write_no_data_value( nb_numeric_like_cell_attribute_names );
   285                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   290                 out_ << 
"TETRA_PROPERTY_CLASSES";
   291                 for( 
const auto& cur_num_like_c_att_name : numeric_like_cell_attribute_names_ ) {
   292                     out_ << 
" " << cur_num_like_c_att_name;
   295                 out_ << 
"TETRA_PROPERTY_KINDS";
   296                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   297                     if( is_integer_like_attribute[i] ) {
   298                         out_ << 
" \"Number\"";
   300                         out_ << 
" \"Real Number\"";
   304                 out_ << 
"TETRA_PROPERTY_SUBCLASSES";
   305                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   307                     out_ << 
" QUANTITY Float";
   310                 out_ << 
"TETRA_ESIZES";
   311                 for( 
const auto& cur_cell_attr_dim : cell_attribute_dimensions_ ) {
   312                     out_ << 
" " << std::to_string( cur_cell_attr_dim );
   315                 out_ << 
"TETRA_UNITS";
   316                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   321                 for( 
auto i : 
range( nb_numeric_like_cell_attribute_names ) ) {
   322                     out_ << 
"TETRA_PROPERTY_CLASS_HEADER "   323                         << numeric_like_cell_attribute_names_[i] << 
" {" << 
EOL;
   324                     if( is_integer_like_attribute[i] ) {
   325                         out_ << 
"kind: Number" << 
EOL;
   327                         out_ << 
"kind: Real Number" << 
EOL;
   329                     out_ << 
"unit: unitless" << 
EOL;
   335         void export_one_region( 
const Region3D& region )
   338             out_ << 
"TVOLUME " << region.name() << 
EOL;
   339             export_region_vertices( region );
   340             export_tetrahedra( region );
   343         void export_region_vertices( 
const Region3D& region )
   346             for( 
auto c : 
range( region.nb_mesh_elements() ) ) {
   347                 export_region_cell_vertices( region, c );
   351         void export_region_cell_vertices( 
const Region3D& region, index_t c )
   353             const auto& mesh = geomodel_mesh( region );
   354             auto cell = mesh.cells.cell( region.gmme().index(), c );
   355             auto cell_center = mesh.cells.barycenter( cell );
   356             for( 
auto v : 
range( mesh.cells.nb_vertices( cell ) ) ) {
   357                 export_region_cell_vertex( region, cell, v, cell_center );
   361         void export_region_cell_vertex(
   362             const Region3D& region,
   365             const vec3& cell_center )
   368             const auto& mesh = geomodel_mesh( region );
   369             auto atom_id = mesh.cells.duplicated_corner_index( { cell, v } );
   370             if( atom_id == NO_ID ) {
   371                 auto vertex_id = mesh.cells.vertex( { cell, v } );
   372                 if( vertex_exported_[vertex_id] ) 
return;
   373                 vertex_exported_[vertex_id] = 
true;
   374                 vertex_exported_id_[vertex_id] = nb_vertices_exported_;
   377                 out_ << 
"PVRTX " << nb_vertices_exported_++ << 
" "   378                     << mesh.vertices.vertex( vertex_id );
   381                 export_region_cell_vertex_attributes( region, vertex_id,
   387         void export_region_cell_vertex_attributes(
   388             const Region3D& region,
   390             const vec3& cell_center )
   393             auto& reg_vertex_attr_mgr =
   394                 region.vertex_attribute_manager();
   395             auto vertex_id_in_reg = find_gmm_cell_in_gm_region( region, vertex_id,
   399             for( 
auto attr_dbl_itr : 
range(
   400                 static_cast< index_t >( numeric_like_vertex_attribute_names_.size() ) ) ) {
   401                 if( reg_vertex_attr_mgr.is_defined(
   402                     numeric_like_vertex_attribute_names_[attr_dbl_itr] ) ) {
   404                         reg_vertex_attr_mgr.find_attribute_store(
   405                             numeric_like_vertex_attribute_names_[attr_dbl_itr] )
   408                         reg_vertex_attr_mgr.find_attribute_store(
   409                             numeric_like_vertex_attribute_names_[attr_dbl_itr] )->dimension()
   410                             == vertex_attribute_dimensions_[attr_dbl_itr] );
   412                         GEO::ReadOnlyScalarAttributeAdapter::can_be_bound_to(
   413                             reg_vertex_attr_mgr.find_attribute_store(
   414                                 numeric_like_vertex_attribute_names_[attr_dbl_itr] ) ) );
   415                     GEO::ReadOnlyScalarAttributeAdapter cur_attr(
   417                         numeric_like_vertex_attribute_names_[attr_dbl_itr] );
   418                     for( 
auto dim_itr :
range(vertex_attribute_dimensions_[attr_dbl_itr] ) ) {
   420                             << cur_attr[vertex_id_in_reg
   421                                 * vertex_attribute_dimensions_[attr_dbl_itr]
   426                         vertex_attribute_dimensions_[attr_dbl_itr] );
   431         index_t find_gmm_cell_in_gm_region(
   432             const Region3D& region,
   434             const vec3& cell_center )
 const   436             const auto& mesh = geomodel_mesh( region );
   442             const auto& gme_vertices =
   443                 mesh.vertices.gme_vertices( vertex_id );
   444             for( 
const auto& cur_gme_vertex : gme_vertices ) {
   445                 if( cur_gme_vertex.gmme != region.gmme() ) {
   448                 auto cells_around_vertex =
   449                     region.cells_around_vertex( cur_gme_vertex.v_index, NO_ID );
   453                 for( 
const auto& cur_cell_around_vertex : cells_around_vertex ) {
   454                     auto center = region.mesh_element_barycenter(
   455                         cur_cell_around_vertex );
   456                     if( ( center - cell_center ).length()
   457                         < region.geomodel().epsilon() ) {
   458                         return cur_gme_vertex.v_index;
   466         void export_tetrahedra( 
const Region3D& region )
   469             export_duplicated_vertices();
   472             mark_boundary_ending_in_region( region );
   474             const auto& mesh = geomodel_mesh( region );
   475             for( 
auto c : 
range(region.nb_mesh_elements() ) ) {
   477                 auto cell = mesh.cells.cell( region.gmme().index(), c );
   478                 export_tetra( region, cell );
   480                 out_ << 
"# CTETRA " << region.name();
   481                 export_ctetra( region, c );
   486         void export_duplicated_vertices()
 const   506         void mark_boundary_ending_in_region( 
const Region3D& region )
   508             std::map< index_t, index_t > sides;
   509             for( 
auto s : 
range( region.nb_boundaries() ) ) {
   510                 if( sides.count( region.boundary_gmme( s ).index() ) > 0 ) {
   512                     sides[region.boundary_gmme( s ).index()] = 2;
   514                     sides[region.boundary_gmme( s ).index()] = region.side( s );
   519         void export_tetra( 
const Region3D& region, index_t cell )
   521             export_tetra_coordinates( region, cell );
   523             export_tetra_attributes( region, cell );
   526         void export_tetra_coordinates( 
const Region3D& region, index_t cell )
   529             const auto& mesh = geomodel_mesh( region );
   531                 region.geomodel().mesh.cells.nb_vertices( cell ) ) ) {
   532                 auto atom_id = mesh.cells.duplicated_corner_index(
   534                 if( atom_id == NO_ID ) {
   535                     auto vertex_id = mesh.cells.vertex(
   537                     out_ << 
" " << vertex_exported_id_[vertex_id];
   539                     out_ << 
" " << atom_exported_id_[atom_id];
   544         void export_tetra_attributes( 
const Region3D& region, index_t cell )
   547             auto& reg_cell_attr_mgr =
   548                 region.cell_attribute_manager();
   549             const auto& mesh = geomodel_mesh( region );
   550             auto center = mesh.cells.barycenter( cell );
   551             const auto c_in_reg =
   552                 region.cell_nn_search().get_neighbors( center,
   553                     region.geomodel().epsilon() );
   555             for( 
auto attr_dbl_itr : 
range(
   556                 numeric_like_cell_attribute_names_.size() ) ) {
   557                 if( reg_cell_attr_mgr.is_defined(
   558                     numeric_like_cell_attribute_names_[attr_dbl_itr] ) ) {
   560                         reg_cell_attr_mgr.find_attribute_store(
   561                             numeric_like_cell_attribute_names_[attr_dbl_itr] )
   564                         reg_cell_attr_mgr.find_attribute_store(
   565                             numeric_like_cell_attribute_names_[attr_dbl_itr] )->dimension()
   566                             == cell_attribute_dimensions_[attr_dbl_itr] );
   568                         GEO::ReadOnlyScalarAttributeAdapter::can_be_bound_to(
   569                             reg_cell_attr_mgr.find_attribute_store(
   570                                 numeric_like_cell_attribute_names_[attr_dbl_itr] ) ) );
   571                     GEO::ReadOnlyScalarAttributeAdapter cur_attr( reg_cell_attr_mgr,
   572                         numeric_like_cell_attribute_names_[attr_dbl_itr] );
   573                     for( 
auto dim_itr : 
range(
   574                         cell_attribute_dimensions_[attr_dbl_itr] ) ) {
   576                             << cur_attr[c_in_reg[0]
   577                                 * cell_attribute_dimensions_[attr_dbl_itr] + dim_itr];
   580                     write_no_data_value( cell_attribute_dimensions_[attr_dbl_itr] );
   585         void export_ctetra( 
const Region3D& region, index_t c )
   588             const auto& mesh = geomodel_mesh( region );
   589             for( 
auto f : 
range( mesh.cells.nb_facets( c ) ) ) {
   591                 index_t polygon { NO_ID };
   593                 if( mesh.cells.is_cell_facet_on_surface( c, f, polygon, side ) ) {
   594                     index_t surface_id { mesh.polygons.surface( polygon ) };
   595                     side ? out_ << 
"+" : out_ << 
"-";
   597                         << region.geomodel().surface( surface_id ).parent( 0 ).name();
   604         void export_model( 
const GeoModel3D& geomodel )
   607             out_ << 
"MODEL" << 
EOL;
   610             const auto& polygons = geomodel.mesh.polygons;
   611             for( 
auto& cur_interface : geomodel.geol_entities(
   612                 Interface3D::type_name_static() ) ) {
   613                 out_ << 
"SURFACE " << cur_interface.name() << 
EOL;
   614                 for( 
auto s : 
range( cur_interface.nb_children() ) ) {
   615                     out_ << 
"TFACE " << tface_count++ << 
EOL;
   616                     auto surface_id = cur_interface.child_gmme( s ).index();
   617                     out_ << 
"KEYVERTICES";
   618                     auto key_polygon_id = polygons.polygon( surface_id, 0 );
   619                     for( 
auto v : 
range( polygons.nb_vertices( key_polygon_id ) ) ) {
   621                             << vertex_exported_id_[polygons.vertex(
   622                                 { key_polygon_id, v } )];
   625                     for( 
auto p : 
range( polygons.nb_polygons( surface_id ) ) ) {
   626                         auto polygon_id = polygons.polygon( surface_id, p );
   628                         for( 
auto v : 
range( polygons.nb_vertices( polygon_id ) ) ) {
   630                                 << vertex_exported_id_[polygons.vertex(
   631                                     { polygon_id, v } )];
   638         void export_model_region( 
const GeoModel3D& geomodel )
   641             for( 
auto& region : geomodel.regions() ) {
   642                 out_ << 
"MODEL_REGION " << region.name() << 
" ";
   643                 region.side( 0 ) ? out_ << 
"+" : out_ << 
"-";
   644                 out_ << region.boundary_gmme( 0 ).index() + 1 << 
EOL;
   648         void write_no_data_value( index_t nb )
   650             for( 
auto i : 
range( nb ) ) {
   652                 out_ << 
" " << GEO::String::to_string( gocad_no_data_value_ );
   667         std::vector< std::string > numeric_like_vertex_attribute_names_;
   668         std::vector< index_t > vertex_attribute_dimensions_;
   669         std::vector< std::string > numeric_like_cell_attribute_names_;
   670         std::vector< index_t > cell_attribute_dimensions_;
   671         std::vector< bool > vertex_exported_;
   672         std::vector< bool > atom_exported_;
   673         std::vector< index_t > vertex_exported_id_;
   674         std::vector< index_t > atom_exported_id_;
   675         index_t nb_vertices_exported_ { 1 };
   678         const double gocad_no_data_value_ { -99999 };
 
void ringmesh_unused(const T &)
 
Builds a meshed GeoModel from a Gocad TSolid (file.so) 
 
#define ringmesh_assert(x)
 
bool contains(const container &in, const T &value)
 
Classes to build GeoModel from various inputs. 
 
#define ringmesh_assert_not_reached