MeshKit
1.0
|
00001 #include "meshkit/SwapEdges.hpp" 00002 00003 #include <iostream> 00004 #include <iomanip> 00005 00006 using namespace Jaal; 00007 00008 //############################################################################# 00009 00010 int SwapTriEdges:: one_sweep(int entity, int rule) 00011 { 00012 size_t total_count = 0; 00013 size_t numnodes = mesh->getSize(0); 00014 size_t numfaces = mesh->getSize(2); 00015 00016 // Sweep over nodes in the mesh... 00017 if( entity == 0 ) { 00018 while(1) { 00019 size_t curr_count = 0; 00020 for (size_t i = 0; i < numnodes; i++) { 00021 int err = atomicOp( mesh->getNodeAt(i), rule); 00022 if (!err) curr_count++; 00023 } 00024 if( curr_count == 0) break; 00025 total_count += curr_count; 00026 } 00027 } 00028 00029 // Sweep over faces in the mesh... 00030 if( entity == 2 ) { 00031 while(1) { 00032 size_t curr_count = 0; 00033 for (size_t i = 0; i < numfaces; i++) { 00034 int err = atomicOp( mesh->getFaceAt(i), rule); 00035 if (!err) curr_count++; 00036 } 00037 if( curr_count == 0) break; 00038 total_count += curr_count; 00039 } 00040 } 00041 00042 assert( numnodes == mesh->getSize(0) ); 00043 assert( numfaces == mesh->getSize(2) ); 00044 00045 mesh->make_consistently_oriented(); 00046 00047 return total_count; 00048 } 00049 00050 //############################################################################# 00051 00052 int SwapTriEdges::apply_rule(int rule ) 00053 { 00054 int relexist2 = mesh->build_relations(0, 2); 00055 00056 mesh->search_boundary(); 00057 00058 assert(mesh->getAdjTable(0, 2)); 00059 00060 num_edges_flipped = 0; 00061 Jaal::MeshOptimization mopt; 00062 00063 int curr_count; 00064 while(1) { 00065 curr_count = one_sweep( 2, rule); 00066 if( curr_count == 0) { 00067 mopt.shape_optimize(mesh); 00068 curr_count = one_sweep( 2, rule ); 00069 if( curr_count == 0) break; 00070 num_edges_flipped+= curr_count; 00071 } else 00072 num_edges_flipped+= curr_count; 00073 } 00074 00075 if (!relexist2) mesh->clear_relations(0, 2); 00076 00077 cout << "# of edges swapped " << num_edges_flipped << endl; 00078 00079 return num_edges_flipped; 00080 } 00081 00082 //############################################################################# 00083 00084 int SwapTriEdges::atomicOp(const Face *face, int rule) 00085 { 00086 if( !face->isActive() ) return 1; 00087 00088 for (int i = 0; i < 3; i++) { 00089 Vertex *v1 = face->getNodeAt(i + 1); 00090 Vertex *v2 = face->getNodeAt(i + 2); 00091 FlipEdge edge(v1, v2); 00092 if (is_edge_flip_allowed(edge, rule)) { 00093 int err = commit(edge); 00094 if( !err) return 0; 00095 } 00096 } 00097 return 2; 00098 } 00099 00100 //############################################################################# 00101 00102 void SwapTriEdges::FlipEdge::process(Vertex *v1, Vertex *v2) 00103 { 00104 assert(v1 != v2); 00105 00106 this->setNodes(v1, v2); 00107 00108 faces[0] = NULL; 00109 faces[1] = NULL; 00110 opposite_nodes[0] = NULL; 00111 opposite_nodes[1] = NULL; 00112 00113 if (v1->isBoundary() && v2->isBoundary()) return; 00114 00115 FaceSequence neighs; 00116 Mesh::getRelations112(v1, v2, neighs); 00117 00118 assert(neighs.size() == 2); 00119 00120 Vertex *ov1 = Face::opposite_node(neighs[0], v1, v2); 00121 Vertex *ov2 = Face::opposite_node(neighs[1], v1, v2); 00122 assert(ov1 && ov2); 00123 00124 faces[0] = neighs[0]; 00125 faces[1] = neighs[1]; 00126 opposite_nodes[0] = ov1; 00127 opposite_nodes[1] = ov2; 00128 } 00129 00130 //############################################################################# 00131 00132 bool SwapTriEdges::FlipEdge::isSharp(double featureAngle) const 00133 { 00134 Vertex *v1 = getNodeAt(0); 00135 Vertex *v2 = getNodeAt(1); 00136 Vertex *ov1 = opposite_nodes[0]; 00137 Vertex *ov2 = opposite_nodes[1]; 00138 00139 Vec3D A, B; 00140 A = Face::normal(ov1, v1, v2); 00141 B = Face::normal(ov2, v2, v1); 00142 00143 double angle = Math::getVectorAngle(A, B, ANGLE_IN_DEGREES); 00144 if (angle > featureAngle && fabs(180 - angle) > 1.0E-06) return 1; 00145 00146 return 0; 00147 } 00148 00149 //############################################################################# 00150 00151 bool SwapTriEdges::FlipEdge::isConcave() const 00152 { 00153 Vertex *v1 = getNodeAt(0); 00154 Vertex *v2 = getNodeAt(1); 00155 Vertex *ov1 = opposite_nodes[0]; 00156 Vertex *ov2 = opposite_nodes[1]; 00157 00158 assert( v1 && v2 ); 00159 assert( ov1 && ov2 ); 00160 00161 bool convex = Face::is_convex_quad(v1->getXYZCoords(), 00162 ov1->getXYZCoords(), 00163 v2->getXYZCoords(), 00164 ov2->getXYZCoords()); 00165 if (!convex) return 1; 00166 00167 return 0; 00168 } 00169 00170 00171 //***************************************************************************** 00172 00173 bool SwapTriEdges::is_edge_flip_allowed(const FlipEdge &edge, int rule) const 00174 { 00175 if (!edge.isValid()) return 0; 00176 if (edge.isConcave()) return 0; 00177 00178 Vertex *v1 = edge.getNodeAt(0); 00179 Vertex *v2 = edge.getNodeAt(1); 00180 Vertex *ov1 = edge.opposite_nodes[0]; 00181 Vertex *ov2 = edge.opposite_nodes[1]; 00182 00183 if (v1->isBoundary() && v2->isBoundary() ) return 0; 00184 if (ov1->isBoundary() || ov2->isBoundary() ) return 0; 00185 00186 int d1 = v1->getNumRelations(2); 00187 int d2 = v2->getNumRelations(2); 00188 int d3 = ov1->getNumRelations(2); 00189 int d4 = ov2->getNumRelations(2); 00190 00191 if( rule == DELAUNAY_RULE) { 00192 double len1 = Vertex::length2(v1, v2); 00193 double len2 = Vertex::length2(ov1, ov2); 00194 if (len1 <= len2) return 0; 00195 00196 if (edge.isSharp(creaseAngle)) return 0; 00197 return 1; 00198 } 00199 00200 if( rule == ADVANCE_FRONT_RULE ) { 00201 int ideal_v1 = v1->get_ideal_face_degree(3); 00202 int ideal_v2 = v2->get_ideal_face_degree(3); 00203 int ideal_v3 = ov1->get_ideal_face_degree(3); 00204 int ideal_v4 = ov2->get_ideal_face_degree(3); 00205 00206 int l1 = 0; 00207 v1->getAttribute("Layer", l1); 00208 00209 int l2 = 0; 00210 v2->getAttribute("Layer", l2); 00211 00212 int l3 = 0; 00213 ov1->getAttribute("Layer", l3); 00214 00215 int l4 = 0; 00216 ov2->getAttribute("Layer", l4); 00217 00218 // Decrease the vertex degree 00219 if( (d1 > ideal_v1) && (l2 > l1) && (l3 > l1) && (l4 > l1) ) return 1; 00220 if( (d2 > ideal_v2) && (l1 > l2) && (l3 > l2) && (l4 > l2) ) return 1; 00221 00222 // Increase the vertex degree ... 00223 if( (d3 < ideal_v3) && (l1 > l3) && (l2 > l3) && (l4 > l3) ) return 1; 00224 if( (d4 < ideal_v4) && (l1 > l4) && (l2 > l4) && (l3 > l4) ) return 1; 00225 00226 return 0; 00227 } 00228 00229 if( rule == DEGREE_REDUCTION_RULE) { 00230 int ideal_v1 = v1->get_ideal_face_degree(3); 00231 int ideal_v2 = v2->get_ideal_face_degree(3); 00232 00233 if( v1->isBoundary() && (d1 > ideal_v1) && (d2 >3) ) return 1; 00234 if( v2->isBoundary() && (d2 > ideal_v2) && (d1 >3) ) return 1; 00235 00236 int relaxation_index = d1 + d2 - d3 - d4; 00237 if (relaxation_index < 3) return 0; 00238 return 1; 00239 } 00240 00241 return 0; 00242 } 00243 00244 //############################################################################# 00245 00246 int SwapTriEdges::commit(const FlipEdge &edge) 00247 { 00248 Face *t1 = edge.faces[0]; 00249 Face *t2 = edge.faces[1]; 00250 Vertex *v1 = edge.getNodeAt(0); 00251 Vertex *v2 = edge.getNodeAt(1); 00252 Vertex *ov1 = edge.opposite_nodes[0]; 00253 Vertex *ov2 = edge.opposite_nodes[1]; 00254 00255 int pos1 = t1->getPosOf(v1); 00256 int pos2 = t2->getPosOf(v1); 00257 00258 v1->removeRelation(t1); 00259 v1->removeRelation(t2); 00260 v2->removeRelation(t1); 00261 v2->removeRelation(t2); 00262 v1->removeRelation(v2); 00263 v2->removeRelation(v1); 00264 00265 NodeSequence vconn(3); 00266 00267 if( t1->getNodeAt(pos1+1) == ov1 && t2->getNodeAt(pos2+2) == ov2 ) { 00268 vconn[0] = v1; 00269 vconn[1] = ov1; 00270 vconn[2] = ov2; 00271 t1->setNodes(vconn); 00272 00273 vconn[0] = v2; 00274 vconn[1] = ov2; 00275 vconn[2] = ov1; 00276 t2->setNodes(vconn); 00277 00278 mesh->reactivate(t1); 00279 mesh->reactivate(t2); 00280 return 0; 00281 } 00282 00283 if( t1->getNodeAt(pos1+2) == ov1 && t2->getNodeAt(pos2+1) == ov2 ) { 00284 vconn[0] = v1; 00285 vconn[1] = ov2; 00286 vconn[2] = ov1; 00287 t1->setNodes(vconn); 00288 00289 vconn[0] = v2; 00290 vconn[1] = ov1; 00291 vconn[2] = ov2; 00292 t2->setNodes(vconn); 00293 00294 mesh->reactivate(t1); 00295 mesh->reactivate(t2); 00296 return 0; 00297 } 00298 00299 cout << "Fatal Error: Orientation of faces unknown " << endl; 00300 exit(0); 00301 00302 return 0; 00303 } 00304 00305 //############################################################################# 00306 00307 int SwapTriEdges ::atomicOp(Vertex *apexVertex, int rule) 00308 { 00309 FaceSequence vneighs; 00310 apexVertex->getRelations( vneighs ); 00311 int numNeighs = vneighs.size(); 00312 00313 for( int i = 0; i < numNeighs; i++) { 00314 if( unchecked(vneighs[i] ) ) { 00315 int err = atomicOp( vneighs[i], rule); 00316 if( err == 0) return 0; 00317 } 00318 } 00319 00320 return 1; 00321 } 00323 int SwapTriEdges :: apply_advance_front_rule() 00324 { 00325 int relexist2 = mesh->build_relations(0, 2); 00326 int relexist0 = mesh->build_relations(0, 0); 00327 00328 mesh->search_boundary(); 00329 00330 size_t numNodes = mesh->getSize(0); 00331 NodeSequence currlayer, vneighs; 00332 NodeSet nextlayer; 00333 00334 for(size_t i = 0; i < numNodes; i++) { 00335 Vertex *v = mesh->getNodeAt(i); 00336 if( v->isBoundary() ) { 00337 v->setAttribute("Layer", 0); 00338 currlayer.push_back(v); 00339 } else 00340 v->setAttribute("Layer",std::numeric_limits< int >::max()); 00341 } 00342 00343 Jaal::MeshOptimization mopt; 00344 size_t ncount, nSize, num_edges_flipped = 0; 00345 mesh->make_consistently_oriented(); 00346 mopt.shape_optimize(mesh); 00347 00348 LaplaceNoWeight lw; 00349 LaplaceSmoothing lapsmooth(mesh); 00350 lapsmooth.setWeight(&lw); 00351 lapsmooth.setNumIterations(100); 00352 00353 int curr_layer_id = 0; 00354 int nirregular0, nirregular1; 00355 00356 while(1) { 00357 nSize = currlayer.size(); 00358 nirregular0 = 0; 00359 for( size_t i = 0; i < nSize; i++) { 00360 Vertex *v = currlayer[i]; 00361 if( !v->isRemoved() && !isIdeal(v) ) nirregular0++; 00362 } 00363 00364 for( int k = 0; k < 3; k++) { // Three attempts for single layer 00365 while(1) { 00366 nSize = currlayer.size(); 00367 ncount = 0; 00368 for( size_t i = 0; i < nSize; i++) { 00369 Vertex *v = currlayer[i]; 00370 if( !v->isRemoved() && !isIdeal(v)) { 00371 int err = atomicOp( v, ADVANCE_FRONT_RULE ); 00372 if( !err ) ncount++; 00373 } 00374 } 00375 if( ncount == 0) break; 00376 num_edges_flipped += ncount; 00377 } 00378 00379 nSize = currlayer.size(); 00380 nirregular1 = 0; 00381 for( size_t i = 0; i < nSize; i++) { 00382 Vertex *v = currlayer[i]; 00383 if( !v->isRemoved() && !isIdeal(v) ) nirregular1++; 00384 } 00385 assert( nirregular1 <= nirregular0); 00386 if( nirregular1 == 0) break; 00387 } 00388 lapsmooth.execute(); 00389 00390 // mopt.shape_optimize(mesh); 00391 00392 cout << "Layer : " << curr_layer_id << endl; 00393 cout << "# of Irregular nodes before swapping : " << nirregular0 << endl; 00394 cout << "# of Irregular nodes after swapping : " << nirregular1 << endl; 00395 00396 int lid = 0; 00397 00398 nextlayer.clear(); 00399 nSize = currlayer.size(); 00400 for( size_t i = 0; i < nSize; i++) { 00401 Vertex *v = currlayer[i]; 00402 v->getRelations( vneighs ); 00403 for( size_t k = 0; k < vneighs.size(); k++) { 00404 vneighs[k]->getAttribute( "Layer", lid); 00405 if( lid > curr_layer_id ) { 00406 vneighs[k]->setAttribute("Layer", curr_layer_id+1 ); 00407 nextlayer.insert( vneighs[k] ); 00408 } 00409 } 00410 } 00411 if( nextlayer.empty() ) break; 00412 00413 NodeSet::const_iterator it; 00414 currlayer.resize(nextlayer.size() ); 00415 int index = 0; 00416 for( it = nextlayer.begin(); it != nextlayer.end(); ++it) 00417 currlayer[index++] = *it; 00418 curr_layer_id++; 00419 } 00420 cout << "# of Edges Swapped " << num_edges_flipped << endl; 00421 00422 vector<int> less_than_ideal, more_than_ideal, total_ideal; 00423 00424 int numLayers = curr_layer_id; 00425 less_than_ideal.resize( numLayers ); 00426 more_than_ideal.resize( numLayers ); 00427 total_ideal.resize( numLayers ); 00428 00429 for( int i = 0; i < numLayers; i++) { 00430 less_than_ideal[i] = 0; 00431 more_than_ideal[i] = 0; 00432 total_ideal[i] = 0; 00433 } 00434 00435 int lid = 0; 00436 00437 numNodes = mesh->getSize(0); 00438 int final_irregular = 0; 00439 for( size_t i = 0; i < numNodes; i++) { 00440 Vertex *v = mesh->getNodeAt(i); 00441 if( !v->isRemoved()) { 00442 v->getAttribute("Layer", lid ); 00443 int curr_degree = v->getNumRelations(2); 00444 int ideal_degree = v->get_ideal_face_degree(3); 00445 if( curr_degree != ideal_degree ) { 00446 final_irregular++; 00447 if( curr_degree < ideal_degree) less_than_ideal[lid]++; 00448 if( curr_degree > ideal_degree) more_than_ideal[lid]++; 00449 } else 00450 total_ideal[lid]++; 00451 } 00452 } 00453 00454 cout << " Layer Less More Ideal " << endl; 00455 for( int i = 0; i < numLayers; i++) 00456 cout << i << setw(10) << less_than_ideal[i] 00457 << setw(10) << more_than_ideal[i] 00458 << setw(10) << total_ideal[i] << endl; 00459 cout << " Final # of irregular nodes : " << final_irregular << endl; 00460 00461 mopt.shape_optimize(mesh); 00462 00463 if (!relexist2) mesh->clear_relations(0, 2); 00464 if (!relexist0) mesh->clear_relations(0, 0); 00465 00466 return num_edges_flipped; 00467 } 00468