mesh_triangle_interface.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 #include "libmesh/libmesh_config.h" 00020 00021 #ifdef LIBMESH_HAVE_TRIANGLE 00022 00023 // C/C++ includes 00024 #include <sstream> 00025 00026 #include "libmesh/mesh_triangle_interface.h" 00027 #include "libmesh/unstructured_mesh.h" 00028 #include "libmesh/face_tri3.h" 00029 #include "libmesh/face_tri6.h" 00030 #include "libmesh/mesh_generation.h" 00031 #include "libmesh/mesh_smoother_laplace.h" 00032 #include "libmesh/boundary_info.h" 00033 #include "libmesh/mesh_triangle_holes.h" 00034 #include "libmesh/mesh_triangle_wrapper.h" 00035 00036 namespace libMesh 00037 { 00038 // 00039 // Function definitions for the TriangleInterface class 00040 // 00041 00042 // Constructor 00043 TriangleInterface::TriangleInterface(UnstructuredMesh& mesh) 00044 : _mesh(mesh), 00045 _holes(NULL), 00046 _elem_type(TRI3), 00047 _desired_area(0.1), 00048 _triangulation_type(GENERATE_CONVEX_HULL), 00049 _insert_extra_points(false), 00050 _smooth_after_generating(true), 00051 _serializer(_mesh) 00052 {} 00053 00054 00055 00056 // Primary function responsible for performing the triangulation 00057 void TriangleInterface::triangulate() 00058 { 00059 // Will the triangulation have holes? 00060 const bool have_holes = ((_holes != NULL) && (!_holes->empty())); 00061 00062 // If the initial PSLG is really simple, e.g. an L-shaped domain or 00063 // a square/rectangle, the resulting triangulation may be very 00064 // "structured" looking. Sometimes this is a problem if your 00065 // intention is to work with an "unstructured" looking grid. We can 00066 // attempt to work around this limitation by inserting midpoints 00067 // into the original PSLG. Inserting additional points into a 00068 // set of points meant to be a convex hull usually makes less sense. 00069 00070 // May or may not need to insert new points ... 00071 if ((_triangulation_type==PSLG) && (_insert_extra_points)) 00072 { 00073 // Make a copy of the original points from the Mesh 00074 std::vector<Point> original_points (_mesh.n_nodes()); 00075 00076 MeshBase::node_iterator node_it = _mesh.nodes_begin(); 00077 const MeshBase::node_iterator node_end = _mesh.nodes_end(); 00078 00079 for (unsigned int ctr=0; node_it != node_end; ++node_it) 00080 original_points[ctr++] = **node_it; 00081 00082 // Clear out the mesh 00083 _mesh.clear(); 00084 00085 // Make sure the new Mesh will be 2D 00086 _mesh.set_mesh_dimension(2); 00087 00088 // Insert a new point on each PSLG at some random location 00089 // np=index into new points vector 00090 // n =index into original points vector 00091 for (unsigned int np=0, n=0; np<2*original_points.size(); ++np) 00092 { 00093 // the even entries are the original points 00094 if (np%2==0) 00095 _mesh.add_point(original_points[n++]); 00096 00097 else // the odd entries are the midpoints of the original PSLG segments 00098 _mesh.add_point ((original_points[n] + original_points[n-1])/2); 00099 } 00100 } 00101 00102 // Regardless of whether we added additional points, the set of points to 00103 // triangulate is now sitting in the mesh. 00104 00105 // If the holes vector is non-NULL (and non-empty) we need to determine 00106 // the number of additional points which the holes will add to the 00107 // triangulation. 00108 unsigned int n_hole_points = 0; 00109 00110 if (have_holes) 00111 { 00112 for (unsigned int i=0; i<_holes->size(); ++i) 00113 n_hole_points += (*_holes)[i]->n_points(); 00114 } 00115 00116 // Triangle data structure for the mesh 00117 TriangleWrapper::triangulateio initial; 00118 TriangleWrapper::triangulateio final; 00119 00120 // Pseudo-Constructor for the triangle io structs 00121 TriangleWrapper::init(initial); 00122 TriangleWrapper::init(final); 00123 00124 initial.numberofpoints = _mesh.n_nodes() + n_hole_points; 00125 initial.pointlist = static_cast<REAL*>(std::malloc(initial.numberofpoints * 2 * sizeof(REAL))); 00126 00127 if (_triangulation_type==PSLG) 00128 { 00129 // Implicit segment ordering: One segment per point, including hole points 00130 if (this->segments.empty()) 00131 initial.numberofsegments = initial.numberofpoints; 00132 00133 // User-defined segment ordering: One segment per entry in the segments vector 00134 else 00135 initial.numberofsegments = this->segments.size(); 00136 } 00137 00138 else if (_triangulation_type==GENERATE_CONVEX_HULL) 00139 initial.numberofsegments = n_hole_points; // One segment for each hole point 00140 00141 // Debugging 00142 // libMesh::out << "Number of segments set to: " << initial.numberofsegments << std::endl; 00143 00144 // Allocate space for the segments (2 int per segment) 00145 if (initial.numberofsegments > 0) 00146 { 00147 initial.segmentlist = static_cast<int*> (std::malloc(initial.numberofsegments * 2 * sizeof(int))); 00148 } 00149 00150 00151 // Copy all the holes' points and segments into the triangle struct. 00152 00153 // The hole_offset is a constant offset into the points vector which points 00154 // past the end of the last hole point added. 00155 unsigned int hole_offset=0; 00156 00157 if (have_holes) 00158 for (unsigned int i=0; i<_holes->size(); ++i) 00159 { 00160 for (unsigned int ctr=0, h=0; h<(*_holes)[i]->n_points(); ctr+=2, ++h) 00161 { 00162 Point p = (*_holes)[i]->point(h); 00163 00164 const unsigned int index0 = 2*hole_offset+ctr; 00165 const unsigned int index1 = 2*hole_offset+ctr+1; 00166 00167 // Save the x,y locations in the triangle struct. 00168 initial.pointlist[index0] = p(0); 00169 initial.pointlist[index1] = p(1); 00170 00171 // Set the points which define the segments 00172 initial.segmentlist[index0] = hole_offset+h; 00173 initial.segmentlist[index1] = (h==(*_holes)[i]->n_points()-1) ? hole_offset : hole_offset+h+1; // wrap around 00174 } 00175 00176 // Update the hole_offset for the next hole 00177 hole_offset += (*_holes)[i]->n_points(); 00178 } 00179 00180 00181 // Copy all the non-hole points and segments into the triangle struct. 00182 { 00183 MeshBase::node_iterator it = _mesh.nodes_begin(); 00184 const MeshBase::node_iterator end = _mesh.nodes_end(); 00185 00186 for (dof_id_type ctr=0; it != end; ctr+=2, ++it) 00187 { 00188 dof_id_type index = 2*hole_offset + ctr; 00189 00190 // Get pointer to the current node 00191 Node* node = *it; 00192 00193 // Set x,y values in pointlist 00194 initial.pointlist[index] = (*node)(0); 00195 initial.pointlist[index+1] = (*node)(1); 00196 00197 // If the user requested a PSLG, the non-hole points are also segments 00198 if (_triangulation_type==PSLG) 00199 { 00200 // Use implicit ordering to define segments 00201 if (this->segments.empty()) 00202 { 00203 dof_id_type n = ctr/2; // ctr is always even 00204 initial.segmentlist[index] = hole_offset+n; 00205 initial.segmentlist[index+1] = (n==_mesh.n_nodes()-1) ? hole_offset : hole_offset+n+1; // wrap around 00206 } 00207 } 00208 } 00209 } 00210 00211 00212 // If the user provided it, use his ordering to define the segments 00213 for (unsigned int ctr=0, s=0; s<this->segments.size(); ctr+=2, ++s) 00214 { 00215 const unsigned int index0 = 2*hole_offset+ctr; 00216 const unsigned int index1 = 2*hole_offset+ctr+1; 00217 00218 initial.segmentlist[index0] = hole_offset + this->segments[s].first; 00219 initial.segmentlist[index1] = hole_offset + this->segments[s].second; 00220 } 00221 00222 00223 00224 // Tell the input struct about the holes 00225 if (have_holes) 00226 { 00227 initial.numberofholes = _holes->size(); 00228 initial.holelist = static_cast<REAL*>(std::malloc(initial.numberofholes * 2 * sizeof(REAL))); 00229 for (unsigned int i=0, ctr=0; i<_holes->size(); ++i, ctr+=2) 00230 { 00231 Point inside_point = (*_holes)[i]->inside(); 00232 initial.holelist[ctr] = inside_point(0); 00233 initial.holelist[ctr+1] = inside_point(1); 00234 } 00235 } 00236 00237 // Set the triangulation flags. 00238 // c ~ enclose convex hull with segments 00239 // z ~ use zero indexing 00240 // B ~ Suppresses boundary markers in the output 00241 // Q ~ run in "quiet" mode 00242 // p ~ Triangulates a Planar Straight Line Graph 00243 // If the `p' switch is used, `segmentlist' must point to a list of 00244 // segments, `numberofsegments' must be properly set, and 00245 // `segmentmarkerlist' must either be set to NULL (in which case all 00246 // markers default to zero), or must point to a list of markers. 00247 // D ~ Conforming Delaunay: use this switch if you want all triangles 00248 // in the mesh to be Delaunay, and not just constrained Delaunay 00249 // q ~ Quality mesh generation with no angles smaller than 20 degrees. 00250 // An alternate minimum angle may be specified after the q 00251 // a ~ Imposes a maximum triangle area constraint. 00252 // -P Suppresses the output .poly file. Saves disk space, but you lose the ability to maintain 00253 // constraining segments on later refinements of the mesh. 00254 // Create the flag strings, depends on element type 00255 std::ostringstream flags; 00256 00257 // Default flags always used 00258 flags << "zBPQq"; 00259 00260 // Flags which are specific to the type of triangulation 00261 switch (_triangulation_type) 00262 { 00263 case GENERATE_CONVEX_HULL: 00264 { 00265 flags << "c"; 00266 break; 00267 } 00268 00269 case PSLG: 00270 { 00271 flags << "p"; 00272 break; 00273 } 00274 00275 case INVALID_TRIANGULATION_TYPE: 00276 { 00277 libmesh_error(); 00278 break; 00279 } 00280 00281 default: 00282 { 00283 libmesh_error(); 00284 } 00285 } 00286 00287 00288 // Flags specific to the type of element 00289 switch (_elem_type) 00290 { 00291 case TRI3: 00292 { 00293 // do nothing. 00294 break; 00295 } 00296 00297 case TRI6: 00298 { 00299 flags << "o2"; 00300 break; 00301 } 00302 00303 default: 00304 { 00305 libMesh::err << "ERROR: Unrecognized triangular element type." << std::endl; 00306 libmesh_error(); 00307 } 00308 } 00309 00310 00311 // If we do have holes and the user asked to GENERATE_CONVEX_HULL, 00312 // need to add the p flag so the triangulation respects those segments. 00313 if ((_triangulation_type==GENERATE_CONVEX_HULL) && (have_holes)) 00314 flags << "p"; 00315 00316 // Finally, add the area constraint 00317 flags << "a" << std::fixed << _desired_area; 00318 00319 // Refine the initial output to conform to the area constraint 00320 TriangleWrapper::triangulate(const_cast<char*>(flags.str().c_str()), 00321 &initial, 00322 &final, 00323 NULL); // voronoi ouput -- not used 00324 00325 00326 // Send the information computed by Triangle to the Mesh. 00327 TriangleWrapper::copy_tri_to_mesh(final, 00328 _mesh, 00329 _elem_type); 00330 00331 // To the naked eye, a few smoothing iterations usually looks better, 00332 // so we do this by default unless the user says not to. 00333 if (this->_smooth_after_generating) 00334 LaplaceMeshSmoother(_mesh).smooth(2); 00335 00336 00337 // Clean up. 00338 TriangleWrapper::destroy(initial, TriangleWrapper::INPUT); 00339 TriangleWrapper::destroy(final, TriangleWrapper::OUTPUT); 00340 00341 } 00342 00343 } // namespace libMesh 00344 00345 00346 00347 00348 00349 00350 00351 #endif // LIBMESH_HAVE_TRIANGLE 00352 00353 00354 00355 00356 00357 00358 00359
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:47 UTC
Hosted By: