MeshKit
1.0
|
00001 #include "meshkit/Mesh.hpp" 00002 00003 using namespace Jaal; 00004 00005 // 00006 // QTrack is similar to "Motorcycle graph" proposed by Eppestein group. 00007 // But somehow, I don't like this term. 00008 // 00009 00010 #ifdef CSV 00011 struct QTrack { 00012 const static int END_AT_TERMINALS = 0; 00013 const static int END_AT_CROSSINGS = 1; 00014 00015 NodeSequence sequence; 00016 00017 bool operator ==(const QTrack & rhs) const { 00018 size_t nSize = sequence.size(); 00019 if (nSize != rhs.sequence.size()) return 0; 00020 00021 Vertex *v0src = sequence.front(); 00022 Vertex *v0dst = sequence.back(); 00023 Vertex *v1src = rhs.sequence.front(); 00024 Vertex *v1dst = rhs.sequence.back(); 00025 00026 if (v0src == v1src && v0dst == v1dst) return 1; 00027 if (v0src == v1dst && v0dst == v1src) return 1; 00028 00029 return 0; 00030 } 00031 00032 bool operator<(const QTrack & rhs) const { 00033 return sequence.size() < rhs.sequence.size(); 00034 } 00035 00037 // There are two ways to advance along the track. 00038 // (1) Incremental: All track propagate simulateneously and 00039 // at the intersection, only one is allowed 00040 // to proceed towards other irregular node. 00041 // (11) Greedy : Start from one vertex and complete its 00042 // track. 00043 // It is not clear which method is better, but "greedy" may likely 00044 // give very high aspect ratio quad patches. Incremental on the 00045 // other hand may produce many small patches.. 00046 // 00048 00049 int advance_single_step(int endat) { 00051 // ********************** 00052 // * * * 00053 // * * Next * 00054 // * * * 00055 // Avoid ********************** Avoid 00056 // * * * 00057 // * * Current * 00058 // * * * 00059 // * * * 00060 // ********************** 00061 // Source 00062 // A Source vertex and Current edge is chosen. 00063 // We want to avoid two edges and want to select "Next" edge. 00065 Vertex *v0, *v1, *v2, *v3, *v4; 00066 00067 vector<Face*> adjFaces; 00068 vector<Vertex*> vneighs; 00069 set<Vertex*> vset; 00070 00071 size_t index = sequence.size(); 00072 v0 = sequence[index - 2]; 00073 v1 = sequence[index - 1]; 00074 v0->setVisitMark(1); 00075 00076 if (endat == END_AT_CROSSINGS && v1->isVisited()) return 0; 00077 if (v1->isBoundary()) return 0; 00078 00079 v1->setVisitMark(1); 00080 vneighs = v1->getRelations0(); 00081 if (vneighs.size() != 4) return 0; 00082 00083 adjFaces = Mesh::getRelations112(v0, v1); 00084 assert(adjFaces.size() == 2); 00085 v2 = Face::opposite_node(adjFaces[0], v0); 00086 v3 = Face::opposite_node(adjFaces[1], v0); 00087 00088 vset.clear(); 00089 vset.insert(vneighs[0]); 00090 vset.insert(vneighs[1]); 00091 vset.insert(vneighs[2]); 00092 vset.insert(vneighs[3]); 00093 vset.erase(v0); 00094 vset.erase(v2); 00095 vset.erase(v3); 00096 assert(vset.size() == 1); 00097 v4 = *vset.begin(); 00098 sequence.push_back(v4); 00099 return 1; 00100 } 00101 00102 void advance(int endat) { 00103 assert(sequence.size() == 2); 00104 00105 // Starting node is always irregular ... 00106 vector<Face*> vfaces = sequence[0]->getRelations2(); 00107 assert(vfaces.size() != 4); 00108 00109 while (1) { 00110 int progress = advance_single_step(endat); 00111 if (!progress) break; 00112 } 00113 00114 /* 00115 // The path is reversible and therefore, we will give a direction 00116 // from the lower source node to higher destination node. 00117 if (sequence.front() > sequence.back()) 00118 reverse(sequence.begin(), sequence.end()); 00119 assert(sequence.front() < sequence.back()); 00120 */ 00121 // Checking the correctness.. 00122 if (endat == END_AT_TERMINALS) { 00123 vfaces = sequence.front()->getRelations2(); 00124 assert(vfaces.size() != 4); 00125 vfaces = sequence.back()->getRelations2(); 00126 assert(vfaces.size() != 4); 00127 for (int i = 1; i < sequence.size() - 1; i++) { 00128 vfaces = sequence[i]->getRelations2(); 00129 assert(vfaces.size() == 4); 00130 } 00131 00132 } 00133 } 00134 00135 }; 00136 00138 00139 struct StructuredMesh2D { 00140 00141 StructuredMesh2D() { 00142 nx = ny = 0; 00143 } 00144 int nx, ny; 00145 00146 vector<Face*> faces; 00147 vector<Vertex*> nodes; 00148 set<Vertex*> cornerNodes; 00149 00150 void clearAll() { 00151 nodes.clear(); 00152 faces.clear(); 00153 neighs.clear(); 00154 cornerNodes.clear(); 00155 nx = 0; 00156 ny = 0; 00157 } 00158 00159 bool operator<(const StructuredMesh2D & rhs) const { 00160 return this->getSize(2) < rhs.getSize(2); 00161 } 00162 00163 size_t getSize(int e) const { 00164 if (e == 0) return nodes.size(); 00165 if (e == 2) return faces.size(); 00166 return 0; 00167 } 00168 00169 int myID; 00170 vector<int> neighs; 00171 }; 00172 #endif 00173 00175 00176 void build_submesh_topology(StructuredMesh2D &smesh) 00177 { 00178 /* 00179 smesh.neighs.clear(); 00180 00181 FaceSequence adjfaces; 00182 set<int> nset; 00183 00184 size_t numFaces = smesh.faces.size(); 00185 for (size_t i = 0; i < numFaces; i++) { 00186 Face *face = smesh.faces[i]; 00187 for (int j = 0; j < 4; j++) { 00188 Vertex *v0 = face->getNodeAt(j + 0); 00189 Vertex *v1 = face->getNodeAt(j + 1); 00190 Mesh::getRelations112(v0, v1, adjfaces); 00191 int numneighs = adjfaces.size(); 00192 for (int k = 0; k < numneighs; k++) { 00193 int nid = adjfaces[k]->getTag(); 00194 nset.insert(nid); 00195 } 00196 } 00197 } 00198 00199 nset.erase(smesh.myID); 00200 set<int>::const_iterator it1; 00201 for (it1 = nset.begin(); it1 != nset.end(); ++it1) 00202 smesh.neighs.push_back(*it1); 00203 */ 00204 } 00205 00207 00208 Face *getSeedFace(Jaal::Mesh *mesh) { 00209 size_t numfaces = mesh->getSize(2); 00210 for (size_t i = 0; i < numfaces; i++) { 00211 Face *f = mesh->getFaceAt(i); 00212 if (!f->isVisited()) return f; 00213 } 00214 return NULL; 00215 } 00216 00218 00219 size_t independent_components(Jaal::Mesh *mesh) { 00220 00221 size_t numfaces = mesh->getSize(2); 00222 size_t numneighs; 00223 00224 for (size_t i = 0; i < numfaces; i++) { 00225 Face *f = mesh->getFaceAt(i); 00226 f->setVisitMark(0); 00227 f->setAttribute( "Partition", 0); 00228 } 00229 00230 size_t compid = 0; 00231 deque<Face*> faceQ; 00232 FaceSequence adjfaces; 00233 while (1) { 00234 Face *currface = getSeedFace(mesh); 00235 if (currface == NULL) break; 00236 faceQ.push_back(currface); 00237 while (!faceQ.empty()) { 00238 currface = faceQ.front(); 00239 faceQ.pop_front(); 00240 if (!currface->isVisited()) { 00241 currface->setAttribute( "Partition", compid); 00242 currface->setVisitMark(1); 00243 for (int i = 0; i < 4; i++) { 00244 Vertex *v0 = currface->getNodeAt(i + 0); 00245 Vertex *v1 = currface->getNodeAt(i + 1); 00246 if (v0->isVisited() && v1->isVisited()) continue; 00247 Mesh::getRelations112(v0, v1, adjfaces); 00248 numneighs= adjfaces.size(); 00249 for (size_t j = 0; j < numneighs; j++) 00250 faceQ.push_back(adjfaces[j]); 00251 } 00252 } 00253 } 00254 compid++; 00255 } 00256 00257 #ifdef DEBUG 00258 for (size_t i = 0; i < numfaces; i++) { 00259 Face *f = mesh->getFaceAt(i); 00260 assert(f->isVisited()); 00261 } 00262 #endif 00263 00264 return compid; 00265 } 00266 00268 00269 int merge_submesh(StructuredMesh2D &amesh, StructuredMesh2D &bmesh) { 00270 if (amesh.myID == bmesh.myID) return 1; 00271 00272 if (amesh.cornerNodes.size() != 4) return 2; 00273 if (bmesh.cornerNodes.size() != 4) return 2; 00274 00275 vector<Vertex*> common; 00276 set_intersection(amesh.cornerNodes.begin(), amesh.cornerNodes.end(), 00277 bmesh.cornerNodes.begin(), bmesh.cornerNodes.end(), 00278 back_inserter(common)); 00279 00280 if (common.size() != 2) return 3; 00281 00282 size_t numFaces; 00283 00284 FaceSequence vfaces; 00285 numFaces = amesh.faces.size(); 00286 for (size_t i = 0; i < numFaces; i++) { 00287 for (int j = 0; j < 4; j++) { 00288 Vertex *v = amesh.faces[i]->getNodeAt(j); 00289 if (!v->isBoundary()) { 00290 if ( v->getNumRelations(2) != 4) return 4; 00291 } 00292 } 00293 } 00294 00295 numFaces = bmesh.faces.size(); 00296 for (size_t i = 0; i < numFaces; i++) { 00297 for (int j = 0; j < 4; j++) { 00298 Vertex *v = bmesh.faces[i]->getNodeAt(j); 00299 if (!v->isBoundary()) { 00300 if ( v->getNumRelations(2) != 4) return 4; 00301 } 00302 } 00303 } 00304 00305 numFaces = bmesh.faces.size(); 00306 for (size_t i = 0; i < numFaces; i++) { 00307 amesh.faces.push_back(bmesh.faces[i]); 00308 bmesh.faces[i]->setAttribute("Partition", amesh.myID); 00309 } 00310 00311 NodeSet::const_iterator it; 00312 for (it = bmesh.cornerNodes.begin(); it != bmesh.cornerNodes.end(); ++it) 00313 amesh.cornerNodes.insert(*it); 00314 00315 assert(amesh.cornerNodes.size() == 6); 00316 00317 amesh.cornerNodes.erase(common[0]); 00318 amesh.cornerNodes.erase(common[1]); 00319 00320 bmesh.clearAll(); 00321 00322 return 0; 00323 } 00325 00326 StructuredMesh2D getQuadPatch(Jaal::Mesh *mesh, int compid) { 00327 StructuredMesh2D smesh; 00328 smesh.myID = compid; 00329 smesh.nx = 1; 00330 smesh.ny = 1; 00331 00332 size_t numfaces = mesh->getSize(2); 00333 00334 set<Face*> faceSet; 00335 set<Face*>::const_iterator fit; 00336 set<Vertex*> nodeSet; 00337 set<Vertex*>::const_iterator nit; 00338 00339 int ival = 0; 00340 for (size_t i = 0; i < numfaces; i++) { 00341 Face *face = mesh->getFaceAt(i); 00342 if( face->isActive() ) { 00343 face->getAttribute("Partition", ival ); 00344 if ( ival == compid) { 00345 faceSet.insert(face); 00346 nodeSet.insert(face->getNodeAt(0)); 00347 nodeSet.insert(face->getNodeAt(1)); 00348 nodeSet.insert(face->getNodeAt(2)); 00349 nodeSet.insert(face->getNodeAt(3)); 00350 } 00351 } 00352 } 00353 if (faceSet.empty()) return smesh; 00354 00355 NodeSet boundNodes, cornerNodes; 00356 FaceSet boundFaces, cornerFaces; 00357 00358 FaceSequence vfaces; 00359 int ncount; 00360 size_t numneighs; 00361 for (nit = nodeSet.begin(); nit != nodeSet.end(); ++nit) { 00362 Vertex *vertex = *nit; 00363 vertex->getRelations( vfaces); 00364 ncount = 0; 00365 numneighs = vfaces.size(); 00366 for (size_t j = 0; j < numneighs; j++) 00367 if (faceSet.find(vfaces[j]) != faceSet.end()) ncount++; 00368 00369 if (ncount == 1) { 00370 cornerNodes.insert(vertex); 00371 for (size_t j = 0; j < numneighs; j++) 00372 if (faceSet.find(vfaces[j]) != faceSet.end()) cornerFaces.insert(vfaces[j]); 00373 } 00374 00375 if (ncount != 4) boundNodes.insert(vertex); 00376 } 00377 00378 for (fit = faceSet.begin(); fit != faceSet.end(); ++fit) 00379 smesh.faces.push_back(*fit); 00380 00381 for (nit = nodeSet.begin(); nit != nodeSet.end(); ++nit) 00382 smesh.nodes.push_back(*nit); 00383 00384 smesh.cornerNodes = cornerNodes; 00385 00386 build_submesh_topology(smesh); 00387 00388 return smesh; 00389 00390 } 00392 00393 int Mesh::search_quad_patches() 00394 { 00395 int nTopo = isHomogeneous(); 00396 if (nTopo != 4) { 00397 cout << "Error: The mesh must be all Quads " << endl; 00398 return 1; 00399 } 00400 00401 int relexist2 = build_relations(0, 2); 00402 int relexist0 = build_relations(0, 0); 00403 00404 search_boundary(); 00405 00406 size_t numnodes = getSize(0); 00407 for (size_t i = 0; i < numnodes; i++) { 00408 Vertex *vertex = getNodeAt(i); 00409 vertex->setVisitMark(0); 00410 } 00411 00412 size_t numfaces = getSize(2); 00413 for (size_t i = 0; i < numfaces; i++) { 00414 Face *face = getFaceAt(i); 00415 face->setVisitMark(0); 00416 } 00417 00418 vector<QTrack> qpath; 00419 QTrack qp; 00420 qp.sequence.resize(2); // As we know the starting edge 00421 00422 size_t nCount = 0; 00423 NodeSequence vnodes; 00424 for (size_t i = 0; i < numnodes; i++) { 00425 Vertex *vertex = getNodeAt(i); 00426 if (!vertex->isBoundary()) { 00427 vertex->getRelations( vnodes ); 00428 size_t numneighs = vnodes.size(); 00429 if (numneighs != 4) { 00430 qp.sequence[0] = vertex; 00431 for (size_t j = 0; j < numneighs; j++) { 00432 qp.sequence[1] = vnodes[j]; 00433 nCount++; 00434 qpath.push_back(qp); 00435 } 00436 } 00437 } 00438 } 00439 00440 if (qpath.empty()) { 00441 cout << "Info: There are no irregular nodes in the mesh" << endl; 00442 return 0; 00443 } else 00444 cout << "# of branches spawned " << nCount << endl; 00445 00446 for (size_t j = 0; j < qpath.size(); j++) 00447 qpath[j].advance(0); 00448 00449 sort(qpath.begin(), qpath.end()); 00450 00451 /* 00452 saveAs("b.dat"); 00453 for (int i = 0; i < qpath.size(); i++) { 00454 if (qpath[i].sequence.front()->isBoundary()) continue; 00455 if (qpath[i].sequence.back()->isBoundary() ) continue; 00456 int found = 0; 00457 cout << " PATH SIZE " << qpath[i].sequence.size() << endl; 00458 for (int k = 0; k < qpath[i].sequence.size(); k++) 00459 cout << qpath[i].sequence[k]->getID() << " "; 00460 cout << endl; 00461 for (int j = 0; j < qpath.size(); j++) { 00462 if ((i != j) && (qpath[i] == qpath[j])) { 00463 found = 1; 00464 cout << "Same path " << i << " " << j << endl; 00465 for (int k = 0; k < qpath[j].sequence.size(); k++) 00466 cout << qpath[j].sequence[k]->getID() << " "; 00467 cout << endl; 00468 } 00469 } 00470 assert(found); 00471 } 00472 */ 00473 exit(0); 00474 00475 int numPatches = independent_components(this); 00476 00477 deque<StructuredMesh2D> submesh(numPatches); 00478 00479 // New we can merge some sub-meshes 00480 for (int i = 0; i < numPatches; i++) { 00481 StructuredMesh2D sm = getQuadPatch(this, i); 00482 submesh[i] = sm; 00483 } 00484 sort(submesh.begin(), submesh.end()); 00485 00486 while (1) { 00487 int nSize = submesh.size(); 00488 cout << "#Submeshes " << submesh.size() << endl; 00489 size_t count_merged = 0; 00490 for (int i = 0; i < nSize; i++) { 00491 for (int j = i + 1; j < nSize; j++) { 00492 int err = merge_submesh(submesh[i], submesh[j]); 00493 if (!err) count_merged++; 00494 } 00495 } 00496 cout << " #of Submesh merged " << count_merged << endl; 00497 if (count_merged == 0) break; 00498 00499 // 00500 // Retain only those submeshes which are not empty. ( Note 00501 // that when two submeshes merge, one of them become empty. 00502 // 00503 for (int i = 0; i < nSize; i++) { 00504 StructuredMesh2D sm = submesh.front(); 00505 submesh.pop_front(); 00506 if (sm.getSize(2)) submesh.push_back(sm); 00507 } 00508 } 00509 00510 sort(submesh.begin(), submesh.end()); 00511 00512 exit(0); 00513 00514 /* 00515 for (size_t i = 0; i < numnodes; i++) { 00516 Vertex *vertex = getNodeAt(i); 00517 vertex->setTag(vertex->isVisited()); 00518 } 00519 */ 00520 00521 if (relexist0) 00522 clear_relations(0, 0); 00523 00524 if (relexist2) 00525 clear_relations(0, 2); 00526 return submesh.size(); 00527 }