MeshKit  1.0
QslimDecimation.cpp
Go to the documentation of this file.
00001 /*
00002  * QslimDecimation.cpp
00003  *
00004  *  Created on: Mar 10, 2010
00005  *      Author: iulian
00006  */
00007 
00008 #include <assert.h>
00009 #include "QslimDecimation.hpp"
00010 
00011 // for proximity searches
00012 #include "moab/AdaptiveKDTree.hpp"
00013 #include "moab/ReadUtilIface.hpp"
00014 
00015 #include "Mat4.h"
00016 #include "defs.h"
00017 #include "quadrics.h"
00018 #include <time.h>
00019 #include <map>
00020 #include <limits>
00021 
00022 // those are used in model navigation/simplification
00023 #include "primitives.h"
00024 
00025 // this is the global thing, that everybody will use
00026 moab::Interface * mb;
00027 moab::Tag uniqIDtag; // this will be used to mark vertices moab::EntityHandles
00028 moab::Tag validTag;
00029 
00030 moab::Tag costTag; // simplification induces an error cost at each vertex
00031 // try to keep adding the cost, to see if it is spreading nicely
00032 
00033 // this will be used to store plane data for each triangle, as 4 doubles
00034 // will be updated only if needed ( -m option == opts.will_preserve_mesh_quality)
00035 moab::Tag planeDataTag;
00036 
00037 moab::Range verts; // original list of vertices, that are part of the original triangles
00038 moab::Range triangles;
00039 moab::Range edgs;
00040 QslimOptions opts; // external
00041 moab::EntityHandle iniSet;
00042 
00043 int uniqID(moab::EntityHandle v) {
00044   int val;
00045   moab::ErrorCode rval = mb->tag_get_data(uniqIDtag, &v, 1, &val);
00046   (void) rval;
00047   assert(rval==moab::MB_SUCCESS);
00048   return val;
00049 }
00050 // the vertices are not deleted anymore, just invalidated
00051 // the edges are deleted, though, and triangles
00052 int ehIsValid(moab::EntityHandle v) {
00053   unsigned char val;
00054   moab::ErrorCode rval = mb->tag_get_data(validTag, &v, 1, &val);
00055   (void) rval;
00056   assert(rval==moab::MB_SUCCESS);
00057   return (int) val;
00058 }
00059 
00060 // include here the main classes used for decimation
00061 
00062 #include "Heap.hpp"
00063 // prox grid is used for proximity grid only
00064 //#include "ProxGrid.h"
00065 
00066 class pair_info: public Heapable {
00067 public:
00068   moab::EntityHandle v0, v1; // Vertex *v0, *v1;
00069 
00070   Vec3 candidate;
00071   double cost;
00072 
00073   //pair_info ( Vertex *a,Vertex *b ) { v0=a; v1=b; cost=HUGE; }
00074   pair_info(moab::EntityHandle a, moab::EntityHandle b) {
00075     v0 = a;
00076     v1 = b;
00077     cost = std::numeric_limits<double>::max();
00078   }
00079 
00080   bool isValid() {
00081     return ehIsValid(v0) && ehIsValid(v1);
00082   }//  :v0->isValid() && v1->isValid(); }
00083 };
00084 
00085 typedef buffer<pair_info *> pair_buffer;
00086 
00087 class vert_info {
00088 public:
00089 
00090   pair_buffer pairs;
00091 
00092   Mat4 Q;
00093   double norm;
00094 
00095   vert_info() :
00096     Q(Mat4::zero) {
00097     pairs.init(2);
00098     norm = 0.0;
00099   }
00100 };
00101 
00102 // these are
00103 static Heap *heap;
00104 static array<vert_info> vinfo;
00105 static double proximity_limit; // distance threshold squared
00106 
00107 int validFaceCount;
00108 int validVertCount;
00109 
00111 //
00112 // Low-level routines for manipulating pairs
00113 //
00114 
00115 static inline vert_info& vertex_info(moab::EntityHandle v)//Vertex *v )
00116 {
00117   //  moab::EntityHandle should return an integer tag with an
00118   //  index in the big array of vert_info
00119   //   something like: return tag
00120   //   for the time being, we can return the simple id...
00121   return vinfo(uniqID(v));
00122 }
00123 
00124 static
00125 bool check_for_pair(moab::EntityHandle v0, moab::EntityHandle v1)//Vertex *v0, Vertex *v1 )
00126 {
00127   const pair_buffer& pairs = vertex_info(v0).pairs;
00128 
00129   for (int i = 0; i < pairs.length(); i++) {
00130     if (pairs(i)->v0 == v1 || pairs(i)->v1 == v1)
00131       return true;
00132   }
00133 
00134   return false;
00135 }
00136 
00137 static pair_info *new_pair(moab::EntityHandle v0, moab::EntityHandle v1)//  Vertex *v0, Vertex *v1 )
00138 {
00139   vert_info& v0_info = vertex_info(v0);
00140   vert_info& v1_info = vertex_info(v1);
00141 
00142   pair_info *pair = new pair_info(v0, v1);
00143   v0_info.pairs.add(pair);
00144   v1_info.pairs.add(pair);
00145 
00146   return pair;
00147 }
00148 
00149 static
00150 void delete_pair(pair_info *pair) {
00151   vert_info& v0_info = vertex_info(pair->v0);
00152   vert_info& v1_info = vertex_info(pair->v1);
00153 
00154   v0_info.pairs.remove(v0_info.pairs.find(pair));
00155   v1_info.pairs.remove(v1_info.pairs.find(pair));
00156 
00157   if (pair->isInHeap())
00158     heap->kill(pair->getHeapPos());
00159 
00160   delete pair;
00161 }
00162 
00164 //
00165 // The actual guts of the algorithm:
00166 //
00167 //     - pair_is_valid
00168 //     - compute_pair_info
00169 //     - do_contract
00170 //
00171 /*
00172 static
00173 bool pair_is_valid(moab::EntityHandle u, moab::EntityHandle v)// Vertex *u, Vertex *v )
00174 {
00175   //
00176   Vec3 vu = getVec3FromMBVertex(mb, u);
00177   Vec3 vv = getVec3FromMBVertex(mb, v);
00178   return norm2(vu - vv) < proximity_limit;
00179   //return  norm2 ( *u - *v ) < proximity_limit;
00180 }*/
00181 
00182 static
00183 int predict_face(moab::EntityHandle tria, moab::EntityHandle v1,
00184     moab::EntityHandle v2, /*Face& F, Vertex *v1, Vertex *v2,*/
00185     Vec3& vnew, Vec3& f1, Vec3& f2, Vec3& f3) {
00186   int nmapped = 0;
00187   const moab::EntityHandle * conn;
00188   int num_nodes;
00189   moab::ErrorCode rval = mb->get_connectivity(tria, conn, num_nodes);
00190   (void) rval;
00191   assert(3==num_nodes && rval == moab::MB_SUCCESS);
00192   if (conn[0] == v1 || conn[0] == v2) {
00193     f1 = vnew;
00194     nmapped++;
00195   } else
00196     f1 = getVec3FromMBVertex(mb, conn[0]);
00197 
00198   if (conn[1] == v1 || conn[1] == v2) {
00199     f2 = vnew;
00200     nmapped++;
00201   } else
00202     f2 = getVec3FromMBVertex(mb, conn[1]);
00203 
00204   if (conn[2] == v1 || conn[2] == v2) {
00205     f3 = vnew;
00206     nmapped++;
00207   } else
00208     f3 = getVec3FromMBVertex(mb, conn[2]);
00209 
00210   // find vertices in face tria
00211   /*
00212    if ( F.vertex ( 0 ) == v1 || F.vertex ( 0 ) == v2 )
00213    { f1 = vnew;  nmapped++; }
00214    else f1 = *F.vertex ( 0 );
00215 
00216    if ( F.vertex ( 1 ) == v1 || F.vertex ( 1 ) == v2 )
00217    { f2 = vnew;  nmapped++; }
00218    else f2 = *F.vertex ( 1 );
00219 
00220    if ( F.vertex ( 2 ) == v1 || F.vertex ( 2 ) == v2 )
00221    { f3 = vnew;  nmapped++; }
00222    else f3 = *F.vertex ( 2 );
00223    */
00224   return nmapped;
00225 }
00226 
00227 #define MESH_INVERSION_PENALTY 1e9
00228 
00229 static
00230 double pair_mesh_positivity(/* Model& M,*/moab::EntityHandle v1,
00231     moab::EntityHandle v2, /*Vertex *v1, Vertex *v2,*/
00232     Vec3& vnew) {
00233   std::vector<moab::EntityHandle> changed;
00234 
00235   // :  construct the list of faces influenced by the
00236   //   moving of vertices v1 and v2 into vnew
00237   //M.contractionRegion ( v1, v2, changed );
00238   moab::ErrorCode rval = contractionRegion(mb, v1, v2, changed);
00239   if (rval != moab::MB_SUCCESS) {
00240     std::cout << "error in getting adjacency information vs: "
00241         << mb->id_from_handle(v1) << " " << mb->id_from_handle(v2) << "\n";
00242   }
00243 
00244   // double Nsum = 0;
00245   if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
00246     *opts.logfile << " positivity for v1, v2: " << mb->id_from_handle(v1)
00247         << " " << mb->id_from_handle(v2) << std::endl;
00248 
00249   for (unsigned int i = 0; i < changed.size(); i++) {
00250     //Face& F = *changed ( i );
00251     moab::EntityHandle F = changed[i];
00252     Vec3 f1, f2, f3;
00253 
00254     int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3);
00255 
00256     //
00257     // Only consider non-degenerate faces
00258     if (nmapped < 2) {
00259       //Plane Pnew ( f1, f2, f3 );
00260 #if 0
00261       Vec3 normalNew = Pnew.normal();
00262       if ( normalNew[Z] < positivityMin )
00263       positivityMin=normalNew[Z]; // Z direction!!!
00264       if (opts.logfile && opts.selected_output&OUTPUT_CONTRACTIONS )
00265       *opts.logfile << "Triangle " << mb->id_from_handle(F)
00266       << " nmapped " << nmapped << std::endl;
00267       if (opts.logfile && positivityMin<=0 && opts.selected_output&OUTPUT_CONTRACTIONS )
00268       *opts.logfile << "Triangle " << mb->id_from_handle(F)
00269       << " normal Z:" << normalNew[Z] << std::endl;
00270 #endif
00271       double positiv = (f2[0] - f1[0]) * (f3[1] - f1[1]) - (f2[1] - f1[1])
00272           * (f3[0] - f1[0]);
00273       if (positiv <= 0) {
00274         if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
00275           *opts.logfile << "Triangle " << mb->id_from_handle(F) << " nmapped "
00276               << nmapped << " orient: " << positiv << std::endl;
00277         return MESH_INVERSION_PENALTY * 10;
00278       }
00279     }
00280   }
00281 
00282   //return (-Nmin) * MESH_INVERSION_PENALTY;
00283 
00284   return 0.0;
00285 }
00286 
00287 // will make sure that no hole would be closed
00288 /*
00289  * will accomplish that by looking at the edges connected to both vertices
00290  * if there would be edges that would merge without a connecting triangle,
00291  * it would increase the cost (penalize it harshly)
00292  */
00293 static double pair_mesh_topology(moab::EntityHandle v1, moab::EntityHandle v2)
00294 {
00295   // first, find nodes v3 that are connected to both v1 and v2 by edges
00296   // if there is no triangle that is formed with v1, v2, v3, it means it would
00297   //  collapse a hole
00298   std::vector<moab::EntityHandle> edges1, edges2;
00299   moab::Range nodes1, nodes2;
00300   moab::ErrorCode rval = mb->get_adjacencies(&v1, 1, 1, false, edges1);
00301   assert (moab::MB_SUCCESS == rval);
00302   filterValid(mb, edges1);
00303   rval = mb->get_adjacencies(&v2, 1, 1, false, edges2);
00304   assert (moab::MB_SUCCESS == rval);
00305   filterValid(mb, edges2);
00306   rval = mb->get_connectivity(&edges1[0], edges1.size(), nodes1);
00307   assert (moab::MB_SUCCESS == rval);
00308   rval = mb->get_connectivity(&edges2[0], edges2.size(), nodes2);
00309   assert (moab::MB_SUCCESS == rval);
00310   moab::Range commonV=intersect (nodes1, nodes2);
00311   moab::Range v12;
00312   v12.insert(v1); v12.insert(v2);
00313   moab::Range leftOver = subtract(commonV, v12);
00314   for (moab::Range::iterator it = leftOver.begin(); it!=leftOver.end(); it++)
00315   {
00316     moab::EntityHandle thirdNode = *it;
00317     if (!ehIsValid(thirdNode))
00318       continue;
00319     // the moment we find a triple v1, v2, thirdNode that is not a triangle, return penalty
00320     moab::Range triple=v12;
00321     triple.insert(thirdNode);
00322     moab::Range connTris;
00323     rval = mb->get_adjacencies(triple, 2, false, connTris );
00324     if (moab::MB_SUCCESS == rval)
00325     {
00326       if (connTris.empty())
00327         return MESH_INVERSION_PENALTY; // this means that there are no
00329                                        // so it would close a hole/tunnel
00330 
00331       int noValidTris = 0;
00332       for (moab::Range::iterator it2 = connTris.begin(); it2!=connTris.end(); it2++)
00333       {
00334         if (ehIsValid(*it2))
00335         {
00336           noValidTris++;
00337           break;
00338         }
00339       }
00340       if (0==noValidTris)
00341         return MESH_INVERSION_PENALTY; // this means that there are no
00342                                        // triangles connected to the 3 nodes
00343                                        // so it would close a hole/tunnel
00344 
00345     }
00346 
00347   }
00348   return 0.; // no penalty
00349 }
00350 static
00351 double pair_mesh_penalty( /*Model& M, Vertex *v1, Vertex *v2,*/
00352 moab::EntityHandle v1, moab::EntityHandle v2, Vec3& vnew) {
00353   std::vector<moab::EntityHandle> changed;
00354 
00355   //   construct the list of faces influenced by the
00356   //   moving of vertices v1 and v2 into vnew
00357   //M.contractionRegion ( v1, v2, changed );
00358   moab::ErrorCode rval = contractionRegion(mb, v1, v2, changed);
00359   if (rval != moab::MB_SUCCESS) {
00360     std::cout << "error in getting adjacency information vs: "
00361         << mb->id_from_handle(v1) << " " << mb->id_from_handle(v2) << "\n";
00362   }
00363 
00364   // double Nsum = 0;
00365   double Nmin = 0;
00366 
00367   for (unsigned int i = 0; i < changed.size(); i++) {
00368     //Face& F = *changed ( i );
00369     moab::EntityHandle F = changed[i];
00370     Vec3 f1, f2, f3;
00371 
00372     int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3);
00373     //
00374     // Only consider non-degenerate faces
00375     if (nmapped < 2) {
00376       Plane Pnew(f1, f2, f3);
00377       Plane p = trianglePlane(mb, F);
00378       double delta = Pnew.normal() * p.normal(); //  Pnew.normal() * F.plane().normal();
00379 
00380       if (Nmin > delta)
00381         Nmin = delta;
00382     }
00383   }
00384 
00385   //return (-Nmin) * MESH_INVERSION_PENALTY;
00386   if (Nmin < 0.0)
00387     return MESH_INVERSION_PENALTY;
00388   else
00389     return 0.0;
00390 }
00391 
00392 static
00393 void compute_pair_info(pair_info *pair /* Model * pM0,*/) {
00394   moab::EntityHandle v0 = pair->v0;
00395   moab::EntityHandle v1 = pair->v1;
00396 
00397   // Vertex *v0 = pair->v0;
00398   // Vertex *v1 = pair->v1;
00399 
00400   vert_info& v0_info = vertex_info(v0);
00401   vert_info& v1_info = vertex_info(v1);
00402 
00403   Mat4 Q = v0_info.Q + v1_info.Q;
00404   double norm = v0_info.norm + v1_info.norm;
00405 
00406   pair->cost = quadrix_pair_target(Q, v0, v1, pair->candidate);
00407 
00408   if (opts.will_weight_by_area)
00409     pair->cost /= norm;
00410 
00411   if (opts.will_preserve_mesh_quality)
00412     pair->cost += pair_mesh_penalty(/* *pM0,*/v0, v1, pair->candidate);
00413 
00414   if (opts.height_fields)
00415     pair->cost += pair_mesh_positivity(/* *pM0, */v0, v1, pair->candidate);
00416 
00417   if (opts.topology)
00418     pair->cost += pair_mesh_topology(v0, v1);
00419 
00420   if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
00421 
00422     *opts.logfile << "pair ( v" << mb->id_from_handle(v0) << " v"
00423         << mb->id_from_handle(v1) << " ) cost: " << -pair->cost << std::endl;
00424   //
00425   // NOTICE:  In the heap we use the negative cost.  That's because
00426   //          the heap is implemented as a MAX heap.
00427   //
00428   if (pair->isInHeap()) {
00429     heap->update(pair, -pair->cost);
00430   } else {
00431     heap->insert(pair, -pair->cost);
00432   }
00433   if (opts.logfile && opts.selected_output & OUTPUT_COST) {
00434     heap_node *top = heap->top();
00435     pair_info *pairTop = (pair_info *) top->obj;
00436     *opts.logfile << " i/u pair (" << uniqID(pair->v0) << "," << uniqID(
00437         pair->v1) << ")=" << pair->cost << "  min : (" << uniqID(pairTop->v0)
00438         << "," << uniqID(pairTop->v1) << ") " << pairTop->cost << std::endl;
00439   }
00440 }
00441 void recomputeChangedPairsCost(std::vector<moab::EntityHandle> & changed, moab::EntityHandle v0) {
00442   //
00443   for (unsigned int i = 0; i < changed.size(); i++) {
00444 
00445     moab::EntityHandle F = changed[i];
00446     const moab::EntityHandle * conn;
00447     int num_nodes;
00448     mb->get_connectivity(F, conn, num_nodes);
00449     //if (!F->isValid())
00450     //   continue;
00451     // recompute the pair that is not connected to vertex v0
00452     // loop over all the vertices of F that are not v0, and recompute the costs
00453     // of all the pairs associated  that do not contain v0
00454     // we do not have to recreate or delete any pair, we just recompute what we have
00455     // some will be recomputed 2 times, but it is OK
00456     for (int k = 0; k < 3; k++) {
00457       moab::EntityHandle v = conn[k];
00458       if (v == v0)
00459         continue;
00460       vert_info & v_info = vertex_info(v);
00461       for (int j = 0; j < v_info.pairs.length(); j++) {
00462         pair_info *p = v_info.pairs(j);
00463         if (p->v0 == v0 || p->v1 == v0)
00464           continue; // do not recompute cost of pairs already computed
00465         if (opts.logfile && (opts.selected_output & OUTPUT_COST))
00466           *opts.logfile << "recompute cost of pair (v" << uniqID(p->v0) + 1
00467               << " v" << uniqID(p->v1) + 1 << ")" << std::endl;
00468         compute_pair_info(p);
00469       }
00470 
00471     }
00472 
00473   }
00474 }
00475 
00476 static
00477 void do_contract(pair_info *pair) {
00478 
00479   moab::EntityHandle v0 = pair->v0;
00480   moab::EntityHandle v1 = pair->v1;
00481   // cost of contraction is accumulated at v0
00482   double costToContract = pair->cost;
00483   vert_info& v0_info = vertex_info(v0);
00484   vert_info& v1_info = vertex_info(v1);
00485   Vec3 vnew = pair->candidate;
00486   if (opts.logfile && (opts.selected_output & OUTPUT_COST)) {
00487     *opts.logfile << "---- do contract v0:" << uniqID(v0) + 1 << " v1:"
00488         << uniqID(v1) + 1 << std::endl;
00489   }
00490   int i;
00491 
00492   //
00493   // Make v0 be the new vertex
00494   v0_info.Q += v1_info.Q;
00495   v0_info.norm += v1_info.norm;
00496 
00497   //
00498   // Perform the actual contraction
00499   std::vector<moab::EntityHandle> changed;
00500   moab::ErrorCode rval1 = contract(mb, v0, v1, vnew, changed);
00501   (void) rval1;
00502   // this is a list of triangles still connected to v0 (are they valid? probably)
00503   if (opts.will_preserve_mesh_quality) {
00504     // recompute normals only in this case, because they are not needed otherwise
00505     int size = changed.size();
00506     for (int i = 0; i < size; i++) {
00507       computeTrianglePlane(mb, changed[i]);
00508     }
00509   }
00510   assert (moab::MB_SUCCESS == rval1 || moab::MB_MULTIPLE_ENTITIES_FOUND == rval1);
00511 
00512 #ifdef SUPPORT_VCOLOR
00513   //
00514   // If the vertices are colored, color the new vertex
00515   // using the average of the old colors.
00516   v0->props->color += v1->props->color;
00517   v0->props->color /= 2;
00518 #endif
00519 
00520   //
00521   // Remove the pair that we just contracted
00522   delete_pair(pair);
00523   //
00524   // Recalculate pairs associated with v0
00525   for (i = 0; i < v0_info.pairs.length(); i++) {
00526     pair_info *p = v0_info.pairs(i);
00527     compute_pair_info(p);
00528   }
00529 
00530   //
00531   // Process pairs associated with now dead vertex
00532 
00533   static pair_buffer condemned(6); // collect condemned pairs for execution
00534   condemned.reset();
00535 
00536   for (i = 0; i < v1_info.pairs.length(); i++) {
00537     pair_info *p = v1_info.pairs(i);
00538 
00539     moab::EntityHandle u = 0L;
00540     if (p->v0 == v1)
00541       u = p->v1;
00542     else if (p->v1 == v1)
00543       u = p->v0;
00544     else
00545       std::cerr << "YOW!  This is a bogus pair." << std::endl;
00546 
00547     if (!check_for_pair(u, v0)) {
00548       p->v0 = v0;
00549       p->v1 = u;
00550       v0_info.pairs.add(p);
00551       compute_pair_info(p);
00552     } else
00553       condemned.add(p);
00554   }
00555 
00556   for (i = 0; i < condemned.length(); i++)
00557     // Do you have any last requests?
00558     delete_pair(condemned(i));
00559   // only now you can delete the vertex v1 from database
00560   // moab::ErrorCode rval = mb->delete_entities(&v1, 1);
00561   // no, it is better to invalidate the vertex, do not delete it
00562   // maybe we will delete at the end all that are invalid ??
00563   int invalid = 0;
00564   moab::ErrorCode rval = mb->tag_set_data(validTag, &v1, 1, &invalid);
00565   (void) rval;
00566   assert (moab::MB_SUCCESS == rval);
00567 
00568   if (opts.plotCost) {
00569     double cost_at_v0 = 0; // maybe it is already set before
00570     rval = mb->tag_get_data(costTag, &v0, 1, &cost_at_v0);
00571     cost_at_v0 += costToContract;
00572     rval = mb->tag_set_data(costTag, &v0, 1, &cost_at_v0);
00573   }
00574 
00575   v1_info.pairs.reset(); // safety precaution
00576   recomputeChangedPairsCost(changed, v0);
00577 
00578 }
00579 
00581 //
00582 // External interface: setup and single step iteration
00583 //
00584 
00585 bool decimate_quadric(moab::EntityHandle v, Mat4& Q) {
00586   if (vinfo.length() > 0) {
00587     vert_info & vinf = vertex_info(v);
00588     Q = vinf.Q;
00589     return true;
00590   } else
00591     return false;
00592 }
00593 
00594 // it is assumed it is mb, moab interface
00595 void decimate_contract() {
00596   heap_node *top;
00597   pair_info *pair;
00598 
00599   for (;;) {
00600     top = heap->extract();
00601     if (!top)
00602       return;
00603     pair = (pair_info *) top->obj;
00604 
00605     //
00606     // This may or may not be necessary.  I'm just not quite
00607     // willing to assume that all the junk has been removed from the
00608     // heap.
00609     if (pair->isValid())
00610       break;
00611 
00612     delete_pair(pair);
00613   }
00614 
00615   if (opts.logfile && (opts.selected_output & OUTPUT_COST))
00616     *opts.logfile << "#$cost " << validFaceCount << " before contract: "
00617         << pair->cost << std::endl;
00618 
00619   do_contract(pair);
00620 
00621   if (opts.logfile && (opts.selected_output & OUTPUT_COST))
00622     *opts.logfile << "#$cost " << validFaceCount << std::endl;
00623 
00624   validVertCount--; // Attempt to maintain valid vertex information
00625 }
00626 
00627 double decimate_error(moab::EntityHandle v) {
00628   vert_info& info = vertex_info(v);
00629 
00630   double err = quadrix_evaluate_vertex(v, info.Q);
00631 
00632   if (opts.will_weight_by_area)
00633     err /= info.norm;
00634 
00635   return err;
00636 }
00637 
00638 double decimate_min_error() {
00639   heap_node *top;
00640   pair_info *pair;
00641 
00642   for (;;) {
00643     top = heap->top();
00644     if (!top)
00645       return -1.0;
00646     pair = (pair_info *) top->obj;
00647 
00648     if (pair->isValid())
00649       break;
00650 
00651     top = heap->extract();
00652     delete_pair(pair);
00653   }
00654 
00655   return pair->cost;
00656 }
00657 #if 0
00658 double decimate_max_error ( )
00659 {
00660   real max_err = 0;
00661 
00662   for ( int i=0; i<m.vertCount(); i++ )
00663   if ( m.vertex ( i )->isValid() )
00664   {
00665     max_err = MAX ( max_err, decimate_error ( m.vertex ( i ) ) );
00666   }
00667 
00668   return max_err;
00669 }
00670 #endif
00671 namespace MeshKit {
00672 
00673 QslimDecimation::QslimDecimation(moab::Interface * mbi,
00674     moab::EntityHandle root_set) {
00675   _mb = mbi;
00676   iniSet = root_set;// it is not necessarily the root set; this is external; bad design
00677 }
00678 
00679 QslimDecimation::~QslimDecimation() {
00680 }
00681 int QslimDecimation::decimate(QslimOptions & iOpts, moab::Range & oRange) {
00682   // opts is external
00683   opts = iOpts;
00684 
00685   mb = _mb; // (reinterpret_cast<MBiMesh *> (m_mesh))->mbImpl;
00686   // need to get all the triangles from the set
00687   // also all the edges, and all vertices
00688   // not  a good design here; mb is extern !
00689   //
00690   if (NULL == mb)
00691     return 1;// error
00692   //moab::EntityHandle mbSet = reinterpret_cast<moab::EntityHandle>(m_InitialSet);
00693 
00694   clock_t start_time = clock();
00695   int err = Init();
00696   if (err) {
00697     std::cerr << "Error in initialization of decimation. Abort\n";
00698     return 1;
00699   }
00700   clock_t init_time = clock();
00701   std::cout << "   Initialization  " << (double) (init_time - start_time)
00702       / CLOCKS_PER_SEC << " s.\n";
00703 
00704   int faces_reduction = validFaceCount - opts.face_target;
00705   int counter = 0, interval = 0;
00706   clock_t currentTime = init_time;
00707   while (validFaceCount > opts.face_target && decimate_min_error()
00708       < opts.error_tolerance) {
00709     int initf = validFaceCount;
00710     // big routine
00711     decimate_contract();
00712     counter += (initf - validFaceCount);
00713     if (counter > faces_reduction / opts.timingIntervals) {
00714       // print some time stats
00715       clock_t p10_time = clock();
00716       std::cout << "     " << ++interval << "/" << opts.timingIntervals
00717           << " reduce to " << validFaceCount << " faces in "
00718           << (double) (p10_time - currentTime) / CLOCKS_PER_SEC << " s, total:"
00719           << (double) (p10_time - init_time) / CLOCKS_PER_SEC << " s.\n";
00720       counter = 0;
00721       currentTime = p10_time;
00722     }
00723   }
00724 
00725   clock_t finish_time = clock();
00726   std::cout << "   Decimation: " << (double) (finish_time - init_time)
00727       / CLOCKS_PER_SEC << " s.\n";
00728 
00729   if (opts.create_range) {
00730     // the remaining nodes and triangles are copied in the range
00731     // they are put in the old set, too
00732     // maybe this has to change
00733     // count first valid vertices and triangles
00734     moab::Range::iterator it;
00735     std::vector<moab::EntityHandle> validVerts;
00736     std::vector<moab::EntityHandle> validTris;
00737     for (it = triangles.begin(); it != triangles.end(); it++) {
00738       if (ehIsValid(*it))
00739         validTris.push_back(*it);
00740     }
00741     for (it = verts.begin(); it != verts.end(); it++) {
00742       if (ehIsValid(*it))
00743         validVerts.push_back(*it);
00744     }
00745     //
00746     std::vector<double> coords;
00747     int numNodes = (int) validVerts.size();
00748     int numTriangles = (int) validTris.size();
00749     coords.resize(3 * numNodes);
00750 
00751     moab::ErrorCode rval = mb->get_coords(&(validVerts[0]), numNodes,
00752         &(coords[0]));
00753     (void) rval;
00754     assert(moab::MB_SUCCESS==rval);
00755 
00756     // create the new vertices, at the same  coordinates
00757     // put those verts in the range that is output
00758 
00759     // to make sure, the range is cleared
00760     oRange.clear();
00761     rval = mb->create_vertices(&coords[0], numNodes, oRange);
00762     assert(moab::MB_SUCCESS==rval);
00763     // the first element in the range must be the start of the new vertex sequence
00764     std::map<moab::EntityHandle, moab::EntityHandle> mapping; // this will be from old
00765     //  to new vertices, for connectivity
00766     for (int i = 0; i < numNodes; i++) {
00767       mapping[validVerts[i]] = oRange[i];
00768     }
00769 
00770     //get the query interface, which we will use to create the triangles directly
00771     moab::ReadUtilIface *iface;
00772     rval = mb -> query_interface(iface);// use the new query interface
00773     assert(moab::MB_SUCCESS==rval);
00774 
00775     //create the triangles, get a direct ptr to connectivity
00776     moab::EntityHandle starth, *connect;
00777     rval = iface -> get_element_connect(numTriangles, 3, moab::MBTRI, 1,
00778         starth, connect);
00779     assert(moab::MB_SUCCESS==rval);
00780     // get first the connectivity of the old triangles
00781     const moab::EntityHandle * conn3;
00782     for (int i = 0; i < numTriangles; i++) {
00783       int num_nodes;
00784       // get each valid triangle one by one, and set the new connectivity directly
00785       rval = mb->get_connectivity(validTris[i], conn3, num_nodes);
00786       assert( (moab::MB_SUCCESS==rval) && (num_nodes==3));
00787       // directly modify the connect array in database
00788       for (int j = 0; j < 3; j++)
00789         connect[j] = mapping[conn3[j]];
00790 
00791       // update adjacencies
00792       // not very smart...; we would like to update once and for all triangles
00793       // not in a loop
00794       rval = iface -> update_adjacencies(starth+i, 1, 3, connect);
00795       assert(moab::MB_SUCCESS==rval);
00796 
00797       connect += 3; // advance
00798     }
00799 
00800 
00801 
00802     // clear completely the initial set, after deleting all elements from it...
00803     //   ok, we are done, commit to ME ?
00804     rval = mb->delete_entities(triangles);
00805     assert(moab::MB_SUCCESS==rval);
00806     rval = mb->delete_entities(edgs);
00807     assert(moab::MB_SUCCESS==rval);
00808     rval = mb->delete_entities(verts);
00809     assert(moab::MB_SUCCESS==rval);
00810     // remove everything from the initial set, because we will add the new triangles
00811     mb->remove_entities(iniSet, triangles);
00812     mb->remove_entities(iniSet, verts);
00813     mb->remove_entities(iniSet, edgs);
00814 
00815     //add triangles to output range (for the MESelection)
00816     oRange.insert(starth, starth + numTriangles - 1);
00817     // add all entities from the range to the initial set, now
00818     rval = mb->add_entities(iniSet, oRange);
00819     assert(moab::MB_SUCCESS==rval);
00820     //me->commit_mesh(mit->second, COMPLETE_MESH);
00821     // end copy
00822   } else {
00823     moab::Range::const_reverse_iterator rit;
00824     if (opts.useDelayedDeletion) {
00825 
00826       // put in a range triangles to delete
00827       moab::Range delRange;
00828       // delete triangles and edges that are invalid
00829       for (rit = triangles.rbegin(); rit != triangles.rend(); rit++) {
00830         moab::EntityHandle tr = *rit;
00831         // check the validity
00832         if (ehIsValid(tr))
00833           continue;
00834         mb->delete_entities(&tr, 1);
00835         delRange.insert(tr);
00836       }
00837       mb->remove_entities(iniSet, delRange);
00838       // maybe we should delete all edges, but for now, we will keep them
00839       for (rit = edgs.rbegin(); rit != edgs.rend(); rit++) {
00840         moab::EntityHandle v = *rit;
00841         // check the validity
00842         if (ehIsValid(v))
00843           continue;
00844         mb->delete_entities(&v, 1);
00845       }
00846 
00847     }
00848     // delete them one by one
00849     for (rit = verts.rbegin(); rit != verts.rend(); rit++) {
00850       moab::EntityHandle v = *rit;
00851       // check the validity
00852       if (ehIsValid(v))
00853         continue;
00854       mb->delete_entities(&v, 1);
00855     }
00856   }
00857   clock_t delete_vTime = clock();
00858   std::cout << "   Delete Vertices: " << (double) (delete_vTime - finish_time)
00859       / CLOCKS_PER_SEC << " s.\n";
00860   // we need to delete the tags we created; they are artificial
00861   // list of tags to delete:
00862   // moab::Tag uniqIDtag; // this will be used to mark vertices moab::EntityHandles
00863   // moab::Tag validTag;
00864   // moab::Tag planeDataTag;
00865 
00866   // moab::Tag costTag; // simplification induces an error cost at each vertex
00867   // try to keep adding the cost, to see if it is spreading nicely
00868 
00869   // keep only the cost, the rest are artificial
00870   mb->tag_delete(uniqIDtag);
00871   mb->tag_delete(validTag);
00872   mb->tag_delete(planeDataTag);
00873   //
00874 
00875   return 0;
00876 }
00877 
00878 int QslimDecimation::Init() {
00879   int i;
00880   unsigned int j;
00881 
00882   //moab::EntityHandle * set = reinterpret_cast<moab::EntityHandle *> (&_InitialSet);
00883   moab::ErrorCode rval = mb->get_entities_by_type(iniSet, moab::MBTRI,
00884       triangles);
00885   validFaceCount = triangles.size();// this gets reduced every time we simplify the model
00886 
00887   // store the normals/planes computed at each triangle
00888   // we may need just the normals, but compute planes, it is about the same job
00889   double defPlane[] = { 0., 0., 1., 0. };
00890   rval = mb->tag_get_handle("PlaneTriangleData", 4, moab::MB_TYPE_DOUBLE,
00891       planeDataTag, moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &defPlane);
00892 
00893   // compute the triangle plane and store it, for each triangle
00894   for (moab::Range::iterator itr = triangles.begin(); itr != triangles.end(); itr++) {
00895     // this index i will be the index in the vinfo array
00896     moab::EntityHandle tri = *itr;
00897     computeTrianglePlane(mb, tri);
00898     // setting the data for the tag/triangle is done in the compute
00899     //rval = mb->tag_set_data(planeDataTag, &tri, 1, &plane);
00900   }
00901 
00902   // create all the edges if not existing
00903   mb->get_adjacencies(triangles, 1, true, edgs, moab::Interface::UNION);
00904 
00905   // moab::Range verts;// the vertices are always there, they do not need to be created
00906   mb->get_adjacencies(triangles, 0, true, verts, moab::Interface::UNION);
00907   int numNodes = verts.size();
00908   validVertCount = numNodes; // this will be kept
00909   vinfo.init(numNodes);
00910   // set a unique integer tag with the position in vinfo array
00911   //  this will be used instead of v->uniqID in the vinfo array
00912   int def_data = -1;
00913 
00914   rval = mb->tag_get_handle("uniqID", 1, moab::MB_TYPE_INTEGER, uniqIDtag,
00915       moab::MB_TAG_DENSE | moab::MB_TAG_EXCL, &def_data);
00916   if (moab::MB_SUCCESS != rval)
00917     return 1;
00918 
00919   unsigned char def_data_bit = 1;// valid by default
00920 
00921   rval = mb->tag_get_handle("valid", 1, moab::MB_TYPE_BIT, validTag,
00922       moab::MB_TAG_EXCL | moab::MB_TAG_BIT, &def_data_bit);
00923   if (moab::MB_SUCCESS != rval)
00924     return 1;
00925 
00926   if (opts.plotCost) {
00927     double cost_default = 0.;
00928 
00929     rval = mb->tag_get_handle("costTAG", 1, moab::MB_TYPE_DOUBLE, costTag,
00930         moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &cost_default);
00931     if (moab::MB_SUCCESS != rval)
00932       return 1;
00933   }
00934 
00935   // set tag for each vertex; this will not be changed during simplification
00936   i = 0; // for index
00937   for (moab::Range::iterator it = verts.begin(); it != verts.end(); it++, i++) {
00938     // this index i will be the index in the vinfo array
00939     moab::EntityHandle v = *it;
00940     rval = mb->tag_set_data(uniqIDtag, &v, 1, &i);
00941     // the default valid data is 1; set it to 0 only to "mark" the vertex invalid for future deletion
00942     // is it really necessary if we put the default value as 1 anyway
00943 
00944     //rval = mb->tag_set_data(validTag, &v, 1, &def_data_bit);
00945   }
00946   moab::Range::iterator it;
00947   if (opts.logfile && opts.selected_output & OUTPUT_MODEL_DEFN) {
00948     for (it = verts.begin(); it != verts.end(); it++) {
00949       moab::EntityHandle v = *it;
00950       double coords[3];
00951       rval = mb->get_coords(&v, 1, coords);
00952       *opts.logfile << "v: " << uniqID(v) << " " << mb->id_from_handle(v)
00953           << " " << coords[0] << " " << coords[1] << " " << coords[2]
00954           << std::endl;
00955     }
00956   }
00957   std::cout << "  Decimate:  Distributing shape constraints." << std::endl;
00958 
00959   if (opts.will_use_vertex_constraint)
00960     for (it = verts.begin(); it != verts.end(); it++) {
00961       moab::EntityHandle v = *it;
00962       vertex_info(v).Q = quadrix_vertex_constraint(v);
00963     }
00964 
00965   if (opts.will_use_plane_constraint) {
00966     for (it = triangles.begin(); it != triangles.end(); it++) {
00967 
00968       moab::EntityHandle tr = *it;
00969       Mat4 Q = quadrix_plane_constraint(tr);
00970       double norm = 0.0;
00971 
00972       if (opts.will_weight_by_area) {
00973         norm = 1; // triangle area : m_model->face ( i )->area();
00974         Q *= norm;
00975       }
00976       const moab::EntityHandle * conn;
00977       int num_nodes;
00978       rval = mb->get_connectivity(tr, conn, num_nodes);
00979       for (j = 0; j < 3; j++) {
00980         vert_info& vj_info = vertex_info(conn[j]);
00981         vj_info.Q += Q;
00982         vertex_info(conn[j]).norm += norm;
00983 
00984       }
00985     }
00986   }
00987   // just define (one uniqTag for a triangle, see what is happening)
00988   moab::EntityHandle tr1 = triangles[0];
00989   rval = mb->tag_set_data(uniqIDtag, &tr1, 1, &i);// just some value
00990 
00991   if (opts.will_constrain_boundaries) {
00992     std::cout << "  Decimate:  Accumulating discontinuity constraints."
00993         << std::endl;
00994     for (it = edgs.begin(); it != edgs.end(); it++) {
00995       moab::EntityHandle edg = *it;
00996       if (is_border(edg)) {
00997         const moab::EntityHandle * conn;
00998         int num_nodes;
00999         rval = mb->get_connectivity(edg, conn, num_nodes);
01000         if (moab::MB_SUCCESS != rval)
01001           return 1;// fail
01002         Mat4 B = quadrix_discontinuity_constraint(edg);
01003         double norm = 0.0;
01004 
01005         if (opts.will_weight_by_area) {
01006           Vec3 ve1 = getVec3FromMBVertex(mb, conn[0]);
01007           Vec3 ve2 = getVec3FromMBVertex(mb, conn[1]);
01008           norm = norm2(ve1 - ve2);
01009           B *= norm;
01010         }
01011 
01012         B *= opts.boundary_constraint_weight;
01013         vert_info& v0_info = vertex_info(conn[0]);
01014         vert_info& v1_info = vertex_info(conn[1]);
01015         v0_info.Q += B;
01016         v0_info.norm += norm;
01017         v1_info.Q += B;
01018         v1_info.norm += norm;
01019       }
01020     }
01021   }
01022 
01023   std::cout << "  Decimate:  Allocating heap." << std::endl;
01024   heap = new Heap(edgs.size());
01025 
01026   int pair_count = 0;
01027 
01028   std::cout << "  Decimate:  Collecting pairs [edges]." << std::endl;
01029   for (it = edgs.begin(); it != edgs.end(); it++) {
01030     moab::EntityHandle edg = *it;
01031     const moab::EntityHandle * conn;
01032     int num_nodes;
01033     rval = mb->get_connectivity(edg, conn, num_nodes);
01034     if (moab::MB_SUCCESS != rval)
01035       return 1;// fail
01036     pair_info *pair = new_pair(conn[0], conn[1]);
01037     compute_pair_info(pair);
01038     pair_count++;
01039   }
01040 
01041   if (opts.pair_selection_tolerance < 0) {
01042     opts.pair_selection_tolerance = 1;//m_model->bounds.radius * 0.05;
01043     std::cout << "  Decimate:  Auto-limiting at 5% of model radius."
01044         << std::endl;
01045   }
01046   proximity_limit = opts.pair_selection_tolerance
01047       * opts.pair_selection_tolerance;
01048   if (proximity_limit > 0) {
01049     std::cout << "  Decimate:  Collecting pairs [limit="
01050         << opts.pair_selection_tolerance << "]." << std::endl;
01051     // use adaptive kd tree to find proximity vertices
01052     moab::EntityHandle tree_root = 0;
01053     moab::AdaptiveKDTree kd(mb);
01054     rval = kd.build_tree(verts, &tree_root);
01055     if (rval != moab::MB_SUCCESS) {
01056       std::cout << "Can't build tree for vertices" << std::endl;
01057       return 1;
01058     }
01059 
01060     for (it = verts.begin(); it != verts.end(); it++) {
01061       moab::Range closeVertices;
01062       closeVertices.clear();
01063       moab::EntityHandle v = *it;
01064       double coords[3];
01065       mb->get_coords(&v, 1, coords);
01066       //moab::CartVect v1(coords);
01067       std::vector<moab::EntityHandle> leaves; // sets of vertices close by
01068       kd.distance_search( coords,
01069           opts.pair_selection_tolerance, leaves);
01070       // add to the list of close vertices
01071       for (j = 0; j < leaves.size(); j++) {
01072         rval = mb->get_entities_by_type(leaves[j], moab::MBVERTEX,
01073             closeVertices);// add to the list
01074       }
01075 
01076       for (moab::Range::iterator it2 = closeVertices.begin(); it2
01077           != closeVertices.end(); it2++) {
01078         moab::EntityHandle vclose = *it2;
01079         if (v == vclose)
01080           continue;
01081         double coords2[3];
01082         mb->get_coords(&vclose, 1, coords2);
01083 
01084         //moab::CartVect v2(coords2);
01085         double dd = (coords[0] - coords2[0]) * (coords[0] - coords2[0])
01086             + (coords[1] - coords2[1]) * (coords[1] - coords2[1]) + (coords[2]
01087             - coords2[2]) * (coords[2] - coords2[2]);
01088 
01089         if (dd > proximity_limit)
01090           continue;
01091 
01092 /*
01093 #ifdef SAFETY
01094         assert ( pair_is_valid ( v1,v2 ) );
01095 #endif
01096 */
01097         if (!check_for_pair(v, vclose)) {
01098           pair_info *pair = new_pair(v, vclose);
01099           compute_pair_info(pair);
01100           pair_count++;
01101         }
01102       }
01103 
01104     }
01105   } else
01106     std::cout << "  Decimate:  Ignoring non-edge pairs [limit=0]." << std::endl;
01107 
01108   std::cout << "  Decimate:  Designated " << pair_count << " pairs."
01109       << std::endl;
01110 
01111   return 0;// no error
01112 }
01113 
01114 } // namespace MeshKit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines