moab
MergeMesh.cpp
Go to the documentation of this file.
00001 #include "moab/MergeMesh.hpp"
00002 
00003 #include "moab/Skinner.hpp"
00004 #include "moab/AdaptiveKDTree.hpp"
00005 #include "moab/Range.hpp"
00006 #include "moab/CartVect.hpp"
00007 
00008 #include <vector>
00009 #include <algorithm>
00010 #include <string>
00011 #include <vector>
00012 #include <cassert>
00013 #include <iostream>
00014 #include <iomanip>
00015 
00016 namespace moab {
00017 
00018   moab::ErrorCode MergeMesh::merge_entities(moab::EntityHandle *elems,
00019                         int elems_size,
00020                         const double merge_tol,
00021                         const int do_merge,
00022                         const int update_sets,
00023                         moab::Tag merge_tag, 
00024                         bool do_higher_dim) 
00025 {
00026   mergeTol = merge_tol;
00027   mergeTolSq = merge_tol*merge_tol;
00028   moab::Range tmp_elems;
00029   tmp_elems.insert( elems, elems + elems_size);
00030   moab::ErrorCode result = merge_entities(tmp_elems, merge_tol, do_merge, update_sets,
00031                       (moab::Tag)merge_tag, do_higher_dim);
00032 
00033   return result;
00034 }
00035 
00036 /*  This function appears to be not necessary after MOAB conversion
00037 
00038 void MergeMesh::perform_merge(iBase_TagHandle merge_tag) 
00039 {
00040   // put into a range
00041   moab::ErrorCode result = perform_merge((moab::Tag) merge_tag);
00042   if (result != moab::MB_SUCCESS)
00043     throw MKException(iBase_FAILURE, "");
00044 }*/
00045 
00046 moab::ErrorCode MergeMesh::merge_entities(moab::Range &elems,
00047                                           const double merge_tol,
00048                                           const int do_merge,
00049                                           const int ,
00050                                           moab::Tag merge_tag,
00051                       bool merge_higher_dim) 
00052 {
00053   //If merge_higher_dim is true, do_merge must also be true
00054   if(merge_higher_dim && !do_merge){
00055     return moab::MB_FAILURE;
00056   }
00057 
00058   mergeTol = merge_tol;
00059   mergeTolSq = merge_tol*merge_tol;
00060 
00061   // get the skin of the entities
00062   moab::Skinner skinner(mbImpl);
00063   moab::Range skin_range;
00064   moab::ErrorCode result = skinner.find_skin(0, elems, 0, skin_range, false, false);
00065   if (moab::MB_SUCCESS != result) return result;
00066 
00067   // create a tag to mark merged-to entity; reuse tree_root
00068   moab::EntityHandle tree_root = 0;
00069   if (0 == merge_tag) {
00070     result = mbImpl->tag_get_handle("__merge_tag", 1, moab::MB_TYPE_HANDLE, 
00071                                     mbMergeTag, 
00072                                     moab::MB_TAG_DENSE|moab::MB_TAG_EXCL,
00073                                     &tree_root);
00074     if (moab::MB_SUCCESS != result) return result;
00075   }
00076   else mbMergeTag = merge_tag;
00077   
00078   // build a kd tree with the vertices
00079   moab::AdaptiveKDTree kd(mbImpl);
00080   result = kd.build_tree(skin_range, &tree_root);
00081   if (moab::MB_SUCCESS != result) return result;
00082 
00083   // find matching vertices, mark them
00084   result = find_merged_to(tree_root, kd, mbMergeTag);
00085   if (moab::MB_SUCCESS != result) return result;
00086 
00087   // merge them if requested
00088   if (do_merge) {
00089     result = perform_merge(mbMergeTag);
00090     if (moab::MB_SUCCESS != result) return result;
00091   }
00092 
00093   if(merge_higher_dim && deadEnts.size() != 0){
00094     result = merge_higher_dimensions(elems);
00095     if(moab::MB_SUCCESS != result) return result;
00096   }
00097   
00098   return moab::MB_SUCCESS;
00099 }
00100 
00101 moab::ErrorCode MergeMesh::perform_merge(moab::Tag merge_tag) 
00102 {
00103   moab::ErrorCode result;
00104   if (deadEnts.size()==0){
00105     if(printError)std::cout << "\nWarning: Geometries don't have a common face; Nothing to merge" << std::endl;
00106     return moab::MB_SUCCESS; //nothing to merge carry on with the program
00107   }
00108   if  (mbImpl->type_from_handle(*deadEnts.rbegin()) != moab::MBVERTEX) 
00109     return moab::MB_FAILURE;
00110   std::vector<moab::EntityHandle> merge_tag_val(deadEnts.size());
00111   result = mbImpl->tag_get_data(merge_tag, deadEnts, &merge_tag_val[0]);
00112   if (moab::MB_SUCCESS != result) return result;
00113   
00114   moab::Range::iterator rit;
00115   unsigned int i;
00116   for (rit = deadEnts.begin(), i = 0; rit != deadEnts.end(); rit++, i++) {
00117     assert(merge_tag_val[i]);
00118     result = mbImpl->merge_entities(merge_tag_val[i], *rit, false, false);
00119     if (moab::MB_SUCCESS != result) {
00120       return result;
00121     }
00122   }
00123   result = mbImpl->delete_entities(deadEnts);
00124   return result;
00125 }
00126 
00127 moab::ErrorCode MergeMesh::find_merged_to(moab::EntityHandle &tree_root, 
00128                                           moab::AdaptiveKDTree &tree,
00129                       moab::Tag merge_tag) 
00130 {
00131   moab::AdaptiveKDTreeIter iter;
00132   
00133   // evaluate vertices in this leaf
00134   moab::Range leaf_range, leaf_range2;
00135   std::vector<moab::EntityHandle> sorted_leaves;
00136   std::vector<double> coords;
00137   std::vector<moab::EntityHandle> merge_tag_val, leaves_out;
00138   
00139   moab::ErrorCode result = tree.get_tree_iterator(tree_root, iter);
00140   if (moab::MB_SUCCESS != result) return result;
00141   while (result == moab::MB_SUCCESS) {
00142     sorted_leaves.push_back( iter.handle() );
00143     result = iter.step();
00144   }
00145   if (result != moab::MB_ENTITY_NOT_FOUND)
00146     return result;
00147   std::sort( sorted_leaves.begin(), sorted_leaves.end() );
00148   
00149   std::vector<moab::EntityHandle>::iterator it;
00150   for (it = sorted_leaves.begin(); it != sorted_leaves.end(); ++it) {
00151 
00152     leaf_range.clear();
00153     result = mbImpl->get_entities_by_handle(*it, leaf_range);
00154     if (moab::MB_SUCCESS != result) return result;
00155     coords.resize(3*leaf_range.size());
00156     merge_tag_val.resize(leaf_range.size());
00157     result = mbImpl->get_coords(leaf_range, &coords[0]);
00158     if (moab::MB_SUCCESS != result) return result;
00159     result = mbImpl->tag_get_data(merge_tag, leaf_range, &merge_tag_val[0]);
00160     if (moab::MB_SUCCESS != result) return result;
00161     moab::Range::iterator rit;
00162     unsigned int i;
00163     bool inleaf_merged, outleaf_merged = false;
00164     unsigned int lr_size = leaf_range.size();
00165     
00166     for (i = 0, rit = leaf_range.begin(); i != lr_size; rit++, i++) {
00167       if (0 != merge_tag_val[i]) continue;
00168       moab::CartVect from(&coords[3*i]);
00169       inleaf_merged = false;
00170 
00171       // check close-by leaves too
00172       leaves_out.clear();
00173       result = tree.distance_search(from.array(), mergeTol,
00174                                     leaves_out, mergeTol, 1.0e-6, NULL, NULL, &tree_root);
00175       leaf_range2.clear();
00176       for (std::vector<moab::EntityHandle>::iterator vit = leaves_out.begin();
00177            vit != leaves_out.end(); vit++) {
00178         if (*vit > *it) { // if we haven't visited this leaf yet in the outer loop
00179           result = mbImpl->get_entities_by_handle(*vit, leaf_range2, moab::Interface::UNION);
00180           if (moab::MB_SUCCESS != result) return result;
00181         }
00182       }
00183       if (!leaf_range2.empty()) {
00184         coords.resize(3*(lr_size+leaf_range2.size()));
00185         merge_tag_val.resize(lr_size+leaf_range2.size());
00186         result = mbImpl->get_coords(leaf_range2, &coords[3*lr_size]);
00187         if (moab::MB_SUCCESS != result) return result;
00188         result = mbImpl->tag_get_data(merge_tag, leaf_range2, &merge_tag_val[lr_size]);
00189         if (moab::MB_SUCCESS != result) return result;
00190         outleaf_merged = false;
00191       }
00192 
00193       // check other verts in this leaf
00194       for (unsigned int j = i+1; j < merge_tag_val.size(); j++) {
00195         moab::EntityHandle to_ent = j >= lr_size ? leaf_range2[j-lr_size] : 
00196       leaf_range[j];
00197         
00198         if (*rit == to_ent) continue;
00199         
00200         if ((from - moab::CartVect(&coords[3*j])).length_squared() < mergeTolSq) {
00201           merge_tag_val[j] = *rit;
00202           if (j < lr_size){
00203         inleaf_merged = true;}
00204           else{
00205         outleaf_merged = true;}
00206           deadEnts.insert(to_ent);
00207         }
00208 
00209       }
00210       if (outleaf_merged) {
00211     result = mbImpl->tag_set_data(merge_tag, leaf_range2, &merge_tag_val[leaf_range.size()]);
00212         if (moab::MB_SUCCESS != result) return result;
00213     outleaf_merged = false;
00214       }
00215       if (inleaf_merged) {
00216     result = mbImpl->tag_set_data(merge_tag, leaf_range, &merge_tag_val[0]);
00217     if (moab::MB_SUCCESS != result) return result;
00218       }
00219 
00220     }
00221   }
00222   return moab::MB_SUCCESS;
00223 }
00224 
00225 
00226 //Determine which higher dimensional entities should be merged
00227 moab::ErrorCode MergeMesh::merge_higher_dimensions(moab::Range &elems)
00228 { 
00229   Range skinEnts, adj, matches, moreDeadEnts;  moab::ErrorCode result;
00230   moab::Skinner skinner(mbImpl);
00231   //Go through each dimension
00232   for(int dim = 1; dim <3; dim++){
00233     skinEnts.clear();
00234     moreDeadEnts.clear();
00235     result = skinner.find_skin(0, elems, dim, skinEnts, false, false);
00236     //Go through each skin entity and see if it shares adjacancies with another entity
00237     for(moab::Range::iterator skinIt = skinEnts.begin(); skinIt != skinEnts.end(); skinIt++){
00238       adj.clear();
00239       //Get the adjacencies 1 dimension lower
00240       result = mbImpl->get_adjacencies(&(*skinIt), 1, dim-1, false, adj);
00241       if(result != moab::MB_SUCCESS) return result;
00242       //See what other entities share these adjacencies
00243       matches.clear();
00244       result = mbImpl->get_adjacencies(adj, dim, false, matches, moab::Interface::INTERSECT);
00245       if(result != moab::MB_SUCCESS) return result;
00246       //If there is more than one entity, then we have some to merge and erase
00247       if(matches.size() > 1){
00248     for(moab::Range::iterator matchIt = matches.begin(); matchIt != matches.end(); matchIt++){
00249       if(*matchIt != *skinIt){
00250         moreDeadEnts.insert(*matchIt);
00251         result = mbImpl->merge_entities(*skinIt, *matchIt, false, false);
00252         if(result != moab::MB_SUCCESS) return result;
00253         skinEnts.erase(*matchIt);
00254       }
00255     }
00256       }      
00257     }
00258     //Delete the entities
00259     result = mbImpl->delete_entities(moreDeadEnts);
00260     if(result != moab::MB_SUCCESS)return result;
00261   }
00262   return moab::MB_SUCCESS;
00263 }
00264 
00265 }//End namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines