moab
|
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