RINGMesh  Version 5.0.0
A programming library for geological model meshes
mesh.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 <algorithm>
41 #include <memory>
42 
43 #include <ringmesh/basic/factory.h>
45 
46 #include <ringmesh/mesh/aabb.h>
47 
48 namespace GEO
49 {
50  class AttributesManager;
51 }
52 
53 namespace RINGMesh
54 {
56  FORWARD_DECLARATION_DIMENSION_CLASS( MeshBaseBuilder );
57  FORWARD_DECLARATION_DIMENSION_CLASS( PointSetMeshBuilder );
58  FORWARD_DECLARATION_DIMENSION_CLASS( LineMeshBuilder );
59  FORWARD_DECLARATION_DIMENSION_CLASS( SurfaceMeshBuilder );
60  FORWARD_DECLARATION_DIMENSION_CLASS( VolumeMeshBuilder );
62  struct EdgeLocalVertex;
63  struct PolygonLocalEdge;
64  struct CellLocalFacet;
65 } // namespace RINGMesh
66 
67 namespace RINGMesh
68 {
69  using MeshType = std::string;
70 
71  struct RINGMESH_API ElementLocalVertex
72  {
73  ElementLocalVertex() = default;
74  ElementLocalVertex( index_t element_id, index_t local_vertex_id )
75  : element_id_( element_id ), local_vertex_id_( local_vertex_id )
76  {
77  }
78  ElementLocalVertex( EdgeLocalVertex edge_local_vertex );
79  ElementLocalVertex( PolygonLocalEdge polygon_local_edge );
80  ElementLocalVertex( CellLocalFacet cell_local_facet );
81  index_t element_id_{ NO_ID };
82  index_t local_vertex_id_{ NO_ID };
83  };
84 
85  struct RINGMESH_API EdgeLocalVertex
86  {
87  EdgeLocalVertex() = default;
88  EdgeLocalVertex( index_t edge_id, index_t local_vertex_id )
89  : edge_id_( edge_id ), local_vertex_id_( local_vertex_id )
90  {
91  }
92  EdgeLocalVertex( ElementLocalVertex edge_local_vertex )
93  : edge_id_( std::move( edge_local_vertex.element_id_ ) ),
94  local_vertex_id_(
95  std::move( edge_local_vertex.local_vertex_id_ ) )
96  {
97  }
98  index_t edge_id_{ NO_ID };
99  index_t local_vertex_id_{ NO_ID };
100  };
101 
102  struct RINGMESH_API PolygonLocalEdge
103  {
104  PolygonLocalEdge() = default;
105  PolygonLocalEdge( index_t polygon_id, index_t local_edge_id )
106  : polygon_id_( polygon_id ), local_edge_id_( local_edge_id )
107  {
108  }
109  PolygonLocalEdge( ElementLocalVertex polygon_local_vertex )
110  : polygon_id_( std::move( polygon_local_vertex.element_id_ ) ),
111  local_edge_id_(
112  std::move( polygon_local_vertex.local_vertex_id_ ) )
113  {
114  }
115  index_t polygon_id_{ NO_ID };
116  index_t local_edge_id_{ NO_ID };
117  };
118 
119  struct RINGMESH_API CellLocalFacet
120  {
121  CellLocalFacet() = default;
122  CellLocalFacet( index_t cell_id, index_t local_facet_id )
123  : cell_id_( cell_id ), local_facet_id_( local_facet_id )
124  {
125  }
126  index_t cell_id_{ NO_ID };
127  index_t local_facet_id_{ NO_ID };
128  };
129 
137  template < index_t DIMENSION >
138  class MeshBase
139  {
142  friend class MeshBaseBuilder< DIMENSION >;
143 
144  public:
145  virtual ~MeshBase() = default;
146 
147  virtual void save_mesh( const std::string& filename ) const = 0;
148 
149  virtual std::tuple< index_t, std::vector< index_t > >
150  connected_components() const = 0;
151 
152  // TODO maybe reimplement the function with a RINGMesh::Mesh??
153  virtual void print_mesh_bounded_attributes() const = 0;
163  virtual const vecn< DIMENSION >& vertex( index_t v_id ) const = 0;
164  /*
165  * @brief Gets the number of vertices in the Mesh.
166  */
167  virtual index_t nb_vertices() const = 0;
168 
169  virtual GEO::AttributesManager& vertex_attribute_manager() const = 0;
170 
178  {
179  if( !vertex_nn_search_ )
180  {
181  std::vector< vecn< DIMENSION > > vec_vertices( nb_vertices() );
182  for( auto v : range( nb_vertices() ) )
183  {
184  vec_vertices[v] = vertex( v );
185  }
186  vertex_nn_search_.reset(
187  new NNSearch< DIMENSION >( vec_vertices, true ) );
188  }
189  return *vertex_nn_search_.get();
190  }
191 
192  virtual MeshType type_name() const = 0;
193 
194  virtual std::string default_extension() const = 0;
195 
196  virtual bool is_mesh_valid() const = 0;
197 
201  protected:
202  MeshBase() = default;
203 
204  protected:
205  mutable std::unique_ptr< NNSearch< DIMENSION > > vertex_nn_search_{};
206  };
208 
212  template < index_t DIMENSION >
213  class PointSetMesh : public MeshBase< DIMENSION >
214  {
215  friend class PointSetMeshBuilder< DIMENSION >;
216 
217  public:
218  static std::unique_ptr< PointSetMesh< DIMENSION > > create_mesh(
219  const MeshType type = "" );
220  std::tuple< index_t, std::vector< index_t > >
221  connected_components() const final;
222  bool is_mesh_valid() const override
223  {
224  return true;
225  }
226 
227  protected:
228  PointSetMesh() = default;
229  };
231 
232  template < index_t DIMENSION >
235 
239  template < index_t DIMENSION >
240  class LineMesh : public MeshBase< DIMENSION >
241  {
242  friend class LineMeshBuilder< DIMENSION >;
243 
244  public:
245  static std::unique_ptr< LineMesh< DIMENSION > > create_mesh(
246  const MeshType type = "" );
247 
248  /*
249  * @brief Gets the index of an edge vertex.
250  * @param[in] edge_local_vertex index of the edge and of the
251  * local index of the vertex, in {0,1}
252  * @return the global index of vertex in \p edge_local_vertex.
253  */
254  virtual index_t edge_vertex(
255  const ElementLocalVertex& edge_local_vertex ) const = 0;
256 
260  virtual index_t nb_edges() const = 0;
261 
265  double edge_length( index_t edge_id ) const
266  {
267  const vecn< DIMENSION >& e0 =
268  this->vertex( edge_vertex( ElementLocalVertex( edge_id, 0 ) ) );
269  const vecn< DIMENSION >& e1 =
270  this->vertex( edge_vertex( ElementLocalVertex( edge_id, 1 ) ) );
271  return ( e1 - e0 ).length();
272  }
273 
274  vecn< DIMENSION > edge_barycenter( index_t edge_id ) const
275  {
276  const vecn< DIMENSION >& e0 =
277  this->vertex( edge_vertex( ElementLocalVertex( edge_id, 0 ) ) );
278  const vecn< DIMENSION >& e1 =
279  this->vertex( edge_vertex( ElementLocalVertex( edge_id, 1 ) ) );
280  return ( e1 + e0 ) / 2.;
281  }
282 
290  {
291  if( !edge_nn_search_ )
292  {
293  std::vector< vecn< DIMENSION > > edge_centers( nb_edges() );
294  for( auto e : range( nb_edges() ) )
295  {
296  edge_centers[e] = edge_barycenter( e );
297  }
298  edge_nn_search_.reset(
299  new NNSearch< DIMENSION >( edge_centers, true ) );
300  }
301  return *edge_nn_search_.get();
302  }
307  {
308  if( !edge_aabb_ )
309  {
310  edge_aabb_.reset( new LineAABBTree< DIMENSION >( *this ) );
311  }
312  return *edge_aabb_.get();
313  }
314 
315  virtual GEO::AttributesManager& edge_attribute_manager() const = 0;
316 
317  bool is_mesh_valid() const override
318  {
319  bool valid{ true };
320 
321  if( this->nb_vertices() < 2 )
322  {
323  Logger::err( "LineMesh", "Mesh has less than 2 vertices " );
324  valid = false;
325  }
326 
327  if( nb_edges() == 0 )
328  {
329  Logger::err( "LineMesh", "Mesh has no edge" );
330  valid = false;
331  }
332 
333  // No isolated vertices
334  std::vector< index_t > nb( this->nb_vertices(), 0 );
335  for( auto p : range( nb_edges() ) )
336  {
337  for( auto v : range( 2 ) )
338  {
339  nb[edge_vertex( { p, v } )]++;
340  }
341  }
342  auto nb_isolated_vertices =
343  static_cast< index_t >( std::count( nb.begin(), nb.end(), 0 ) );
344  if( nb_isolated_vertices > 0 )
345  {
346  Logger::warn( "LineMesh", "Mesh has ", nb_isolated_vertices,
347  " isolated vertices " );
348  valid = false;
349  }
350 
351  return valid;
352  }
353  std::tuple< index_t, std::vector< index_t > >
354  connected_components() const final;
355 
356  protected:
357  LineMesh() = default;
358 
359  protected:
360  mutable std::unique_ptr< NNSearch< DIMENSION > > edge_nn_search_{};
361  mutable std::unique_ptr< LineAABBTree< DIMENSION > > edge_aabb_{};
362  };
364 
365  template < index_t DIMENSION >
368 
372  template < index_t DIMENSION >
373  class SurfaceMeshBase : public MeshBase< DIMENSION >
374  {
375  friend class SurfaceMeshBuilder< DIMENSION >;
376 
377  public:
378  static std::unique_ptr< SurfaceMesh< DIMENSION > > create_mesh(
379  const MeshType type = "" );
380 
386  virtual index_t polygon_vertex(
387  const ElementLocalVertex& polygon_local_vertex ) const = 0;
388 
392  virtual index_t nb_polygons() const = 0;
397  virtual index_t nb_polygon_vertices( index_t polygon_id ) const = 0;
405  const ElementLocalVertex& polygon_local_vertex ) const
406  {
407  const index_t local_vertex_id =
408  polygon_local_vertex.local_vertex_id_;
410  local_vertex_id
411  < nb_polygon_vertices( polygon_local_vertex.element_id_ ) );
412  if( local_vertex_id
413  != nb_polygon_vertices( polygon_local_vertex.element_id_ ) - 1 )
414  {
415  return { polygon_local_vertex.element_id_,
416  local_vertex_id + 1 };
417  }
418  return { polygon_local_vertex.element_id_, 0 };
419  }
434  PolygonLocalEdge next_on_border(
435  const PolygonLocalEdge& polygon_local_edge ) const;
436 
444  const ElementLocalVertex& polygon_local_vertex ) const
445  {
447  polygon_local_vertex.local_vertex_id_
448  < nb_polygon_vertices( polygon_local_vertex.element_id_ ) );
449  if( polygon_local_vertex.local_vertex_id_ > 0 )
450  {
451  return { polygon_local_vertex.element_id_,
452  polygon_local_vertex.local_vertex_id_ - 1 };
453  }
454  return { polygon_local_vertex.element_id_,
455  nb_polygon_vertices( polygon_local_vertex.element_id_ ) - 1 };
456  }
457 
473  PolygonLocalEdge prev_on_border(
474  const PolygonLocalEdge& polygon_local_edge ) const;
475 
482  index_t vertex_index_in_polygon(
483  index_t polygon_index, index_t vertex_id ) const;
484 
493  index_t closest_vertex_in_polygon(
494  index_t polygon_index, const vecn< DIMENSION >& query_point ) const;
495 
504  index_t polygon_from_vertex_ids( index_t in0, index_t in1 ) const;
505 
521  std::vector< index_t > polygons_around_vertex(
522  index_t vertex_id, bool border_only, index_t first_polygon ) const;
523 
534  virtual index_t polygon_adjacent(
535  const PolygonLocalEdge& polygon_local_edge ) const = 0;
536 
537  virtual GEO::AttributesManager& polygon_attribute_manager() const = 0;
543  virtual bool polygons_are_simplicies() const = 0;
547  bool is_triangle( index_t polygon_id ) const
548  {
549  return nb_polygon_vertices( polygon_id ) == 3;
550  }
551 
552  PolygonType polygone_type( index_t polygon_id ) const
553  {
554  if( is_triangle( polygon_id ) )
555  {
556  return PolygonType::TRIANGLE;
557  }
558  if( nb_polygon_vertices( polygon_id ) == 4 )
559  {
560  return PolygonType::QUAD;
561  }
562  return PolygonType::UNDEFINED;
563  }
564 
570  const PolygonLocalEdge& polygon_local_edge ) const
571  {
572  return polygon_adjacent( polygon_local_edge ) == NO_ID;
573  }
574 
578  bool is_polygon_on_border( index_t polygon_index ) const
579  {
580  for( auto v : range( nb_polygon_vertices( polygon_index ) ) )
581  {
582  if( is_edge_on_border( PolygonLocalEdge( polygon_index, v ) ) )
583  {
584  return true;
585  }
586  }
587  return false;
588  }
589 
596  const PolygonLocalEdge& polygon_local_edge ) const
597  {
598  const vecn< DIMENSION >& e0 =
599  this->vertex( polygon_edge_vertex( polygon_local_edge, 0 ) );
600  const vecn< DIMENSION >& e1 =
601  this->vertex( polygon_edge_vertex( polygon_local_edge, 1 ) );
602  return ( e1 - e0 ).length();
603  }
610  const PolygonLocalEdge& polygon_local_edge ) const
611  {
612  const vecn< DIMENSION >& e0 =
613  this->vertex( polygon_edge_vertex( polygon_local_edge, 0 ) );
614  const vecn< DIMENSION >& e1 =
615  this->vertex( polygon_edge_vertex( polygon_local_edge, 1 ) );
616  return ( e1 + e0 ) / 2.;
617  }
626  index_t polygon_edge_vertex( const PolygonLocalEdge& polygon_local_edge,
627  index_t vertex_id ) const
628  {
629  ringmesh_assert( vertex_id < 2 );
630  if( vertex_id == 0 )
631  {
632  return polygon_vertex( polygon_local_edge );
633  }
634  return polygon_vertex( ElementLocalVertex(
635  polygon_local_edge.polygon_id_,
636  ( polygon_local_edge.local_edge_id_ + vertex_id )
637  % nb_polygon_vertices( polygon_local_edge.polygon_id_ ) ) );
638  }
639 
645  vecn< DIMENSION > polygon_barycenter( index_t polygon_id ) const
646  {
647  vecn< DIMENSION > result;
648  ringmesh_assert( nb_polygon_vertices( polygon_id ) >= 1 );
649  for( auto v : range( nb_polygon_vertices( polygon_id ) ) )
650  {
651  result += this->vertex(
652  polygon_vertex( ElementLocalVertex( polygon_id, v ) ) );
653  }
654  return ( 1.0 / nb_polygon_vertices( polygon_id ) ) * result;
655  }
661  virtual double polygon_area( index_t polygon_id ) const = 0;
662 
667  {
668  if( !nn_search_ )
669  {
670  std::vector< vecn< DIMENSION > > polygon_centers(
671  nb_polygons() );
672  for( auto p : range( nb_polygons() ) )
673  {
674  polygon_centers[p] = polygon_barycenter( p );
675  }
676  nn_search_.reset(
677  new NNSearch< DIMENSION >( polygon_centers, true ) );
678  }
679  return *nn_search_.get();
680  }
685  {
686  if( !polygon_aabb_ )
687  {
688  polygon_aabb_.reset(
689  new SurfaceAABBTree< DIMENSION >( *this ) );
690  }
691  return *polygon_aabb_;
692  }
693 
694  bool is_mesh_valid() const override
695  {
696  bool valid{ true };
697 
698  if( this->nb_vertices() < 3 )
699  {
700  Logger::warn( "SurfaceMesh has less than 3 vertices " );
701  valid = false;
702  }
703  if( nb_polygons() == 0 )
704  {
705  Logger::warn( "SurfaceMesh has no polygon" );
706  valid = false;
707  }
708 
709  // No isolated vertices
710  std::vector< index_t > nb( this->nb_vertices(), 0 );
711  for( auto p : range( nb_polygons() ) )
712  {
713  for( auto v : range( nb_polygon_vertices( p ) ) )
714  {
715  nb[polygon_vertex( { p, v } )]++;
716  }
717  }
718  auto nb_isolated_vertices =
719  static_cast< index_t >( std::count( nb.begin(), nb.end(), 0 ) );
720  if( nb_isolated_vertices > 0 )
721  {
722  Logger::warn( "SurfaceMesh", "Mesh has ", nb_isolated_vertices,
723  " isolated vertices " );
724  valid = false;
725  }
726 
727  return valid;
728  }
729  std::tuple< index_t, std::vector< index_t > >
730  connected_components() const final;
731 
732  protected:
733  SurfaceMeshBase() = default;
734 
735  protected:
736  mutable std::unique_ptr< NNSearch< DIMENSION > > nn_search_{};
737  mutable std::unique_ptr< SurfaceAABBTree< DIMENSION > > polygon_aabb_{};
738  };
740 
741  template < index_t DIMENSION >
742  class SurfaceMesh : public SurfaceMeshBase< DIMENSION >
743  {
744  };
745 
746  template < index_t DIMENSION >
749 
750  template <>
751  class RINGMESH_API SurfaceMesh< 3 > : public SurfaceMeshBase< 3 >
752  {
753  public:
759  double polygon_area( index_t polygon_id ) const;
760 
766  vec3 polygon_normal( index_t polygon_id ) const
767  {
768  const vec3& p1 = this->vertex(
769  this->polygon_vertex( ElementLocalVertex( polygon_id, 0 ) ) );
770  const vec3& p2 = this->vertex(
771  this->polygon_vertex( ElementLocalVertex( polygon_id, 1 ) ) );
772  const vec3& p3 = this->vertex(
773  this->polygon_vertex( ElementLocalVertex( polygon_id, 2 ) ) );
774  vec3 norm = cross( p2 - p1, p3 - p1 );
775  return normalize( norm );
776  }
777 
786  vec3 normal_at_vertex( index_t vertex_id, index_t p0 = NO_ID ) const
787  {
788  ringmesh_assert( vertex_id < nb_vertices() );
789  index_t p = 0;
790  while( p0 == NO_ID && p < nb_polygons() )
791  {
792  for( auto lv : range( nb_polygon_vertices( p ) ) )
793  {
794  if( polygon_vertex( ElementLocalVertex( p, lv ) )
795  == vertex_id )
796  {
797  p0 = p;
798  break;
799  }
800  }
801  p++;
802  }
803 
804  std::vector< index_t > polygon_ids =
805  polygons_around_vertex( vertex_id, false, p0 );
806  vec3 norm;
807  for( auto polygon_id : polygon_ids )
808  {
809  norm += polygon_normal( polygon_id );
810  }
811  return normalize( norm );
812  }
813  };
814 
815  template <>
816  class RINGMESH_API SurfaceMesh< 2 > : public SurfaceMeshBase< 2 >
817  {
818  public:
824  double polygon_area( index_t polygon_id ) const override
825  {
826  double result = 0.0;
827  if( nb_polygon_vertices( polygon_id ) == 0 )
828  {
829  return result;
830  }
831  const vec2& p1 =
832  vertex( polygon_vertex( ElementLocalVertex( polygon_id, 0 ) ) );
833  for( auto i : range( 1, nb_polygon_vertices( polygon_id ) - 1 ) )
834  {
835  const vec2& p2 = vertex(
836  polygon_vertex( ElementLocalVertex( polygon_id, i ) ) );
837  const vec2& p3 = vertex(
838  polygon_vertex( ElementLocalVertex( polygon_id, i + 1 ) ) );
839  result += GEO::Geom::triangle_signed_area( p1, p2, p3 );
840  }
841  return std::fabs( result );
842  }
843  };
844 
846 
850  template < index_t DIMENSION >
851  class VolumeMesh : public MeshBase< DIMENSION >
852  {
853  ringmesh_template_assert_3d( DIMENSION );
854  friend class VolumeMeshBuilder< DIMENSION >;
855 
856  public:
857  static std::unique_ptr< VolumeMesh< DIMENSION > > create_mesh(
858  const MeshType type = "" );
859 
867  virtual index_t cell_vertex(
868  const ElementLocalVertex& cell_local_vertex ) const = 0;
869 
879  virtual index_t cell_edge_vertex(
880  index_t cell_id, index_t edge_id, index_t vertex_id ) const = 0;
881 
892  virtual index_t cell_facet_vertex(
893  const CellLocalFacet& cell_local_facet,
894  index_t vertex_id ) const = 0;
895 
902  virtual index_t cell_facet(
903  const CellLocalFacet& cell_local_facet ) const = 0;
904 
911  double cell_edge_length( index_t cell_id, index_t edge_id ) const
912  {
913  const vecn< DIMENSION >& e0 =
914  this->vertex( cell_edge_vertex( cell_id, edge_id, 0 ) );
915  const vecn< DIMENSION >& e1 =
916  this->vertex( cell_edge_vertex( cell_id, edge_id, 1 ) );
917  return ( e1 - e0 ).length();
918  }
919 
927  index_t cell_id, index_t edge_id ) const
928  {
929  const vecn< DIMENSION >& e0 =
930  this->vertex( cell_edge_vertex( cell_id, edge_id, 0 ) );
931  const vecn< DIMENSION >& e1 =
932  this->vertex( cell_edge_vertex( cell_id, edge_id, 1 ) );
933  return ( e1 + e0 ) / 2.;
934  }
935 
941  virtual index_t nb_cell_facets( index_t cell_id ) const = 0;
945  virtual index_t nb_cell_facets() const = 0;
946 
952  virtual index_t nb_cell_edges( index_t cell_id ) const = 0;
953 
961  virtual index_t nb_cell_facet_vertices(
962  const CellLocalFacet& cell_local_facet ) const = 0;
963 
969  virtual index_t nb_cell_vertices( index_t cell_id ) const = 0;
970 
974  virtual index_t nb_cells() const = 0;
975 
976  virtual index_t cell_begin( index_t cell_id ) const = 0;
977 
978  virtual index_t cell_end( index_t cell_id ) const = 0;
979 
983  virtual index_t cell_adjacent(
984  const CellLocalFacet& cell_local_facet ) const = 0;
985 
986  virtual GEO::AttributesManager& cell_attribute_manager() const = 0;
987 
988  virtual GEO::AttributesManager&
989  cell_facet_attribute_manager() const = 0;
990 
995  virtual CellType cell_type( index_t cell_id ) const = 0;
996 
1002  virtual bool cells_are_simplicies() const = 0;
1003 
1011  const CellLocalFacet& cell_local_facet ) const
1012  {
1013  vecn< DIMENSION > result;
1014  index_t nb_vertices = nb_cell_facet_vertices( cell_local_facet );
1015  for( auto v : range( nb_vertices ) )
1016  {
1017  result +=
1018  this->vertex( cell_facet_vertex( cell_local_facet, v ) );
1019  }
1020  ringmesh_assert( nb_vertices > 0 );
1021 
1022  return result / static_cast< double >( nb_vertices );
1023  }
1027  vecn< DIMENSION > cell_barycenter( index_t cell_id ) const
1028  {
1029  vecn< DIMENSION > result;
1030  ringmesh_assert( nb_cell_vertices( cell_id ) >= 1 );
1031  for( auto v : range( nb_cell_vertices( cell_id ) ) )
1032  {
1033  result += this->vertex(
1034  cell_vertex( ElementLocalVertex( cell_id, v ) ) );
1035  }
1036  return ( 1.0 / nb_cell_vertices( cell_id ) ) * result;
1037  }
1045  const CellLocalFacet& cell_local_facet ) const
1046  {
1047  ringmesh_assert( cell_local_facet.cell_id_ < nb_cells() );
1048  ringmesh_assert( cell_local_facet.local_facet_id_
1049  < nb_cell_facets( cell_local_facet.cell_id_ ) );
1050 
1051  const vecn< DIMENSION >& p1 =
1052  this->vertex( cell_facet_vertex( cell_local_facet, 0 ) );
1053  const vecn< DIMENSION >& p2 =
1054  this->vertex( cell_facet_vertex( cell_local_facet, 1 ) );
1055  const vecn< DIMENSION >& p3 =
1056  this->vertex( cell_facet_vertex( cell_local_facet, 2 ) );
1057 
1058  return cross( p2 - p1, p3 - p1 );
1059  }
1060 
1064  virtual double cell_volume( index_t cell_id ) const = 0;
1065 
1066  std::vector< index_t > cells_around_vertex(
1067  index_t vertex_id, index_t cell_hint ) const;
1068 
1069  index_t find_cell_corner( index_t cell_id, index_t vertex_id ) const
1070  {
1071  for( auto v : range( nb_cell_vertices( cell_id ) ) )
1072  {
1073  if( cell_vertex( ElementLocalVertex( cell_id, v ) )
1074  == vertex_id )
1075  {
1076  return v;
1077  }
1078  }
1079  return NO_ID;
1080  }
1081 
1082  bool find_cell_from_colocated_vertex_within_distance_if_any(
1083  const vecn< DIMENSION >& vertex_vec,
1084  double distance,
1085  index_t& cell_id,
1086  index_t& cell_vertex_id ) const;
1087 
1095  {
1096  if( !cell_facet_nn_search_ )
1097  {
1098  std::vector< vecn< DIMENSION > > cell_facet_centers(
1099  nb_cell_facets() );
1100  index_t cf = 0;
1101  for( auto c : range( nb_cells() ) )
1102  {
1103  for( auto f : range( nb_cell_facets( c ) ) )
1104  {
1105  cell_facet_centers[cf] =
1106  cell_facet_barycenter( CellLocalFacet( c, f ) );
1107  ++cf;
1108  }
1109  }
1110  cell_facet_nn_search_.reset(
1111  new NNSearch< DIMENSION >( cell_facet_centers, true ) );
1112  }
1113  return *cell_facet_nn_search_.get();
1114  }
1119  {
1120  if( !cell_nn_search_ )
1121  {
1122  std::vector< vecn< DIMENSION > > cell_centers( nb_cells() );
1123  for( auto c : range( nb_cells() ) )
1124  {
1125  cell_centers[c] = cell_barycenter( c );
1126  }
1127  cell_nn_search_.reset(
1128  new NNSearch< DIMENSION >( cell_centers, true ) );
1129  }
1130  return *cell_nn_search_.get();
1131  }
1136  {
1137  if( !cell_aabb_ )
1138  {
1139  cell_aabb_.reset( new VolumeAABBTree< DIMENSION >( *this ) );
1140  }
1141  return *cell_aabb_.get();
1142  }
1143 
1144  bool is_mesh_valid() const override
1145  {
1146  bool valid{ true };
1147 
1148  if( this->nb_vertices() < 4 )
1149  {
1150  Logger::warn( "VolumeMesh has less than 4 vertices " );
1151  valid = false;
1152  }
1153  if( nb_cells() == 0 )
1154  {
1155  Logger::warn( "VolumeMesh has no cell" );
1156  valid = false;
1157  }
1158 
1159  // No isolated vertices
1160  std::vector< index_t > nb( this->nb_vertices(), 0 );
1161  for( auto c : range( nb_cells() ) )
1162  {
1163  for( auto v : range( nb_cell_vertices( c ) ) )
1164  {
1165  nb[cell_vertex( { c, v } )]++;
1166  }
1167  }
1168  auto nb_isolated_vertices =
1169  static_cast< index_t >( std::count( nb.begin(), nb.end(), 0 ) );
1170  if( nb_isolated_vertices > 0 )
1171  {
1172  Logger::warn( "VolumeMesh", "Mesh has ", nb_isolated_vertices,
1173  " isolated vertices " );
1174  valid = false;
1175  }
1176 
1177  return valid;
1178  }
1179  std::tuple< index_t, std::vector< index_t > >
1180  connected_components() const final;
1181 
1182  protected:
1183  VolumeMesh() = default;
1184 
1185  protected:
1186  mutable std::unique_ptr< NNSearch< DIMENSION > >
1187  cell_facet_nn_search_{};
1188  mutable std::unique_ptr< NNSearch< DIMENSION > > cell_nn_search_{};
1189  mutable std::unique_ptr< VolumeAABBTree< DIMENSION > > cell_aabb_{};
1190  };
1191 
1193 
1194  template < index_t DIMENSION >
1197 
1201  template < index_t DIMENSION >
1203  {
1205  ringmesh_template_assert_2d_or_3d( DIMENSION );
1206 
1207  public:
1208  void create_point_set_mesh( MeshType type );
1209  void create_line_mesh( MeshType type );
1210  void create_well_mesh( MeshType type );
1211  void create_surface_mesh( MeshType type );
1212 
1213  protected:
1214  MeshSetBase();
1215  virtual ~MeshSetBase() = default;
1216 
1217  public:
1218  std::unique_ptr< PointSetMesh< DIMENSION > > point_set_mesh{};
1219  std::unique_ptr< LineMesh< DIMENSION > > well_mesh{};
1220  std::unique_ptr< LineMesh< DIMENSION > > line_mesh{};
1221  std::unique_ptr< SurfaceMesh< DIMENSION > > surface_mesh{};
1222  };
1223 
1224  template < index_t DIMENSION >
1225  class MeshSet : public MeshSetBase< DIMENSION >
1226  {
1227  public:
1228  MeshSet() = default;
1229  };
1230 
1231  template <>
1232  class RINGMESH_API MeshSet< 3 > : public MeshSetBase< 3 >
1233  {
1234  public:
1235  MeshSet();
1236 
1237  void create_volume_mesh( MeshType type );
1238 
1239  public:
1240  std::unique_ptr< VolumeMesh3D > volume_mesh{};
1241  };
1242 } // namespace RINGMesh
#define ringmesh_disable_copy_and_move(Class)
Definition: common.h:76
vecn< DIMENSION > cell_edge_barycenter(index_t cell_id, index_t edge_id) const
Definition: mesh.h:926
GEO::vecng< DIMENSION, double > vecn
Definition: types.h:74
double edge_length(index_t edge_id) const
Gets the length of the edge.
Definition: mesh.h:265
const VolumeAABBTree< DIMENSION > & cell_aabb() const
Creates an AABB tree for a Mesh cells.
Definition: mesh.h:1135
vecn< 3 > vec3
Definition: types.h:76
CellLocalFacet(index_t cell_id, index_t local_facet_id)
Definition: mesh.h:122
const NNSearch< DIMENSION > & edge_nn_search() const
return the NNSearch at edges
Definition: mesh.h:289
double RINGMESH_API triangle_signed_area(const vec3 &p0, const vec3 &p1, const vec3 &p2, const vec3 &triangle_normal)
Definition: geometry.cpp:66
const SurfaceAABBTree< DIMENSION > & polygon_aabb() const
Creates an AABB tree for a Mesh polygons.
Definition: mesh.h:684
#define ringmesh_template_assert_2d_or_3d(type)
Definition: common.h:80
vecn< DIMENSION > cell_facet_normal(const CellLocalFacet &cell_local_facet) const
Definition: mesh.h:1044
#define ringmesh_template_assert_3d(type)
Definition: common.h:84
vec3 polygon_normal(index_t polygon_id) const
Definition: mesh.h:766
index_t polygon_edge_vertex(const PolygonLocalEdge &polygon_local_edge, index_t vertex_id) const
Gets the vertex index on the polygon edge.
Definition: mesh.h:626
bool is_mesh_valid() const override
Definition: mesh.h:694
#define FORWARD_DECLARATION_DIMENSION_CLASS(Class)
Definition: common.h:95
vecn< DIMENSION > cell_barycenter(index_t cell_id) const
Definition: mesh.h:1027
EdgeLocalVertex(ElementLocalVertex edge_local_vertex)
Definition: mesh.h:92
double polygon_edge_length(const PolygonLocalEdge &polygon_local_edge) const
Gets the length of the edge starting at a given vertex.
Definition: mesh.h:595
vec3 normal_at_vertex(index_t vertex_id, index_t p0=NO_ID) const
Computes the normal of the Mesh2D at the vertex location it computes the average value of polygon nor...
Definition: mesh.h:786
vecn< 2 > vec2
Definition: types.h:78
const NNSearch< DIMENSION > & cell_nn_search() const
return the NNSearch at cells
Definition: mesh.h:1118
CellType
Definition: types.h:89
std::string MeshType
Definition: mesh.h:69
vecn< DIMENSION > edge_barycenter(index_t edge_id) const
Definition: mesh.h:274
PolygonType
Definition: types.h:105
const NNSearch< DIMENSION > & vertex_nn_search() const
return the NNSearch at vertices
Definition: mesh.h:177
encapsulate adimensional mesh functionalities in order to provide an API on which we base the RINGMes...
Definition: mesh.h:138
bool is_triangle(index_t polygon_id) const
Definition: mesh.h:547
bool is_mesh_valid() const override
Definition: mesh.h:317
ElementLocalVertex prev_polygon_vertex(const ElementLocalVertex &polygon_local_vertex) const
Gets the previous vertex index in the polygon.
Definition: mesh.h:443
const NNSearch< DIMENSION > & cell_facet_nn_search() const
return the NNSearch at cell facets
Definition: mesh.h:1094
const LineAABBTree< DIMENSION > & edge_aabb() const
Creates an AABB tree for a Mesh edges.
Definition: mesh.h:306
PolygonLocalEdge(index_t polygon_id, index_t local_edge_id)
Definition: mesh.h:105
vecn< DIMENSION > polygon_barycenter(index_t polygon_id) const
Definition: mesh.h:645
#define ringmesh_assert(x)
bool is_mesh_valid() const override
Definition: mesh.h:1144
vecn< DIMENSION > cell_facet_barycenter(const CellLocalFacet &cell_local_facet) const
Definition: mesh.h:1010
double polygon_area(index_t polygon_id) const override
Definition: mesh.h:824
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
ElementLocalVertex next_polygon_vertex(const ElementLocalVertex &polygon_local_vertex) const
Gets the next vertex index in the polygon vertex.
Definition: mesh.h:404
ElementLocalVertex(index_t element_id, index_t local_vertex_id)
Definition: mesh.h:74
index_t find_cell_corner(index_t cell_id, index_t vertex_id) const
Definition: mesh.h:1069
PolygonType polygone_type(index_t polygon_id) const
Definition: mesh.h:552
bool is_polygon_on_border(index_t polygon_index) const
Definition: mesh.h:578
#define ALIAS_2D_AND_3D(Class)
Definition: common.h:91
vecn< DIMENSION > polygon_edge_barycenter(const PolygonLocalEdge &polygon_local_edge) const
Gets the barycenter of the edge starting at a given vertex.
Definition: mesh.h:609
const NNSearch< DIMENSION > & polygon_nn_search() const
return the NNSearch at polygons
Definition: mesh.h:666
bool is_edge_on_border(const PolygonLocalEdge &polygon_local_edge) const
Definition: mesh.h:569
double cell_edge_length(index_t cell_id, index_t edge_id) const
Definition: mesh.h:911
EdgeLocalVertex(index_t edge_id, index_t local_vertex_id)
Definition: mesh.h:88
PolygonLocalEdge(ElementLocalVertex polygon_local_vertex)
Definition: mesh.h:109
index_t local_facet_id_
Definition: mesh.h:127