![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
00001 /************************************************************************ 00002 * MechSys - Open Library for Mechanical Systems * 00003 * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand * 00004 * Copyright (C) 2009 Sergio Galindo * 00005 * * 00006 * This program is free software: you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation, either version 3 of the License, or * 00009 * any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License * 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00018 ************************************************************************/ 00019 00020 #ifndef MECHSYS_MESH_UNSTRUCTURED_H 00021 #define MECHSYS_MESH_UNSTRUCTURED_H 00022 00023 /* LOCAL indexes of Vertices, Edges, and Faces 00024 00025 2D: 00026 Nodes Edges 00027 00028 y 2 00029 | @ @ 00030 +--x / \ / \ 00031 5 / \ 4 / \ 00032 @ @ 2 / \ 1 00033 / \ / \ 00034 / \ / \ 00035 @-----@-----@ @-----------@ 00036 0 3 1 0 00037 */ 00038 00039 // STL 00040 #include <iostream> // for cout, endl, ostream 00041 #include <sstream> // for ostringstream 00042 #include <fstream> // for ofstream 00043 #include <cfloat> // for DBL_EPSILON 00044 #include <map> 00045 00046 // Jonathan R Shewchuk' Triangle 00047 extern "C" 00048 { 00049 #define REAL double 00050 #define ANSI_DECLARATORS 00051 #define VOID int 00052 #include "triangle.h" 00053 #undef REAL 00054 #undef ANSI_DECLARATORS 00055 #undef VOID 00056 } 00057 00058 // Hang Si' Tetgen 00059 #define TETLIBRARY 00060 #include "tetgen.h" 00061 #undef REAL 00062 #undef TETLIBRARY 00063 00064 // MechSys 00065 #include <mechsys/util/array.h> 00066 #include <mechsys/util/fatal.h> 00067 #include <mechsys/util/stopwatch.h> 00068 #include <mechsys/mesh/mesh.h> 00069 #include <mechsys/draw.h> 00070 00071 namespace Mesh 00072 { 00073 00074 00076 00077 00079 typedef triangulateio TriIO; 00080 00082 typedef tetgenio TetIO; 00083 00084 inline void TriAllocate (int NPoints, int NSegments, int NRegions, int NHoles, TriIO & Tio) 00085 { 00086 // check 00087 if (NPoints<3) throw new Fatal("Mesh::TriAllocate: At least 3 points are required. (%d is invalid)",NPoints); 00088 if (NSegments<3) throw new Fatal("Mesh::TriAllocate: At least 3 segments are required. (%d is invalid)",NSegments); 00089 00090 // points 00091 Tio.pointlist = (double*)malloc(NPoints*2*sizeof(double)); 00092 Tio.numberofpoints = NPoints; 00093 Tio.pointmarkerlist = (int*)malloc(NPoints*sizeof(int)); 00094 00095 // segments 00096 Tio.segmentlist = (int*)malloc(NSegments*2*sizeof(int)); 00097 Tio.segmentmarkerlist = (int*)malloc(NSegments * sizeof(int)); 00098 Tio.numberofsegments = NSegments; 00099 for (int i=0; i<NSegments; ++i) Tio.segmentmarkerlist[i]=0; 00100 00101 // regions 00102 if (NRegions>0) 00103 { 00104 Tio.regionlist = (double*)malloc(NRegions*4*sizeof(double)); 00105 Tio.numberofregions = NRegions; 00106 } 00107 00108 // holes 00109 if (NHoles>0) 00110 { 00111 Tio.holelist = (double*)malloc(NHoles*2*sizeof(double)); 00112 Tio.numberofholes = NHoles; 00113 } 00114 } 00115 00116 inline void TriSetAllToNull (TriIO & Tio) 00117 { 00118 // points 00119 Tio.pointlist = NULL; 00120 Tio.pointattributelist = NULL; 00121 Tio.pointmarkerlist = NULL; 00122 Tio.numberofpoints = 0; 00123 Tio.numberofpointattributes = 0; 00124 00125 // triangles 00126 Tio.trianglelist = NULL; 00127 Tio.triangleattributelist = NULL; 00128 Tio.trianglearealist = NULL; 00129 Tio.neighborlist = NULL; 00130 Tio.numberoftriangles = 0; 00131 Tio.numberofcorners = 0; 00132 Tio.numberoftriangleattributes = 0; 00133 Tio.triedgemarks = NULL; 00134 00135 // segments 00136 Tio.segmentlist = NULL; 00137 Tio.segmentmarkerlist = NULL; 00138 Tio.numberofsegments = 0; 00139 00140 // holes 00141 Tio.holelist = NULL; 00142 Tio.numberofholes = 0; 00143 00144 // regions 00145 Tio.regionlist = NULL; 00146 Tio.numberofregions = 0; 00147 00148 // edges 00149 Tio.edgelist = NULL; 00150 Tio.edgemarkerlist = NULL; 00151 Tio.normlist = NULL; 00152 Tio.numberofedges = 0; 00153 } 00154 00155 inline void TriDeallocateAll (TriIO & Tio) 00156 { 00157 // Points 00158 if (Tio.pointlist != NULL) free(Tio.pointlist); 00159 if (Tio.pointattributelist != NULL) free(Tio.pointattributelist); 00160 if (Tio.pointmarkerlist != NULL) free(Tio.pointmarkerlist); 00161 00162 // Triangles 00163 if (Tio.trianglelist != NULL) free(Tio.trianglelist); 00164 if (Tio.triangleattributelist != NULL) free(Tio.triangleattributelist); 00165 if (Tio.trianglearealist != NULL) free(Tio.trianglearealist); 00166 if (Tio.neighborlist != NULL) free(Tio.neighborlist); 00167 if (Tio.triedgemarks != NULL) free(Tio.triedgemarks); 00168 00169 // Segments 00170 if (Tio.segmentlist != NULL) free(Tio.segmentlist); 00171 if (Tio.segmentmarkerlist != NULL) free(Tio.segmentmarkerlist); 00172 00173 // Holes 00174 if (Tio.holelist != NULL) free(Tio.holelist); 00175 00176 // Regions 00177 if (Tio.regionlist != NULL) free(Tio.regionlist); 00178 00179 // Edges 00180 if (Tio.edgelist != NULL) free(Tio.edgelist); 00181 if (Tio.edgemarkerlist != NULL) free(Tio.edgemarkerlist); 00182 if (Tio.normlist != NULL) free(Tio.normlist); 00183 00184 // Clear all 00185 TriSetAllToNull (Tio); 00186 } 00187 00188 00190 00191 00192 class Unstructured : public virtual Mesh::Generic 00193 { 00194 public: 00195 // Constants 00196 static size_t FEM2TriPoint[]; 00197 static size_t FEM2TriEdge []; 00198 static size_t FEM2TetPoint[]; 00199 static size_t FEM2TetFace []; 00200 00201 // Constructor 00202 Unstructured (int NDim); 00203 00204 // Destructor 00205 ~Unstructured () { TriDeallocateAll(Tin); } 00206 00210 void Set (size_t NPoints, size_t NSegmentsOrFacets, size_t NRegions, size_t NHoles); 00211 void SetReg (size_t iReg, int RTag, double MaxAreaOrVolume, double X, double Y, double Z=0.0); 00212 void SetHol (size_t iHol, double X, double Y, double Z=0.0); 00213 void SetPnt (size_t iPnt, int PTag, double X, double Y, double Z=0.0); 00214 void SetSeg (size_t iSeg, int ETag, int L, int R); 00215 void SetFac (size_t iFac, int FTag, Array<int> const & VertsOnFace); 00216 void SetFac (size_t iFac, int FTag, Array<int> const & Polygon1, Array<int> const & Polygon2); 00217 00218 // Methods 00219 void Generate (bool O2=false, double GlobalMaxArea=-1, bool Quiet=true, double MinAngle=-1); 00220 void WritePLY (char const * FileKey, bool Blender=true); 00221 void GenBox (bool O2=false, double MaxVolume=-1.0, double Lx=1.0, double Ly=1.0, double Lz=1.0); 00222 bool IsSet () const; 00223 00224 // Alternative methods 00225 void Delaunay (Array<double> const & X, Array<double> const & Y, int Tag=-1); 00226 00227 // Data 00228 TriIO Tin; 00229 TetIO Pin; 00230 00231 #ifdef USE_BOOST_PYTHON 00232 void PySet (BPy::dict const & Dat); 00233 #endif 00234 00235 private: 00236 // Data 00237 bool _lst_reg_set; 00238 bool _lst_hol_set; 00239 bool _lst_pnt_set; 00240 bool _lst_seg_set; 00241 bool _lst_fac_set; 00242 }; 00243 00244 size_t Unstructured::FEM2TriPoint[] = {0,1,2,5,3,4}; 00245 size_t Unstructured::FEM2TriEdge [] = {0,1,2}; 00246 size_t Unstructured::FEM2TetPoint[] = {0,1,2,3,4,5,6,7,8,9}; 00247 size_t Unstructured::FEM2TetFace [] = {3,1,0,2}; 00248 00249 00251 00252 inline Unstructured::Unstructured (int NDim) 00253 : Mesh::Generic (NDim), 00254 _lst_reg_set (false), 00255 _lst_hol_set (false), 00256 _lst_pnt_set (false), 00257 _lst_seg_set (false), 00258 _lst_fac_set (false) 00259 { 00260 TriSetAllToNull (Tin); 00261 Pin.deinitialize (); 00262 } 00263 00264 inline void Unstructured::Set (size_t NPoints, size_t NSegmentsOrFacets, size_t NRegions, size_t NHoles) 00265 { 00266 00267 //std::cout << "NRegions = " << NRegions << std::endl; 00268 //std::cout << "NPoints = " << NPoints << std::endl; 00269 //std::cout << "NFacets = " << NSegmentsOrFacets << std::endl; 00270 //std::cout << "NHoles = " << NHoles << std::endl; 00271 00272 // check 00273 if (NPoints<3) throw new Fatal("Mesh::Unstructured::Set: The number of points must be greater than 2. (%d is invalid)",NPoints); 00274 if (NSegmentsOrFacets<3) throw new Fatal("Mesh::Unstructured::Set: The number of segments or faces must be greater than 2. (%d is invalid)",NSegmentsOrFacets); 00275 if (NRegions<1) throw new Fatal("Mesh::Unstructured::Set: The number of regions must be greater than 1. (%d is invalid)",NRegions); 00276 00277 // flags 00278 _lst_reg_set = false; 00279 _lst_hol_set = false; 00280 _lst_pnt_set = false; 00281 _lst_seg_set = false; 00282 _lst_fac_set = false; 00283 00284 if (NDim==2) 00285 { 00286 // erase previous PSLG 00287 TriDeallocateAll (Tin); 00288 00289 // allocate PSLG 00290 TriAllocate (NPoints, NSegmentsOrFacets, NRegions, NHoles, Tin); 00291 } 00292 else if (NDim==3) 00293 { 00294 // erase previous PLC 00295 Pin.deinitialize (); 00296 00297 // allocate PLC 00298 Pin.initialize (); 00299 00300 // points 00301 Pin.firstnumber = 0; 00302 Pin.numberofpoints = NPoints; 00303 Pin.pointlist = new double [NPoints*3]; 00304 Pin.pointmarkerlist = new int [NPoints]; 00305 00306 // facets 00307 Pin.numberoffacets = NSegmentsOrFacets; 00308 Pin.facetlist = new TetIO::facet [NSegmentsOrFacets]; 00309 Pin.facetmarkerlist = new int [NSegmentsOrFacets]; 00310 00311 // regions 00312 Pin.numberofregions = NRegions; 00313 Pin.regionlist = new double [NRegions*5]; 00314 00315 // holes 00316 Pin.numberofholes = NHoles; 00317 Pin.holelist = new double [NHoles*3]; 00318 } 00319 else throw new Fatal("Unstructured::Set: NDim must be either 2 or 3. NDim==%d is invalid",NDim); 00320 } 00321 00322 inline void Unstructured::SetReg (size_t iReg, int RTag, double MaxAreaOrVolume, double X, double Y, double Z) 00323 { 00324 if (NDim==2) 00325 { 00326 Tin.regionlist[iReg*4 ] = X; 00327 Tin.regionlist[iReg*4+1] = Y; 00328 Tin.regionlist[iReg*4+2] = RTag; 00329 Tin.regionlist[iReg*4+3] = MaxAreaOrVolume; 00330 if ((int)iReg==Tin.numberofregions-1) _lst_reg_set = true; 00331 } 00332 else if (NDim==3) 00333 { 00334 Pin.regionlist[iReg*5 ] = X; 00335 Pin.regionlist[iReg*5+1] = Y; 00336 Pin.regionlist[iReg*5+2] = Z; 00337 Pin.regionlist[iReg*5+3] = RTag; 00338 Pin.regionlist[iReg*5+4] = MaxAreaOrVolume; 00339 if ((int)iReg==Pin.numberofregions-1) _lst_reg_set = true; 00340 } 00341 } 00342 00343 inline void Unstructured::SetHol (size_t iHol, double X, double Y, double Z) 00344 { 00345 if (NDim==2) 00346 { 00347 Tin.holelist[iHol*2 ] = X; 00348 Tin.holelist[iHol*2+1] = Y; 00349 if ((int)iHol==Tin.numberofholes-1) _lst_hol_set = true; 00350 } 00351 else if (NDim==3) 00352 { 00353 Pin.holelist[iHol*3 ] = X; 00354 Pin.holelist[iHol*3+1] = Y; 00355 Pin.holelist[iHol*3+2] = Z; 00356 if ((int)iHol==Pin.numberofholes-1) _lst_hol_set = true; 00357 } 00358 } 00359 00360 inline void Unstructured::SetPnt (size_t iPnt, int PTag, double X, double Y, double Z) 00361 { 00362 if (NDim==2) 00363 { 00364 Tin.pointlist[iPnt*2 ] = X; 00365 Tin.pointlist[iPnt*2+1] = Y; 00366 Tin.pointmarkerlist[iPnt] = PTag; 00367 if ((int)iPnt==Tin.numberofpoints-1) _lst_pnt_set = true; 00368 } 00369 else if (NDim==3) 00370 { 00371 Pin.pointlist[iPnt*3 ] = X; 00372 Pin.pointlist[iPnt*3+1] = Y; 00373 Pin.pointlist[iPnt*3+2] = Z; 00374 Pin.pointmarkerlist[iPnt] = PTag; 00375 if ((int)iPnt==Pin.numberofpoints-1) _lst_pnt_set = true; 00376 } 00377 } 00378 00379 inline void Unstructured::SetSeg (size_t iSeg, int ETag, int L, int R) 00380 { 00381 if (NDim==3) throw new Fatal("Unstructured::SetSeg: This method must be called for 2D meshes only"); 00382 Tin.segmentlist[iSeg*2 ] = L; 00383 Tin.segmentlist[iSeg*2+1] = R; 00384 Tin.segmentmarkerlist[iSeg] = ETag; 00385 if ((int)iSeg==Tin.numberofsegments-1) _lst_seg_set = true; 00386 } 00387 00388 inline void Unstructured::SetFac (size_t iFac, int FTag, Array<int> const & VertsOnFace) 00389 { 00390 if (NDim==2) throw new Fatal("Unstructured::SetSeg: This method must be called for 3D meshes only"); 00391 00392 Pin.facetmarkerlist[iFac] = FTag; 00393 TetIO::facet * f = &Pin.facetlist[iFac]; 00394 f->numberofpolygons = 1; 00395 f->polygonlist = new TetIO::polygon [f->numberofpolygons]; 00396 f->numberofholes = 0; 00397 f->holelist = NULL; 00398 00399 // read vertices 00400 TetIO::polygon * p = &f->polygonlist[0]; 00401 int npoints = static_cast<int>(VertsOnFace.Size()); 00402 p->numberofvertices = npoints; 00403 p->vertexlist = new int [npoints]; 00404 for (int j=0; j<npoints; ++j) p->vertexlist[j] = VertsOnFace[j]; 00405 00406 if ((int)iFac==Pin.numberoffacets-1) _lst_fac_set = true; 00407 } 00408 00409 inline void Unstructured::SetFac (size_t iFac, int FTag, Array<int> const & Polygon1, Array<int> const & Polygon2) 00410 { 00411 if (NDim==2) throw new Fatal("Unstructured::SetSeg: This method must be called for 3D meshes only"); 00412 00413 Pin.facetmarkerlist[iFac] = FTag; 00414 TetIO::facet * f = &Pin.facetlist[iFac]; 00415 f->numberofpolygons = 2; 00416 f->polygonlist = new TetIO::polygon [f->numberofpolygons]; 00417 f->numberofholes = 0; 00418 f->holelist = NULL; 00419 00420 // read vertices of polygon 1 00421 TetIO::polygon * p1 = &f->polygonlist[0]; 00422 int np1 = static_cast<int>(Polygon1.Size()); 00423 p1->numberofvertices = np1; 00424 p1->vertexlist = new int [np1]; 00425 for (int j=0; j<np1; ++j) p1->vertexlist[j] = Polygon1[j]; 00426 00427 // read vertices of polygon 2 00428 TetIO::polygon * p2 = &f->polygonlist[1]; 00429 int np2 = static_cast<int>(Polygon2.Size()); 00430 p2->numberofvertices = np2; 00431 p2->vertexlist = new int [np2]; 00432 for (int j=0; j<np2; ++j) p2->vertexlist[j] = Polygon2[j]; 00433 00434 if ((int)iFac==Pin.numberoffacets-1) _lst_fac_set = true; 00435 } 00436 00437 inline void Unstructured::Generate (bool O2, double GlobalMaxArea, bool Quiet, double MinAngle) 00438 { 00439 // check 00440 if (!IsSet()) throw new Fatal("Unstructured::Generate: Please, set the input data (regions,points,segments/facets) first."); 00441 00442 // info 00443 Util::Stopwatch stopwatch(/*activated*/WithInfo); 00444 00445 // parameters 00446 String prms("pzA"); // Q=quiet, p=poly, q=quality, z=zero 00447 if (Quiet) prms.Printf("Q%s", prms.CStr()); 00448 if (GlobalMaxArea>0) prms.Printf("%sa%f", prms.CStr(), GlobalMaxArea); 00449 if (MinAngle>0) prms.Printf("%sq%f", prms.CStr(), MinAngle); 00450 else prms.Printf("%sq", prms.CStr()); 00451 if (O2) prms.Printf("%so2", prms.CStr()); 00452 prms.Printf("%sa", prms.CStr()); 00453 00454 if (NDim==2) 00455 { 00456 // generate 00457 TriIO tou; 00458 TriSetAllToNull (tou); 00459 triangulate (prms.CStr(), &Tin, &tou, NULL); 00460 00461 // verts 00462 Verts.Resize (tou.numberofpoints); 00463 for (size_t i=0; i<Verts.Size(); ++i) 00464 { 00465 Verts[i] = new Vertex; 00466 Verts[i]->ID = i; 00467 Verts[i]->Tag = 0; 00468 Verts[i]->C = tou.pointlist[i*2], tou.pointlist[i*2+1], 0.0; 00469 00470 /* tou.pointmarkerlist[ipoint] will be equal to: 00471 * == edgeTag (<0) => on edge with tag <<<<<<<<<<<<<<<<<< REMOVED 00472 * == 0 => internal vertex (not on boundary) 00473 * == 1 => on boundary */ 00474 int mark = tou.pointmarkerlist[i]; 00475 if (mark<0) 00476 { 00477 Verts[i]->Tag = mark; 00478 TgdVerts.Push (Verts[i]); 00479 } 00480 } 00481 00482 // cells 00483 Cells.Resize (tou.numberoftriangles); 00484 for (size_t i=0; i<Cells.Size(); ++i) 00485 { 00486 Cells[i] = new Cell; 00487 Cells[i]->ID = i; 00488 Cells[i]->Tag = tou.triangleattributelist[i*tou.numberoftriangleattributes]; 00489 Cells[i]->PartID = 0; // partition id (domain decomposition) 00490 Cells[i]->V.Resize (tou.numberofcorners); 00491 for (size_t j=0; j<Cells[i]->V.Size(); ++j) 00492 { 00493 Share sha = {Cells[i],j}; 00494 Cells[i]->V[j] = Verts[tou.trianglelist[i*tou.numberofcorners+FEM2TriPoint[j]]]; 00495 Cells[i]->V[j]->Shares.Push (sha); 00496 } 00497 bool has_bry_tag = false; 00498 for (size_t j=0; j<3; ++j) 00499 { 00500 int edge_tag = tou.triedgemarks[i*3+FEM2TriEdge[j]]; 00501 if (edge_tag<0) 00502 { 00503 Cells[i]->BryTags[j] = edge_tag; 00504 has_bry_tag = true; 00505 } 00506 } 00507 if (has_bry_tag) TgdCells.Push (Cells[i]); 00508 } 00509 00510 // clean up 00511 /* After triangulate (with -p switch), tou.regionlist gets the content of Tin.regionlist and 00512 * tou.holelist gets the content of Tin.holelist. Thus, these output variables must be set 00513 * to NULL in order to tell TriDeallocateAll to ignore them and do not double-free memory. */ 00514 tou.regionlist = NULL; 00515 tou.numberofregions = 0; 00516 tou.holelist = NULL; 00517 tou.numberofholes = 0; 00518 TriDeallocateAll (tou); 00519 } 00520 else 00521 { 00522 //for (size_t i=0; i<Pin.numberofpoints; ++i) std::cout << Util::_20_15 << Pin.pointlist[i*3] << " " << Util::_20_15 << Pin.pointlist[i*3+1] << " " << Util::_20_15 << Pin.pointlist[i*3+2] << std::endl; 00523 00524 //prms = "CpJVVV"; // debug 00525 00526 // generate 00527 prms.append("f"); 00528 char sw[prms.size()+1]; 00529 strcpy (sw, prms.CStr()); 00530 TetIO pou; 00531 tetrahedralize (sw, &Pin, &pou); 00532 00533 // verts 00534 Verts.Resize (pou.numberofpoints); 00535 for (size_t i=0; i<Verts.Size(); ++i) 00536 { 00537 Verts[i] = new Vertex; 00538 Verts[i]->ID = i; 00539 Verts[i]->Tag = 0; 00540 Verts[i]->C = pou.pointlist[i*3], pou.pointlist[i*3+1], pou.pointlist[i*3+2]; 00541 00542 /* pou.pointmarkerlist[ipoint] will be equal to: 00543 * == faceTag (<0) => on face with tag <<<<<<<<<<<<<<<<<< REMOVED 00544 * == 0 => internal vertex (not on boundary) 00545 * == 1 => on boundary */ 00546 int mark = pou.pointmarkerlist[i]; 00547 if (mark<0) 00548 { 00549 Verts[i]->Tag = mark; 00550 TgdVerts.Push (Verts[i]); 00551 } 00552 } 00553 00554 // cells 00555 Cells.Resize (pou.numberoftetrahedra); 00556 for (size_t i=0; i<Cells.Size(); ++i) 00557 { 00558 Cells[i] = new Cell; 00559 Cells[i]->ID = i; 00560 Cells[i]->Tag = pou.tetrahedronattributelist[i*pou.numberoftetrahedronattributes]; 00561 Cells[i]->V.Resize (pou.numberofcorners); 00562 for (size_t j=0; j<Cells[i]->V.Size(); ++j) 00563 { 00564 Share sha = {Cells[i],j}; 00565 Cells[i]->V[j] = Verts[pou.tetrahedronlist[i*pou.numberofcorners+FEM2TetPoint[j]]]; 00566 Cells[i]->V[j]->Shares.Push (sha); 00567 } 00568 } 00569 00570 // face tags 00571 for (std::map<int,tetgenio::facemarkers>::const_iterator p=pou.tetfacemarkers.begin(); p!=pou.tetfacemarkers.end(); ++p) 00572 { 00573 int icell = p->first; 00574 bool has_bry_tag = false; 00575 for (size_t j=0; j<4; ++j) 00576 { 00577 int face_tag = p->second.m[FEM2TetFace[j]]; 00578 //std::cout << icell << " " << j << " " << face_tag << "\n"; 00579 if (face_tag<0) 00580 { 00581 Cells[icell]->BryTags[j] = face_tag; 00582 has_bry_tag = true; 00583 } 00584 } 00585 if (has_bry_tag) TgdCells.Push (Cells[icell]); 00586 } 00587 } 00588 00589 // check 00590 if (Verts.Size()<1) throw new Fatal("Unstructured::Generate: Failed with %d vertices and %d cells", Verts.Size(), Cells.Size()); 00591 if (Cells.Size()<1) throw new Fatal("Unstructured::Generate: Failed with %d vertices and %d cells", Verts.Size(), Cells.Size()); 00592 00593 // info 00594 if (WithInfo) 00595 { 00596 printf("\n%s--- Unstructured Mesh Generation --- %dD --- O%d -------------------------------------%s\n",TERM_CLR1,NDim,(O2?2:1),TERM_RST); 00597 printf("%s %s = %s%s\n",TERM_CLR4,(NDim==2?"Triangle command":"Tetgen command "),prms.CStr(),TERM_RST); 00598 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 00599 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 00600 } 00601 } 00602 00603 inline void Unstructured::WritePLY (char const * FileKey, bool Blender) 00604 { 00605 // output string 00606 String fn(FileKey); fn.append(".ply"); 00607 std::ostringstream oss; 00608 00609 if (Blender) 00610 { 00611 // header 00612 oss << "import Blender\n"; 00613 oss << "import bpy\n"; 00614 00615 // scene, mesh, and object 00616 oss << "scn = bpy.data.scenes.active\n"; 00617 oss << "msh = bpy.data.meshes.new('unstruct_poly')\n"; 00618 oss << "obj = scn.objects.new(msh,'unstruct_poly')\n"; 00619 00620 if (NDim==2) 00621 { 00622 // points 00623 oss << "pts = ["; 00624 for (int i=0; i<Tin.numberofpoints; ++i) 00625 { 00626 oss << "[" << Tin.pointlist[i*2]; 00627 oss << "," << Tin.pointlist[i*2+1] << ", 0.0]"; 00628 if (i==Tin.numberofpoints-1) oss << "]\n"; 00629 else oss << ",\n "; 00630 } 00631 oss << "\n"; 00632 00633 // edges 00634 oss << "edg = ["; 00635 for (int i=0; i<Tin.numberofsegments; ++i) 00636 { 00637 oss << "[" << Tin.segmentlist[i*2] << "," << Tin.segmentlist[i*2+1] << "]"; 00638 if (i==Tin.numberofsegments-1) oss << "]\n"; 00639 else oss << ",\n "; 00640 } 00641 oss << "\n"; 00642 } 00643 else 00644 { 00645 // points 00646 oss << "pts = ["; 00647 for (int i=0; i<Pin.numberofpoints; ++i) 00648 { 00649 oss << "[" << Pin.pointlist[i*3]; 00650 oss << "," << Pin.pointlist[i*3+1]; 00651 oss << "," << Pin.pointlist[i*3+2] << "]"; 00652 if (i==Pin.numberofpoints-1) oss << "]\n"; 00653 else oss << ",\n "; 00654 } 00655 oss << "\n"; 00656 00657 // edges 00658 oss << "edg = ["; 00659 for (int i=0; i<Pin.numberoffacets; ++i) 00660 { 00661 TetIO::facet * f = &Pin.facetlist[i]; 00662 for (int j=0; j<f->numberofpolygons; ++j) 00663 { 00664 TetIO::polygon * p = &f->polygonlist[j]; 00665 for (int k=1; k<p->numberofvertices; ++k) 00666 { 00667 oss << "[" << p->vertexlist[k-1] << "," << p->vertexlist[k] << "]"; 00668 if (k==p->numberofvertices-1) oss << ",[" << p->vertexlist[k] << "," << p->vertexlist[0] << "]"; 00669 if ((i==Pin.numberoffacets-1) && (j==f->numberofpolygons-1) && (k==p->numberofvertices-1)) oss << "]\n"; 00670 else oss << ",\n "; 00671 } 00672 } 00673 } 00674 oss << "\n"; 00675 } 00676 00677 // extend mesh 00678 oss << "msh.verts.extend(pts)\n"; 00679 oss << "msh.edges.extend(edg)\n"; 00680 } 00681 else // matplotlib 00682 { 00683 if (NDim==3) throw new Fatal("Unstructured::WritePLY: Method not available for 3D and MatPlotLib"); 00684 00685 // header 00686 MPL::Header (oss); 00687 00688 // vertices and commands 00689 oss << "# vertices and commands\n"; 00690 oss << "dat = []\n"; 00691 for (int i=0; i<Tin.numberofsegments; ++i) 00692 { 00693 int I = Tin.segmentlist[i*2]; 00694 int J = Tin.segmentlist[i*2+1]; 00695 oss << "dat.append((PH.MOVETO, (" << Tin.pointlist[I*2] << "," << Tin.pointlist[I*2+1] << ")))\n"; 00696 oss << "dat.append((PH.LINETO, (" << Tin.pointlist[J*2] << "," << Tin.pointlist[J*2+1] << ")))\n"; 00697 } 00698 oss << "\n"; 00699 00700 // draw edges 00701 MPL::AddPatch (oss); 00702 00703 // draw tags 00704 oss << "# draw tags\n"; 00705 for (int i=0; i<Tin.numberofpoints; ++i) 00706 { 00707 int pt_tag = Tin.pointmarkerlist[i]; 00708 if (pt_tag<0) oss << "ax.text(" << Tin.pointlist[i*2] << "," << Tin.pointlist[i*2+1] << ", " << pt_tag << ", ha='center', va='center', fontsize=14, backgroundcolor=lyellow)\n"; 00709 } 00710 for (int i=0; i<Tin.numberofsegments; ++i) 00711 { 00712 int edge_tag = Tin.segmentmarkerlist[i]; 00713 if (edge_tag<0) 00714 { 00715 int I = Tin.segmentlist[i*2]; 00716 int J = Tin.segmentlist[i*2+1]; 00717 double x0 = Tin.pointlist[I*2]; 00718 double y0 = Tin.pointlist[I*2+1]; 00719 double x1 = Tin.pointlist[J*2]; 00720 double y1 = Tin.pointlist[J*2+1]; 00721 double xm = (x0+x1)/2.0; 00722 double ym = (y0+y1)/2.0; 00723 oss << "ax.text(" << xm << "," << ym << ", " << edge_tag << ", ha='center', va='center', fontsize=14, backgroundcolor=pink)\n"; 00724 } 00725 } 00726 oss << "\n"; 00727 00728 // show 00729 oss << "# show\n"; 00730 oss << "axis ('scaled')\n"; 00731 oss << "show ()\n"; 00732 } 00733 00734 // create file 00735 std::ofstream of(fn.CStr(), std::ios::out); 00736 of << oss.str(); 00737 of.close(); 00738 } 00739 00740 inline void Unstructured::GenBox (bool O2, double MaxVolume, double Lx, double Ly, double Lz) 00741 { 00742 Set (8, 6, 1, 0); // nverts, nfaces, nregs, nholes 00743 SetPnt (0, -1, 0.0, 0.0, 0.0); // id, vtag, x, y, z 00744 SetPnt (1, -2, Lx, 0.0, 0.0); 00745 SetPnt (2, -3, Lx, Ly, 0.0); 00746 SetPnt (3, -4, 0.0, Ly, 0.0); 00747 SetPnt (4, -5, 0.0, 0.0, Lz); 00748 SetPnt (5, -6, Lx, 0.0, Lz); 00749 SetPnt (6, -7, Lx, Ly, Lz); 00750 SetPnt (7, -8, 0.0, Ly, Lz); 00751 SetReg (0, -1, MaxVolume, Lx/2., Ly/2., Lz/2.); // id, tag, max_vol, reg_x, reg_y, reg_z 00752 SetFac (0, -10, Array<int>(0,3,7,4)); // id, ftag, npolys, nverts, v0,v1,v2,v3 00753 SetFac (1, -20, Array<int>(1,2,6,5)); 00754 SetFac (2, -30, Array<int>(0,1,5,4)); 00755 SetFac (3, -40, Array<int>(2,3,7,6)); 00756 SetFac (4, -50, Array<int>(0,1,2,3)); 00757 SetFac (5, -60, Array<int>(4,5,6,7)); 00758 Generate (O2); 00759 } 00760 00761 inline bool Unstructured::IsSet () const 00762 { 00763 if (NDim==2) 00764 { 00765 bool hol_ok = (Tin.numberofholes>0 ? _lst_hol_set : true); 00766 return (_lst_reg_set && hol_ok && _lst_pnt_set && _lst_seg_set); 00767 } 00768 if (NDim==3) 00769 { 00770 bool hol_ok = (Pin.numberofholes>0 ? _lst_hol_set : true); 00771 return (_lst_reg_set && hol_ok && _lst_pnt_set && _lst_fac_set); 00772 } 00773 return false; 00774 } 00775 00776 inline void Unstructured::Delaunay (Array<double> const & X, Array<double> const & Y, int Tag) 00777 { 00778 // check 00779 if (NDim==3) throw new Fatal("Unstructured::Delaunay: This method is only available for 2D"); 00780 if (X.Size()!=Y.Size()) throw new Fatal("Unstructured::Delaunay: Size of X and Y arrays must be equal (%d!=%d)",X.Size(),Y.Size()); 00781 00782 // erase previous PSLG 00783 TriDeallocateAll (Tin); 00784 00785 // allocate only the pointlist array inside Triangle's IO structure 00786 size_t npoints = X.Size(); 00787 Tin.pointlist = (double*)malloc(npoints*2*sizeof(double)); 00788 Tin.numberofpoints = npoints; 00789 00790 // set points 00791 for (size_t i=0; i<npoints; ++i) 00792 { 00793 Tin.pointlist[0+i*2] = X[i]; 00794 Tin.pointlist[1+i*2] = Y[i]; 00795 } 00796 00797 // triangulate 00798 TriIO tou; 00799 TriSetAllToNull (tou); 00800 triangulate ("Qz", &Tin, &tou, NULL); // Quiet, zero-based 00801 00802 // verts 00803 Verts.Resize (tou.numberofpoints); 00804 for (size_t i=0; i<Verts.Size(); ++i) 00805 { 00806 Verts[i] = new Vertex; 00807 Verts[i]->ID = i; 00808 Verts[i]->Tag = 0; 00809 Verts[i]->C = tou.pointlist[i*2], tou.pointlist[i*2+1], 0.0; 00810 } 00811 00812 // cells 00813 Cells.Resize (tou.numberoftriangles); 00814 for (size_t i=0; i<Cells.Size(); ++i) 00815 { 00816 Cells[i] = new Cell; 00817 Cells[i]->ID = i; 00818 Cells[i]->Tag = Tag; 00819 Cells[i]->V.Resize (tou.numberofcorners); 00820 for (size_t j=0; j<Cells[i]->V.Size(); ++j) 00821 { 00822 Share sha = {Cells[i],j}; 00823 Cells[i]->V[j] = Verts[tou.trianglelist[i*tou.numberofcorners+FEM2TriPoint[j]]]; 00824 Cells[i]->V[j]->Shares.Push (sha); 00825 } 00826 } 00827 00828 // clean up 00829 /* After triangulate (with -p switch), tou.regionlist gets the content of Tin.regionlist and 00830 * tou.holelist gets the content of Tin.holelist. Thus, these output variables must be set 00831 * to NULL in order to tell TriDeallocateAll to ignore them and do not double-free memory. */ 00832 //tou.regionlist = NULL; 00833 //tou.numberofregions = 0; 00834 //tou.holelist = NULL; 00835 //tou.numberofholes = 0; 00836 TriDeallocateAll (tou); 00837 } 00838 00839 #ifdef USE_BOOST_PYTHON 00840 00841 inline void Unstructured::PySet (BPy::dict const & Dat) 00842 { 00843 BPy::list const & pts = BPy::extract<BPy::list>(Dat["pts"])(); // points 00844 BPy::list const & rgs = BPy::extract<BPy::list>(Dat["rgs"])(); // regions 00845 BPy::list const & hls = BPy::extract<BPy::list>(Dat["hls"])(); // holes 00846 BPy::list const & con = BPy::extract<BPy::list>(Dat["con"])(); 00847 00848 size_t NPoints = BPy::len(pts); 00849 size_t NSegmentsOrFacets = BPy::len(con); 00850 size_t NRegions = BPy::len(rgs); 00851 size_t NHoles = BPy::len(hls); 00852 00853 // allocate memory 00854 Set (NPoints, NSegmentsOrFacets, NRegions, NHoles); 00855 00856 // read regions 00857 for (size_t i=0; i<NRegions; ++i) SetReg (i, BPy::extract<int >(rgs[i][0])(), // tag 00858 BPy::extract<double>(rgs[i][1])(), // MaxArea/MaxVolume 00859 BPy::extract<double>(rgs[i][2])(), // x 00860 BPy::extract<double>(rgs[i][3])(), // y 00861 (NDim==3 ? BPy::extract<double>(rgs[i][4])() : 0.0)); // z 00862 00863 // read holes 00864 for (size_t i=0; i<NHoles; ++i) SetHol (i, BPy::extract<double>(hls[i][0])(), // x 00865 BPy::extract<double>(hls[i][1])(), // y 00866 (NDim==3 ? BPy::extract<double>(hls[i][2])() : 0.0)); // z 00867 00868 // read points 00869 for (size_t i=0; i<NPoints; ++i) SetPnt (i, BPy::extract<int >(pts[i][0])(), // tag 00870 BPy::extract<double>(pts[i][1])(), // x 00871 BPy::extract<double>(pts[i][2])(), // y 00872 (NDim==3 ? BPy::extract<double>(pts[i][3])() : 0.0)); // y 00873 00874 // read segments 00875 if (NDim==2) 00876 { 00877 for (size_t i=0; i<NSegmentsOrFacets; ++i) SetSeg (i, BPy::extract<int>(con[i][0])(), // tag 00878 BPy::extract<int>(con[i][1])(), // L 00879 BPy::extract<int>(con[i][2])()); // R 00880 } 00881 00882 // read facets 00883 else 00884 { 00885 for (size_t i=0; i<NSegmentsOrFacets; ++i) SetFac (i, BPy::extract<int >(con[i][0])(), // tag 00886 Array<int>(BPy::extract<BPy::list>(con[i][1])())); // verts 00887 } 00888 } 00889 00890 #endif 00891 00892 }; // namespace Mesh 00893 00894 #endif // MECHSYS_MESH_UNSTRUCTURED_H