MeshKit  1.0
SwapTriEdges.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines