RINGMesh  Version 5.0.0
A programming library for geological model meshes
io_model3d.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 
36 namespace {
37 
41  index_t nb_polygons( const GeoModel3D& geomodel )
42  {
43  index_t result { 0 };
44  for( const auto& surface : surface_range < 3 > ( geomodel ) ) {
45  result += surface.nb_mesh_elements();
46  }
47  return result;
48  }
49 
58  void save_region( index_t count, const Region3D& region, std::ostream& out )
59  {
60  out << "REGION " << count << " " << region.name() << " " << EOL;
61  index_t it { 0 };
62 
63  for( auto i : range( region.nb_boundaries() ) ) {
64  out << " ";
65  if( region.side( i ) ) {
66  out << "+";
67  } else {
68  out << "-";
69  }
70  out << region.boundary( i ).index() + 1;
71  it++;
72  if( it == 5 ) {
73  out << EOL;
74  it = 0;
75  }
76  }
77  out << " 0" << EOL;
78  }
79 
80  void save_universe(
81  index_t count,
82  const GeoModel3D& geomodel,
83  std::ostream& out )
84  {
85  const SurfaceSide surface_region_sides = geomodel.voi_surfaces();
86 
87  out << "REGION " << count << " Universe "
88  << EOL;
89  index_t it { 0 };
90 
91  for( auto i : range( surface_region_sides.surfaces_.size() ) ) {
92  out << " ";
93  if( surface_region_sides.sides_[ i ] ) {
94  out << "+";
95  } else {
96  out << "-";
97  }
98  out << surface_region_sides.surfaces_[ i ] + 1;
99  it++;
100  if( it == 5 ) {
101  out << EOL;
102  it = 0;
103  }
104  }
105  out << " 0" << EOL;
106  }
107 
117  void save_layer(
118  index_t offset,
119  const GeoModelGeologicalEntity3D& layer,
120  std::ostream& out )
121  {
122  out << "LAYER " << layer.name() << " " << EOL;
123  index_t it { 0 };
124 
125  for( auto i : range( layer.nb_children() ) ) {
126  out << " " << layer.child_gmme( i ).index() + offset + 1;
127  it++;
128  if( it == 5 ) {
129  out << EOL;
130  it = 0;
131  }
132  }
133  out << " 0" << EOL;
134  }
135 
140  void save_coordinate_system( std::ostream& out )
141  {
142  out << "GOCAD_ORIGINAL_COORDINATE_SYSTEM" << EOL << "NAME Default"
143  << EOL << "AXIS_NAME \"X\" \"Y\" \"Z\"" << EOL
144  << "AXIS_UNIT \"m\" \"m\" \"m\"" << EOL << "ZPOSITIVE Elevation"
145  << EOL << "END_ORIGINAL_COORDINATE_SYSTEM" << EOL;
146  }
147 
156  bool check_gocad_validity( const GeoModel3D& geomodel )
157  {
158  auto nb_interfaces = geomodel.nb_geological_entities(
159  Interface3D::type_name_static() );
160  if( nb_interfaces == 0 ) {
161  Logger::err( "", " The GeoModel ", geomodel.name(),
162  " has no Interface" );
163  return false;
164  }
165  for( auto& cur_interface : geomodel.geol_entities(
166  Interface3D::type_name_static() ) ) {
167  if( !cur_interface.has_geological_feature() ) {
168  Logger::err( "", cur_interface.gmge(), " has no geological feature" );
169  return false;
170  }
171  }
172  for( const auto& surface : surface_range < 3 > ( geomodel ) ) {
173  if( !surface.has_parent() ) {
174  Logger::err( "", surface.gmme(),
175  " does not belong to any Interface of the geomodel" );
176  return false;
177  }
178  if( !surface.is_simplicial() ) {
179  Logger::err( "", surface.gmme(), " is not triangulated " );
180  return false;
181  }
182  }
183  return true;
184  }
185 
187  bool has_surface_edge(
188  const Surface3D& surface,
189  index_t v0_in,
190  index_t v1_in )
191  {
192  for( auto i : range( surface.nb_mesh_elements() ) ) {
193  for( auto j : range( surface.nb_mesh_element_vertices( i ) ) ) {
194  auto v0 = surface.mesh_element_vertex_index(
195  { i, j } );
196  auto v1 = surface.mesh_element_vertex_index(
197  surface.mesh().next_polygon_vertex(
198  { i, j } ) );
199  if( ( v0 == v0_in && v1 == v1_in )
200  || ( v0 == v1_in && v1 == v0_in ) ) {
201  return true;
202  }
203  }
204  }
205  return false;
206  }
207 
213  void save_gocad_model3d( const GeoModel3D& geomodel, std::ostream& out )
214  {
215  if( !check_gocad_validity( geomodel ) ) {
216  throw RINGMeshException( "I/O", " The GeoModel ", geomodel.name(),
217  " cannot be saved in .ml format" );
218  }
219  out.precision( 16 );
220 
221  // Gocad Model3d headers
222  out << "GOCAD Model3d 1" << EOL << "HEADER {" << EOL << "name: "
223  << geomodel.name() << EOL << "}" << EOL;
224 
225  save_coordinate_system( out );
226 
227  // Gocad::TSurf = RINGMesh::Interface
228  for( auto& tsurf : geomodel.geol_entities(
229  Interface3D::type_name_static() ) ) {
230  out << "TSURF " << tsurf.name() << EOL;
231  }
232 
233  index_t count { 1 };
234 
235  // Gocad::TFace = RINGMesh::Surface
236  for( const auto& surface : geomodel.surfaces() ) {
237  const gmge_id& parent_interface = surface.parent_gmge(
238  Interface3D::type_name_static() );
239  if( !parent_interface.is_defined() ) {
240  throw RINGMeshException( "I/O", "Failed to save GeoModel",
241  " in .ml Gocad format because Surface ", surface.index(),
242  " has no Interface parent)" );
243  }
244  const auto& cur_geol_feature =
245  geomodel.geological_entity( parent_interface ).geological_feature();
246 
247  out << "TFACE " << count << " ";
248  out << GeoModelGeologicalEntity3D::geol_name( cur_geol_feature );
249  out << " " << surface.parent( Interface3D::type_name_static() ).name()
250  << EOL;
251 
252  // Print the key polygon which is the first three
253  // vertices of the first polygon
254  out << " "
255  << surface.mesh_element_vertex( { 0, 0 } )
256  << EOL;
257  out << " "
258  << surface.mesh_element_vertex( { 0, 1 } )
259  << EOL;
260  out << " "
261  << surface.mesh_element_vertex( { 0, 2 } )
262  << EOL;
263 
264  ++count;
265  }
266  // Universe
267  auto offset_layer = count;
268  save_universe( count, geomodel, out );
269  ++count;
270  // Regions
271  for( const auto& region : geomodel.regions() ) {
272  save_region( count, region, out );
273  ++count;
274  }
275  // Layers
276  if( geomodel.entity_type_manager().geological_entity_manager.is_valid_type(
277  Layer3D::type_name_static() ) ) {
278  for( auto& layer : geomodel.geol_entities( Layer3D::type_name_static() ) ) {
279  save_layer( offset_layer, layer, out );
280  ++count;
281  }
282  }
283  out << "END" << EOL;
284 
285  const auto& geomodel_vertices = geomodel.mesh.vertices;
286  // Save the geometry of the Surfaces, Interface per Interface
287  for( auto& tsurf : geomodel.geol_entities( Interface3D::type_name_static() ) ) {
288  // TSurf beginning header
289  out << "GOCAD TSurf 1" << EOL << "HEADER {" << EOL << "name:"
290  << tsurf.name() << EOL << "name_in_model_list:" << tsurf.name()
291  << EOL << "}" << EOL;
292  save_coordinate_system( out );
293 
294  out << "GEOLOGICAL_FEATURE " << tsurf.name() << EOL
295  << "GEOLOGICAL_TYPE ";
296  out << GeoModelGeologicalEntity < 3
297  > ::geol_name( tsurf.geological_feature() );
298  out << EOL;
299  out << "PROPERTY_CLASS_HEADER Z {" << EOL << "is_z:on" << EOL
300  << "}" << EOL;
301 
302  index_t vertex_count { 1 };
303  // TFace vertex index = Surface vertex index + offset
304  auto offset = vertex_count;
305 
306  // To collect Corners(BStones) indexes
307  // and boundary (Line) first and second vertex indexes
308  std::set< index_t > corners;
309  std::set< std::pair< index_t, index_t > > lineindices;
310  for( auto j : range( tsurf.nb_children() ) ) {
311  offset = vertex_count;
312  const auto& surface =
313  dynamic_cast< const Surface3D& >( tsurf.child( j ) );
314 
315  out << "TFACE" << EOL;
316  for( auto k : range( surface.nb_vertices() ) ) {
317  out << "VRTX " << vertex_count << " " << surface.vertex( k )
318  << EOL;
319  vertex_count++;
320  }
321  for( auto k : range( surface.nb_mesh_elements() ) ) {
322  out << "TRGL "
323  << surface.mesh_element_vertex_index(
324  { k, 0 } ) + offset << " "
325  << surface.mesh_element_vertex_index(
326  { k, 1 } ) + offset << " "
327  << surface.mesh_element_vertex_index(
328  { k, 2 } ) + offset << EOL;
329  }
330  for( auto k : range( surface.nb_boundaries() ) ) {
331  const auto& line = surface.boundary( k );
332  auto v0_model_id = geomodel_vertices.geomodel_vertex_id(
333  line.gmme(), 0 );
334  auto v1_model_id = geomodel_vertices.geomodel_vertex_id(
335  line.gmme(), 1 );
336 
337  auto v0_surface_ids =
338  geomodel_vertices.mesh_entity_vertex_id( surface.gmme(),
339  v0_model_id );
340  auto v1_surface_ids =
341  geomodel_vertices.mesh_entity_vertex_id( surface.gmme(),
342  v1_model_id );
343 
344  if( !surface.has_inside_border() ) {
345  auto v0 = v0_surface_ids[0];
346  auto v1 = v1_surface_ids[0];
347  v0 += offset;
348  v1 += offset;
349 
350  lineindices.insert(
351  std::pair< index_t, index_t >( v0, v1 ) );
352  corners.insert( v0 );
353  } else {
354  // We need to get the right pair of v0 - v1 (not crossing the inside boundary)
355  // corner and a border
356  int count = 0;
357  bool to_break = false;
358  for( auto v0 : v0_surface_ids ) {
359  for( auto v1 : v1_surface_ids ) {
360  if( has_surface_edge( surface, v0, v1 ) ) {
361  lineindices.insert(
362  std::pair< index_t, index_t >( v0 + offset,
363  v1 + offset ) );
364  count++;
365  }
366  if( !line.is_inside_border( surface )
367  && count == 1 ) {
368  to_break = true;
369  break;
370  } else if( count == 2 ) {
371  to_break = true;
372  break;
373  }
374  }
375  if( to_break ) {
376  corners.insert( v0 + offset );
377  break;
378  }
379  }
380  }
381 
382  // Set a BSTONE at the line other extremity
383  const auto& c1_id = line.boundary_gmme( 1 );
384  auto gme_vertices =
385  geomodel_vertices.mesh_entity_vertex_id( surface.gmme(),
386  geomodel_vertices.geomodel_vertex_id( c1_id ) );
387  corners.insert( gme_vertices.front() + offset );
388  }
389  }
390  // Add the remaining bstones that are not already in bstones
391  for( auto it( corners.begin() ); it != corners.end(); ++it ) {
392  out << "BSTONE " << *it << EOL;
393  }
394  for( auto it( lineindices.begin() ); it != lineindices.end(); ++it ) {
395  out << "BORDER " << vertex_count << " " << it->first << " "
396  << it->second << EOL;
397  vertex_count++;
398  }
399  out << "END" << EOL;
400  }
401  }
402 
403  class MLIOHandler final: public GeoModelIOHandler< 3 > {
404  public:
408  void load( const std::string& filename, GeoModel3D& geomodel ) final
409  {
410  std::ifstream input( filename.c_str() );
411  if( !input ) {
412  throw RINGMeshException( "I/O", "Failed to open file ", filename );
413  }
414  GeoModelBuilderML builder( geomodel, filename );
415  builder.build_geomodel();
416  }
417 
418  void save( const GeoModel< 3 >& geomodel, const std::string& filename ) final
419  {
420  std::ofstream out( filename.c_str() );
421  save_gocad_model3d( geomodel, out );
422  out << std::flush;
423  }
424  };
425 }
const char EOL
Definition: io.h:45