MeshKit  1.0
cw_func.cpp
Go to the documentation of this file.
00001 // *********************************
00002 
00003 // Patrick Shriwise
00004 // October, 2013
00005 
00006 // functions needed to check models for watertightness
00007 
00008 #include <iostream>
00009 #include <iomanip> // for setprecision
00010 #include <limits> // for min/max values
00011 #include <assert.h>
00012 #include <math.h>
00013 #include <time.h>
00014 #include <vector>
00015 #include <cmath>
00016 #include <cstdlib>
00017 #include <ctime>
00018 #include <set>
00019 #include <algorithm>
00020 #include "moab/Core.hpp"
00021 #include "MBTagConventions.hpp"
00022 #include "moab/Range.hpp"
00023 #include "moab/Skinner.hpp"
00024 
00025 #include "moab/GeomTopoTool.hpp"
00026 #include "meshkit/cw_func.hpp"
00027 #include "meshkit/gen.hpp"
00028 #include "meshkit/zip.hpp"
00029 #include "moab/Skinner.hpp"
00030 
00031 using namespace moab;
00032 namespace cw_func {
00033 
00034  ErrorCode check_mesh_for_watertightness( EntityHandle input_set, double tol, bool &sealed, bool test, bool verbose, bool check_topology )
00035  {
00036 
00037   ErrorCode result;
00038 
00039  // create tags on geometry
00040   Tag geom_tag, id_tag;
00041   result = MBI()->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, 
00042                             MB_TYPE_INTEGER, geom_tag, MB_TAG_DENSE|MB_TAG_CREAT );
00043   if(gen::error(MB_SUCCESS != result, "could not get GEOM_DIMENSION_TAG_NAME handle")) return result;
00044 
00045   result = MBI()->tag_get_handle( GLOBAL_ID_TAG_NAME, 1, 
00046                             MB_TYPE_INTEGER, id_tag, MB_TAG_DENSE|MB_TAG_CREAT );
00047   if(gen::error(MB_SUCCESS != result, "could not get GLOBAL_ID_TAG_NAME handle")) return result;
00048 
00049   
00050   // get surface and volume sets
00051   Range surf_sets, vol_sets; // Range of set of surfaces and volumes
00052   // surface sets
00053   int dim = 2;
00054   void* input_dim[] = {&dim};
00055   result = MBI()->get_entities_by_type_and_tag( input_set, MBENTITYSET, &geom_tag, 
00056                                                 input_dim, 1, surf_sets);
00057   if(MB_SUCCESS != result)
00058     {
00059       return result;
00060     }
00061 
00062   // volume sets
00063   dim = 3;
00064   result = MBI()->get_entities_by_type_and_tag( input_set, MBENTITYSET, &geom_tag, 
00065                                                 input_dim, 1, vol_sets);
00066   if(MB_SUCCESS != result)
00067     {
00068       return result;
00069     }
00070  if(!test)
00071   {
00072   std::cout<< "number of surfaces=" << surf_sets.size() << std::endl;
00073   std::cout<< "number of volumes="  << vol_sets.size() << std::endl;
00074   }
00075   // ******************************************************************
00076   // Watertightness is a property of volumes. Check each surface for
00077   // watertightness.
00078   // ******************************************************************
00079   // counted leaky surfaces
00080   int total_counter = 0, unmatched_counter=0;
00081   std::set<int> leaky_surfs, leaky_vols;
00082   Skinner tool(MBI());
00083 
00084   // remove all edges for fast skinning
00085   Range edges;
00086 
00087   result = MBI()->get_entities_by_type( 0, MBEDGE, edges ); // get all edges
00088   if(MB_SUCCESS != result) // failed to get edge data
00089     {
00090       return result; // failed
00091     }
00092 //10/11/13
00093 //removed as a result of the change from the gen::find_skin function to the Skinner:find_skin function
00094 /*
00095   result = MBI()->delete_entities( edges ); //otherwise delete all edge
00096   
00097   if(MB_SUCCESS != result) // failed to delete edge data
00098     {
00099       return result; // failed
00100     }
00101 */  
00102   // loop over each volume meshset
00103   int vol_counter = 0;
00104   for(Range::iterator i=vol_sets.begin(); i!=vol_sets.end(); ++i)
00105     {
00106       ++vol_counter;
00107       int surf_counter=0;
00108       Range child_sets;
00109 
00110       result = MBI()->get_child_meshsets( *i, child_sets ); // get child set
00111       if(MB_SUCCESS != result)
00112         {
00113           return result; // failed
00114         }
00115 
00116       // get the volume id of the volume meshset to print a status message
00117       int vol_id=0;
00118       // i is the iterator, so &(*i) is a pointer to the first element of Range
00119       result = MBI()->tag_get_data( id_tag, &(*i), 1, &vol_id );
00120 
00121       if(MB_SUCCESS != result)
00122         {
00123           return result;
00124         }
00125 
00126       if(verbose) 
00127         {
00128           std::cout << "checking volume " << vol_counter << "/" << vol_sets.size()
00129                           << " id=" << vol_id << std::endl;
00130         }
00131 
00132       // determine how many skin edges are in each volume
00133       int n_tris = 0;
00134 
00135       for(Range::iterator j=child_sets.begin(); j!=child_sets.end(); ++j)
00136         {
00137           result = MBI()->get_number_entities_by_type( *j, MBTRI, n_tris ); // for each child set get number of triangles
00138           if(MB_SUCCESS != result)
00139             {
00140               return result;
00141             }
00142         }
00143 
00144       // save the edges in a vector that is large enough to avoid resizing
00145       // presumably some kind of efficiency thing?? ad ??
00146       std::vector<coords_and_id> the_coords_and_id;
00147       the_coords_and_id.reserve(n_tris);
00148 
00149       // loop over the surface meshsets of each volume meshset
00150       for(Range::iterator j=child_sets.begin(); j!=child_sets.end(); ++j)
00151         {
00152 
00153           // get the surface id of the surface meshset
00154           surf_counter++;
00155           int surf_id=0;
00156           result = MBI()->tag_get_data( id_tag, &(*j), 1, &surf_id );
00157           if(MB_SUCCESS != result)
00158             {
00159               return result;
00160             }
00161 
00162           // get the range of facets of the surface meshset
00163           Range facets;
00164           result = MBI()->get_entities_by_type( *j, MBTRI, facets );
00165           if(MB_SUCCESS != result)
00166             {
00167               return result;
00168             }
00169 
00170           // get the range of skin edges from the range of facets
00171           // Fiasco: Jason wrote an optimized function (find_skin_vertices) that performed
00172           // almost as well as my specialized version (gen::find_skin). When he made then
00173           // generalized find_skin_vertices for MOAB it killed performance. As it stands,
00174           // gen::find_skin is ~7x faster (January 29, 2010).
00175           Range skin_edges;
00176           Skinner sk(MBI());
00177           if(!facets.empty()) 
00178             {
00179               result = sk.find_skin( 0 , facets, 1, skin_edges, false );
00180               if(MB_SUCCESS != result)
00181                 {
00182                   return result;
00183                 }
00184             }
00185 
00186       // count the number of skin edges in the range
00187       if(verbose) 
00188         {
00189           std::cout << "surface " << surf_counter << "/" << child_sets.size()
00190                     << " id=" << surf_id << " contains " << facets.size() 
00191                     << " facets and " << skin_edges.size() << " skin edges" << std::endl;
00192         }
00193      
00194       for(Range::const_iterator k=skin_edges.begin(); k!=skin_edges.end(); ++k) {
00195         // get the endpoint vertices of the facet edge
00196         Range verts;
00197         result = MBI()->get_adjacencies( &(*k), 1, 0, false, verts );
00198         if(MB_SUCCESS != result) return result;
00199         if(2 != verts.size()) {
00200           std::cout << "  WARNING: verts.size()=" << verts.size() << std::endl;
00201           continue;
00202         }  
00203 
00204         // Save the range of verts to an array of verts that can store duplicates.
00205         coords_and_id temp;
00206         if(check_topology) {
00207           temp.vert1 = verts[0];
00208           temp.vert2 = verts[1];
00209         } else {
00210           // get the coordinates of endpoint vertices
00211           double coords0[3], coords1[3];
00212           result = MBI()->get_coords( &(verts.front()), 1, coords0 );
00213           if(MB_SUCCESS != result) return result;
00214           result = MBI()->get_coords( &(verts.back()), 1, coords1 );
00215           if(MB_SUCCESS != result) return result;
00216           // orient the edge by endpoint coords
00217           if((!check_topology) &&
00218             (coords1[0]< coords0[0] ||
00219             (coords1[0]==coords0[0] && coords1[1]< coords0[1]) ||
00220             (coords1[0]==coords0[0] && coords1[1]==coords0[1] && coords1[2]< coords0[2]))) {
00221             temp.x1 = coords1[0];
00222             temp.y1 = coords1[1];
00223             temp.z1 = coords1[2];
00224             temp.x2 = coords0[0];
00225             temp.y2 = coords0[1];
00226             temp.z2 = coords0[2];
00227             temp.vert1 = verts[1];
00228             temp.vert2 = verts[0];
00229           } else {
00230             temp.x1 = coords0[0];
00231             temp.y1 = coords0[1];
00232             temp.z1 = coords0[2];
00233             temp.x2 = coords1[0];
00234             temp.y2 = coords1[1];
00235             temp.z2 = coords1[2];
00236             temp.vert1 = verts[0];
00237             temp.vert2 = verts[1];
00238           }
00239         }
00240         temp.surf_id = surf_id;
00241         temp.matched = false;
00242         the_coords_and_id.push_back(temp);
00243       }
00244       //10/10/13
00245       // Removed the following to avoid altering the data set at all
00246       // -No need to delete skin_edges with the moab:Skinner find_skin function
00247       // -skin_edges size will be reset to zero upon new Range skin_edges; call
00248       // clean up the edges for the next find_skin call
00249       //result = MBI()->delete_entities( skin_edges );
00250       //if(MB_SUCCESS != result) return result;
00251 
00252       //10/10/13
00253       // - No ned to ensure edges aren't in the meshset with Skinner find_skin function
00254       //int n_edges;
00255       //result = MBI()->get_number_entities_by_type(0, MBEDGE, n_edges );
00256       //if(MB_SUCCESS != result) return result;
00257       //if(gen::error(0 != n_edges, "n_edges not equal to zero")) return MB_MULTIPLE_ENTITIES_FOUND;
00258     }
00259 
00260     // sort the edges by the first vert. The first vert has a lower handle than the second.
00261     int n_edges = the_coords_and_id.size();
00262     total_counter += n_edges;
00263     if(check_topology) {
00264       qsort( &the_coords_and_id[0], n_edges, sizeof(struct coords_and_id), compare_by_handle);
00265     } else {
00266       qsort( &the_coords_and_id[0], n_edges, sizeof(struct coords_and_id), compare_by_coords);
00267     }
00268 
00269     // ******************************************************************
00270     // Iterate through each facet edge, looking for its match. If a match
00271     // is found set the edge's flag to 'matched' so that we do not check
00272     // it again.
00273     // WARNING: The logic is different for checking by topology vs. proximity.
00274     // ******************************************************************
00275     // loop over each facet edge in the volume
00276     for(int j=0; j!=n_edges; ++j) {
00277 
00278       // if the edge has already been matched, skip it
00279       if (the_coords_and_id[j].matched) continue;
00280     
00281       // try to match the edge with another facet edge:
00282       for(int k=j+1; k!=n_edges+1; ++k) {
00283 
00284         // look for a match
00285         if(check_topology) {
00286           if( the_coords_and_id[j].vert1==the_coords_and_id[k].vert1 &&
00287               the_coords_and_id[j].vert2==the_coords_and_id[k].vert2 ) {
00288             the_coords_and_id[j].matched = true;
00289             the_coords_and_id[k].matched = true;
00290             //std::cout<< "matched by handle" << std::endl;
00291             break;
00292           }
00293         } else {
00294           // When matching by proximity, it is possible that the k edge has already
00295           // been matched. If so, skip it.
00296           if (the_coords_and_id[k].matched) continue;
00297 
00298           // see if the edge matches
00299           CartVect diff0(the_coords_and_id[j].x1-the_coords_and_id[k].x1,
00300                            the_coords_and_id[j].y1-the_coords_and_id[k].y1,
00301                            the_coords_and_id[j].z1-the_coords_and_id[k].z1);
00302           CartVect diff1(the_coords_and_id[j].x2-the_coords_and_id[k].x2,
00303                            the_coords_and_id[j].y2-the_coords_and_id[k].y2,
00304                            the_coords_and_id[j].z2-the_coords_and_id[k].z2);
00305           double d0 = diff0.length_squared();
00306           double d1 = diff1.length_squared();
00307           if( d0<tol*tol && d1<tol*tol ) {
00308             the_coords_and_id[j].matched = true;
00309             the_coords_and_id[k].matched = true;
00310             //std::cout<< "matched by proximity" << std::endl;
00311             break;
00312           }
00313           // Due to the sort, once the x-coords are out of tolerance, a match 
00314           // cannot exist.
00315           if( the_coords_and_id[k].x1 - the_coords_and_id[j].x1 <= tol) continue;
00316         }
00317 
00318         // If no break or continue has been hit, the edge is unmatched.    
00319         // if we have a new leaky surface, save it
00320         std::set<int>::iterator found;
00321         found = leaky_surfs.find( the_coords_and_id[j].surf_id );
00322         if(found == leaky_surfs.end()) {
00323           leaky_surfs.insert( the_coords_and_id[j].surf_id );
00324         }
00325         found = leaky_vols.find( vol_id );
00326         if(found == leaky_vols.end()) {
00327           leaky_vols.insert( vol_id );
00328         }
00329         // print info for unmatched edge
00330         if(verbose) {
00331           // get the coordinates if we don't already have them
00332           if(check_topology) {
00333             double endpt_coords[3];
00334             result = MBI()->get_coords( &the_coords_and_id[j].vert1, 1, endpt_coords );
00335             if(MB_SUCCESS != result) return result;
00336             the_coords_and_id[j].x1 = endpt_coords[0]; 
00337             the_coords_and_id[j].y1 = endpt_coords[1];
00338             the_coords_and_id[j].z1 = endpt_coords[2];
00339             result = MBI()->get_coords( &the_coords_and_id[j].vert2, 1, endpt_coords );
00340             if(MB_SUCCESS != result) return result;
00341             the_coords_and_id[j].x2 = endpt_coords[0]; 
00342             the_coords_and_id[j].y2 = endpt_coords[1];
00343             the_coords_and_id[j].z2 = endpt_coords[2];
00344           }
00345           std::cout << "  edge of surf " << the_coords_and_id[j].surf_id 
00346                  << " unmatched: " << " (" 
00347                  << the_coords_and_id[j].x1 << "," 
00348                  << the_coords_and_id[j].y1 << ","
00349                  << the_coords_and_id[j].z1 << ") (" 
00350                  << the_coords_and_id[j].x2 << ","
00351                  << the_coords_and_id[j].y2 << ","
00352                  << the_coords_and_id[j].z2 << ")" 
00353                  << " v0=" << the_coords_and_id[j].vert1 
00354                  << " v1=" << the_coords_and_id[j].vert2
00355                  << " j=" << j << " k=" << k <<std::endl;
00356         }
00357         unmatched_counter++;
00358         break;        
00359       }  // k loop
00360     }    // j loop
00361   }      // volume loop
00362 
00363 
00364   
00365   
00366    
00367   
00368   if(!test)
00369   {
00370   // print time and summary
00371   
00372   std::cout << std::endl << unmatched_counter << "/" << total_counter << " ("
00373             << double(100.0*unmatched_counter)/total_counter 
00374             << "%) unmatched edges" << std::endl;
00375   std::cout << leaky_surfs.size() << "/" << surf_sets.size() << " ("
00376             << double(100.0*leaky_surfs.size())/surf_sets.size() 
00377             << "%) unsealed surfaces" << std::endl;
00378   std::cout << leaky_vols.size() << "/" << vol_sets.size() << " ("
00379             << double(100.0*leaky_vols.size())/vol_sets.size() 
00380             << "%) unsealed volumes" << std::endl;
00381   
00382 
00383   // list the leaky surface and volume ids
00384   std::cout << "leaky surface ids=";
00385   for( std::set<int>::iterator i=leaky_surfs.begin(); i!=leaky_surfs.end(); i++) {
00386     std::cout << *i << " ";
00387   }
00388   std::cout << std::endl;
00389   std::cout << "leaky volume ids=";
00390   for( std::set<int>::iterator i=leaky_vols.begin(); i!=leaky_vols.end(); i++) {
00391     std::cout << *i << " ";
00392   }
00393   std::cout << std::endl;
00394  }
00395 
00396 
00397  if(unmatched_counter == 0 && leaky_vols.size() == 0 && leaky_surfs.size() == 0 )
00398  {
00399   sealed=true;
00400  }
00401  else
00402  {
00403   sealed=false;
00404  }
00405  return MB_SUCCESS;
00406  }
00407 
00408 /* qsort struct comparision function */
00409 int compare_by_handle(const void *a, const void *b)
00410 {
00411   struct coords_and_id *ia = (struct coords_and_id *)a;
00412   struct coords_and_id *ib = (struct coords_and_id *)b;
00413   if(ia->vert1 == ib->vert1) 
00414   {
00415     return (int)(ia->vert2 - ib->vert2);
00416   } 
00417   else 
00418   {
00419     return (int)(ia->vert1 - ib->vert1);
00420   }
00421   /* float comparison: returns negative if b > a 
00422      and positive if a > b. We multiplied result by 100.0
00423      to preserve decimal fraction */
00424 } 
00425 
00426 /* qsort struct comparision function */
00427 // This is tricky because doubles always get rounded down to ints.
00428 int compare_by_coords(const void *a, const void *b)
00429 {
00430   struct coords_and_id *ia = (struct coords_and_id *)a;
00431   struct coords_and_id *ib = (struct coords_and_id *)b;
00432   if(ia->x1 == ib->x1) {
00433     if(ia->y1 == ib->y1) {
00434       if(ia->z1 == ib->z1) {
00435         if(ia->x2 == ib->x2) {
00436           if(ia->y2 == ib->y2) {
00437             if(ia->z2 == ib->z2) {
00438               return ia->surf_id - ib->surf_id;
00439             } else {
00440               return (ia->z2 > ib->z2) - (ia->z2 < ib->z2);
00441             }
00442           } else {
00443             return (ia->y2 > ib->y2) - (ia->y2 < ib->y2);
00444           }
00445         } else {
00446           return (ia->x2 > ib->x2) - (ia->x2 < ib->x2);
00447         }
00448       } else {
00449         return (ia->z1 > ib->z1) - (ia->z1 < ib->z1);
00450       }
00451     } else {
00452       return (ia->y1 > ib->y1) - (ia->y1 < ib->y1);;
00453     }
00454   } else {
00455     return (ia->x1 > ib->x1) - (ia->x1 < ib->x1);
00456   }
00457   /* float comparison: returns negative if b > a 
00458      and positive if a > b. We multiplied result by 100.0
00459      to preserve decimal fraction */
00460 }
00461 
00462 }
00463 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines