MeshKit
1.0
|
00001 #include "meshkit/ExtrudeMesh.hpp" 00002 #include "meshkit/CopyMesh.hpp" 00003 #include "meshkit/MKCore.hpp" 00004 #include "meshkit/ModelEnt.hpp" 00005 #include "meshkit/SizingFunction.hpp" 00006 #include "meshkit/RegisterMeshOp.hpp" 00007 #include "meshkit/LocalSet.hpp" 00008 00009 #include "iMesh_extensions.h" 00010 00011 #define CHKERR(err) do { \ 00012 if ((err) != iBase_SUCCESS) \ 00013 return iBase_ErrorType(err); \ 00014 } while(false) 00015 00016 namespace MeshKit 00017 { 00018 00019 // static registration of this mesh scheme 00020 moab::EntityType ExtrudeMesh_tps[] = { moab::MBVERTEX, 00021 moab::MBEDGE, 00022 moab::MBTRI, 00023 moab::MBHEX, 00024 moab::MBMAXTYPE}; 00025 00026 const moab::EntityType* ExtrudeMesh::output_types() 00027 { return ExtrudeMesh_tps; } 00028 00029 ExtrudeMesh::ExtrudeMesh(MKCore *mkcore, const MEntVector &me_vec) 00030 : MeshScheme(mkcore, me_vec), 00031 mesh(mkcore->imesh_instance()), 00032 extrudeTag(mkcore, "__ExtrudeMeshTag"), 00033 copyTag(mkcore, "__CopyMeshTag"), 00034 transform(0), 00035 copyFaces(false), 00036 extrudeSets(mkcore), 00037 copySets(mkcore), 00038 expandSets(mkcore) 00039 {} 00040 00041 ExtrudeMesh::~ExtrudeMesh() 00042 {} 00043 00044 00045 bool ExtrudeMesh::add_modelent(ModelEnt *model_ent) 00046 { 00047 return MeshOp::add_modelent(model_ent); 00048 } 00049 00050 void ExtrudeMesh::setup_this() 00051 {} 00052 00053 void ExtrudeMesh::execute_this() 00054 { 00055 std::vector<iMesh::EntityHandle> orig_ents(mentSelection.size()); 00056 00057 int i = 0; 00058 for (MEntSelection::iterator mit = mentSelection.begin(); 00059 mit != mentSelection.end(); mit++) { 00060 ModelEnt *me = mit->first; 00061 orig_ents[i++] = reinterpret_cast<iBase_EntityHandle> (me->mesh_handle()); 00062 } 00063 00064 LocalSet set(this->mk_core()); 00065 00066 IBERRCHK(mesh->addEntArrToSet(&orig_ents[0], orig_ents.size(), set), *mesh); 00067 do_extrude(set); 00068 } 00069 00070 int ExtrudeMesh::getStructure(iMesh_Instance instance, 00071 iBase_EntitySetHandle set, 00072 std::vector<iBase_EntityHandle> &ents, 00073 std::vector<iBase_EntityHandle> &unique_adj, 00074 std::vector<int> &indices, 00075 std::vector<int> &offsets) 00076 { 00077 // 1) Get source entities, making sure verts are first 00078 int num; 00079 int err; 00080 iMesh_getNumOfTypeRec(instance, set, iBase_ALL_TYPES, true, &num, &err); 00081 CHKERR(err); 00082 00083 ents.resize(num); 00084 offsets.resize(num+1); 00085 00086 iBase_EntityHandle *block = &ents[0]; 00087 int block_alloc = ents.size(), block_size, num_verts = 0; 00088 for (int t = iMesh_POINT; t < iMesh_ALL_TOPOLOGIES && block_alloc; ++t) { 00089 iMesh_getEntitiesRec(instance, set, iBase_ALL_TYPES, t, true, 00090 &block, &block_alloc, &block_size, &err); 00091 CHKERR(err); 00092 00093 block_alloc -= block_size; 00094 block += block_size; 00095 if (t == iMesh_POINT) 00096 num_verts = block_size; 00097 } 00098 00099 // 2) Get verts adjacent to all source entitites (verts are adj to themselves) 00100 std::vector<iBase_EntityHandle> all_adj(ents.begin(), ents.begin()+num_verts); 00101 00102 // first, fill the vertex-vertex adjacencies 00103 for (int i = 0; i < num_verts; ++i) 00104 offsets[i] = i; 00105 00106 iBase_EntityHandle *tmp_adj = NULL; 00107 int tmp_adj_alloc = 0, tmp_adj_size; 00108 int *tmp_off = &offsets[num_verts]; 00109 int tmp_off_alloc = offsets.size() - num_verts, tmp_off_size; 00110 iMesh_getEntArrAdj(instance, &ents[num_verts], ents.size()-num_verts, 00111 iBase_VERTEX, &tmp_adj, &tmp_adj_alloc, &tmp_adj_size, 00112 &tmp_off, &tmp_off_alloc, &tmp_off_size, &err); 00113 CHKERR(err); 00114 00115 // shift all the offsets to account for vertices 00116 for(unsigned int i = num_verts; i < offsets.size(); ++i) 00117 offsets[i] += num_verts; 00118 00119 all_adj.reserve(all_adj.size() + tmp_adj_size); 00120 all_adj.insert(all_adj.end(), tmp_adj, tmp_adj+tmp_adj_size); 00121 free(tmp_adj); 00122 00123 // 3) Get unique adjacent vertices and offsets 00124 unique_adj.resize(all_adj.size()); 00125 indices.resize(all_adj.size()); 00126 std::copy(all_adj.begin(), all_adj.end(), unique_adj.begin()); 00127 std::sort(unique_adj.begin(), unique_adj.end()); 00128 00129 size_t unique_size; 00130 unique_size = std::unique(unique_adj.begin(), unique_adj.end()) - 00131 unique_adj.begin(); 00132 unique_adj.resize(unique_size); 00133 00134 for (size_t i = 0; i < all_adj.size(); ++i) { 00135 indices[i] = std::lower_bound(unique_adj.begin(), unique_adj.end(), 00136 all_adj[i]) - unique_adj.begin(); 00137 } 00138 00139 return 0; 00140 } 00141 00142 void ExtrudeMesh::update_sets() 00143 { 00144 copySets.update_tagged_sets(); 00145 expandSets.update_tagged_sets(); 00146 } 00147 00148 void ExtrudeMesh::do_extrude(iBase_EntitySetHandle src) 00149 { 00150 assert(transform && transform->steps() > 0); 00151 00152 update_sets(); 00153 00154 std::vector<iBase_EntityHandle> ents; 00155 std::vector<iBase_EntityHandle> verts; 00156 std::vector<int> indices; 00157 std::vector<int> offsets; 00158 00159 // IBERRCHK(iMesh_getStructure(mesh->instance(), src, ents, verts, 00160 // indices, offsets), *mesh); 00161 getStructure(mesh->instance(), src, ents, verts, 00162 indices, offsets); 00163 00164 if (ents.size() == 0) return; 00165 00166 std::vector<iBase_EntityHandle> curr; 00167 std::vector<iBase_EntityHandle> next; 00168 std::vector<int> normals; 00169 00170 LocalTag local_extrude_tag(this->mk_core()); 00171 LocalTag local_copy_tag(this->mk_core()); 00172 00173 curr.resize(verts.size()); 00174 next.resize(verts.size()); 00175 transform->transform(1, mesh, verts, next); 00176 00177 // Get the offset between vertices between steps 00178 Vector<3> xa, xb, dx; 00179 IBERRCHK(mesh->getVtxCoord(next[0], xa[0], xa[1], xa[2]), *mesh); 00180 IBERRCHK(mesh->getVtxCoord(verts[0], xb[0], xb[1], xb[2]), *mesh); 00181 dx = xa-xb; 00182 00183 get_normals(verts, indices, offsets, dx, normals); 00184 00185 // Make the first set of volumes 00186 connect_up_dots(&ents[0], ents.size(), local_extrude_tag, &normals[0], 00187 &indices[0], &offsets[0], &verts[0], &next[0]); 00188 00189 // Now do the rest 00190 for (int i=2; i<=transform->steps(); i++) { 00191 std::swap(curr, next); 00192 transform->transform(i, mesh, verts, next); 00193 connect_up_dots(&ents[0], ents.size(), local_extrude_tag, &normals[0], 00194 &indices[0], &offsets[0], &curr[0], &next[0]); 00195 } 00196 00197 tag_copy_sets(extrudeSets, local_extrude_tag, extrudeTag); 00198 00199 if (copyFaces) { 00200 // set the local copy tags on vertices 00201 // XXX: Should this really happen? Doing so adds more entities to copysets 00202 // than explicitly passed into this function. This may be a domain- 00203 // specific question. 00204 IBERRCHK(mesh->setEHArrData(&verts[0], verts.size(), local_copy_tag, 00205 &next[0]), *mesh); 00206 00207 connect_the_dots(mesh, local_copy_tag, ents, indices, offsets, next); 00208 00209 link_expand_sets(expandSets, local_copy_tag); 00210 00211 process_ce_sets(mesh, copySets.sets(), local_copy_tag); 00212 process_ce_sets(mesh, expandSets.sets(), local_copy_tag); 00213 00214 tag_copy_sets(copySets, local_copy_tag, copyTag); 00215 } 00216 } 00217 00218 // calculate the normals for each face (1 = towards v, -1 = away from v) 00219 // TODO: this can fail with non-convex faces 00220 void ExtrudeMesh::get_normals(const std::vector<iBase_EntityHandle> &verts, 00221 const std::vector<int> &indices, 00222 const std::vector<int> &offsets, 00223 const Vector<3> &dv, std::vector<int> &normals) 00224 { 00225 size_t size = offsets.size() - 1; 00226 normals.resize(size); 00227 00228 for(size_t i=0; i<size; i++) { 00229 Vector<3> a, b; 00230 iBase_EntityHandle curr_verts[3]; 00231 00232 if(offsets[i+1] - offsets[i] > 2) { // face 00233 for(int j=0; j<3; j++) 00234 curr_verts[j] = verts[indices[ offsets[i]+j ]]; 00235 00236 std::vector< Vector<3> > coords(3); 00237 IBERRCHK(mesh->getVtxArrCoords(curr_verts, 3, iBase_INTERLEAVED, 00238 vec2ptr(coords)), *mesh); 00239 00240 a = coords[1] - coords[0]; 00241 b = coords[2] - coords[1]; 00242 normals[i] = (vector_product(a, b) % dv) > 0 ? 1:-1; 00243 } 00244 else if(offsets[i+1] - offsets[i] == 2) { // line 00245 normals[i] = 1; // TODO: figure out a way of distinguishing swapped 00246 // lines 00247 } 00248 else // vertex 00249 normals[i] = 1; 00250 } 00251 } 00252 00253 void ExtrudeMesh::connect_up_dots( 00254 iBase_EntityHandle *src, int size, iBase_TagHandle local_tag, 00255 int *pre_norms, int *pre_inds, int *pre_offs, iBase_EntityHandle *pre, 00256 int *post_norms, int *post_inds, int *post_offs, iBase_EntityHandle *post) 00257 { 00258 for(int i=0; i<size; i++) { 00259 int count = pre_offs[i+1] - pre_offs[i]; 00260 00261 // If the normal is facing in the wrong direction (away from the 00262 // translation) we add the vertices in reverse order. Otherwise, we go 00263 // in the usual order. If count is 2, then we are creating quads and so 00264 // need to swap the order of the post set of verts. 00265 00266 int dx = pre_norms [i]; 00267 int dy = post_norms[i] * (count == 2 ? -1:1); 00268 int x = (dx == 1) ? pre_offs [i] : pre_offs [i+1]-1; 00269 int y = (dy == 1) ? post_offs[i] : post_offs[i+1]-1; 00270 00271 iBase_EntityHandle *nodes = new iBase_EntityHandle[count*2]; 00272 for(int j=0; j<count; j++) { 00273 nodes[j] = pre [ pre_inds [x + dx*j] ]; 00274 nodes[j+count] = post[ post_inds[y + dy*j] ]; 00275 } 00276 00277 iBase_EntityHandle out; 00278 00279 iMesh::Error err; 00280 if(count == 4) // quad 00281 err = mesh->createEnt(iMesh_HEXAHEDRON, nodes, 8, out); 00282 else if(count == 3) // tri 00283 err = mesh->createEnt(iMesh_PRISM, nodes, 6, out); 00284 else if(count == 2) // line 00285 err = mesh->createEnt(iMesh_QUADRILATERAL, nodes, 4, out); 00286 else if(count == 1) // vertex 00287 err = mesh->createEnt(iMesh_LINE_SEGMENT, nodes, 2, out); 00288 else 00289 throw Error(iBase_FAILURE, "Couldn't extrude face; unusual shape."); 00290 00291 IBERRCHK(err, *mesh); 00292 delete[] nodes; 00293 00294 IBERRCHK(mesh->setEHData(src[i], local_tag, out), *mesh); 00295 } 00296 00297 process_ce_sets(mesh, extrudeSets.sets(), local_tag); 00298 } 00299 } // namespace MeshKit