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