40 #include <geogram/basic/file_system.h>    41 #include <geogram/basic/line_stream.h>    43 #include <geogram/mesh/mesh.h>    44 #include <geogram/mesh/mesh_geometry.h>    45 #include <geogram/mesh/mesh_io.h>    46 #include <geogram/mesh/mesh_repair.h>    56     std::vector< std::string > bounded_attribute_names(
    57         GEO::AttributesManager& manager )
    59         GEO::vector< std::string > names;
    60         manager.list_attribute_names( names );
    61         std::vector< std::string > bounded_names;
    62         bounded_names.reserve( names.size() );
    65             for( std::string name : names )
    67                 if( manager.find_attribute_store( name )->has_observers() )
    69                     bounded_names.push_back( name );
    77         const std::string& output_location )
    81             Logger::err( 
"Attributes", 
"Attributes still bounded on ",
    82                 output_location, 
":" );
    83             for( std::string name : names )
    91         GEO::AttributesManager& manager, 
const std::string& output_location )
    93         std::vector< std::string > names = bounded_attribute_names( manager );
   100     class TSurfMeshIOHandler final : 
public GEO::MeshIOHandler
   104             : starting_index_( 1 ),
   105               mesh_dimension_( 3 ),
   122         bool load( 
const std::string& filename,
   124             const GEO::MeshIOFlags& flag = GEO::MeshIOFlags() ) final
   127             filename_ = filename;
   128             if( !is_file_valid() )
   134                 read_number_of_vertices_and_triangles();
   135                 read_vertex_property_names();
   136                 read_vertex_property_sizes();
   138                 allocate_triangles();
   139                 allocate_vertex_properties();
   140                 read_vertices_and_triangles();
   141                 assign_and_repair_mesh( mesh );
   149         bool save( 
const GEO::Mesh& mesh,
   150             const std::string& filename,
   151             const GEO::MeshIOFlags& flag = GEO::MeshIOFlags() ) final
   154             if( !mesh.facets.are_simplices() )
   157                     "Cannot save a non triangulated mesh into TSurf format" );
   160             std::ofstream out( filename.c_str() );
   162             save_header( out, GEO::FileSystem::base_name( filename ) );
   163             std::vector< std::string > att_v_double_names;
   164             std::vector< index_t > vertex_attr_dims;
   165             fill_vertex_attribute_header(
   166                 mesh, out, att_v_double_names, vertex_attr_dims );
   168             out << 
"TFACE" << std::endl;
   169             save_vertices( out, mesh, att_v_double_names, vertex_attr_dims );
   170             save_triangles( out, mesh );
   171             out << 
"END" << std::endl;
   177         void save_vertices( std::ofstream& out,
   178             const GEO::Mesh& mesh,
   179             const std::vector< std::string >& att_v_double_names,
   180             const std::vector< index_t >& vertex_attr_dims )
   182             for( 
auto v : 
range( mesh.vertices.nb() ) )
   186                 out << 
"PVRTX " << v + starting_index_ << 
" "   187                     << mesh.vertices.point( v );
   188                 for( 
auto attr_dbl_itr : 
range( att_v_double_names.size() ) )
   190                     GEO::Attribute< double > cur_attr(
   191                         mesh.vertices.attributes(),
   192                         att_v_double_names[attr_dbl_itr] );
   193                     index_t nb_dimensions = vertex_attr_dims[attr_dbl_itr];
   194                     for( 
auto dim_itr : 
range( nb_dimensions ) )
   196                         out << 
" " << cur_attr[v * nb_dimensions + dim_itr];
   202         void save_triangles( std::ofstream& out, 
const GEO::Mesh& mesh )
   204             for( 
auto t : 
range( mesh.facets.nb() ) )
   207                 for( 
auto v : 
range( 3 ) )
   209                     out << 
" " << mesh.facets.vertex( t, v ) + starting_index_;
   214         void save_header( std::ofstream& out, 
const std::string& mesh_name )
   216             out << 
"GOCAD TSurf" << std::endl;
   217             out << 
"HEADER {" << std::endl;
   218             out << 
"name: " << mesh_name << std::endl;
   219             out << 
"}" << std::endl;
   221         void fill_vertex_attribute_header( 
const GEO::Mesh& mesh,
   223             std::vector< std::string >& att_v_double_names,
   224             std::vector< index_t >& vertex_attr_dims )
 const   226             GEO::vector< std::string > att_v_names;
   227             GEO::AttributesManager& mesh_vertex_mgr =
   228                 mesh.vertices.attributes();
   229             mesh_vertex_mgr.list_attribute_names( att_v_names );
   230             for( 
auto att_v : 
range( mesh_vertex_mgr.nb() ) )
   232                 if( att_v_names[att_v] == 
"point" )
   237                 if( !GEO::Attribute< double >::is_defined(
   238                         mesh_vertex_mgr, att_v_names[att_v] ) )
   242                 att_v_double_names.push_back( att_v_names[att_v] );
   244                     mesh_vertex_mgr.find_attribute_store( att_v_names[att_v] )
   246                 vertex_attr_dims.push_back( cur_dim );
   249             if( !att_v_double_names.empty() )
   251                 index_t nb_attributes =
   252                     static_cast< index_t 
>( att_v_double_names.size() );
   254                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   256                     out << 
" " << att_v_double_names[attr_dbl_itr];
   259                 out << 
"PROP_LEGAL_RANGES";
   260                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   263                     out << 
" **none**  **none**";
   266                 out << 
"NO_DATA_VALUES";
   267                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   274                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   280                 out << 
"PROPERTY_CLASSES";
   281                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   283                     out << 
" " << att_v_double_names[attr_dbl_itr];
   286                 out << 
"PROPERTY_KINDS";
   287                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   290                     out << 
" \"Real Number\"";
   293                 out << 
"PROPERTY_SUBCLASSES";
   294                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   297                     out << 
" QUANTITY Float";
   301                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   304                         << std::to_string( vertex_attr_dims[attr_dbl_itr] );
   308                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   314                 for( 
auto attr_dbl_itr : 
range( nb_attributes ) )
   316                     out << 
"PROPERTY_CLASS_HEADER "   317                         << att_v_double_names[attr_dbl_itr] << 
" {"   319                     out << 
"kind: Real Number" << std::endl;
   320                     out << 
"unit: unitless" << std::endl;
   321                     out << 
"}" << std::endl;
   326         void read_number_of_vertices_and_triangles()
   328             GEO::LineInput in( filename_ );
   329             while( !in.eof() && in.get_line() )
   332                 if( in.nb_fields() > 0 )
   334                     if( in.field_matches( 0, 
"ZPOSITIVE" ) )
   336                         if( in.field_matches( 1, 
"Elevation" ) )
   340                         else if( in.field_matches( 1, 
"Depth" ) )
   345                     else if( in.field_matches( 0, 
"VRTX" )
   346                              || in.field_matches( 0, 
"PVRTX" ) )
   350                     else if( in.field_matches( 0, 
"PATOM" )
   351                              || in.field_matches( 0, 
"ATOM" ) )
   355                     else if( in.field_matches( 0, 
"TRGL" ) )
   363         void read_vertices_and_triangles()
   365             GEO::LineInput in( filename_ );
   368             while( !in.eof() && in.get_line() )
   371                 if( in.nb_fields() > 0 )
   373                     if( in.field_matches( 0, 
"VRTX" )
   374                         || in.field_matches( 0, 
"PVRTX" ) )
   376                         vertices_[mesh_dimension_ * v] =
   377                             in.field_as_double( 2 );
   378                         vertices_[mesh_dimension_ * v + 1] =
   379                             in.field_as_double( 3 );
   380                         vertices_[mesh_dimension_ * v + 2] =
   381                             in.field_as_double( 4 ) * z_sign_;
   382                         if( in.field_matches( 0, 
"PVRTX" ) )
   385                             for( 
auto prop_name_itr :
   386                                 range( vertex_property_names_.size() ) )
   388                                 for( 
auto v_attr_dim_itr :
   389                                     range( vertex_attribute_dims_
   392                                     vertex_attributes_[prop_name_itr][v]
   402                     else if( in.field_matches( 0, 
"PATOM" )
   403                              || in.field_matches( 0, 
"ATOM" ) )
   405                         index_t v0 = in.field_as_uint( 2 ) - starting_index_;
   406                         vertices_[mesh_dimension_ * v] =
   407                             vertices_[mesh_dimension_ * v0];
   408                         vertices_[mesh_dimension_ * v + 1] =
   409                             vertices_[mesh_dimension_ * v0 + 1];
   410                         vertices_[mesh_dimension_ * v + 2] =
   411                             vertices_[mesh_dimension_ * v0 + 2];
   414                     else if( in.field_matches( 0, 
"TRGL" ) )
   417                             index_t( in.field_as_uint( 1 ) - starting_index_ );
   418                         triangles_[3 * t + 1] =
   419                             index_t( in.field_as_uint( 2 ) - starting_index_ );
   420                         triangles_[3 * t + 2] =
   421                             index_t( in.field_as_uint( 3 ) - starting_index_ );
   428         void read_vertex_property_names()
   430             GEO::LineInput in( filename_ );
   431             while( !in.eof() && in.get_line() )
   434                 if( in.nb_fields() > 0 )
   436                     if( !in.field_matches( 0, 
"PROPERTIES" ) )
   440                     vertex_property_names_.reserve( in.nb_fields() - 1 );
   441                     for( 
auto prop_name_itr : 
range( 1, in.nb_fields() ) )
   443                         vertex_property_names_.push_back(
   444                             in.field( prop_name_itr ) );
   451         void read_vertex_property_sizes()
   453             GEO::LineInput in( filename_ );
   454             while( !in.eof() && in.get_line() )
   457                 if( in.nb_fields() > 0 )
   459                     if( !in.field_matches( 0, 
"ESIZES" ) )
   463                     vertex_property_names_.reserve( in.nb_fields() - 1 );
   464                     for( 
auto prop_size_itr : 
range( 1, in.nb_fields() ) )
   466                         vertex_attribute_dims_.push_back(
   467                             in.field_as_uint( prop_size_itr ) );
   474         void assign_and_repair_mesh( GEO::Mesh& mesh )
   476             GEO::coord_index_t dimension =
   477                 static_cast< GEO::coord_index_t 
>( mesh_dimension_ );
   478             mesh.facets.assign_triangle_mesh(
   479                 dimension, vertices_, triangles_, 
true );
   481             assign_tsurf_properties_to_geogram_mesh( mesh );
   485             GEO::mesh_repair( mesh, GEO::MESH_REPAIR_DUP_F );
   488         void assign_tsurf_properties_to_geogram_mesh( GEO::Mesh& mesh )
   490             for( 
auto prop_name_itr : 
range( vertex_property_names_.size() ) )
   492                 index_t nb_dimensions = vertex_attribute_dims_[prop_name_itr];
   493                 GEO::Attribute< double > attr;
   494                 attr.create_vector_attribute( mesh.vertices.attributes(),
   495                     vertex_property_names_[prop_name_itr], nb_dimensions );
   496                 for( 
auto v_itr : 
range( nb_vertices_ ) )
   498                     for( 
auto prop_dim_itr : 
range( nb_dimensions ) )
   500                         attr[v_itr * nb_dimensions + prop_dim_itr] =
   501                             vertex_attributes_[prop_name_itr][v_itr]
   510             GEO::LineInput in( filename_ );
   521         void allocate_vertices()
   523             vertices_.resize( mesh_dimension_ * nb_vertices_ );
   526         void allocate_triangles()
   528             triangles_.resize( 3 * nb_triangles_ );
   530         void allocate_vertex_properties()
   532             vertex_attributes_.resize( vertex_property_names_.size() );
   533             for( 
auto vertex_attributes_itr :
   534                 range( vertex_attributes_.size() ) )
   536                 vertex_attributes_[vertex_attributes_itr].resize(
   538                 for( 
auto vertex_itr : 
range( nb_vertices_ ) )
   540                     vertex_attributes_[vertex_attributes_itr][vertex_itr]
   542                             vertex_attribute_dims_[vertex_attributes_itr], 0 );
   548         index_t starting_index_;
   549         index_t mesh_dimension_;
   550         index_t nb_vertices_;
   551         index_t nb_triangles_;
   553         std::string filename_;
   554         GEO::vector< double > vertices_;
   555         GEO::vector< index_t > triangles_;
   556         GEO::vector< std::string > vertex_property_names_;
   557         GEO::vector< index_t > vertex_attribute_dims_;
   558         GEO::vector< GEO::vector< GEO::vector< double > > > vertex_attributes_;
   561     class LINMeshIOHandler final : 
public GEO::MeshIOHandler
   564         bool load( 
const std::string& filename,
   566             const GEO::MeshIOFlags& flag = GEO::MeshIOFlags() ) final
   569             GEO::LineInput file( filename );
   571             while( !file.eof() && file.get_line() )
   574                 if( file.nb_fields() > 0 )
   576                     if( file.field_matches( 0, 
"v" ) )
   578                         vec3 vertex = load_vertex( file, 1 );
   579                         mesh.vertices.create_vertex( vertex.data() );
   581                     else if( file.field_matches( 0, 
"s" ) )
   583                         mesh.edges.create_edge( file.field_as_uint( 1 ) - 1,
   584                             file.field_as_uint( 2 ) - 1 );
   590         bool save( 
const GEO::Mesh& M,
   591             const std::string& filename,
   592             const GEO::MeshIOFlags& ioflags = GEO::MeshIOFlags() ) final
   598                 "I/O", 
"Saving a Mesh into .lin format not implemented yet" );
   603         vec3 load_vertex( GEO::LineInput& file, index_t field )
 const   605             double x = file.field_as_double( field++ );
   606             double y = file.field_as_double( field++ );
   607             double z = file.field_as_double( field++ );
   608             return vec3( x, y, z );
   621         geo_register_MeshIOHandler_creator( TSurfMeshIOHandler, 
"ts" );
   622         geo_register_MeshIOHandler_creator( LINMeshIOHandler, 
"lin" );
   628         switch( M.cells.type( c ) )
   631             volume = GEO::Geom::tetra_signed_volume(
   632                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 0 ) ),
   633                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 1 ) ),
   634                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 2 ) ),
   635                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 3 ) ) );
   637         case GEO::MESH_PYRAMID:
   638             volume = GEO::Geom::tetra_signed_volume(
   639                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 0 ) ),
   640                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 1 ) ),
   641                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 2 ) ),
   642                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 4 ) ) );
   643             volume += GEO::Geom::tetra_signed_volume(
   644                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 0 ) ),
   645                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 2 ) ),
   646                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 3 ) ),
   647                 GEO::Geom::mesh_vertex( M, M.cells.vertex( c, 4 ) ) );
   649         case GEO::MESH_PRISM:
   653             for( 
auto f : 
range( M.cells.nb_facets( c ) ) )
   655                 switch( M.cells.facet_nb_vertices( c, f ) )
   658                     volume += GEO::Geom::tetra_signed_volume(
   659                         GEO::Geom::mesh_vertex(
   660                             M, M.cells.facet_vertex( c, f, 0 ) ),
   661                         GEO::Geom::mesh_vertex(
   662                             M, M.cells.facet_vertex( c, f, 1 ) ),
   663                         GEO::Geom::mesh_vertex(
   664                             M, M.cells.facet_vertex( c, f, 2 ) ),
   668                     volume += GEO::Geom::tetra_signed_volume(
   669                         GEO::Geom::mesh_vertex(
   670                             M, M.cells.facet_vertex( c, f, 0 ) ),
   671                         GEO::Geom::mesh_vertex(
   672                             M, M.cells.facet_vertex( c, f, 1 ) ),
   673                         GEO::Geom::mesh_vertex(
   674                             M, M.cells.facet_vertex( c, f, 2 ) ),
   676                     volume += GEO::Geom::tetra_signed_volume(
   677                         GEO::Geom::mesh_vertex(
   678                             M, M.cells.facet_vertex( c, f, 0 ) ),
   679                         GEO::Geom::mesh_vertex(
   680                             M, M.cells.facet_vertex( c, f, 2 ) ),
   681                         GEO::Geom::mesh_vertex(
   682                             M, M.cells.facet_vertex( c, f, 3 ) ),
   704         const GEO::Mesh& M, index_t cell, index_t f )
   706         vec3 result( 0., 0., 0. );
   707         index_t nb_vertices = M.cells.facet_nb_vertices( cell, f );
   708         for( 
auto v : 
range( nb_vertices ) )
   711                 GEO::Geom::mesh_vertex( M, M.cells.facet_vertex( cell, f, v ) );
   715         return result / 
static_cast< double >( nb_vertices );
   720         vec3 result( 0.0, 0.0, 0.0 );
   721         for( 
auto v : 
range( M.cells.nb_vertices( cell ) ) )
   723             result += GEO::Geom::mesh_vertex( M, M.cells.vertex( cell, v ) );
   725         return ( 1.0 / M.cells.nb_vertices( cell ) ) * result;
   730         std::vector< std::string > names =
   731             bounded_attribute_names( M.vertices.attributes() );
   732         names.erase( 
std::find( names.begin(), names.end(), 
"point" ) );
   737             M.facet_corners.attributes(), 
"facet_corners" );
   740             M.cell_corners.attributes(), 
"cell_corners" );
 
vec3 RINGMESH_API mesh_cell_barycenter(const GEO::Mesh &M, index_t cell)
void ringmesh_unused(const T &)
double RINGMESH_API mesh_cell_signed_volume(const GEO::Mesh &M, index_t c)
void RINGMESH_API print_bounded_attributes(const GEO::Mesh &M)
index_t find(const container &in, const T &value)
Returns the position of the first entity matching. 
static void err(const std::string &feature, const Args &... args)
double RINGMESH_API mesh_cell_volume(const GEO::Mesh &M, index_t c)
#define ringmesh_assert(x)
vec3 RINGMESH_API mesh_cell_facet_barycenter(const GEO::Mesh &M, index_t cell, index_t f)
Classes to build GeoModel from various inputs. 
void RINGMESH_API ringmesh_mesh_io_initialize()
complement the available MeshIOHandler 
#define ringmesh_assert_not_reached