53 template < index_t DIMENSION >
57 const auto& geomodel_vertices = geomodel.
mesh.vertices;
58 const auto& vertices =
59 geomodel_vertices.gme_vertices( geomodel_point_id );
60 for(
const auto& vertex : vertices )
75 template < index_t DIMENSION >
77 const std::vector< index_t >& rhs_vertices )
83 const auto& geomodel_vertices = line.
geomodel().mesh.vertices;
88 != geomodel_vertices.geomodel_vertex_id( line.
gmme(), i ) )
103 != geomodel_vertices.geomodel_vertex_id(
117 template < index_t DIMENSION >
118 void reorder_closed_line_vertices_to_start_at_corner(
120 std::vector< index_t >& line_vertices )
122 if( geomodel.
nb_corners() == 0 || line_vertices.empty() )
126 for(
auto i :
range( 1, line_vertices.size() - 1 ) )
128 auto corner = find_corner( geomodel, line_vertices[i] );
129 if( corner.is_defined() )
131 line_vertices.pop_back();
132 std::rotate( line_vertices.begin(), line_vertices.begin() + i,
133 line_vertices.end() );
134 line_vertices.push_back( line_vertices.front() );
147 index_t surface, index_t polygon, index_t v0, index_t v1 )
148 : v0_( v0 ), v1_( v1 ), surface_( surface ), polygon_( polygon )
156 bool operator<(
const BorderPolygon& rhs )
const 158 if( std::min( v0_, v1_ ) != std::min( rhs.v0_, rhs.v1_ ) )
160 return std::min( v0_, v1_ ) < std::min( rhs.v0_, rhs.v1_ );
162 if( std::max( v0_, v1_ ) != std::max( rhs.v0_, rhs.v1_ ) )
164 return std::max( v0_, v1_ ) < std::max( rhs.v0_, rhs.v1_ );
166 if( surface_ != rhs.surface_ )
168 return surface_ < rhs.surface_;
170 return polygon_ < rhs.polygon_;
173 bool same_edge(
const BorderPolygon& rhs )
const 175 return std::min( v0_, v1_ ) == std::min( rhs.v0_, rhs.v1_ )
176 && std::max( v0_, v1_ ) == std::max( rhs.v0_, rhs.v1_ );
189 template < index_t DIMENSION >
190 class CommonDataFromGeoModelSurfaces
196 explicit CommonDataFromGeoModelSurfaces(
198 : geomodel_( geomodel )
200 const auto& geomodel_vertices = geomodel_.mesh.vertices;
201 for(
const auto& surface : geomodel_.surfaces() )
203 const auto& mesh = surface.mesh();
204 auto S_id = surface.gmme();
205 for(
auto p :
range( surface.nb_mesh_elements() ) )
208 range( surface.nb_mesh_element_vertices( p ) ) )
210 if( mesh.is_edge_on_border( { p, v } ) )
212 auto vertex = geomodel_vertices.geomodel_vertex_id(
215 geomodel_vertices.geomodel_vertex_id( S_id,
216 mesh.next_polygon_vertex( { p, v } ) );
217 border_polygons_.emplace_back(
218 surface.index(), p, vertex, next_vertex );
223 std::sort( border_polygons_.begin(), border_polygons_.end() );
225 ~CommonDataFromGeoModelSurfaces() =
default;
227 bool have_border_polygons_same_boundary_edge(
228 index_t t0, index_t t1 )
const 230 return this->border_polygons_[t0].same_edge(
231 this->border_polygons_[t1] );
237 std::vector< BorderPolygon > border_polygons_;
246 class GeoModelRegionFromSurfaces
264 PolygonToSort( index_t index,
265 index_t surface_index,
269 : index_( index ), surface_index_( surface_index ), N_( normal )
272 auto e1 = normalize( p1 - p0 );
273 B_A_ = normalize( cross( e1, N_ ) );
276 bool operator<(
const PolygonToSort& r )
const 278 return angle_ < r.angle_;
285 index_t surface_index_;
295 double angle_{ -max_float64() };
299 void add_polygon_edge( index_t surface_index,
304 auto polygon_id =
static_cast< index_t
>( polygons_.size() );
305 polygons_.emplace_back( polygon_id, surface_index, normal, p0, p1 );
317 auto q = normalize( axis ) * std::sin( 0.5 * angle );
318 vecn< 4 > quat( q[0], q[1], q[2], std::cos( 0.5 * angle ) );
320 GEO::Matrix< 4, double > mat;
321 mat( 0, 0 ) = 1 - 2.0 * ( quat[1] * quat[1] + quat[2] * quat[2] );
322 mat( 1, 0 ) = 2.0 * ( quat[0] * quat[1] + quat[2] * quat[3] );
323 mat( 2, 0 ) = 2.0 * ( quat[2] * quat[0] - quat[1] * quat[3] );
326 mat( 0, 1 ) = 2.0 * ( quat[0] * quat[1] - quat[2] * quat[3] );
327 mat( 1, 1 ) = 1 - 2.0 * ( quat[2] * quat[2] + quat[0] * quat[0] );
328 mat( 2, 1 ) = 2.0 * ( quat[1] * quat[2] + quat[0] * quat[3] );
331 mat( 0, 2 ) = 2.0 * ( quat[2] * quat[0] + quat[1] * quat[3] );
332 mat( 1, 2 ) = 2.0 * ( quat[1] * quat[2] - quat[0] * quat[3] );
333 mat( 2, 2 ) = 1 - 2.0 * ( quat[1] * quat[1] + quat[0] * quat[0] );
341 vecn< 4 > normalizedV( V.x, V.y, V.z, 1.0 );
343 GEO::mult( mat, normalizedV.data(), result.data() );
346 double inv_w{ 1.0 / result.w };
347 return { result.x * inv_w, result.y * inv_w, result.z * inv_w };
354 std::pair< index_t, bool > default_pair( index_t( -1 ),
false );
355 sorted_polygons_.resize( 2 * polygons_.size(), default_pair );
358 if( polygons_.size() == 1 )
360 sorted_polygons_[0] = std::pair< index_t, bool >(
361 polygons_[0].surface_index_, true );
362 sorted_polygons_[1] = std::pair< index_t, bool >(
363 polygons_[0].surface_index_, false );
369 sorted_polygons_[0] =
370 std::pair< index_t, bool >( polygons_[0].surface_index_, true );
373 vec3 N_ref{ polygons_[0].N_ };
374 vec3 B_A_ref{ polygons_[0].B_A_ };
375 vec3 Ax_ref{ normalize( cross( B_A_ref, N_ref ) ) };
379 polygons_[0].angle_ = 2 * M_PI;
380 polygons_[0].side_ =
false;
382 for(
auto i :
range( 1, polygons_.size() ) )
384 auto& cur = polygons_[i];
388 double cos = dot( B_A_ref, cur.B_A_ );
398 cur.angle_ = std::acos( cos );
400 if( dot( cross( B_A_ref, cur.B_A_ ), Ax_ref ) < 0. )
402 cur.angle_ = 2 * M_PI - cur.angle_;
407 auto N_rotate =
rotate( Ax_ref, -cur.angle_, cur.N_ );
408 cur.side_ = dot( N_rotate, N_ref ) < 0;
412 std::sort( polygons_.begin(), polygons_.end() );
416 for(
auto& cur : polygons_ )
418 if( cur.index_ == 0 )
420 sorted_polygons_[it].first = cur.surface_index_;
421 sorted_polygons_[it].second = cur.side_;
425 sorted_polygons_[it].first = cur.surface_index_;
426 sorted_polygons_[it].second = cur.side_;
427 sorted_polygons_[it + 1].first = cur.surface_index_;
428 sorted_polygons_[it + 1].second = !cur.side_;
434 sorted_polygons_.end(), default_pair )
441 sorted_polygons_.clear();
446 const std::pair< index_t, bool >& next(
447 const std::pair< index_t, bool >& in )
const 449 for(
auto i :
range( sorted_polygons_.size() ) )
451 if( sorted_polygons_[i] == in )
453 if( i == sorted_polygons_.size() - 1 )
455 return sorted_polygons_[sorted_polygons_.size() - 2];
459 return sorted_polygons_[1];
462 if( sorted_polygons_[i + 1].first
463 == sorted_polygons_[i].first )
466 if( sorted_polygons_[i + 1].second
467 != sorted_polygons_[i].second )
469 return sorted_polygons_[i - 1];
472 return sorted_polygons_[i + 1];
475 == sorted_polygons_[i].first );
476 if( sorted_polygons_[i - 1].second
477 != sorted_polygons_[i].second )
479 return sorted_polygons_[i + 1];
481 return sorted_polygons_[i - 1];
485 return sorted_polygons_.front();
489 std::vector< PolygonToSort > polygons_;
491 std::vector< std::pair< index_t, bool > > sorted_polygons_;
494 class RegionTopologyFromGeoModelSurfaces
495 :
public CommonDataFromGeoModelSurfaces< 3 >
498 explicit RegionTopologyFromGeoModelSurfaces(
499 const GeoModel3D& geomodel )
500 : CommonDataFromGeoModelSurfaces3D( geomodel ),
501 region_info_( geomodel.nb_lines() )
505 void compute_region_info()
507 const auto& vertices = this->geomodel_.mesh.vertices;
508 for(
const auto& line : geomodel_.lines() )
510 BorderPolygon line_border{ NO_ID, NO_ID,
511 vertices.geomodel_vertex_id( line.
gmme(), 0 ),
512 vertices.geomodel_vertex_id( line.
gmme(), 1 ) };
513 for(
const auto& border : this->border_polygons_ )
515 if( line_border.same_edge( border ) )
517 auto surface_id = border.surface_;
518 region_info_[line.
index()].add_polygon_edge( surface_id,
519 this->geomodel_.surface( surface_id )
521 .polygon_normal( border.polygon_ ),
522 vertices.vertex( border.v0_ ),
523 vertices.vertex( border.v1_ ) );
526 region_info_[line.
index()].sort();
530 const std::vector< GeoModelRegionFromSurfaces >& region_info()
const 536 std::vector< GeoModelRegionFromSurfaces > region_info_;
539 struct LineDefinition
543 return vertices_.front() == vertices_.back();
546 template < index_t DIMENSION >
547 void reoder_closed_line_vertices(
551 reorder_closed_line_vertices_to_start_at_corner(
552 geomodel, vertices_ );
558 adjacent_surfaces_.clear();
561 std::vector< index_t > vertices_;
562 std::vector< index_t > adjacent_surfaces_;
574 template < index_t DIMENSION >
575 class LineGeometryFromGeoModelSurfaces
576 :
public CommonDataFromGeoModelSurfaces< DIMENSION >
585 explicit LineGeometryFromGeoModelSurfaces(
587 : CommonDataFromGeoModelSurfaces< DIMENSION >( geomodel ),
588 cur_border_polygon_( 0 )
590 visited_.resize( this->border_polygons_.size(), false );
599 bool compute_next_line_geometry()
601 for( ; cur_border_polygon_ < this->border_polygons_.size();
602 cur_border_polygon_++ )
604 if( is_visited( cur_border_polygon_ ) )
609 compute_line_geometry();
615 LineDefinition& current_line()
621 void compute_line_geometry()
623 visit_border_polygons_on_same_edge( cur_border_polygon_ );
624 auto p0 = this->border_polygons_[cur_border_polygon_].v0_;
625 auto p1 = this->border_polygons_[cur_border_polygon_].v1_;
626 cur_line_.vertices_.push_back( p0 );
627 cur_line_.vertices_.push_back( p1 );
629 cur_line_.adjacent_surfaces_ =
630 get_adjacent_surfaces( cur_border_polygon_ );
632 bool backward{
false };
633 get_one_line_vertices( backward );
635 get_one_line_vertices( backward );
643 void get_one_line_vertices(
bool backward )
646 cur_border_polygon_ < this->border_polygons_.size() );
649 auto t = get_next_border_polygon( cur_border_polygon_, backward );
651 while( propagate( t ) )
653 visit_border_polygons_on_same_edge( t );
654 add_border_polygon_vertices_to_line( t, backward );
655 t = get_next_border_polygon( t, backward );
660 bool propagate( index_t t )
const 662 return t != cur_border_polygon_ && !is_visited( t )
663 && equal_to_line_adjacent_surfaces( t );
666 bool is_visited( index_t i )
const 671 bool equal_to_line_adjacent_surfaces( index_t t )
const 673 auto input = get_adjacent_surfaces( t );
674 if( input.size() != cur_line_.adjacent_surfaces_.size() )
678 return std::equal( input.begin(), input.end(),
679 cur_line_.adjacent_surfaces_.begin() );
682 void add_border_polygon_vertices_to_line(
683 index_t polygon_index,
bool backward )
685 const auto& border_polygon = this->border_polygons_[polygon_index];
686 add_vertices_to_line(
687 border_polygon.v0_, border_polygon.v1_, !backward );
690 void add_vertices_to_line( index_t v0, index_t v1,
bool at_the_end )
695 auto end_vertex = cur_line_.vertices_.back();
696 if( v1 == end_vertex )
704 cur_line_.vertices_.push_back( to_add );
708 auto first_vertex = cur_line_.vertices_.front();
709 if( v1 == first_vertex )
717 cur_line_.vertices_.insert(
718 cur_line_.vertices_.begin(), to_add );
725 index_t get_next_border_polygon( index_t from,
bool backward )
const 727 const auto& border_polygon = this->border_polygons_[from];
728 const auto& S = this->geomodel_.surface( border_polygon.surface_ );
729 const auto& mesh = S.mesh();
730 auto surface_id = S.gmme();
731 const auto& geomodel_vertices = this->geomodel_.mesh.vertices;
734 auto p = border_polygon.polygon_;
735 auto possible_v0_id = geomodel_vertices.mesh_entity_vertex_id(
736 surface_id, border_polygon.v0_ );
738 index_t v0_id{ NO_ID };
739 for(
auto id : possible_v0_id )
741 if( mesh.vertex_index_in_polygon( p,
id ) != NO_ID )
747 auto v0_id_in_polygon = mesh.vertex_index_in_polygon( p, v0_id );
753 backward ? mesh.prev_on_border( cur_polygon_local_edge )
754 : mesh.next_on_border( cur_polygon_local_edge );
756 next_polygon_local_edge0_on_border.
polygon_id_ != NO_ID );
761 mesh.next_polygon_vertex( next_polygon_local_edge0_on_border );
763 next_polygon_local_edge1_on_border.
polygon_id_ != NO_ID );
769 BorderPolygon bait{ border_polygon.surface_,
771 geomodel_vertices.geomodel_vertex_id(
772 surface_id, next_polygon_local_edge0_on_border ),
773 geomodel_vertices.geomodel_vertex_id(
774 surface_id, next_polygon_local_edge1_on_border ) };
775 auto result =
find_sorted( this->border_polygons_, bait );
786 void visit_border_polygons_on_same_edge( index_t border_id )
788 visited_[border_id] =
true;
789 for(
auto next_border_id = border_id + 1;
790 next_border_id < this->border_polygons_.size()
791 && this->have_border_polygons_same_boundary_edge(
792 border_id, next_border_id );
795 visited_[next_border_id] =
true;
797 for(
auto prev_border_id = border_id - 1;
798 prev_border_id != NO_ID
799 && this->have_border_polygons_same_boundary_edge(
800 border_id, prev_border_id );
803 visited_[prev_border_id] =
true;
813 std::vector< index_t > get_adjacent_surfaces( index_t border_id )
const 815 std::vector< index_t > adjacent_surfaces;
816 adjacent_surfaces.reserve( 10 );
817 adjacent_surfaces.push_back(
818 this->border_polygons_[border_id].surface_ );
820 for(
auto next_border_id = border_id + 1;
821 next_border_id < this->border_polygons_.size()
822 && this->have_border_polygons_same_boundary_edge(
823 border_id, next_border_id );
826 adjacent_surfaces.push_back(
827 this->border_polygons_[next_border_id].surface_ );
830 for(
auto prev_border_id = border_id - 1;
831 prev_border_id != NO_ID
832 && this->have_border_polygons_same_boundary_edge(
833 border_id, prev_border_id );
836 adjacent_surfaces.push_back(
837 this->border_polygons_[prev_border_id].surface_ );
839 std::sort( adjacent_surfaces.begin(), adjacent_surfaces.end() );
840 return adjacent_surfaces;
846 std::vector< bool > visited_;
849 index_t cur_border_polygon_;
850 LineDefinition cur_line_;
857 template < index_t DIMENSION >
860 : builder_( builder ),
861 geomodel_( geomodel ),
862 geomodel_access_( geomodel )
866 template < index_t DIMENSION >
870 builder_.topology.copy_topology( from );
871 builder_.geometry.copy_meshes( from );
872 builder_.geology.copy_geology( from );
875 template < index_t DIMENSION >
884 template < index_t DIMENSION >
887 : topology( builder, geomodel ),
888 geometry( builder, geomodel ),
889 geology( builder, geomodel ),
890 removal( builder, geomodel ),
891 repair( builder, geomodel ),
892 copy( builder, geomodel ),
893 info( builder, geomodel ),
899 template < index_t DIMENSION >
902 std::vector< vecn< DIMENSION > > point_extremities;
903 point_extremities.reserve( geomodel_.nb_lines() * DIMENSION );
904 for(
const auto& line : geomodel_.lines() )
906 point_extremities.push_back( line.
vertex( 0 ) );
907 point_extremities.push_back(
912 std::vector< index_t > index_map;
913 std::vector< vecn< DIMENSION > > unique_points;
914 std::tie( std::ignore, index_map, unique_points ) =
916 geomodel_.epsilon() );
919 static_cast< index_t >( unique_points.size() ) );
920 for( index_t c :
range( geomodel_.nb_corners() ) )
922 geometry.set_corner( c, unique_points[c] );
925 for(
const auto& line : geomodel_.lines() )
928 index_t point0 = index_map[index++];
930 index_t point1 = index_map[index++];
932 topology.add_mesh_entity_boundary_relation( line_id, corner0 );
933 topology.add_mesh_entity_boundary_relation( line_id, corner1 );
936 geometry.set_mesh_entity_vertex(
937 line_id, 0, unique_points[point0],
false );
938 geometry.set_mesh_entity_vertex(
939 line_id, line.
nb_vertices() - 1, unique_points[point1], false );
943 template < index_t DIMENSION >
947 LineGeometryFromGeoModelSurfaces< DIMENSION > line_computer(
950 while( line_computer.compute_next_line_geometry() )
952 auto line = line_computer.current_line();
956 line.reoder_closed_line_vertices( geomodel_ );
959 auto& vertices = line.vertices_;
961 topology.find_or_create_corner( vertices.front() );
963 topology.find_or_create_corner( vertices.back() );
965 const auto& adjacent_surfaces = line.adjacent_surfaces_;
966 auto backup_nb_lines = geomodel_.nb_lines();
967 auto line_index = topology.find_or_create_line(
968 adjacent_surfaces, first_corner, second_corner );
970 bool created_line = geomodel_.nb_lines() != backup_nb_lines;
973 geometry.set_line( line_index.index(), vertices );
975 for(
auto j : adjacent_surfaces )
980 topology.add_mesh_entity_boundary_relation(
981 surface_index, line_index );
983 topology.add_mesh_entity_boundary_relation(
984 line_index, first_corner );
985 topology.add_mesh_entity_boundary_relation(
986 line_index, second_corner );
990 bool same_geometry = line_equal(
991 geomodel_.line( line_index.index() ), vertices );
994 geometry.set_line( line_index.index(), vertices );
998 geometry.clear_geomodel_mesh();
1001 template < index_t DIMENSION >
1004 if( geomodel_.name().empty() )
1006 info.set_geomodel_name(
"model_default_name" );
1009 cut_geomodel_on_internal_boundaries();
1021 geometry.cut_surfaces_by_internal_lines();
1032 geometry.cut_surfaces_by_internal_lines();
1033 geometry.cut_regions_by_internal_surfaces();
1038 RegionTopologyFromGeoModelSurfaces region_computer{
geomodel_ };
1039 region_computer.compute_region_info();
1041 const auto& region_info = region_computer.region_info();
1046 "You need at least 1 line and 2 surfaces to use " 1047 "GeoModelBuilder::build_regions_from_lines_and_surfaces" );
1051 std::vector< index_t > surf_2_region(
1055 std::stack< std::pair< index_t, bool > > S;
1056 S.emplace( 0,
true );
1063 if( surf_2_region[cur.second ? 2 * cur.first : 2 * cur.first + 1]
1069 gmme_id cur_region_id{ Region3D::type_name_static(),
1071 topology.create_mesh_entities( Region3D::type_name_static(), 1 );
1073 std::stack< std::pair< index_t, bool > > SR;
1075 while( !SR.empty() )
1079 index_t s_id = s.second ? 2 * s.first : 2 * s.first + 1;
1081 if( surf_2_region[s_id] != NO_ID )
1086 topology.add_mesh_entity_boundary_relation( cur_region_id,
1087 gmme_id{ Surface3D::type_name_static(), s.first },
1089 surf_2_region[s_id] = cur_region_id.index();
1092 index_t s_id_opp = !s.second ? 2 * s.first : 2 * s.first + 1;
1093 if( surf_2_region[s_id_opp] == NO_ID )
1095 S.emplace( s.first, !s.second );
1099 const auto& surface =
geomodel_.surface( s.first );
1100 for(
auto i :
range( surface.nb_boundaries() ) )
1103 region_info[surface.boundary_gmme( i ).index()].next(
1105 index_t n_id = n.second ? 2 * n.first : 2 * n.first + 1;
1107 if( surf_2_region[n_id] == NO_ID )
1118 if( std::count( surf_2_region.begin(), surf_2_region.end(), NO_ID )
1122 "Small bubble regions were skipped at geomodel building " );
1130 double max_volume{ -1. };
1131 index_t universe_id{ NO_ID };
1132 for(
const auto& region :
geomodel_.regions() )
1134 double cur_volume = region.size();
1135 if( cur_volume > max_volume )
1137 max_volume = cur_volume;
1138 universe_id = region.index();
1141 const auto& cur_region =
geomodel_.region( universe_id );
1142 std::set< gmme_id > to_erase;
1143 to_erase.insert( cur_region.gmme() );
1144 removal.remove_mesh_entities( to_erase );
#define ringmesh_disable_copy_and_move(Class)
const GeoModel< DIMENSION > & geomodel() const
GeoModelMesh< DIMENSION > mesh
GEO::vecng< DIMENSION, double > vecn
GeoModel< DIMENSION > & geomodel_
GeoModelBuilderGeometry< DIMENSION > geometry
const vecn< DIMENSION > & vertex(index_t vertex_index) const
Coordinates of the vertex_index.
GeoModelBuilderBase(GeoModelBuilder< DIMENSION > &builder, GeoModel< DIMENSION > &geomodel)
Base class to build or edit a GeoModel.
void RINGMESH_API rotate(GeoModel3D &geomodel, const vec3 &origin, const vec3 &axis, double angle, bool degrees=false)
Rotate the boundary geomodel.
GeoModelBuilderTopology< DIMENSION > topology
index_t find_sorted(const container &in, const T &value)
Returns the position of the first entity matching.
GeoModel< DIMENSION > & geomodel_
GeoModel< DIMENSION > & geomodel_
#define ringmesh_template_assert_2d_or_3d(type)
A GeoModelEntity of type CORNER.
GeoModelBuilderInfo(GeoModelBuilder< DIMENSION > &builder, GeoModel< DIMENSION > &geomodel)
void cut_geomodel_on_internal_boundaries()
bool is_closed() const
A Line is closed if its two extremities are identitical.
void print_geomodel(const GeoModel< DIMENSION > &geomodel)
Print in the console the geomodel statistics.
GeoModelBuilder< DIMENSION > & builder_
static void err(const std::string &feature, const Args &... args)
static MeshEntityType type_name_static()
GeoModelBuilderRemoval< DIMENSION > removal
GeoModelAccess< DIMENSION > geomodel_access_
GeoModelBuilderCopy(GeoModelBuilder< DIMENSION > &builder, GeoModel< DIMENSION > &geomodel)
index_t nb_corners() const
#define ringmesh_assert(x)
GeoModelAccess< DIMENSION > geomodel_access_
Classes to build GeoModel from various inputs.
A GeoModelEntity of type LINE.
std::tuple< index_t, std::vector< index_t >, std::vector< vecn< DIMENSION > > > get_colocated_index_mapping_and_unique_points(double epsilon) const
Gets the index_map that link all the points to a no duplicated list of index in the list of unique_po...
This template is a specialization of a gme_id to the GeoModelMeshEntity.
index_t nb_vertices() const
void copy_geomodel(const GeoModel< DIMENSION > &from)
#define ringmesh_assert_not_reached