RINGMesh  Version 5.0.0
A programming library for geological model meshes
mesh.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 
38 #include <ringmesh/mesh/mesh.h>
39 
40 #include <numeric>
43 #include <stack>
44 
46 
47 namespace RINGMesh
48 {
50  : element_id_( std::move( edge_local_vertex.edge_id_ ) ),
51  local_vertex_id_( std::move( edge_local_vertex.local_vertex_id_ ) )
52  {
53  }
54 
56  PolygonLocalEdge polygon_local_edge )
57  : element_id_( std::move( polygon_local_edge.polygon_id_ ) ),
58  local_vertex_id_( std::move( polygon_local_edge.local_edge_id_ ) )
59  {
60  }
61 
63  : element_id_( std::move( cell_local_facet.cell_id_ ) ),
64  local_vertex_id_( std::move( cell_local_facet.local_facet_id_ ) )
65  {
66  }
67 
68  template < index_t DIMENSION >
69  std::unique_ptr< PointSetMesh< DIMENSION > >
71  {
72  auto new_type = type;
73  if( new_type.empty() )
74  {
76  }
77  auto mesh = PointSetMeshFactory< DIMENSION >::create( new_type );
78  if( !mesh )
79  {
80  Logger::warn( "PointSetMesh",
81  "Could not create mesh data structure: ", new_type );
82  Logger::warn( "PointSetMesh",
83  "Falling back to GeogramPointSetMesh data structure" );
84 
85  mesh.reset( new GeogramPointSetMesh< DIMENSION > );
86  }
87  return mesh;
88  }
89 
90  template < index_t DIMENSION >
91  std::tuple< index_t, std::vector< index_t > >
93  {
94  const auto nb_compoments = this->nb_vertices();
95  std::vector< index_t > components( nb_compoments );
96  std::iota( components.begin(), components.end(), 0 );
97  return std::make_tuple( nb_compoments, components );
98  }
99 
100  template < index_t DIMENSION >
101  std::unique_ptr< LineMesh< DIMENSION > > LineMesh< DIMENSION >::create_mesh(
102  const MeshType type )
103  {
104  MeshType new_type = type;
105  if( new_type.empty() )
106  {
108  }
109  auto mesh = LineMeshFactory< DIMENSION >::create( new_type );
110  if( !mesh )
111  {
112  Logger::warn( "LineMesh", "Could not create mesh data structure: ",
113  new_type );
114  Logger::warn(
115  "LineMesh", "Falling back to GeogramLineMesh data structure" );
116 
117  mesh.reset( new GeogramLineMesh< DIMENSION > );
118  }
119  return mesh;
120  }
121 
122  template < index_t DIMENSION >
123  std::tuple< index_t, std::vector< index_t > >
125  {
126  std::vector< index_t > components( nb_edges(), NO_ID );
127  std::vector< index_t > vertex_components( this->nb_vertices(), NO_ID );
128  index_t nb_components{ 0 };
129 
130  for( auto edge : range( nb_edges() ) )
131  {
132  ringmesh_assert( components[edge] == NO_ID );
133  const auto v0 = edge_vertex( { edge, 0 } );
134  const auto v1 = edge_vertex( { edge, 1 } );
135  if( vertex_components[v0] == NO_ID
136  && vertex_components[v1] == NO_ID )
137  {
138  vertex_components[v0] = nb_components;
139  vertex_components[v1] = nb_components;
140  components[edge] = nb_components;
141  ++nb_components;
142  }
143  else if( vertex_components[v0] != NO_ID
144  && vertex_components[v1] == NO_ID )
145  {
146  vertex_components[v1] = vertex_components[v0];
147  components[edge] = vertex_components[v0];
148  }
149  else if( vertex_components[v0] == NO_ID
150  && vertex_components[v1] != NO_ID )
151  {
152  vertex_components[v0] = vertex_components[v1];
153  components[edge] = vertex_components[v1];
154  }
155  else
156  {
157  // Case both nodes have already a connected component.
158  if( vertex_components[v0] == vertex_components[v1] )
159  {
160  components[edge] = vertex_components[v0];
161  }
162  else
163  {
164  // It appears that 2 previously identified connected
165  // components
166  // correspond in fact to a unique connected component.
167  auto min_connected_components = std::min(
168  vertex_components[v0], vertex_components[v1] );
169  auto max_connected_components = std::max(
170  vertex_components[v0], vertex_components[v1] );
171  ringmesh_assert( min_connected_components != NO_ID );
172  ringmesh_assert( max_connected_components != NO_ID );
173  for( auto previous_edge : range( edge ) )
174  {
175  ringmesh_assert( components[previous_edge] != NO_ID );
176  ringmesh_assert( vertex_components[edge_vertex(
177  { previous_edge, 0 } )]
178  != NO_ID );
179  ringmesh_assert( vertex_components[edge_vertex(
180  { previous_edge, 1 } )]
181  != NO_ID );
182  if( components[previous_edge]
183  == max_connected_components )
184  {
185  components[previous_edge] =
186  min_connected_components;
187  vertex_components[edge_vertex( { previous_edge,
188  0 } )] = min_connected_components;
189  vertex_components[edge_vertex( { previous_edge,
190  1 } )] = min_connected_components;
191  }
192  else if( components[previous_edge]
193  > max_connected_components )
194  {
196  components[previous_edge] - 1 >= 0 );
197  ringmesh_assert( vertex_components[edge_vertex(
198  { previous_edge, 0 } )]
199  - 1
200  >= 0 );
201  ringmesh_assert( vertex_components[edge_vertex(
202  { previous_edge, 1 } )]
203  - 1
204  >= 0 );
205  --components[previous_edge];
206  vertex_components[edge_vertex( { previous_edge,
207  0 } )] = components[previous_edge];
208  vertex_components[edge_vertex( { previous_edge,
209  1 } )] = components[previous_edge];
211  components[previous_edge] != NO_ID );
212  ringmesh_assert( vertex_components[edge_vertex(
213  { previous_edge, 0 } )]
214  != NO_ID );
215  ringmesh_assert( vertex_components[edge_vertex(
216  { previous_edge, 1 } )]
217  != NO_ID );
218  ringmesh_assert( components[previous_edge]
219  == vertex_components[edge_vertex(
220  { previous_edge, 0 } )] );
221  ringmesh_assert( components[previous_edge]
222  == vertex_components[edge_vertex(
223  { previous_edge, 1 } )] );
224  }
225  }
226  components[edge] = min_connected_components;
227  vertex_components[v0] = min_connected_components;
228  vertex_components[v1] = min_connected_components;
229  --nb_components;
230  }
231  }
232  ringmesh_assert( components[edge] != NO_ID );
233  ringmesh_assert( vertex_components[v0] != NO_ID );
234  ringmesh_assert( vertex_components[v1] != NO_ID );
235  ringmesh_assert( components[edge] == vertex_components[v0] );
236  ringmesh_assert( components[edge] == vertex_components[v1] );
237  }
238 
239  return std::make_tuple( nb_components, components );
240  }
241 
242  template < index_t DIMENSION >
243  std::unique_ptr< SurfaceMesh< DIMENSION > >
245  {
246  MeshType new_type = type;
247  if( new_type.empty() )
248  {
250  }
251  auto mesh = SurfaceMeshFactory< DIMENSION >::create( new_type );
252  if( !mesh )
253  {
254  Logger::warn( "SurfaceMesh",
255  "Could not create mesh data structure: ", new_type );
256  Logger::warn( "SurfaceMesh",
257  "Falling back to GeogramSurfaceMesh data structure" );
258 
259  mesh.reset( new GeogramSurfaceMesh< DIMENSION > );
260  }
261  return mesh;
262  }
263 
264  template < index_t DIMENSION >
266  const PolygonLocalEdge& polygon_local_edge ) const
267  {
269  polygon_local_edge.local_edge_id_
270  < nb_polygon_vertices( polygon_local_edge.polygon_id_ ) );
271  ringmesh_assert( is_edge_on_border( polygon_local_edge ) );
272 
273  // Global indices in the surfaces
274  auto next_v_id =
275  polygon_vertex( next_polygon_vertex( polygon_local_edge ) );
276 
277  // Get the polygons around the shared vertex (next_v_id) that are on the
278  // boundary
279  // There must be one (the current one) or two (the next one on boundary)
280  auto polygons_around_next_v_id = polygons_around_vertex(
281  next_v_id, true, polygon_local_edge.polygon_id_ );
282  auto nb_around =
283  static_cast< index_t >( polygons_around_next_v_id.size() );
284  ringmesh_assert( nb_around == 1 || nb_around == 2 );
285 
286  PolygonLocalEdge next_polygon_local_edge{ NO_ID, NO_ID };
287  auto& next_p = next_polygon_local_edge.polygon_id_;
288  next_p = polygons_around_next_v_id[0];
289  auto& next_e = next_polygon_local_edge.local_edge_id_;
290 
291  if( nb_around == 2 )
292  {
293  if( next_p == polygon_local_edge.polygon_id_ )
294  {
295  next_p = polygons_around_next_v_id[1];
296  }
297  ringmesh_assert( next_p != NO_ID );
298  ringmesh_assert( is_polygon_on_border( next_p ) );
299 
300  // Local index of next vertex in the next polygon
301  next_e = vertex_index_in_polygon( next_p, next_v_id );
302  ringmesh_assert( is_edge_on_border( next_polygon_local_edge ) );
303  }
304  else if( nb_around == 1 )
305  {
306  // next_v_id must be in two border edges of polygon p
307  next_e = vertex_index_in_polygon( next_p, next_v_id );
308  ringmesh_assert( is_edge_on_border( next_polygon_local_edge ) );
309  }
310 
311  return next_polygon_local_edge;
312  }
313 
314  template < index_t DIMENSION >
316  const PolygonLocalEdge& polygon_local_edge ) const
317  {
319  polygon_local_edge.local_edge_id_
320  < nb_polygon_vertices( polygon_local_edge.polygon_id_ ) );
321  ringmesh_assert( is_edge_on_border( polygon_local_edge ) );
322 
323  // Global indices in the surfaces
324  auto v_id = polygon_vertex( { polygon_local_edge } );
325 
326  // Get the polygons around the shared vertex (v_id) that are on the
327  // boundary
328  // There must be one (the current one) or two (the next one on boundary)
329  auto polygons_around_v_id = polygons_around_vertex(
330  v_id, true, polygon_local_edge.polygon_id_ );
331  auto nb_around = static_cast< index_t >( polygons_around_v_id.size() );
332  ringmesh_assert( nb_around == 1 || nb_around == 2 );
333 
334  PolygonLocalEdge prev_polygon_local_edge{ NO_ID, NO_ID };
335  auto& prev_p = prev_polygon_local_edge.polygon_id_;
336  prev_p = polygons_around_v_id[0];
337  auto& prev_e = prev_polygon_local_edge.local_edge_id_;
338 
339  if( nb_around == 2 )
340  {
341  if( prev_p == polygon_local_edge.polygon_id_ )
342  {
343  prev_p = polygons_around_v_id[1];
344  }
345  ringmesh_assert( prev_p != NO_ID );
346  ringmesh_assert( is_polygon_on_border( prev_p ) );
347 
348  // Local index of given vertex in the prev polygon
349  auto v_in_prev_f = vertex_index_in_polygon( prev_p, v_id );
350  // Local index of previous vertex in the prev polygon
351  prev_e =
352  prev_polygon_vertex( { prev_p, v_in_prev_f } ).local_vertex_id_;
353  ringmesh_assert( is_edge_on_border( prev_polygon_local_edge ) );
354  }
355  else if( nb_around == 1 )
356  {
357  // v_id must be in two border edges of polygon p
358  auto v_in_next_polygon = vertex_index_in_polygon( prev_p, v_id );
359  prev_e = prev_polygon_vertex( { prev_p, v_in_next_polygon } )
361  ringmesh_assert( is_edge_on_border( prev_polygon_local_edge ) );
362  }
363 
364  return prev_polygon_local_edge;
365  }
366 
367  template < index_t DIMENSION >
369  index_t in0, index_t in1 ) const
370  {
372  in0 < this->nb_vertices() && in1 < this->nb_vertices() );
373 
374  // Another possible, probably faster, algorithm is to check if the 2
375  // indices
376  // are neighbors in polygons_ and check that they are in the same
377  // polygon
378 
379  // Check if the edge is in one of the polygon
380  for( auto poly : range( nb_polygons() ) )
381  {
382  bool found = false;
383  auto prev =
384  polygon_vertex( { poly, nb_polygon_vertices( poly ) - 1 } );
385  for( auto v : range( nb_polygon_vertices( poly ) ) )
386  {
387  auto p = polygon_vertex( { poly, v } );
388  if( ( prev == in0 && p == in1 ) || ( prev == in1 && p == in0 ) )
389  {
390  found = true;
391  break;
392  }
393  prev = p;
394  }
395  if( found )
396  {
397  return poly;
398  }
399  }
400  return NO_ID;
401  }
402 
403  template < index_t DIMENSION >
405  index_t polygon_index, index_t vertex_id ) const
406  {
407  ringmesh_assert( polygon_index < nb_polygons() );
408  for( auto v : range( nb_polygon_vertices( polygon_index ) ) )
409  {
410  if( polygon_vertex( { polygon_index, v } ) == vertex_id )
411  {
412  return v;
413  }
414  }
415  return NO_ID;
416  }
417 
418  template < index_t DIMENSION >
420  index_t p, const vecn< DIMENSION >& v ) const
421  {
422  index_t result{ 0 };
423  double dist{ DBL_MAX };
424  for( auto v_id : range( nb_polygon_vertices( p ) ) )
425  {
426  double distance = length2(
427  v
428  - this->vertex(
429  polygon_vertex( ElementLocalVertex( p, v_id ) ) ) );
430  if( dist > distance )
431  {
432  dist = distance;
433  result = v_id;
434  }
435  }
436  return result;
437  }
438 
439  template < index_t DIMENSION >
441  index_t surf_vertex_id, bool border_only, index_t p0 ) const
442  {
443  index_t cur_p{ 0 };
444  while( p0 == NO_ID && cur_p < nb_polygons() )
445  {
446  for( auto lv : range( nb_polygon_vertices( cur_p ) ) )
447  {
448  if( polygon_vertex( { cur_p, lv } ) == surf_vertex_id )
449  {
450  p0 = cur_p;
451  break;
452  }
453  }
454  cur_p++;
455  }
456  ringmesh_assert( p0 != NO_ID );
457 
458  // Flag the visited polygons
459  std::vector< index_t > visited;
460  visited.reserve( 10 );
461 
462  // Stack of the adjacent polygons
463  std::stack< index_t > S;
464  S.push( p0 );
465  visited.push_back( p0 );
466 
467  std::vector< index_t > result;
468  result.reserve( 10 );
469  do
470  {
471  auto p = S.top();
472  S.pop();
473 
474  for( auto v : range( nb_polygon_vertices( p ) ) )
475  {
476  if( polygon_vertex( { p, v } ) == surf_vertex_id )
477  {
478  auto adj_P = polygon_adjacent( { p, v } );
479  auto prev =
480  prev_polygon_vertex( { p, v } ).local_vertex_id_;
481  auto adj_prev = polygon_adjacent( { p, prev } );
482 
483  if( adj_P != NO_ID )
484  {
485  // The edge starting at P is not on the boundary
486  if( !contains( visited, adj_P ) )
487  {
488  S.push( adj_P );
489  visited.push_back( adj_P );
490  }
491  }
492  if( adj_prev != NO_ID )
493  {
494  // The edge ending at P is not on the boundary
495  if( !contains( visited, adj_prev ) )
496  {
497  S.push( adj_prev );
498  visited.push_back( adj_prev );
499  }
500  }
501 
502  if( border_only )
503  {
504  if( adj_P == NO_ID || adj_prev == NO_ID )
505  {
506  result.push_back( p );
507  }
508  }
509  else
510  {
511  result.push_back( p );
512  }
513 
514  // We are done with this polygon
515  break;
516  }
517  }
518  } while( !S.empty() );
519 
520  return result;
521  }
522 
523  double SurfaceMesh< 3 >::polygon_area( index_t polygon_id ) const
524  {
525  double result = 0.0;
526  if( nb_polygon_vertices( polygon_id ) == 0 )
527  {
528  return result;
529  }
530  const vec3& p1 =
531  vertex( polygon_vertex( ElementLocalVertex( polygon_id, 0 ) ) );
532  for( auto i : range( 1, nb_polygon_vertices( polygon_id ) - 1 ) )
533  {
534  const vec3& p2 =
535  vertex( polygon_vertex( ElementLocalVertex( polygon_id, i ) ) );
536  const vec3& p3 = vertex(
537  polygon_vertex( ElementLocalVertex( polygon_id, i + 1 ) ) );
538  result += triangle_signed_area(
539  p1, p2, p3, polygon_normal( polygon_id ) );
540  }
541  return std::fabs( result );
542  }
543 
544  template < index_t DIMENSION >
545  std::tuple< index_t, std::vector< index_t > >
547  {
548  std::vector< index_t > components( nb_polygons(), NO_ID );
549  index_t nb_components{ 0 };
550  for( auto polygon : range( nb_polygons() ) )
551  {
552  if( components[polygon] == NO_ID )
553  {
554  std::stack< index_t > S;
555  S.push( polygon );
556  components[polygon] = nb_components;
557  do
558  {
559  auto cur_polygon = S.top();
560  S.pop();
561  for( auto edge :
562  range( nb_polygon_vertices( cur_polygon ) ) )
563  {
564  auto adj_polygon =
565  polygon_adjacent( { cur_polygon, edge } );
566  if( adj_polygon != NO_ID
567  && components[adj_polygon] == NO_ID )
568  {
569  S.push( adj_polygon );
570  components[adj_polygon] = nb_components;
571  }
572  }
573  } while( !S.empty() );
574  nb_components++;
575  }
576  }
577  return std::make_tuple( nb_components, components );
578  }
579 
580  template < index_t DIMENSION >
581  std::unique_ptr< VolumeMesh< DIMENSION > >
583  {
584  auto new_type = type;
585  if( new_type.empty() )
586  {
588  }
589  auto mesh = VolumeMeshFactory< DIMENSION >::create( new_type );
590  if( !mesh )
591  {
592  Logger::warn( "VolumeMesh",
593  "Could not create mesh data structure: ", new_type );
594  Logger::warn( "VolumeMesh",
595  "Falling back to GeogramVolumeMesh data structure" );
596 
597  mesh.reset( new GeogramVolumeMesh< DIMENSION > );
598  }
599  return mesh;
600  }
601 
602  template < index_t DIMENSION >
603  std::tuple< index_t, std::vector< index_t > >
605  {
606  std::vector< index_t > components( nb_cells(), NO_ID );
607  index_t nb_components{ 0 };
608  for( auto cell : range( nb_cells() ) )
609  {
610  if( components[cell] == NO_ID )
611  {
612  std::stack< index_t > S;
613  S.push( cell );
614  components[cell] = nb_components;
615  do
616  {
617  auto cur_cell = S.top();
618  S.pop();
619  for( auto facet : range( nb_cell_facets( cur_cell ) ) )
620  {
621  auto adj_cell = cell_adjacent( { cur_cell, facet } );
622  if( adj_cell != NO_ID && components[adj_cell] == NO_ID )
623  {
624  S.push( adj_cell );
625  components[adj_cell] = nb_components;
626  }
627  }
628  } while( !S.empty() );
629  nb_components++;
630  }
631  }
632  return std::make_tuple( nb_components, components );
633  }
634 
635  template < index_t DIMENSION >
637  index_t vertex_id, index_t cell_hint ) const
638  {
639  std::vector< index_t > result;
640 
641  if( cell_hint == NO_ID )
642  {
643  const vecn< DIMENSION > cur_vec = this->vertex( vertex_id );
644  index_t cell_vertex_not_used = NO_ID;
645  bool found = find_cell_from_colocated_vertex_within_distance_if_any(
646  cur_vec, global_epsilon, cell_hint, cell_vertex_not_used );
647  if( !found )
648  {
649  return result;
650  }
651  }
652  ringmesh_assert( cell_hint != NO_ID );
653 
654  // Flag the visited cells
655  std::vector< index_t > visited;
656  visited.reserve( 10 );
657 
658  // Stack of the adjacent cells
659  std::stack< index_t > S;
660  S.push( cell_hint );
661  visited.push_back( cell_hint );
662 
663  do
664  {
665  auto c = S.top();
666  S.pop();
667 
668  bool cell_includes_vertex{ false };
669  for( auto v : range( nb_cell_vertices( c ) ) )
670  {
671  if( cell_vertex( { c, v } ) == vertex_id )
672  {
673  result.push_back( c );
674  cell_includes_vertex = true;
675  break;
676  }
677  }
678  if( !cell_includes_vertex )
679  {
680  continue;
681  }
682 
683  for( auto f : range( nb_cell_facets( c ) ) )
684  {
685  for( auto v : range( nb_cell_facet_vertices( { c, f } ) ) )
686  {
687  auto vertex = cell_facet_vertex( { c, f }, v );
688  if( vertex == vertex_id )
689  {
690  auto adj_P = cell_adjacent( { c, f } );
691 
692  if( adj_P != NO_ID )
693  {
694  if( !contains( visited, adj_P ) )
695  {
696  S.push( adj_P );
697  visited.push_back( adj_P );
698  }
699  }
700  break;
701  }
702  }
703  }
704  } while( !S.empty() );
705 
706  return result;
707  }
708 
709  template < index_t DIMENSION >
712  const vecn< DIMENSION >& vertex_vec,
713  double distance,
714  index_t& cell_id,
715  index_t& cell_vertex_id ) const
716  {
717  bool result = false;
718  cell_nn_search().get_neighbors( vertex_vec,
719  [this, &vertex_vec, &result, &cell_id, &cell_vertex_id, distance](
720  index_t i ) {
721  for( auto j : range( nb_cell_vertices( i ) ) )
722  {
723  if( inexact_equal( this->vertex( cell_vertex( { i, j } ) ),
724  vertex_vec, distance ) )
725  {
726  cell_vertex_id = cell_vertex( { i, j } );
727  cell_id = i;
728  result = true;
729  break;
730  }
731  }
732  return result;
733  } );
734  return result;
735  }
736 
737  template < index_t DIMENSION >
739  {
740  create_point_set_mesh( "" );
741  create_line_mesh( "" );
742  create_well_mesh( "" );
743  create_surface_mesh( "" );
744  }
745 
746  template < index_t DIMENSION >
748  {
749  point_set_mesh = PointSetMesh< DIMENSION >::create_mesh( type );
750  }
751 
752  template < index_t DIMENSION >
754  {
755  line_mesh = LineMesh< DIMENSION >::create_mesh( type );
756  }
757 
758  template < index_t DIMENSION >
760  {
761  well_mesh = LineMesh< DIMENSION >::create_mesh( type );
762  }
763 
764  template < index_t DIMENSION >
766  {
767  surface_mesh = SurfaceMesh< DIMENSION >::create_mesh( type );
768  }
769 
771  {
772  create_volume_mesh( "" );
773  }
774 
776  {
777  volume_mesh = VolumeMesh3D::create_mesh( type );
778  }
779 
780  template class RINGMESH_API PointSetMesh< 2 >;
781  template class RINGMESH_API LineMesh< 2 >;
782  template class RINGMESH_API SurfaceMeshBase< 2 >;
783  template class RINGMESH_API MeshSetBase< 2 >;
784  template class RINGMESH_API MeshSet< 2 >;
785 
786  template class RINGMESH_API PointSetMesh< 3 >;
787  template class RINGMESH_API LineMesh< 3 >;
788  template class RINGMESH_API SurfaceMeshBase< 3 >;
789  template class RINGMESH_API VolumeMesh< 3 >;
790  template class RINGMESH_API MeshSetBase< 3 >;
791 } // namespace RINGMesh
static std::unique_ptr< PointSetMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:70
index_t polygon_from_vertex_ids(index_t in0, index_t in1) const
Get the first polygon of the surface that has an edge linking the two vertices (ids in the surface) ...
Definition: mesh.cpp:368
virtual double polygon_area(index_t polygon_id) const =0
GEO::vecng< DIMENSION, double > vecn
Definition: types.h:74
std::tuple< index_t, std::vector< index_t > > connected_components() const final
Definition: mesh.cpp:604
static std::unique_ptr< BaseClass > create(const Key &key, const Args &... args)
Definition: factory.h:85
std::tuple< index_t, std::vector< index_t > > connected_components() const final
Definition: mesh.cpp:124
static std::unique_ptr< LineMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:101
PolygonLocalEdge next_on_border(const PolygonLocalEdge &polygon_local_edge) const
Get the next edge on the border.
Definition: mesh.cpp:265
PolygonLocalEdge prev_on_border(const PolygonLocalEdge &polygon_local_edge) const
Get the previous edge on the border.
Definition: mesh.cpp:315
void create_point_set_mesh(MeshType type)
Definition: mesh.cpp:747
vecn< 3 > vec3
Definition: types.h:76
index_t closest_vertex_in_polygon(index_t polygon_index, const vecn< DIMENSION > &query_point) const
Compute closest vertex in a polygon to a point.
Definition: mesh.cpp:419
double RINGMESH_API triangle_signed_area(const vec3 &p0, const vec3 &p1, const vec3 &p2, const vec3 &triangle_normal)
Definition: geometry.cpp:66
index_t vertex_index_in_polygon(index_t polygon_index, index_t vertex_id) const
Get the vertex index in a polygon.
Definition: mesh.cpp:404
static void warn(const std::string &feature, const Args &... args)
Definition: logger.h:75
std::vector< index_t > polygons_around_vertex(index_t vertex_id, bool border_only, index_t first_polygon) const
Determines the polygons around a vertex.
Definition: mesh.cpp:440
void create_well_mesh(MeshType type)
Definition: mesh.cpp:759
bool find_cell_from_colocated_vertex_within_distance_if_any(const vecn< DIMENSION > &vertex_vec, double distance, index_t &cell_id, index_t &cell_vertex_id) const
Definition: mesh.cpp:711
std::string MeshType
Definition: mesh.h:69
std::tuple< index_t, std::vector< index_t > > connected_components() const final
Definition: mesh.cpp:546
std::tuple< index_t, std::vector< index_t > > connected_components() const final
Definition: mesh.cpp:92
#define ringmesh_assert(x)
bool contains(const container &in, const T &value)
Definition: algorithm.h:87
static std::unique_ptr< SurfaceMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:244
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
void create_line_mesh(MeshType type)
Definition: mesh.cpp:753
void create_surface_mesh(MeshType type)
Definition: mesh.cpp:765
std::vector< index_t > cells_around_vertex(index_t vertex_id, index_t cell_hint) const
Definition: mesh.cpp:636
static std::unique_ptr< VolumeMesh< DIMENSION > > create_mesh(const MeshType type="")
Definition: mesh.cpp:582
bool inexact_equal(const vecn< DIMENSION > &v1, const vecn< DIMENSION > &v2, double epsilon)
Definition: geometry.h:67