MeshKit  1.0
ExtrudeMesh.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines