1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 #include "libmesh/libmesh_config.h"
19 #ifdef LIBMESH_HAVE_TETGEN
20
21 // C++ includes
22 #include <iostream>
23
24 // Local includes
25 #include "libmesh/libmesh_common.h"
26 #include "libmesh/mesh_tetgen_wrapper.h"
27 #include "libmesh/auto_ptr.h" // libmesh_make_unique
28
29 namespace libMesh
30 {
31
TetGenWrapper()32 TetGenWrapper::TetGenWrapper() :
33 tetgen_output(libmesh_make_unique<tetgenio>())
34 {
35 this->tetgen_data.mesh_dim = 3;
36 this->tetgen_data.numberofpointattributes = 0;
37 this->tetgen_data.firstnumber = 0;
38 }
39
40
41
~TetGenWrapper()42 TetGenWrapper::~TetGenWrapper()
43 {
44 }
45
46
47
set_node(unsigned i,REAL x,REAL y,REAL z)48 void TetGenWrapper::set_node(unsigned i, REAL x, REAL y, REAL z)
49 {
50 unsigned index = i*3;
51 tetgen_data.pointlist[index++] = x;
52 tetgen_data.pointlist[index++] = y;
53 tetgen_data.pointlist[index++] = z;
54 }
55
56
57
set_hole(unsigned i,REAL x,REAL y,REAL z)58 void TetGenWrapper::set_hole(unsigned i, REAL x, REAL y, REAL z)
59 {
60 unsigned index = i*3;
61 tetgen_data.holelist[index++] = x;
62 tetgen_data.holelist[index++] = y;
63 tetgen_data.holelist[index++] = z;
64 }
65
66
67
set_numberofpoints(int i)68 void TetGenWrapper::set_numberofpoints(int i)
69 {
70 // This is an int in tetgen, so use an int here even though it should be unsigned
71 tetgen_data.numberofpoints = i;
72 }
73
74
75
get_output_node(unsigned i,REAL & x,REAL & y,REAL & z)76 void TetGenWrapper::get_output_node(unsigned i, REAL & x, REAL & y, REAL & z)
77 {
78 // Bounds checking...
79 libmesh_error_msg_if(i >= static_cast<unsigned>(tetgen_output->numberofpoints),
80 "Error, requested point "
81 << i
82 << ", but there are only "
83 << tetgen_output->numberofpoints
84 << " points available.");
85
86 x = tetgen_output->pointlist[3*i];
87 y = tetgen_output->pointlist[3*i+1];
88 z = tetgen_output->pointlist[3*i+2];
89 }
90
91
92
get_numberoftetrahedra()93 int TetGenWrapper::get_numberoftetrahedra()
94 {
95 return tetgen_output->numberoftetrahedra;
96 }
97
98
99
get_numberoftrifaces()100 int TetGenWrapper::get_numberoftrifaces()
101 {
102 return tetgen_output->numberoftrifaces;
103 }
104
105
106
get_numberofpoints()107 int TetGenWrapper::get_numberofpoints()
108 {
109 return tetgen_output->numberofpoints;
110 }
111
112
113
get_element_node(unsigned i,unsigned j)114 int TetGenWrapper::get_element_node(unsigned i, unsigned j)
115 {
116 return tetgen_output->tetrahedronlist[i*4+j];
117 }
118
119
120
get_triface_node(unsigned i,unsigned j)121 int TetGenWrapper::get_triface_node(unsigned i, unsigned j)
122 {
123 return tetgen_output->trifacelist[i*3+j];
124 }
125
126
127
get_element_attribute(unsigned i)128 REAL TetGenWrapper::get_element_attribute(unsigned i)
129 {
130 libmesh_assert(tetgen_output->numberoftetrahedronattributes>0);
131 return tetgen_output->tetrahedronattributelist[tetgen_output->numberoftetrahedronattributes*i];
132 }
133
134
135
allocate_pointlist(int numofpoints)136 void TetGenWrapper::allocate_pointlist(int numofpoints)
137 {
138 // This is stored as an int in tetgen, so we store it that way as well.
139 this->set_numberofpoints(numofpoints);
140
141 // Don't try to allocate an array of size zero, this is not portable...
142 if (this->tetgen_data.numberofpoints > 0)
143 {
144 // Is there previously-allocated memory here?
145 libmesh_error_msg_if(this->tetgen_data.pointlist != nullptr,
146 "Cannot allocate on top of previously allocated memory!");
147
148 // We allocate memory here, the tetgenio destructor will delete it.
149 this->tetgen_data.pointlist = new REAL[this->tetgen_data.numberofpoints * 3];
150 }
151 }
152
153
154
set_switches(const std::string & s)155 void TetGenWrapper::set_switches(const std::string & s)
156 {
157 // A temporary buffer for passing to the C API, it requires
158 // a char *, not a const char *...
159 char buffer[256];
160
161 // Make sure char buffer has enough room
162 libmesh_error_msg_if(s.size() >= sizeof(buffer)-1,
163 "Fixed size buffer of length "
164 << sizeof(buffer)
165 << " not large enough to hold TetGen switches.");
166
167 // Copy the string, don't forget to terminate!
168 buffer[ s.copy( buffer , sizeof( buffer ) - 1 ) ] = '\0' ;
169
170 if (!tetgen_be.parse_commandline(buffer))
171 libMesh::out << "TetGen replies: Wrong switches!" << std::endl;
172 }
173
174
175
run_tetgen()176 void TetGenWrapper::run_tetgen()
177 {
178 // Call tetrahedralize from the TetGen library.
179 tetrahedralize(&tetgen_be, &tetgen_data, tetgen_output.get());
180 }
181
182
183
set_numberoffacets(int i)184 void TetGenWrapper::set_numberoffacets(int i)
185 {
186 // This is stored as an int in TetGen
187 this->tetgen_data.numberoffacets = i;
188 }
189
190
191
set_numberofholes(int i)192 void TetGenWrapper::set_numberofholes(int i)
193 {
194 // This is stored as an int in TetGen
195 this->tetgen_data.numberofholes = i;
196 }
197
198
199
set_numberofregions(int i)200 void TetGenWrapper::set_numberofregions(int i)
201 {
202 // This is stored as an int in TetGen
203 this->tetgen_data.numberofregions = i;
204 }
205
206
207
allocate_facetlist(int numoffacets,int numofholes)208 void TetGenWrapper::allocate_facetlist(int numoffacets, int numofholes)
209 {
210 // These are both stored as ints in TetGen
211 this->set_numberoffacets(numoffacets);
212 this->set_numberofholes(numofholes);
213
214 // Don't try to allocate an array of size zero, this is not portable...
215 if (this->tetgen_data.numberoffacets > 0)
216 {
217 // Is there previously-allocated memory here?
218 libmesh_error_msg_if(this->tetgen_data.facetlist != nullptr,
219 "Cannot allocate on top of previously allocated memory!");
220
221 // We allocate memory here, the tetgenio destructor cleans it up.
222 this->tetgen_data.facetlist = new tetgenio::facet[this->tetgen_data.numberoffacets];
223
224 for (int i=0; i<numoffacets; i++)
225 this->tetgen_data.init(&(this->tetgen_data.facetlist[i]));
226 }
227
228
229 // Don't try to allocate an array of size zero, this is not portable...
230 if (this->tetgen_data.numberofholes > 0)
231 {
232 // Is there previously-allocated memory here?
233 libmesh_error_msg_if(this->tetgen_data.holelist != nullptr,
234 "Cannot allocate on top of previously allocated memory!");
235
236 this->tetgen_data.holelist = new REAL[this->tetgen_data.numberofholes * 3];
237 }
238 }
239
240
241
allocate_regionlist(int numofregions)242 void TetGenWrapper::allocate_regionlist(int numofregions)
243 {
244 this->set_numberofregions(numofregions);
245
246 // Don't try to allocate an array of size zero, this is not portable...
247 if (this->tetgen_data.numberofregions > 0)
248 {
249 // Is there previously-allocated memory here?
250 libmesh_error_msg_if(this->tetgen_data.regionlist != nullptr,
251 "Cannot allocate on top of previously allocated memory!");
252
253 // We allocate memory here, the tetgenio destructor cleans it up.
254 this->tetgen_data.regionlist = new REAL[this->tetgen_data.numberofregions * 5];
255 }
256 }
257
258
259
set_facet_numberofpolygons(unsigned i,int num)260 void TetGenWrapper::set_facet_numberofpolygons(unsigned i, int num)
261 {
262 // numberofpolygons is stored as an int in TetGen
263 this->tetgen_data.facetlist[i].numberofpolygons = num;
264 }
265
266
267
set_facet_numberofholes(unsigned i,int num)268 void TetGenWrapper::set_facet_numberofholes(unsigned i, int num)
269 {
270 // numberofholes is stored as an int in TetGen
271 this->tetgen_data.facetlist[i].numberofholes = num;
272 }
273
274
275
276
allocate_facet_polygonlist(unsigned i,int numofpolygons)277 void TetGenWrapper::allocate_facet_polygonlist(unsigned i, int numofpolygons)
278 {
279 this->set_facet_numberofpolygons(i, numofpolygons);
280 this->set_facet_numberofholes(i, 0);
281
282 // Don't try to create an array of size zero, this isn't portable
283 if (numofpolygons > 0)
284 {
285 // Is there previously-allocated memory here?
286 libmesh_error_msg_if(this->tetgen_data.facetlist[i].polygonlist != nullptr,
287 "Cannot allocate on top of previously allocated memory!");
288
289 // We allocate memory here, the tetgenio destructor cleans it up.
290 this->tetgen_data.facetlist[i].polygonlist = new tetgenio::polygon[numofpolygons];
291
292 for (int j=0; j<this->tetgen_data.facetlist[i].numberofpolygons; j++)
293 this->tetgen_data.init(&(this->tetgen_data.facetlist[i].polygonlist[j]));
294 }
295 }
296
297
298
set_polygon_numberofvertices(unsigned i,unsigned j,int num)299 void TetGenWrapper::set_polygon_numberofvertices(unsigned i, unsigned j, int num)
300 {
301 // numberofvertices is stored as an int in TetGen
302 this->tetgen_data.facetlist[i].polygonlist[j].numberofvertices = num;
303 }
304
305
306
allocate_polygon_vertexlist(unsigned i,unsigned j,int numofvertices)307 void TetGenWrapper::allocate_polygon_vertexlist(unsigned i, unsigned j, int numofvertices)
308 {
309 this->set_polygon_numberofvertices(i, j, numofvertices);
310
311 // Don't try to create an array of size zero, this isn't portable
312 if (numofvertices > 0)
313 {
314 // Is there previously-allocated memory here?
315 libmesh_error_msg_if(this->tetgen_data.facetlist[i].polygonlist[j].vertexlist != nullptr,
316 "Cannot allocate on top of previously allocated memory!");
317
318 // We allocate memory here, the tetgenio destructor cleans it up.
319 this->tetgen_data.facetlist[i].polygonlist[j].vertexlist = new int[numofvertices];
320 }
321 }
322
323
324
325
set_vertex(unsigned i,unsigned j,unsigned k,int nodeindex)326 void TetGenWrapper::set_vertex(unsigned i, unsigned j, unsigned k, int nodeindex)
327 {
328 // vertexlist entries are stored as ints in TetGen
329 this->tetgen_data.facetlist[i].polygonlist[j].vertexlist[k] = nodeindex;
330 }
331
332
333
set_region(unsigned i,REAL x,REAL y,REAL z,REAL attribute,REAL vol_constraint)334 void TetGenWrapper::set_region(unsigned i, REAL x, REAL y, REAL z,
335 REAL attribute, REAL vol_constraint)
336 {
337 unsigned index = i*5;
338 tetgen_data.regionlist[index++] = x;
339 tetgen_data.regionlist[index++] = y;
340 tetgen_data.regionlist[index++] = z;
341 tetgen_data.regionlist[index++] = attribute;
342 tetgen_data.regionlist[index++] = vol_constraint;
343 }
344
345 } // namespace libMesh
346
347
348 #endif // LIBMESH_HAVE_TETGEN
349