LCOV - code coverage report
Current view: top level - algs/Qslim - QslimDecimation.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 318 534 59.6 %
Date: 2020-07-01 15:24:36 Functions: 22 27 81.5 %
Branches: 305 1120 27.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * QslimDecimation.cpp
       3                 :            :  *
       4                 :            :  *  Created on: Mar 10, 2010
       5                 :            :  *      Author: iulian
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <assert.h>
       9                 :            : #include "QslimDecimation.hpp"
      10                 :            : 
      11                 :            : // for proximity searches
      12                 :            : #include "moab/AdaptiveKDTree.hpp"
      13                 :            : #include "moab/ReadUtilIface.hpp"
      14                 :            : 
      15                 :            : #include "Mat4.h"
      16                 :            : #include "defs.h"
      17                 :            : #include "quadrics.h"
      18                 :            : #include <time.h>
      19                 :            : #include <map>
      20                 :            : #include <limits>
      21                 :            : 
      22                 :            : // those are used in model navigation/simplification
      23                 :            : #include "primitives.h"
      24                 :            : 
      25                 :            : // this is the global thing, that everybody will use
      26                 :            : moab::Interface * mb;
      27                 :            : moab::Tag uniqIDtag; // this will be used to mark vertices moab::EntityHandles
      28                 :            : moab::Tag validTag;
      29                 :            : 
      30                 :            : moab::Tag costTag; // simplification induces an error cost at each vertex
      31                 :            : // try to keep adding the cost, to see if it is spreading nicely
      32                 :            : 
      33                 :            : // this will be used to store plane data for each triangle, as 4 doubles
      34                 :            : // will be updated only if needed ( -m option == opts.will_preserve_mesh_quality)
      35                 :            : moab::Tag planeDataTag;
      36                 :            : 
      37                 :         78 : moab::Range verts; // original list of vertices, that are part of the original triangles
      38                 :         78 : moab::Range triangles;
      39                 :         78 : moab::Range edgs;
      40                 :         78 : QslimOptions opts; // external
      41                 :            : moab::EntityHandle iniSet;
      42                 :            : 
      43                 :     227992 : int uniqID(moab::EntityHandle v) {
      44                 :            :   int val;
      45         [ +  - ]:     227992 :   moab::ErrorCode rval = mb->tag_get_data(uniqIDtag, &v, 1, &val);
      46                 :            :   (void) rval;
      47         [ -  + ]:     227992 :   assert(rval==moab::MB_SUCCESS);
      48                 :     227992 :   return val;
      49                 :            : }
      50                 :            : // the vertices are not deleted anymore, just invalidated
      51                 :            : // the edges are deleted, though, and triangles
      52                 :      44424 : int ehIsValid(moab::EntityHandle v) {
      53                 :            :   unsigned char val;
      54         [ +  - ]:      44424 :   moab::ErrorCode rval = mb->tag_get_data(validTag, &v, 1, &val);
      55                 :            :   (void) rval;
      56         [ -  + ]:      44424 :   assert(rval==moab::MB_SUCCESS);
      57                 :      44424 :   return (int) val;
      58                 :            : }
      59                 :            : 
      60                 :            : // include here the main classes used for decimation
      61                 :            : 
      62                 :            : #include "Heap.hpp"
      63                 :            : // prox grid is used for proximity grid only
      64                 :            : //#include "ProxGrid.h"
      65                 :            : 
      66                 :            : class pair_info: public Heapable {
      67                 :            : public:
      68                 :            :   moab::EntityHandle v0, v1; // Vertex *v0, *v1;
      69                 :            : 
      70                 :            :   Vec3 candidate;
      71                 :            :   double cost;
      72                 :            : 
      73                 :            :   //pair_info ( Vertex *a,Vertex *b ) { v0=a; v1=b; cost=HUGE; }
      74                 :      30400 :   pair_info(moab::EntityHandle a, moab::EntityHandle b) {
      75                 :      15200 :     v0 = a;
      76                 :      15200 :     v1 = b;
      77                 :      15200 :     cost = std::numeric_limits<double>::max();
      78                 :      15200 :   }
      79                 :            : 
      80                 :       1088 :   bool isValid() {
      81 [ +  - ][ +  - ]:       1088 :     return ehIsValid(v0) && ehIsValid(v1);
      82                 :            :   }//  :v0->isValid() && v1->isValid(); }
      83                 :            : };
      84                 :            : 
      85                 :            : typedef buffer<pair_info *> pair_buffer;
      86                 :            : 
      87                 :      10404 : class vert_info {
      88                 :            : public:
      89                 :            : 
      90                 :            :   pair_buffer pairs;
      91                 :            : 
      92                 :            :   Mat4 Q;
      93                 :            :   double norm;
      94                 :            : 
      95                 :       5202 :   vert_info() :
      96         [ +  - ]:       5202 :     Q(Mat4::zero) {
      97         [ +  - ]:       5202 :     pairs.init(2);
      98                 :       5202 :     norm = 0.0;
      99                 :       5202 :   }
     100                 :            : };
     101                 :            : 
     102                 :            : // these are
     103                 :            : static Heap *heap;
     104                 :         78 : static array<vert_info> vinfo;
     105                 :            : static double proximity_limit; // distance threshold squared
     106                 :            : 
     107                 :            : int validFaceCount;
     108                 :            : int validVertCount;
     109                 :            : 
     110                 :            : ////////////////////////////////////////////////////////////////////////
     111                 :            : //
     112                 :            : // Low-level routines for manipulating pairs
     113                 :            : //
     114                 :            : 
     115                 :     227992 : static inline vert_info& vertex_info(moab::EntityHandle v)//Vertex *v )
     116                 :            : {
     117                 :            :   //  moab::EntityHandle should return an integer tag with an
     118                 :            :   //  index in the big array of vert_info
     119                 :            :   //   something like: return tag
     120                 :            :   //   for the time being, we can return the simple id...
     121                 :     227992 :   return vinfo(uniqID(v));
     122                 :            : }
     123                 :            : 
     124                 :            : static
     125                 :       2404 : bool check_for_pair(moab::EntityHandle v0, moab::EntityHandle v1)//Vertex *v0, Vertex *v1 )
     126                 :            : {
     127                 :       2404 :   const pair_buffer& pairs = vertex_info(v0).pairs;
     128                 :            : 
     129         [ +  + ]:      12926 :   for (int i = 0; i < pairs.length(); i++) {
     130 [ +  + ][ +  + ]:      11524 :     if (pairs(i)->v0 == v1 || pairs(i)->v1 == v1)
                 [ +  + ]
     131                 :       1002 :       return true;
     132                 :            :   }
     133                 :            : 
     134                 :       1402 :   return false;
     135                 :            : }
     136                 :            : 
     137                 :      15200 : static pair_info *new_pair(moab::EntityHandle v0, moab::EntityHandle v1)//  Vertex *v0, Vertex *v1 )
     138                 :            : {
     139         [ +  - ]:      15200 :   vert_info& v0_info = vertex_info(v0);
     140         [ +  - ]:      15200 :   vert_info& v1_info = vertex_info(v1);
     141                 :            : 
     142 [ +  - ][ +  - ]:      15200 :   pair_info *pair = new pair_info(v0, v1);
     143         [ +  - ]:      15200 :   v0_info.pairs.add(pair);
     144         [ +  - ]:      15200 :   v1_info.pairs.add(pair);
     145                 :            : 
     146                 :      15200 :   return pair;
     147                 :            : }
     148                 :            : 
     149                 :            : static
     150                 :       1546 : void delete_pair(pair_info *pair) {
     151                 :       1546 :   vert_info& v0_info = vertex_info(pair->v0);
     152                 :       1546 :   vert_info& v1_info = vertex_info(pair->v1);
     153                 :            : 
     154                 :       1546 :   v0_info.pairs.remove(v0_info.pairs.find(pair));
     155                 :       1546 :   v1_info.pairs.remove(v1_info.pairs.find(pair));
     156                 :            : 
     157         [ +  + ]:       1546 :   if (pair->isInHeap())
     158                 :       1002 :     heap->kill(pair->getHeapPos());
     159                 :            : 
     160                 :       1546 :   delete pair;
     161                 :       1546 : }
     162                 :            : 
     163                 :            : ////////////////////////////////////////////////////////////////////////
     164                 :            : //
     165                 :            : // The actual guts of the algorithm:
     166                 :            : //
     167                 :            : //     - pair_is_valid
     168                 :            : //     - compute_pair_info
     169                 :            : //     - do_contract
     170                 :            : //
     171                 :            : /*
     172                 :            : static
     173                 :            : bool pair_is_valid(moab::EntityHandle u, moab::EntityHandle v)// Vertex *u, Vertex *v )
     174                 :            : {
     175                 :            :   //
     176                 :            :   Vec3 vu = getVec3FromMBVertex(mb, u);
     177                 :            :   Vec3 vv = getVec3FromMBVertex(mb, v);
     178                 :            :   return norm2(vu - vv) < proximity_limit;
     179                 :            :   //return  norm2 ( *u - *v ) < proximity_limit;
     180                 :            : }*/
     181                 :            : 
     182                 :            : static
     183                 :     556758 : int predict_face(moab::EntityHandle tria, moab::EntityHandle v1,
     184                 :            :     moab::EntityHandle v2, /*Face& F, Vertex *v1, Vertex *v2,*/
     185                 :            :     Vec3& vnew, Vec3& f1, Vec3& f2, Vec3& f3) {
     186                 :     556758 :   int nmapped = 0;
     187                 :            :   const moab::EntityHandle * conn;
     188                 :            :   int num_nodes;
     189         [ +  - ]:     556758 :   moab::ErrorCode rval = mb->get_connectivity(tria, conn, num_nodes);
     190                 :            :   (void) rval;
     191 [ +  - ][ -  + ]:     556758 :   assert(3==num_nodes && rval == moab::MB_SUCCESS);
     192 [ +  + ][ +  + ]:     556758 :   if (conn[0] == v1 || conn[0] == v2) {
     193         [ +  - ]:     220630 :     f1 = vnew;
     194                 :     220630 :     nmapped++;
     195                 :            :   } else
     196 [ +  - ][ +  - ]:     336128 :     f1 = getVec3FromMBVertex(mb, conn[0]);
     197                 :            : 
     198 [ +  + ][ +  + ]:     556758 :   if (conn[1] == v1 || conn[1] == v2) {
     199         [ +  - ]:     219620 :     f2 = vnew;
     200                 :     219620 :     nmapped++;
     201                 :            :   } else
     202 [ +  - ][ +  - ]:     337138 :     f2 = getVec3FromMBVertex(mb, conn[1]);
     203                 :            : 
     204 [ +  + ][ +  + ]:     556758 :   if (conn[2] == v1 || conn[2] == v2) {
     205         [ +  - ]:     227508 :     f3 = vnew;
     206                 :     227508 :     nmapped++;
     207                 :            :   } else
     208 [ +  - ][ +  - ]:     329250 :     f3 = getVec3FromMBVertex(mb, conn[2]);
     209                 :            : 
     210                 :            :   // find vertices in face tria
     211                 :            :   /*
     212                 :            :    if ( F.vertex ( 0 ) == v1 || F.vertex ( 0 ) == v2 )
     213                 :            :    { f1 = vnew;  nmapped++; }
     214                 :            :    else f1 = *F.vertex ( 0 );
     215                 :            : 
     216                 :            :    if ( F.vertex ( 1 ) == v1 || F.vertex ( 1 ) == v2 )
     217                 :            :    { f2 = vnew;  nmapped++; }
     218                 :            :    else f2 = *F.vertex ( 1 );
     219                 :            : 
     220                 :            :    if ( F.vertex ( 2 ) == v1 || F.vertex ( 2 ) == v2 )
     221                 :            :    { f3 = vnew;  nmapped++; }
     222                 :            :    else f3 = *F.vertex ( 2 );
     223                 :            :    */
     224                 :     556758 :   return nmapped;
     225                 :            : }
     226                 :            : 
     227                 :            : #define MESH_INVERSION_PENALTY 1e9
     228                 :            : 
     229                 :            : static
     230                 :      60616 : double pair_mesh_positivity(/* Model& M,*/moab::EntityHandle v1,
     231                 :            :     moab::EntityHandle v2, /*Vertex *v1, Vertex *v2,*/
     232                 :            :     Vec3& vnew) {
     233         [ +  - ]:      60616 :   std::vector<moab::EntityHandle> changed;
     234                 :            : 
     235                 :            :   // :  construct the list of faces influenced by the
     236                 :            :   //   moving of vertices v1 and v2 into vnew
     237                 :            :   //M.contractionRegion ( v1, v2, changed );
     238         [ +  - ]:      60616 :   moab::ErrorCode rval = contractionRegion(mb, v1, v2, changed);
     239         [ -  + ]:      60616 :   if (rval != moab::MB_SUCCESS) {
     240         [ #  # ]:          0 :     std::cout << "error in getting adjacency information vs: "
     241 [ #  # ][ #  # ]:          0 :         << mb->id_from_handle(v1) << " " << mb->id_from_handle(v2) << "\n";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     242                 :            :   }
     243                 :            : 
     244                 :            :   // double Nsum = 0;
     245 [ -  + ][ #  # ]:      60616 :   if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
     246 [ #  # ][ #  # ]:          0 :     *opts.logfile << " positivity for v1, v2: " << mb->id_from_handle(v1)
                 [ #  # ]
     247 [ #  # ][ #  # ]:          0 :         << " " << mb->id_from_handle(v2) << std::endl;
         [ #  # ][ #  # ]
     248                 :            : 
     249         [ +  + ]:     609338 :   for (unsigned int i = 0; i < changed.size(); i++) {
     250                 :            :     //Face& F = *changed ( i );
     251         [ +  - ]:     556758 :     moab::EntityHandle F = changed[i];
     252 [ +  - ][ +  - ]:     556758 :     Vec3 f1, f2, f3;
                 [ +  - ]
     253                 :            : 
     254         [ +  - ]:     556758 :     int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3);
     255                 :            : 
     256                 :            :     //
     257                 :            :     // Only consider non-degenerate faces
     258         [ +  + ]:     556758 :     if (nmapped < 2) {
     259                 :            :       //Plane Pnew ( f1, f2, f3 );
     260                 :            : #if 0
     261                 :            :       Vec3 normalNew = Pnew.normal();
     262                 :            :       if ( normalNew[Z] < positivityMin )
     263                 :            :       positivityMin=normalNew[Z]; // Z direction!!!
     264                 :            :       if (opts.logfile && opts.selected_output&OUTPUT_CONTRACTIONS )
     265                 :            :       *opts.logfile << "Triangle " << mb->id_from_handle(F)
     266                 :            :       << " nmapped " << nmapped << std::endl;
     267                 :            :       if (opts.logfile && positivityMin<=0 && opts.selected_output&OUTPUT_CONTRACTIONS )
     268                 :            :       *opts.logfile << "Triangle " << mb->id_from_handle(F)
     269                 :            :       << " normal Z:" << normalNew[Z] << std::endl;
     270                 :            : #endif
     271 [ +  - ][ +  - ]:     445758 :       double positiv = (f2[0] - f1[0]) * (f3[1] - f1[1]) - (f2[1] - f1[1])
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     272 [ +  - ][ +  - ]:     445758 :           * (f3[0] - f1[0]);
     273         [ +  + ]:     445758 :       if (positiv <= 0) {
     274 [ -  + ][ #  # ]:       8036 :         if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
     275 [ #  # ][ #  # ]:          0 :           *opts.logfile << "Triangle " << mb->id_from_handle(F) << " nmapped "
         [ #  # ][ #  # ]
     276 [ #  # ][ #  # ]:          0 :               << nmapped << " orient: " << positiv << std::endl;
         [ #  # ][ #  # ]
     277                 :     445758 :         return MESH_INVERSION_PENALTY * 10;
     278                 :            :       }
     279                 :            :     }
     280                 :            :   }
     281                 :            : 
     282                 :            :   //return (-Nmin) * MESH_INVERSION_PENALTY;
     283                 :            : 
     284                 :      60616 :   return 0.0;
     285                 :            : }
     286                 :            : 
     287                 :            : // will make sure that no hole would be closed
     288                 :            : /*
     289                 :            :  * will accomplish that by looking at the edges connected to both vertices
     290                 :            :  * if there would be edges that would merge without a connecting triangle,
     291                 :            :  * it would increase the cost (penalize it harshly)
     292                 :            :  */
     293                 :          0 : static double pair_mesh_topology(moab::EntityHandle v1, moab::EntityHandle v2)
     294                 :            : {
     295                 :            :   // first, find nodes v3 that are connected to both v1 and v2 by edges
     296                 :            :   // if there is no triangle that is formed with v1, v2, v3, it means it would
     297                 :            :   //  collapse a hole
     298 [ #  # ][ #  # ]:          0 :   std::vector<moab::EntityHandle> edges1, edges2;
     299 [ #  # ][ #  # ]:          0 :   moab::Range nodes1, nodes2;
     300         [ #  # ]:          0 :   moab::ErrorCode rval = mb->get_adjacencies(&v1, 1, 1, false, edges1);
     301         [ #  # ]:          0 :   assert (moab::MB_SUCCESS == rval);
     302         [ #  # ]:          0 :   filterValid(mb, edges1);
     303         [ #  # ]:          0 :   rval = mb->get_adjacencies(&v2, 1, 1, false, edges2);
     304         [ #  # ]:          0 :   assert (moab::MB_SUCCESS == rval);
     305         [ #  # ]:          0 :   filterValid(mb, edges2);
     306 [ #  # ][ #  # ]:          0 :   rval = mb->get_connectivity(&edges1[0], edges1.size(), nodes1);
     307         [ #  # ]:          0 :   assert (moab::MB_SUCCESS == rval);
     308 [ #  # ][ #  # ]:          0 :   rval = mb->get_connectivity(&edges2[0], edges2.size(), nodes2);
     309         [ #  # ]:          0 :   assert (moab::MB_SUCCESS == rval);
     310         [ #  # ]:          0 :   moab::Range commonV=intersect (nodes1, nodes2);
     311         [ #  # ]:          0 :   moab::Range v12;
     312 [ #  # ][ #  # ]:          0 :   v12.insert(v1); v12.insert(v2);
     313         [ #  # ]:          0 :   moab::Range leftOver = subtract(commonV, v12);
     314 [ #  # ][ #  # ]:          0 :   for (moab::Range::iterator it = leftOver.begin(); it!=leftOver.end(); it++)
         [ #  # ][ #  # ]
                 [ #  # ]
     315                 :            :   {
     316         [ #  # ]:          0 :     moab::EntityHandle thirdNode = *it;
     317 [ #  # ][ #  # ]:          0 :     if (!ehIsValid(thirdNode))
     318                 :          0 :       continue;
     319                 :            :     // the moment we find a triple v1, v2, thirdNode that is not a triangle, return penalty
     320         [ #  # ]:          0 :     moab::Range triple=v12;
     321         [ #  # ]:          0 :     triple.insert(thirdNode);
     322 [ #  # ][ #  # ]:          0 :     moab::Range connTris;
     323         [ #  # ]:          0 :     rval = mb->get_adjacencies(triple, 2, false, connTris );
     324         [ #  # ]:          0 :     if (moab::MB_SUCCESS == rval)
     325                 :            :     {
     326 [ #  # ][ #  # ]:          0 :       if (connTris.empty())
     327                 :          0 :         return MESH_INVERSION_PENALTY; // this means that there are no
     328                 :            :                                        /// triangles connected to the 3 nodes
     329                 :            :                                        // so it would close a hole/tunnel
     330                 :            : 
     331                 :          0 :       int noValidTris = 0;
     332 [ #  # ][ #  # ]:          0 :       for (moab::Range::iterator it2 = connTris.begin(); it2!=connTris.end(); it2++)
         [ #  # ][ #  # ]
                 [ #  # ]
     333                 :            :       {
     334 [ #  # ][ #  # ]:          0 :         if (ehIsValid(*it2))
                 [ #  # ]
     335                 :            :         {
     336                 :          0 :           noValidTris++;
     337                 :          0 :           break;
     338                 :            :         }
     339                 :            :       }
     340         [ #  # ]:          0 :       if (0==noValidTris)
     341         [ #  # ]:          0 :         return MESH_INVERSION_PENALTY; // this means that there are no
     342                 :            :                                        // triangles connected to the 3 nodes
     343                 :            :                                        // so it would close a hole/tunnel
     344                 :            : 
     345                 :            :     }
     346                 :            : 
     347                 :          0 :   }
     348                 :          0 :   return 0.; // no penalty
     349                 :            : }
     350                 :            : static
     351                 :          0 : double pair_mesh_penalty( /*Model& M, Vertex *v1, Vertex *v2,*/
     352                 :            : moab::EntityHandle v1, moab::EntityHandle v2, Vec3& vnew) {
     353         [ #  # ]:          0 :   std::vector<moab::EntityHandle> changed;
     354                 :            : 
     355                 :            :   //   construct the list of faces influenced by the
     356                 :            :   //   moving of vertices v1 and v2 into vnew
     357                 :            :   //M.contractionRegion ( v1, v2, changed );
     358         [ #  # ]:          0 :   moab::ErrorCode rval = contractionRegion(mb, v1, v2, changed);
     359         [ #  # ]:          0 :   if (rval != moab::MB_SUCCESS) {
     360         [ #  # ]:          0 :     std::cout << "error in getting adjacency information vs: "
     361 [ #  # ][ #  # ]:          0 :         << mb->id_from_handle(v1) << " " << mb->id_from_handle(v2) << "\n";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     362                 :            :   }
     363                 :            : 
     364                 :            :   // double Nsum = 0;
     365                 :          0 :   double Nmin = 0;
     366                 :            : 
     367         [ #  # ]:          0 :   for (unsigned int i = 0; i < changed.size(); i++) {
     368                 :            :     //Face& F = *changed ( i );
     369         [ #  # ]:          0 :     moab::EntityHandle F = changed[i];
     370 [ #  # ][ #  # ]:          0 :     Vec3 f1, f2, f3;
                 [ #  # ]
     371                 :            : 
     372         [ #  # ]:          0 :     int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3);
     373                 :            :     //
     374                 :            :     // Only consider non-degenerate faces
     375         [ #  # ]:          0 :     if (nmapped < 2) {
     376         [ #  # ]:          0 :       Plane Pnew(f1, f2, f3);
     377         [ #  # ]:          0 :       Plane p = trianglePlane(mb, F);
     378 [ #  # ][ #  # ]:          0 :       double delta = Pnew.normal() * p.normal(); //  Pnew.normal() * F.plane().normal();
                 [ #  # ]
     379                 :            : 
     380         [ #  # ]:          0 :       if (Nmin > delta)
     381                 :          0 :         Nmin = delta;
     382                 :            :     }
     383                 :            :   }
     384                 :            : 
     385                 :            :   //return (-Nmin) * MESH_INVERSION_PENALTY;
     386         [ #  # ]:          0 :   if (Nmin < 0.0)
     387                 :          0 :     return MESH_INVERSION_PENALTY;
     388                 :            :   else
     389                 :          0 :     return 0.0;
     390                 :            : }
     391                 :            : 
     392                 :            : static
     393                 :      60616 : void compute_pair_info(pair_info *pair /* Model * pM0,*/) {
     394                 :      60616 :   moab::EntityHandle v0 = pair->v0;
     395                 :      60616 :   moab::EntityHandle v1 = pair->v1;
     396                 :            : 
     397                 :            :   // Vertex *v0 = pair->v0;
     398                 :            :   // Vertex *v1 = pair->v1;
     399                 :            : 
     400         [ +  - ]:      60616 :   vert_info& v0_info = vertex_info(v0);
     401         [ +  - ]:      60616 :   vert_info& v1_info = vertex_info(v1);
     402                 :            : 
     403         [ +  - ]:      60616 :   Mat4 Q = v0_info.Q + v1_info.Q;
     404                 :      60616 :   double norm = v0_info.norm + v1_info.norm;
     405                 :            : 
     406         [ +  - ]:      60616 :   pair->cost = quadrix_pair_target(Q, v0, v1, pair->candidate);
     407                 :            : 
     408         [ -  + ]:      60616 :   if (opts.will_weight_by_area)
     409                 :          0 :     pair->cost /= norm;
     410                 :            : 
     411         [ -  + ]:      60616 :   if (opts.will_preserve_mesh_quality)
     412         [ #  # ]:          0 :     pair->cost += pair_mesh_penalty(/* *pM0,*/v0, v1, pair->candidate);
     413                 :            : 
     414         [ +  - ]:      60616 :   if (opts.height_fields)
     415         [ +  - ]:      60616 :     pair->cost += pair_mesh_positivity(/* *pM0, */v0, v1, pair->candidate);
     416                 :            : 
     417         [ -  + ]:      60616 :   if (opts.topology)
     418         [ #  # ]:          0 :     pair->cost += pair_mesh_topology(v0, v1);
     419                 :            : 
     420 [ -  + ][ #  # ]:      60616 :   if (opts.logfile && opts.selected_output & OUTPUT_CONTRACTIONS)
     421                 :            : 
     422 [ #  # ][ #  # ]:          0 :     *opts.logfile << "pair ( v" << mb->id_from_handle(v0) << " v"
         [ #  # ][ #  # ]
     423 [ #  # ][ #  # ]:          0 :         << mb->id_from_handle(v1) << " ) cost: " << -pair->cost << std::endl;
         [ #  # ][ #  # ]
                 [ #  # ]
     424                 :            :   //
     425                 :            :   // NOTICE:  In the heap we use the negative cost.  That's because
     426                 :            :   //          the heap is implemented as a MAX heap.
     427                 :            :   //
     428 [ +  - ][ +  + ]:      60616 :   if (pair->isInHeap()) {
     429         [ +  - ]:      45416 :     heap->update(pair, -pair->cost);
     430                 :            :   } else {
     431         [ +  - ]:      15200 :     heap->insert(pair, -pair->cost);
     432                 :            :   }
     433 [ -  + ][ #  # ]:      60616 :   if (opts.logfile && opts.selected_output & OUTPUT_COST) {
     434         [ #  # ]:          0 :     heap_node *top = heap->top();
     435                 :          0 :     pair_info *pairTop = (pair_info *) top->obj;
     436 [ #  # ][ #  # ]:          0 :     *opts.logfile << " i/u pair (" << uniqID(pair->v0) << "," << uniqID(
         [ #  # ][ #  # ]
     437 [ #  # ][ #  # ]:          0 :         pair->v1) << ")=" << pair->cost << "  min : (" << uniqID(pairTop->v0)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     438 [ #  # ][ #  # ]:          0 :         << "," << uniqID(pairTop->v1) << ") " << pairTop->cost << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     439                 :            :   }
     440                 :      60616 : }
     441                 :        544 : void recomputeChangedPairsCost(std::vector<moab::EntityHandle> & changed, moab::EntityHandle v0) {
     442                 :            :   //
     443         [ +  + ]:       5032 :   for (unsigned int i = 0; i < changed.size(); i++) {
     444                 :            : 
     445         [ +  - ]:       4488 :     moab::EntityHandle F = changed[i];
     446                 :            :     const moab::EntityHandle * conn;
     447                 :            :     int num_nodes;
     448         [ +  - ]:       4488 :     mb->get_connectivity(F, conn, num_nodes);
     449                 :            :     //if (!F->isValid())
     450                 :            :     //   continue;
     451                 :            :     // recompute the pair that is not connected to vertex v0
     452                 :            :     // loop over all the vertices of F that are not v0, and recompute the costs
     453                 :            :     // of all the pairs associated  that do not contain v0
     454                 :            :     // we do not have to recreate or delete any pair, we just recompute what we have
     455                 :            :     // some will be recomputed 2 times, but it is OK
     456         [ +  + ]:      17952 :     for (int k = 0; k < 3; k++) {
     457                 :      13464 :       moab::EntityHandle v = conn[k];
     458         [ +  + ]:      13464 :       if (v == v0)
     459                 :       4488 :         continue;
     460         [ +  - ]:       8976 :       vert_info & v_info = vertex_info(v);
     461 [ +  - ][ +  + ]:      58558 :       for (int j = 0; j < v_info.pairs.length(); j++) {
     462         [ +  - ]:      49582 :         pair_info *p = v_info.pairs(j);
     463 [ +  + ][ +  + ]:      49582 :         if (p->v0 == v0 || p->v1 == v0)
     464                 :       8976 :           continue; // do not recompute cost of pairs already computed
     465 [ -  + ][ #  # ]:      40606 :         if (opts.logfile && (opts.selected_output & OUTPUT_COST))
     466 [ #  # ][ #  # ]:          0 :           *opts.logfile << "recompute cost of pair (v" << uniqID(p->v0) + 1
                 [ #  # ]
     467 [ #  # ][ #  # ]:          0 :               << " v" << uniqID(p->v1) + 1 << ")" << std::endl;
         [ #  # ][ #  # ]
                 [ #  # ]
     468         [ +  - ]:      40606 :         compute_pair_info(p);
     469                 :            :       }
     470                 :            : 
     471                 :            :     }
     472                 :            : 
     473                 :            :   }
     474                 :        544 : }
     475                 :            : 
     476                 :            : static
     477                 :        544 : void do_contract(pair_info *pair) {
     478                 :            : 
     479                 :        544 :   moab::EntityHandle v0 = pair->v0;
     480                 :        544 :   moab::EntityHandle v1 = pair->v1;
     481                 :            :   // cost of contraction is accumulated at v0
     482                 :        544 :   double costToContract = pair->cost;
     483         [ +  - ]:        544 :   vert_info& v0_info = vertex_info(v0);
     484         [ +  - ]:        544 :   vert_info& v1_info = vertex_info(v1);
     485         [ +  - ]:        544 :   Vec3 vnew = pair->candidate;
     486 [ -  + ][ #  # ]:        544 :   if (opts.logfile && (opts.selected_output & OUTPUT_COST)) {
     487 [ #  # ][ #  # ]:          0 :     *opts.logfile << "---- do contract v0:" << uniqID(v0) + 1 << " v1:"
         [ #  # ][ #  # ]
     488 [ #  # ][ #  # ]:          0 :         << uniqID(v1) + 1 << std::endl;
                 [ #  # ]
     489                 :            :   }
     490                 :            :   int i;
     491                 :            : 
     492                 :            :   //
     493                 :            :   // Make v0 be the new vertex
     494         [ +  - ]:        544 :   v0_info.Q += v1_info.Q;
     495                 :        544 :   v0_info.norm += v1_info.norm;
     496                 :            : 
     497                 :            :   //
     498                 :            :   // Perform the actual contraction
     499         [ +  - ]:        544 :   std::vector<moab::EntityHandle> changed;
     500         [ +  - ]:        544 :   moab::ErrorCode rval1 = contract(mb, v0, v1, vnew, changed);
     501                 :            :   (void) rval1;
     502                 :            :   // this is a list of triangles still connected to v0 (are they valid? probably)
     503         [ -  + ]:        544 :   if (opts.will_preserve_mesh_quality) {
     504                 :            :     // recompute normals only in this case, because they are not needed otherwise
     505                 :          0 :     int size = changed.size();
     506         [ #  # ]:          0 :     for (int i = 0; i < size; i++) {
     507 [ #  # ][ #  # ]:          0 :       computeTrianglePlane(mb, changed[i]);
     508                 :            :     }
     509                 :            :   }
     510 [ -  + ][ #  # ]:        544 :   assert (moab::MB_SUCCESS == rval1 || moab::MB_MULTIPLE_ENTITIES_FOUND == rval1);
     511                 :            : 
     512                 :            : #ifdef SUPPORT_VCOLOR
     513                 :            :   //
     514                 :            :   // If the vertices are colored, color the new vertex
     515                 :            :   // using the average of the old colors.
     516                 :            :   v0->props->color += v1->props->color;
     517                 :            :   v0->props->color /= 2;
     518                 :            : #endif
     519                 :            : 
     520                 :            :   //
     521                 :            :   // Remove the pair that we just contracted
     522         [ +  - ]:        544 :   delete_pair(pair);
     523                 :            :   //
     524                 :            :   // Recalculate pairs associated with v0
     525 [ +  - ][ +  + ]:       3952 :   for (i = 0; i < v0_info.pairs.length(); i++) {
     526         [ +  - ]:       3408 :     pair_info *p = v0_info.pairs(i);
     527         [ +  - ]:       3408 :     compute_pair_info(p);
     528                 :            :   }
     529                 :            : 
     530                 :            :   //
     531                 :            :   // Process pairs associated with now dead vertex
     532                 :            : 
     533 [ +  + ][ +  - ]:        544 :   static pair_buffer condemned(6); // collect condemned pairs for execution
         [ +  - ][ #  # ]
     534         [ +  - ]:        544 :   condemned.reset();
     535                 :            : 
     536 [ +  - ][ +  + ]:       2948 :   for (i = 0; i < v1_info.pairs.length(); i++) {
     537         [ +  - ]:       2404 :     pair_info *p = v1_info.pairs(i);
     538                 :            : 
     539                 :       2404 :     moab::EntityHandle u = 0L;
     540         [ +  + ]:       2404 :     if (p->v0 == v1)
     541                 :       1390 :       u = p->v1;
     542         [ +  - ]:       1014 :     else if (p->v1 == v1)
     543                 :       1014 :       u = p->v0;
     544                 :            :     else
     545 [ #  # ][ #  # ]:          0 :       std::cerr << "YOW!  This is a bogus pair." << std::endl;
     546                 :            : 
     547 [ +  - ][ +  + ]:       2404 :     if (!check_for_pair(u, v0)) {
     548                 :       1402 :       p->v0 = v0;
     549                 :       1402 :       p->v1 = u;
     550         [ +  - ]:       1402 :       v0_info.pairs.add(p);
     551         [ +  - ]:       1402 :       compute_pair_info(p);
     552                 :            :     } else
     553         [ +  - ]:       1002 :       condemned.add(p);
     554                 :            :   }
     555                 :            : 
     556 [ +  - ][ +  + ]:       1546 :   for (i = 0; i < condemned.length(); i++)
     557                 :            :     // Do you have any last requests?
     558 [ +  - ][ +  - ]:       1002 :     delete_pair(condemned(i));
     559                 :            :   // only now you can delete the vertex v1 from database
     560                 :            :   // moab::ErrorCode rval = mb->delete_entities(&v1, 1);
     561                 :            :   // no, it is better to invalidate the vertex, do not delete it
     562                 :            :   // maybe we will delete at the end all that are invalid ??
     563                 :        544 :   int invalid = 0;
     564         [ +  - ]:        544 :   moab::ErrorCode rval = mb->tag_set_data(validTag, &v1, 1, &invalid);
     565                 :            :   (void) rval;
     566         [ -  + ]:        544 :   assert (moab::MB_SUCCESS == rval);
     567                 :            : 
     568         [ -  + ]:        544 :   if (opts.plotCost) {
     569                 :          0 :     double cost_at_v0 = 0; // maybe it is already set before
     570         [ #  # ]:          0 :     rval = mb->tag_get_data(costTag, &v0, 1, &cost_at_v0);
     571                 :          0 :     cost_at_v0 += costToContract;
     572         [ #  # ]:          0 :     rval = mb->tag_set_data(costTag, &v0, 1, &cost_at_v0);
     573                 :            :   }
     574                 :            : 
     575         [ +  - ]:        544 :   v1_info.pairs.reset(); // safety precaution
     576         [ +  - ]:        544 :   recomputeChangedPairsCost(changed, v0);
     577                 :            : 
     578                 :        544 : }
     579                 :            : 
     580                 :            : ////////////////////////////////////////////////////////////////////////
     581                 :            : //
     582                 :            : // External interface: setup and single step iteration
     583                 :            : //
     584                 :            : 
     585                 :          0 : bool decimate_quadric(moab::EntityHandle v, Mat4& Q) {
     586         [ #  # ]:          0 :   if (vinfo.length() > 0) {
     587                 :          0 :     vert_info & vinf = vertex_info(v);
     588                 :          0 :     Q = vinf.Q;
     589                 :          0 :     return true;
     590                 :            :   } else
     591                 :          0 :     return false;
     592                 :            : }
     593                 :            : 
     594                 :            : // it is assumed it is mb, moab interface
     595                 :        544 : void decimate_contract() {
     596                 :            :   heap_node *top;
     597                 :            :   pair_info *pair;
     598                 :            : 
     599                 :            :   for (;;) {
     600                 :        544 :     top = heap->extract();
     601         [ -  + ]:        544 :     if (!top)
     602                 :          0 :       return;
     603                 :        544 :     pair = (pair_info *) top->obj;
     604                 :            : 
     605                 :            :     //
     606                 :            :     // This may or may not be necessary.  I'm just not quite
     607                 :            :     // willing to assume that all the junk has been removed from the
     608                 :            :     // heap.
     609         [ +  - ]:        544 :     if (pair->isValid())
     610                 :        544 :       break;
     611                 :            : 
     612                 :          0 :     delete_pair(pair);
     613                 :            :   }
     614                 :            : 
     615 [ -  + ][ #  # ]:        544 :   if (opts.logfile && (opts.selected_output & OUTPUT_COST))
     616                 :          0 :     *opts.logfile << "#$cost " << validFaceCount << " before contract: "
     617                 :          0 :         << pair->cost << std::endl;
     618                 :            : 
     619                 :        544 :   do_contract(pair);
     620                 :            : 
     621 [ -  + ][ #  # ]:        544 :   if (opts.logfile && (opts.selected_output & OUTPUT_COST))
     622                 :          0 :     *opts.logfile << "#$cost " << validFaceCount << std::endl;
     623                 :            : 
     624                 :        544 :   validVertCount--; // Attempt to maintain valid vertex information
     625                 :            : }
     626                 :            : 
     627                 :          0 : double decimate_error(moab::EntityHandle v) {
     628                 :          0 :   vert_info& info = vertex_info(v);
     629                 :            : 
     630         [ #  # ]:          0 :   double err = quadrix_evaluate_vertex(v, info.Q);
     631                 :            : 
     632         [ #  # ]:          0 :   if (opts.will_weight_by_area)
     633                 :          0 :     err /= info.norm;
     634                 :            : 
     635                 :          0 :   return err;
     636                 :            : }
     637                 :            : 
     638                 :        544 : double decimate_min_error() {
     639                 :            :   heap_node *top;
     640                 :            :   pair_info *pair;
     641                 :            : 
     642                 :            :   for (;;) {
     643                 :        544 :     top = heap->top();
     644         [ -  + ]:        544 :     if (!top)
     645                 :          0 :       return -1.0;
     646                 :        544 :     pair = (pair_info *) top->obj;
     647                 :            : 
     648         [ +  - ]:        544 :     if (pair->isValid())
     649                 :        544 :       break;
     650                 :            : 
     651                 :          0 :     top = heap->extract();
     652                 :          0 :     delete_pair(pair);
     653                 :            :   }
     654                 :            : 
     655                 :        544 :   return pair->cost;
     656                 :            : }
     657                 :            : #if 0
     658                 :            : double decimate_max_error ( )
     659                 :            : {
     660                 :            :   real max_err = 0;
     661                 :            : 
     662                 :            :   for ( int i=0; i<m.vertCount(); i++ )
     663                 :            :   if ( m.vertex ( i )->isValid() )
     664                 :            :   {
     665                 :            :     max_err = MAX ( max_err, decimate_error ( m.vertex ( i ) ) );
     666                 :            :   }
     667                 :            : 
     668                 :            :   return max_err;
     669                 :            : }
     670                 :            : #endif
     671                 :            : namespace MeshKit {
     672                 :            : 
     673                 :          2 : QslimDecimation::QslimDecimation(moab::Interface * mbi,
     674                 :          2 :     moab::EntityHandle root_set) {
     675                 :          2 :   _mb = mbi;
     676                 :          2 :   iniSet = root_set;// it is not necessarily the root set; this is external; bad design
     677                 :          2 : }
     678                 :            : 
     679                 :          0 : QslimDecimation::~QslimDecimation() {
     680         [ #  # ]:          0 : }
     681                 :          2 : int QslimDecimation::decimate(QslimOptions & iOpts, moab::Range & oRange) {
     682                 :            :   // opts is external
     683                 :          2 :   opts = iOpts;
     684                 :            : 
     685                 :          2 :   mb = _mb; // (reinterpret_cast<MBiMesh *> (m_mesh))->mbImpl;
     686                 :            :   // need to get all the triangles from the set
     687                 :            :   // also all the edges, and all vertices
     688                 :            :   // not  a good design here; mb is extern !
     689                 :            :   //
     690         [ -  + ]:          2 :   if (NULL == mb)
     691                 :          0 :     return 1;// error
     692                 :            :   //moab::EntityHandle mbSet = reinterpret_cast<moab::EntityHandle>(m_InitialSet);
     693                 :            : 
     694                 :          2 :   clock_t start_time = clock();
     695                 :          2 :   int err = Init();
     696         [ -  + ]:          2 :   if (err) {
     697                 :          0 :     std::cerr << "Error in initialization of decimation. Abort\n";
     698                 :          0 :     return 1;
     699                 :            :   }
     700                 :          2 :   clock_t init_time = clock();
     701                 :          2 :   std::cout << "   Initialization  " << (double) (init_time - start_time)
     702                 :          2 :       / CLOCKS_PER_SEC << " s.\n";
     703                 :            : 
     704                 :          2 :   int faces_reduction = validFaceCount - opts.face_target;
     705                 :          2 :   int counter = 0, interval = 0;
     706                 :          2 :   clock_t currentTime = init_time;
     707 [ +  + ][ +  - ]:        546 :   while (validFaceCount > opts.face_target && decimate_min_error()
                 [ +  + ]
     708                 :        544 :       < opts.error_tolerance) {
     709                 :        544 :     int initf = validFaceCount;
     710                 :            :     // big routine
     711                 :        544 :     decimate_contract();
     712                 :        544 :     counter += (initf - validFaceCount);
     713         [ +  + ]:        544 :     if (counter > faces_reduction / opts.timingIntervals) {
     714                 :            :       // print some time stats
     715                 :         18 :       clock_t p10_time = clock();
     716                 :         18 :       std::cout << "     " << ++interval << "/" << opts.timingIntervals
     717                 :         18 :           << " reduce to " << validFaceCount << " faces in "
     718                 :         18 :           << (double) (p10_time - currentTime) / CLOCKS_PER_SEC << " s, total:"
     719                 :         18 :           << (double) (p10_time - init_time) / CLOCKS_PER_SEC << " s.\n";
     720                 :         18 :       counter = 0;
     721                 :         18 :       currentTime = p10_time;
     722                 :            :     }
     723                 :            :   }
     724                 :            : 
     725                 :          2 :   clock_t finish_time = clock();
     726                 :          2 :   std::cout << "   Decimation: " << (double) (finish_time - init_time)
     727                 :          2 :       / CLOCKS_PER_SEC << " s.\n";
     728                 :            : 
     729         [ -  + ]:          2 :   if (opts.create_range) {
     730                 :            :     // the remaining nodes and triangles are copied in the range
     731                 :            :     // they are put in the old set, too
     732                 :            :     // maybe this has to change
     733                 :            :     // count first valid vertices and triangles
     734         [ #  # ]:          0 :     moab::Range::iterator it;
     735         [ #  # ]:          0 :     std::vector<moab::EntityHandle> validVerts;
     736         [ #  # ]:          0 :     std::vector<moab::EntityHandle> validTris;
     737 [ #  # ][ #  # ]:          0 :     for (it = triangles.begin(); it != triangles.end(); it++) {
         [ #  # ][ #  # ]
                 [ #  # ]
     738 [ #  # ][ #  # ]:          0 :       if (ehIsValid(*it))
                 [ #  # ]
     739 [ #  # ][ #  # ]:          0 :         validTris.push_back(*it);
     740                 :            :     }
     741 [ #  # ][ #  # ]:          0 :     for (it = verts.begin(); it != verts.end(); it++) {
         [ #  # ][ #  # ]
                 [ #  # ]
     742 [ #  # ][ #  # ]:          0 :       if (ehIsValid(*it))
                 [ #  # ]
     743 [ #  # ][ #  # ]:          0 :         validVerts.push_back(*it);
     744                 :            :     }
     745                 :            :     //
     746         [ #  # ]:          0 :     std::vector<double> coords;
     747                 :          0 :     int numNodes = (int) validVerts.size();
     748                 :          0 :     int numTriangles = (int) validTris.size();
     749         [ #  # ]:          0 :     coords.resize(3 * numNodes);
     750                 :            : 
     751         [ #  # ]:          0 :     moab::ErrorCode rval = mb->get_coords(&(validVerts[0]), numNodes,
     752 [ #  # ][ #  # ]:          0 :         &(coords[0]));
     753                 :            :     (void) rval;
     754         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     755                 :            : 
     756                 :            :     // create the new vertices, at the same  coordinates
     757                 :            :     // put those verts in the range that is output
     758                 :            : 
     759                 :            :     // to make sure, the range is cleared
     760         [ #  # ]:          0 :     oRange.clear();
     761 [ #  # ][ #  # ]:          0 :     rval = mb->create_vertices(&coords[0], numNodes, oRange);
     762         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     763                 :            :     // the first element in the range must be the start of the new vertex sequence
     764         [ #  # ]:          0 :     std::map<moab::EntityHandle, moab::EntityHandle> mapping; // this will be from old
     765                 :            :     //  to new vertices, for connectivity
     766         [ #  # ]:          0 :     for (int i = 0; i < numNodes; i++) {
     767 [ #  # ][ #  # ]:          0 :       mapping[validVerts[i]] = oRange[i];
                 [ #  # ]
     768                 :            :     }
     769                 :            : 
     770                 :            :     //get the query interface, which we will use to create the triangles directly
     771                 :            :     moab::ReadUtilIface *iface;
     772         [ #  # ]:          0 :     rval = mb -> query_interface(iface);// use the new query interface
     773         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     774                 :            : 
     775                 :            :     //create the triangles, get a direct ptr to connectivity
     776                 :            :     moab::EntityHandle starth, *connect;
     777                 :            :     rval = iface -> get_element_connect(numTriangles, 3, moab::MBTRI, 1,
     778         [ #  # ]:          0 :         starth, connect);
     779         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     780                 :            :     // get first the connectivity of the old triangles
     781                 :            :     const moab::EntityHandle * conn3;
     782         [ #  # ]:          0 :     for (int i = 0; i < numTriangles; i++) {
     783                 :            :       int num_nodes;
     784                 :            :       // get each valid triangle one by one, and set the new connectivity directly
     785 [ #  # ][ #  # ]:          0 :       rval = mb->get_connectivity(validTris[i], conn3, num_nodes);
     786 [ #  # ][ #  # ]:          0 :       assert( (moab::MB_SUCCESS==rval) && (num_nodes==3));
     787                 :            :       // directly modify the connect array in database
     788         [ #  # ]:          0 :       for (int j = 0; j < 3; j++)
     789         [ #  # ]:          0 :         connect[j] = mapping[conn3[j]];
     790                 :            : 
     791                 :            :       // update adjacencies
     792                 :            :       // not very smart...; we would like to update once and for all triangles
     793                 :            :       // not in a loop
     794         [ #  # ]:          0 :       rval = iface -> update_adjacencies(starth+i, 1, 3, connect);
     795         [ #  # ]:          0 :       assert(moab::MB_SUCCESS==rval);
     796                 :            : 
     797                 :          0 :       connect += 3; // advance
     798                 :            :     }
     799                 :            : 
     800                 :            : 
     801                 :            : 
     802                 :            :     // clear completely the initial set, after deleting all elements from it...
     803                 :            :     //   ok, we are done, commit to ME ?
     804         [ #  # ]:          0 :     rval = mb->delete_entities(triangles);
     805         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     806         [ #  # ]:          0 :     rval = mb->delete_entities(edgs);
     807         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     808         [ #  # ]:          0 :     rval = mb->delete_entities(verts);
     809         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     810                 :            :     // remove everything from the initial set, because we will add the new triangles
     811         [ #  # ]:          0 :     mb->remove_entities(iniSet, triangles);
     812         [ #  # ]:          0 :     mb->remove_entities(iniSet, verts);
     813         [ #  # ]:          0 :     mb->remove_entities(iniSet, edgs);
     814                 :            : 
     815                 :            :     //add triangles to output range (for the MESelection)
     816         [ #  # ]:          0 :     oRange.insert(starth, starth + numTriangles - 1);
     817                 :            :     // add all entities from the range to the initial set, now
     818         [ #  # ]:          0 :     rval = mb->add_entities(iniSet, oRange);
     819         [ #  # ]:          0 :     assert(moab::MB_SUCCESS==rval);
     820                 :            :     //me->commit_mesh(mit->second, COMPLETE_MESH);
     821                 :            :     // end copy
     822                 :            :   } else {
     823         [ +  - ]:          2 :     moab::Range::const_reverse_iterator rit;
     824         [ +  - ]:          2 :     if (opts.useDelayedDeletion) {
     825                 :            : 
     826                 :            :       // put in a range triangles to delete
     827         [ +  - ]:          2 :       moab::Range delRange;
     828                 :            :       // delete triangles and edges that are invalid
     829 [ +  - ][ +  - ]:      10002 :       for (rit = triangles.rbegin(); rit != triangles.rend(); rit++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     830         [ +  - ]:      10000 :         moab::EntityHandle tr = *rit;
     831                 :            :         // check the validity
     832 [ +  - ][ +  + ]:      10000 :         if (ehIsValid(tr))
     833                 :       8998 :           continue;
     834         [ +  - ]:       1002 :         mb->delete_entities(&tr, 1);
     835         [ +  - ]:       1002 :         delRange.insert(tr);
     836                 :            :       }
     837         [ +  - ]:          2 :       mb->remove_entities(iniSet, delRange);
     838                 :            :       // maybe we should delete all edges, but for now, we will keep them
     839 [ +  - ][ +  - ]:      15202 :       for (rit = edgs.rbegin(); rit != edgs.rend(); rit++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     840         [ +  - ]:      15200 :         moab::EntityHandle v = *rit;
     841                 :            :         // check the validity
     842 [ +  - ][ +  + ]:      15200 :         if (ehIsValid(v))
     843                 :      13654 :           continue;
     844         [ +  - ]:       1546 :         mb->delete_entities(&v, 1);
     845                 :          2 :       }
     846                 :            : 
     847                 :            :     }
     848                 :            :     // delete them one by one
     849 [ +  - ][ +  - ]:       5204 :     for (rit = verts.rbegin(); rit != verts.rend(); rit++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     850         [ +  - ]:       5202 :       moab::EntityHandle v = *rit;
     851                 :            :       // check the validity
     852 [ +  - ][ +  + ]:       5202 :       if (ehIsValid(v))
     853                 :       4658 :         continue;
     854         [ +  - ]:        544 :       mb->delete_entities(&v, 1);
     855                 :            :     }
     856                 :            :   }
     857                 :          2 :   clock_t delete_vTime = clock();
     858                 :          2 :   std::cout << "   Delete Vertices: " << (double) (delete_vTime - finish_time)
     859                 :          2 :       / CLOCKS_PER_SEC << " s.\n";
     860                 :            :   // we need to delete the tags we created; they are artificial
     861                 :            :   // list of tags to delete:
     862                 :            :   // moab::Tag uniqIDtag; // this will be used to mark vertices moab::EntityHandles
     863                 :            :   // moab::Tag validTag;
     864                 :            :   // moab::Tag planeDataTag;
     865                 :            : 
     866                 :            :   // moab::Tag costTag; // simplification induces an error cost at each vertex
     867                 :            :   // try to keep adding the cost, to see if it is spreading nicely
     868                 :            : 
     869                 :            :   // keep only the cost, the rest are artificial
     870                 :          2 :   mb->tag_delete(uniqIDtag);
     871                 :          2 :   mb->tag_delete(validTag);
     872                 :          2 :   mb->tag_delete(planeDataTag);
     873                 :            :   //
     874                 :            : 
     875                 :          2 :   return 0;
     876                 :            : }
     877                 :            : 
     878                 :          2 : int QslimDecimation::Init() {
     879                 :            :   int i;
     880                 :            :   unsigned int j;
     881                 :            : 
     882                 :            :   //moab::EntityHandle * set = reinterpret_cast<moab::EntityHandle *> (&_InitialSet);
     883                 :            :   moab::ErrorCode rval = mb->get_entities_by_type(iniSet, moab::MBTRI,
     884         [ +  - ]:          2 :       triangles);
     885         [ +  - ]:          2 :   validFaceCount = triangles.size();// this gets reduced every time we simplify the model
     886                 :            : 
     887                 :            :   // store the normals/planes computed at each triangle
     888                 :            :   // we may need just the normals, but compute planes, it is about the same job
     889                 :          2 :   double defPlane[] = { 0., 0., 1., 0. };
     890                 :            :   rval = mb->tag_get_handle("PlaneTriangleData", 4, moab::MB_TYPE_DOUBLE,
     891         [ +  - ]:          2 :       planeDataTag, moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &defPlane);
     892                 :            : 
     893                 :            :   // compute the triangle plane and store it, for each triangle
     894 [ +  - ][ +  - ]:      10002 :   for (moab::Range::iterator itr = triangles.begin(); itr != triangles.end(); itr++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     895                 :            :     // this index i will be the index in the vinfo array
     896         [ +  - ]:      10000 :     moab::EntityHandle tri = *itr;
     897         [ +  - ]:      10000 :     computeTrianglePlane(mb, tri);
     898                 :            :     // setting the data for the tag/triangle is done in the compute
     899                 :            :     //rval = mb->tag_set_data(planeDataTag, &tri, 1, &plane);
     900                 :            :   }
     901                 :            : 
     902                 :            :   // create all the edges if not existing
     903         [ +  - ]:          2 :   mb->get_adjacencies(triangles, 1, true, edgs, moab::Interface::UNION);
     904                 :            : 
     905                 :            :   // moab::Range verts;// the vertices are always there, they do not need to be created
     906         [ +  - ]:          2 :   mb->get_adjacencies(triangles, 0, true, verts, moab::Interface::UNION);
     907         [ +  - ]:          2 :   int numNodes = verts.size();
     908                 :          2 :   validVertCount = numNodes; // this will be kept
     909         [ +  - ]:          2 :   vinfo.init(numNodes);
     910                 :            :   // set a unique integer tag with the position in vinfo array
     911                 :            :   //  this will be used instead of v->uniqID in the vinfo array
     912                 :          2 :   int def_data = -1;
     913                 :            : 
     914                 :            :   rval = mb->tag_get_handle("uniqID", 1, moab::MB_TYPE_INTEGER, uniqIDtag,
     915         [ +  - ]:          2 :       moab::MB_TAG_DENSE | moab::MB_TAG_EXCL, &def_data);
     916         [ -  + ]:          2 :   if (moab::MB_SUCCESS != rval)
     917                 :          0 :     return 1;
     918                 :            : 
     919                 :          2 :   unsigned char def_data_bit = 1;// valid by default
     920                 :            : 
     921                 :            :   rval = mb->tag_get_handle("valid", 1, moab::MB_TYPE_BIT, validTag,
     922         [ +  - ]:          2 :       moab::MB_TAG_EXCL | moab::MB_TAG_BIT, &def_data_bit);
     923         [ -  + ]:          2 :   if (moab::MB_SUCCESS != rval)
     924                 :          0 :     return 1;
     925                 :            : 
     926         [ -  + ]:          2 :   if (opts.plotCost) {
     927                 :          0 :     double cost_default = 0.;
     928                 :            : 
     929                 :            :     rval = mb->tag_get_handle("costTAG", 1, moab::MB_TYPE_DOUBLE, costTag,
     930         [ #  # ]:          0 :         moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &cost_default);
     931         [ #  # ]:          0 :     if (moab::MB_SUCCESS != rval)
     932                 :          0 :       return 1;
     933                 :            :   }
     934                 :            : 
     935                 :            :   // set tag for each vertex; this will not be changed during simplification
     936                 :          2 :   i = 0; // for index
     937 [ +  - ][ +  - ]:       5204 :   for (moab::Range::iterator it = verts.begin(); it != verts.end(); it++, i++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     938                 :            :     // this index i will be the index in the vinfo array
     939         [ +  - ]:       5202 :     moab::EntityHandle v = *it;
     940         [ +  - ]:       5202 :     rval = mb->tag_set_data(uniqIDtag, &v, 1, &i);
     941                 :            :     // the default valid data is 1; set it to 0 only to "mark" the vertex invalid for future deletion
     942                 :            :     // is it really necessary if we put the default value as 1 anyway
     943                 :            : 
     944                 :            :     //rval = mb->tag_set_data(validTag, &v, 1, &def_data_bit);
     945                 :            :   }
     946         [ +  - ]:          2 :   moab::Range::iterator it;
     947 [ -  + ][ #  # ]:          2 :   if (opts.logfile && opts.selected_output & OUTPUT_MODEL_DEFN) {
     948 [ #  # ][ #  # ]:          0 :     for (it = verts.begin(); it != verts.end(); it++) {
         [ #  # ][ #  # ]
                 [ #  # ]
     949         [ #  # ]:          0 :       moab::EntityHandle v = *it;
     950                 :            :       double coords[3];
     951         [ #  # ]:          0 :       rval = mb->get_coords(&v, 1, coords);
     952 [ #  # ][ #  # ]:          0 :       *opts.logfile << "v: " << uniqID(v) << " " << mb->id_from_handle(v)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     953 [ #  # ][ #  # ]:          0 :           << " " << coords[0] << " " << coords[1] << " " << coords[2]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     954         [ #  # ]:          0 :           << std::endl;
     955                 :            :     }
     956                 :            :   }
     957 [ +  - ][ +  - ]:          2 :   std::cout << "  Decimate:  Distributing shape constraints." << std::endl;
     958                 :            : 
     959         [ -  + ]:          2 :   if (opts.will_use_vertex_constraint)
     960 [ #  # ][ #  # ]:          0 :     for (it = verts.begin(); it != verts.end(); it++) {
         [ #  # ][ #  # ]
                 [ #  # ]
     961         [ #  # ]:          0 :       moab::EntityHandle v = *it;
     962 [ #  # ][ #  # ]:          0 :       vertex_info(v).Q = quadrix_vertex_constraint(v);
                 [ #  # ]
     963                 :            :     }
     964                 :            : 
     965         [ +  - ]:          2 :   if (opts.will_use_plane_constraint) {
     966 [ +  - ][ +  - ]:      10002 :     for (it = triangles.begin(); it != triangles.end(); it++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     967                 :            : 
     968         [ +  - ]:      10000 :       moab::EntityHandle tr = *it;
     969         [ +  - ]:      10000 :       Mat4 Q = quadrix_plane_constraint(tr);
     970                 :      10000 :       double norm = 0.0;
     971                 :            : 
     972         [ -  + ]:      10000 :       if (opts.will_weight_by_area) {
     973                 :          0 :         norm = 1; // triangle area : m_model->face ( i )->area();
     974         [ #  # ]:          0 :         Q *= norm;
     975                 :            :       }
     976                 :            :       const moab::EntityHandle * conn;
     977                 :            :       int num_nodes;
     978         [ +  - ]:      10000 :       rval = mb->get_connectivity(tr, conn, num_nodes);
     979         [ +  + ]:      40000 :       for (j = 0; j < 3; j++) {
     980         [ +  - ]:      30000 :         vert_info& vj_info = vertex_info(conn[j]);
     981         [ +  - ]:      30000 :         vj_info.Q += Q;
     982         [ +  - ]:      30000 :         vertex_info(conn[j]).norm += norm;
     983                 :            : 
     984                 :            :       }
     985                 :            :     }
     986                 :            :   }
     987                 :            :   // just define (one uniqTag for a triangle, see what is happening)
     988         [ +  - ]:          2 :   moab::EntityHandle tr1 = triangles[0];
     989         [ +  - ]:          2 :   rval = mb->tag_set_data(uniqIDtag, &tr1, 1, &i);// just some value
     990                 :            : 
     991         [ +  - ]:          2 :   if (opts.will_constrain_boundaries) {
     992         [ +  - ]:          2 :     std::cout << "  Decimate:  Accumulating discontinuity constraints."
     993         [ +  - ]:          2 :         << std::endl;
     994 [ +  - ][ +  - ]:      15202 :     for (it = edgs.begin(); it != edgs.end(); it++) {
         [ +  - ][ +  - ]
                 [ +  + ]
     995         [ +  - ]:      15200 :       moab::EntityHandle edg = *it;
     996 [ +  - ][ +  + ]:      15200 :       if (is_border(edg)) {
     997                 :            :         const moab::EntityHandle * conn;
     998                 :            :         int num_nodes;
     999         [ +  - ]:        400 :         rval = mb->get_connectivity(edg, conn, num_nodes);
    1000         [ -  + ]:        400 :         if (moab::MB_SUCCESS != rval)
    1001                 :          0 :           return 1;// fail
    1002         [ +  - ]:        400 :         Mat4 B = quadrix_discontinuity_constraint(edg);
    1003                 :        400 :         double norm = 0.0;
    1004                 :            : 
    1005         [ -  + ]:        400 :         if (opts.will_weight_by_area) {
    1006         [ #  # ]:          0 :           Vec3 ve1 = getVec3FromMBVertex(mb, conn[0]);
    1007         [ #  # ]:          0 :           Vec3 ve2 = getVec3FromMBVertex(mb, conn[1]);
    1008 [ #  # ][ #  # ]:          0 :           norm = norm2(ve1 - ve2);
    1009         [ #  # ]:          0 :           B *= norm;
    1010                 :            :         }
    1011                 :            : 
    1012         [ +  - ]:        400 :         B *= opts.boundary_constraint_weight;
    1013         [ +  - ]:        400 :         vert_info& v0_info = vertex_info(conn[0]);
    1014         [ +  - ]:        400 :         vert_info& v1_info = vertex_info(conn[1]);
    1015         [ +  - ]:        400 :         v0_info.Q += B;
    1016                 :        400 :         v0_info.norm += norm;
    1017         [ +  - ]:        400 :         v1_info.Q += B;
    1018                 :        400 :         v1_info.norm += norm;
    1019                 :            :       }
    1020                 :            :     }
    1021                 :            :   }
    1022                 :            : 
    1023 [ +  - ][ +  - ]:          2 :   std::cout << "  Decimate:  Allocating heap." << std::endl;
    1024 [ +  - ][ +  - ]:          2 :   heap = new Heap(edgs.size());
                 [ +  - ]
    1025                 :            : 
    1026                 :          2 :   int pair_count = 0;
    1027                 :            : 
    1028 [ +  - ][ +  - ]:          2 :   std::cout << "  Decimate:  Collecting pairs [edges]." << std::endl;
    1029 [ +  - ][ +  - ]:      15202 :   for (it = edgs.begin(); it != edgs.end(); it++) {
         [ +  - ][ +  - ]
                 [ +  + ]
    1030         [ +  - ]:      15200 :     moab::EntityHandle edg = *it;
    1031                 :            :     const moab::EntityHandle * conn;
    1032                 :            :     int num_nodes;
    1033         [ +  - ]:      15200 :     rval = mb->get_connectivity(edg, conn, num_nodes);
    1034         [ -  + ]:      15200 :     if (moab::MB_SUCCESS != rval)
    1035                 :          0 :       return 1;// fail
    1036         [ +  - ]:      15200 :     pair_info *pair = new_pair(conn[0], conn[1]);
    1037         [ +  - ]:      15200 :     compute_pair_info(pair);
    1038                 :      15200 :     pair_count++;
    1039                 :            :   }
    1040                 :            : 
    1041         [ -  + ]:          2 :   if (opts.pair_selection_tolerance < 0) {
    1042                 :          0 :     opts.pair_selection_tolerance = 1;//m_model->bounds.radius * 0.05;
    1043         [ #  # ]:          0 :     std::cout << "  Decimate:  Auto-limiting at 5% of model radius."
    1044         [ #  # ]:          0 :         << std::endl;
    1045                 :            :   }
    1046                 :            :   proximity_limit = opts.pair_selection_tolerance
    1047                 :          2 :       * opts.pair_selection_tolerance;
    1048         [ -  + ]:          2 :   if (proximity_limit > 0) {
    1049         [ #  # ]:          0 :     std::cout << "  Decimate:  Collecting pairs [limit="
    1050 [ #  # ][ #  # ]:          0 :         << opts.pair_selection_tolerance << "]." << std::endl;
                 [ #  # ]
    1051                 :            :     // use adaptive kd tree to find proximity vertices
    1052                 :          0 :     moab::EntityHandle tree_root = 0;
    1053         [ #  # ]:          0 :     moab::AdaptiveKDTree kd(mb);
    1054         [ #  # ]:          0 :     rval = kd.build_tree(verts, &tree_root);
    1055         [ #  # ]:          0 :     if (rval != moab::MB_SUCCESS) {
    1056 [ #  # ][ #  # ]:          0 :       std::cout << "Can't build tree for vertices" << std::endl;
    1057                 :          0 :       return 1;
    1058                 :            :     }
    1059                 :            : 
    1060 [ #  # ][ #  # ]:          0 :     for (it = verts.begin(); it != verts.end(); it++) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1061         [ #  # ]:          0 :       moab::Range closeVertices;
    1062         [ #  # ]:          0 :       closeVertices.clear();
    1063         [ #  # ]:          0 :       moab::EntityHandle v = *it;
    1064                 :            :       double coords[3];
    1065         [ #  # ]:          0 :       mb->get_coords(&v, 1, coords);
    1066                 :            :       //moab::CartVect v1(coords);
    1067         [ #  # ]:          0 :       std::vector<moab::EntityHandle> leaves; // sets of vertices close by
    1068                 :            :       kd.distance_search( coords,
    1069         [ #  # ]:          0 :           opts.pair_selection_tolerance, leaves);
    1070                 :            :       // add to the list of close vertices
    1071         [ #  # ]:          0 :       for (j = 0; j < leaves.size(); j++) {
    1072         [ #  # ]:          0 :         rval = mb->get_entities_by_type(leaves[j], moab::MBVERTEX,
    1073         [ #  # ]:          0 :             closeVertices);// add to the list
    1074                 :            :       }
    1075                 :            : 
    1076 [ #  # ][ #  # ]:          0 :       for (moab::Range::iterator it2 = closeVertices.begin(); it2
         [ #  # ][ #  # ]
    1077         [ #  # ]:          0 :           != closeVertices.end(); it2++) {
    1078         [ #  # ]:          0 :         moab::EntityHandle vclose = *it2;
    1079         [ #  # ]:          0 :         if (v == vclose)
    1080                 :          0 :           continue;
    1081                 :            :         double coords2[3];
    1082         [ #  # ]:          0 :         mb->get_coords(&vclose, 1, coords2);
    1083                 :            : 
    1084                 :            :         //moab::CartVect v2(coords2);
    1085                 :          0 :         double dd = (coords[0] - coords2[0]) * (coords[0] - coords2[0])
    1086                 :          0 :             + (coords[1] - coords2[1]) * (coords[1] - coords2[1]) + (coords[2]
    1087                 :          0 :             - coords2[2]) * (coords[2] - coords2[2]);
    1088                 :            : 
    1089         [ #  # ]:          0 :         if (dd > proximity_limit)
    1090                 :          0 :           continue;
    1091                 :            : 
    1092                 :            : /*
    1093                 :            : #ifdef SAFETY
    1094                 :            :         assert ( pair_is_valid ( v1,v2 ) );
    1095                 :            : #endif
    1096                 :            : */
    1097 [ #  # ][ #  # ]:          0 :         if (!check_for_pair(v, vclose)) {
    1098         [ #  # ]:          0 :           pair_info *pair = new_pair(v, vclose);
    1099         [ #  # ]:          0 :           compute_pair_info(pair);
    1100                 :          0 :           pair_count++;
    1101                 :            :         }
    1102                 :            :       }
    1103                 :            : 
    1104                 :          0 :     }
    1105                 :            :   } else
    1106 [ +  - ][ +  - ]:          2 :     std::cout << "  Decimate:  Ignoring non-edge pairs [limit=0]." << std::endl;
    1107                 :            : 
    1108 [ +  - ][ +  - ]:          2 :   std::cout << "  Decimate:  Designated " << pair_count << " pairs."
                 [ +  - ]
    1109         [ +  - ]:          2 :       << std::endl;
    1110                 :            : 
    1111                 :          2 :   return 0;// no error
    1112                 :            : }
    1113                 :            : 
    1114 [ +  - ][ +  - ]:        312 : } // namespace MeshKit

Generated by: LCOV version 1.11