40 #include <geogram/mesh/mesh.h> 44 #ifdef RINGMESH_WITH_TETGEN 54 bool is_mesh_tetrahedralizable(
const GEO::Mesh& M )
56 if( M.facets.nb() == 0 )
58 Logger::err(
"RING",
"Mesh to tetrahedralize has no polygons " );
61 if( !M.facets.are_simplices() )
63 Logger::err(
"RING",
"Mesh to tetrahedralize is not triangulated" );
66 if( M.cells.nb() != 0 )
68 Logger::warn(
"RING",
"Mesh to tetrahedralize already have cells" );
76 TetgenMesher::~TetgenMesher()
80 delete[] tetgen_in_.facetlist;
81 tetgen_in_.facetlist =
nullptr;
82 tetgen_in_.numberoffacets = 0;
85 void TetgenMesher::tetrahedralize(
89 copy_mesh_to_tetgen_input( input_mesh );
91 assign_result_tetmesh_to_mesh( output_mesh_builder );
94 void TetgenMesher::initialize()
96 initialize_tetgen_args();
97 tetgen_in_.initialize();
98 tetgen_out_.initialize();
101 void TetgenMesher::tetrahedralize()
105 GEO_3rdParty::tetrahedralize(
106 &tetgen_args_, &tetgen_in_, &tetgen_out_ );
110 Logger::err(
"Tetgen",
"Encountered a problem: " );
117 Logger::err(
"Tetgen",
"Please report this bug to " 118 "Hang.Si@wias-berlin.de. Include" );
120 " the message above, your input data set, and the exact" );
122 " command line you used to run this program, thank you" );
127 "A self-intersection was detected. Program stopped" );
129 "Hint: use -d option to detect all self-intersections" );
132 Logger::err(
"Tetgen",
"A very small input feature size was " 133 "detected. Program stopped." );
135 "Hint: use -T option to set a smaller tolerance." );
138 Logger::err(
"Tetgen",
"Two very close input polygons were " 139 "detected. Program stopped." );
140 Logger::err(
"Tetgen",
"Hint: use -Y option to avoid adding " 141 "Steiner points in boundary." );
145 "Tetgen",
"An input error was detected. Program stopped." );
151 void TetgenMesher::copy_mesh_to_tetgen_input(
const GEO::Mesh& M )
153 if( M.vertices.nb() != 0 )
155 copy_vertices_to_tetgen_input( M );
157 if( M.edges.nb() != 0 )
159 copy_edges_to_tetgen_input( M );
161 if( M.facets.nb() != 0 )
163 copy_polygons_to_tetgen_input( M );
167 void TetgenMesher::copy_vertices_to_tetgen_input(
const GEO::Mesh& M )
169 tetgen_in_.numberofpoints =
static_cast< int >( M.vertices.nb() );
170 tetgen_in_.pointlist =
new double[3 * tetgen_in_.numberofpoints];
171 GEO::Memory::copy( tetgen_in_.pointlist, M.vertices.point_ptr( 0 ),
172 M.vertices.nb() * 3 *
sizeof(
double ) );
175 void TetgenMesher::copy_edges_to_tetgen_input(
const GEO::Mesh& M )
177 tetgen_in_.numberofedges =
static_cast< int >( M.edges.nb() );
178 tetgen_in_.edgelist =
new int[2 * tetgen_in_.numberofedges];
179 GEO::Memory::copy( tetgen_in_.edgelist, M.edges.vertex_index_ptr( 0 ),
180 M.edges.nb() * 2 *
sizeof( int ) );
183 void TetgenMesher::copy_polygons_to_tetgen_input(
const GEO::Mesh& M )
185 polygons_.reset(
new GEO_3rdParty::tetgenio::polygon[M.facets.nb()] );
187 tetgen_in_.numberoffacets =
static_cast< int >( M.facets.nb() );
188 tetgen_in_.facetlist =
189 new GEO_3rdParty::tetgenio::facet[tetgen_in_.numberoffacets];
191 polygon_corners_.reset(
new int[M.facet_corners.nb()] );
192 GEO::Memory::copy( polygon_corners_.get(),
193 M.facet_corners.vertex_index_ptr( 0 ),
194 M.facet_corners.nb() *
sizeof( int ) );
196 for(
auto f :
range( M.facets.nb() ) )
198 GEO_3rdParty::tetgenio::facet& F = tetgen_in_.facetlist[f];
199 GEO_3rdParty::tetgenio::init( &F );
200 F.numberofpolygons = 1;
201 F.polygonlist = &polygons_[f];
203 GEO_3rdParty::tetgenio::polygon& P = F.polygonlist[0];
204 GEO_3rdParty::tetgenio::init( &P );
205 P.numberofvertices =
static_cast< int >( M.facets.nb_corners( f ) );
206 P.vertexlist = &polygon_corners_[M.facets.corners_begin( f )];
210 void TetgenMesher::set_regions(
211 const std::vector< vec3 >& one_point_in_each_region )
213 index_t nb_regions = one_point_in_each_region.size();
214 tetgen_in_.numberofregions =
static_cast< int >( nb_regions );
215 tetgen_in_.regionlist =
new double[5 * nb_regions];
217 for(
auto i :
range( nb_regions ) )
219 tetgen_in_.regionlist[5 * i] = one_point_in_each_region[i].x;
220 tetgen_in_.regionlist[5 * i + 1] = one_point_in_each_region[i].y;
221 tetgen_in_.regionlist[5 * i + 2] = one_point_in_each_region[i].z;
222 tetgen_in_.regionlist[5 * i + 3] = i;
223 tetgen_in_.regionlist[5 * i + 4] =
228 void TetgenMesher::initialize_tetgen_args()
230 std::vector< char > copy(
231 tetgen_command_line_.begin(), tetgen_command_line_.end() );
232 copy.push_back(
'\0' );
233 tetgen_args_.parse_commandline( copy.data() );
236 void TetgenMesher::assign_result_tetmesh_to_mesh(
245 std::vector< double > TetgenMesher::get_result_tetmesh_points()
const 247 auto nb_points =
static_cast< index_t
>( tetgen_out_.numberofpoints );
248 std::vector< double > points( 3 * nb_points );
249 double* points_ptr = tetgen_out_.pointlist;
250 parallel_for( 3 * nb_points, [&points, &points_ptr]( index_t i ) {
251 points[i] = points_ptr[i];
256 std::vector< index_t > TetgenMesher::get_result_tetmesh_tets()
const 258 std::vector< index_t > tets_to_keep = determine_tets_to_keep();
260 auto nb_tets =
static_cast< index_t
>( tets_to_keep.size() );
261 std::vector< index_t > tets( 4 * nb_tets );
262 int* tets_ptr = tetgen_out_.tetrahedronlist;
263 parallel_for( nb_tets, [&tets_to_keep, &tets_ptr, &tets]( index_t i ) {
264 index_t tetra = tets_to_keep[i];
265 for(
auto v :
range( 4 ) )
268 static_cast< index_t
>( tets_ptr[4 * tetra + v] );
274 std::set< double > TetgenMesher::determine_tet_regions_to_keep()
const 280 std::set< double > regions_to_keep;
281 auto nb_tets =
static_cast< index_t
>( tetgen_out_.numberoftetrahedra );
282 for(
auto t :
range( nb_tets ) )
284 for(
auto f :
range( 4 ) )
286 signed_index_t n = tetgen_out_.neighborlist[t * 4 + f];
289 regions_to_keep.insert(
290 tetgen_out_.tetrahedronattributelist[t] );
295 return regions_to_keep;
298 std::vector< index_t > TetgenMesher::determine_tets_to_keep()
const 300 std::vector< index_t > tets_to_keep;
301 std::set< double > regions_to_keep = determine_tet_regions_to_keep();
303 auto nb_tets =
static_cast< index_t
>( tetgen_out_.numberoftetrahedra );
304 tets_to_keep.reserve( nb_tets );
305 for(
auto t :
range( nb_tets ) )
307 if( regions_to_keep.find( tetgen_out_.tetrahedronattributelist[t] )
308 != regions_to_keep.end() )
310 tets_to_keep.push_back( t );
317 const GEO::Mesh& in_mesh,
321 if( !is_mesh_tetrahedralizable( in_mesh ) )
324 "TetGen",
"Mesh cannot be tetrahedralized" );
329 mesher.add_points_to_match_quality( quality );
331 mesher.tetrahedralize( in_mesh, out_tet_mesh );
334 void TetgenMesher::add_points_to_match_quality(
double quality )
336 tetgen_command_line_ +=
"q" + std::to_string( quality );
static void warn(const std::string &feature, const Args &... args)
void remove_isolated_vertices()
static void err(const std::string &feature, const Args &... args)
virtual void connect_cells()=0
Retrieve the adjacencies.
Classes to build GeoModel from various inputs.
void assign_cell_tet_mesh(const std::vector< index_t > &tets)
void assign_vertices(const std::vector< double > &point_coordinates)
set vertex coordinates from a std::vector of coordinates
void parallel_for(index_t size, const ACTION &action)