contrib/brl/bbas/imesh/imesh_operations.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/imesh_operations.cxx
00002 #include "imesh_operations.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_map.h>
00008 #include <vcl_cassert.h>
00009 #include <vgl/vgl_point_2d.h>
00010 #include <vgl/vgl_point_3d.h>
00011 #include <vgl/vgl_vector_3d.h>
00012 
00013 //: Subdivide mesh faces into triangle
00014 vcl_auto_ptr<imesh_regular_face_array<3> >
00015 imesh_triangulate(const imesh_face_array_base& faces)
00016 {
00017   vcl_auto_ptr<imesh_regular_face_array<3> > tris(new imesh_regular_face_array<3>);
00018   int group = -1;
00019   if (faces.has_groups())
00020     group = 0;
00021   for (unsigned int f=0; f<faces.size(); ++f) {
00022     for (unsigned i=2; i<faces.num_verts(f); ++i)
00023       tris->push_back(imesh_tri(faces(f,0),faces(f,i-1),faces(f,i)));
00024     if (group >= 0 && f+1 >= faces.groups()[group].second) {
00025       tris->make_group(faces.groups()[group++].first);
00026     }
00027   }
00028   return tris;
00029 }
00030 
00031 
00032 //: Subdivide quadrilaterals into triangle
00033 vcl_auto_ptr<imesh_regular_face_array<3> >
00034 imesh_triangulate(const imesh_regular_face_array<4>& faces)
00035 {
00036   vcl_auto_ptr<imesh_regular_face_array<3> > tris(new imesh_regular_face_array<3>);
00037   int group = -1;
00038   if (faces.has_groups())
00039     group = 0;
00040   for (unsigned int f=0; f<faces.size(); ++f) {
00041     const imesh_regular_face<4>& face = faces[f];
00042     tris->push_back(imesh_tri(face[0],face[1],face[2]));
00043     tris->push_back(imesh_tri(face[0],face[2],face[3]));
00044     if (group >= 0 && f+1 >= faces.groups()[group].second) {
00045       tris->make_group(faces.groups()[group++].first);
00046     }
00047   }
00048   return tris;
00049 }
00050 
00051 
00052 //: Triangulate the faces of the mesh (in place)
00053 void
00054 imesh_triangulate(imesh_mesh& mesh)
00055 {
00056   switch (mesh.faces().regularity())
00057   {
00058     case 3: break;
00059     case 4:
00060     {
00061       vcl_auto_ptr<imesh_face_array_base> tris(
00062           imesh_triangulate(static_cast<const imesh_regular_face_array<4>&>(mesh.faces())));
00063       mesh.set_faces(tris);
00064       break;
00065     }
00066     default:
00067     {
00068       vcl_auto_ptr<imesh_face_array_base> tris(imesh_triangulate(mesh.faces()));
00069       mesh.set_faces(tris);
00070       break;
00071     }
00072   }
00073 }
00074 
00075 
00076 namespace {
00077 
00078 void average_verts_2(imesh_vertex_array_base& verts,
00079                      const vcl_vector<vcl_vector<unsigned int> >& idx)
00080 {
00081   assert(dynamic_cast<imesh_vertex_array<2>*>(&verts));
00082   imesh_vertex_array<2>& verts2 = static_cast<imesh_vertex_array<2>&>(verts);
00083 
00084   for (unsigned int i=0; i<idx.size(); ++i) {
00085     const vcl_vector<unsigned int>& new_idx = idx[i];
00086     imesh_vertex<2> new_v;
00087     for (unsigned int j=0; j<new_idx.size(); ++j) {
00088       const imesh_vertex<2>& v = verts2[new_idx[j]];
00089       new_v[0] += v[0];
00090       new_v[1] += v[1];
00091     }
00092     new_v[0] /= new_idx.size();
00093     new_v[1] /= new_idx.size();
00094     verts2.push_back(new_v);
00095   }
00096 }
00097 
00098 
00099 void average_verts_3(imesh_vertex_array_base& verts,
00100                      const vcl_vector<vcl_vector<unsigned int> >& idx)
00101 {
00102   assert(dynamic_cast<imesh_vertex_array<3>*>(&verts));
00103   imesh_vertex_array<3>& verts3 = static_cast<imesh_vertex_array<3>&>(verts);
00104 
00105   for (unsigned int i=0; i<idx.size(); ++i) {
00106     const vcl_vector<unsigned int>& new_idx = idx[i];
00107     imesh_vertex<3> new_v;
00108     for (unsigned int j=0; j<new_idx.size(); ++j) {
00109       const imesh_vertex<3>& v = verts3[new_idx[j]];
00110       new_v[0] += v[0];
00111       new_v[1] += v[1];
00112       new_v[2] += v[2];
00113     }
00114     new_v[0] /= new_idx.size();
00115     new_v[1] /= new_idx.size();
00116     new_v[2] /= new_idx.size();
00117     verts3.push_back(new_v);
00118   }
00119 }
00120 // end of namespace
00121 };
00122 
00123 
00124 //: Subdivide faces into quadrilaterals (in place)
00125 //  Add a vertex at the center of each edge
00126 //  And a vertex at the center of each face
00127 void
00128 imesh_quad_subdivide(imesh_mesh& mesh)
00129 {
00130   bool had_edges = mesh.has_half_edges();
00131   if (!had_edges)
00132     mesh.build_edge_graph();
00133 
00134   const imesh_face_array_base& faces = mesh.faces();
00135   imesh_vertex_array_base& verts = mesh.vertices();
00136   const imesh_half_edge_set& half_edges = mesh.half_edges();
00137 
00138   const unsigned int num_o_verts = mesh.num_verts(); // original vertices
00139   const unsigned int num_e_verts = mesh.num_edges(); // edge vertices
00140   const unsigned int num_f_verts = mesh.num_faces(); // face vertices
00141 
00142   // construct vector of indices of vertices to average to create new vertices
00143   vcl_vector<vcl_vector<unsigned int> > merge_idx;
00144   // edge indices
00145   for (unsigned int e=0; e<num_e_verts; ++e) {
00146     vcl_vector<unsigned int> new_e_vert;
00147     new_e_vert.push_back(half_edges[2*e].vert_index());
00148     new_e_vert.push_back(half_edges[2*e+1].vert_index());
00149     merge_idx.push_back(new_e_vert);
00150   }
00151   // face indices
00152   for (unsigned int f=0; f<num_f_verts; ++f) {
00153     vcl_vector<unsigned int> new_f_vert;
00154     for (unsigned int i=0; i<faces.num_verts(f); ++i) {
00155       new_f_vert.push_back(faces(f,i));
00156     }
00157     merge_idx.push_back(new_f_vert);
00158   }
00159 
00160   // create and append new vertices
00161   switch (verts.dim()) {
00162     case 2:
00163       average_verts_2(verts,merge_idx);
00164       break;
00165     case 3:
00166       average_verts_3(verts,merge_idx);
00167       break;
00168     default:
00169       vcl_cerr << "can not handle vertices of dimension: "
00170                << verts.dim() << '\n';
00171       return;
00172   }
00173 
00174   if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT) {
00175     vcl_vector<vgl_point_2d<double> > tex_coords(mesh.tex_coords());
00176     for (unsigned int i=0; i<merge_idx.size(); ++i) {
00177       const vcl_vector<unsigned int>& new_idx = merge_idx[i];
00178       vgl_point_2d<double> new_tc(0,0);
00179       for (unsigned int j=0; j<new_idx.size(); ++j) {
00180         const vgl_point_2d<double>& v = tex_coords[new_idx[j]];
00181         new_tc.x() += v.x();
00182         new_tc.y() += v.y();
00183       }
00184       new_tc.x() /= new_idx.size();
00185       new_tc.y() /= new_idx.size();
00186       tex_coords.push_back(new_tc);
00187     }
00188     mesh.set_tex_coords(tex_coords);
00189   }
00190 
00191   // construct the new quad faces
00192   vcl_auto_ptr<imesh_regular_face_array<4> > new_faces(new imesh_regular_face_array<4>);
00193   vcl_vector<vgl_point_2d<double> > tex_coords;
00194   unsigned int f_vert_base = num_o_verts+num_e_verts;
00195   for (unsigned int he=0; he<half_edges.size(); ++he) {
00196     if (half_edges[he].is_boundary())
00197       continue;
00198     unsigned int next = half_edges[he].next_index(); // next edge
00199     new_faces->push_back(imesh_quad(f_vert_base + half_edges[he].face_index(), // face vertex
00200                                     num_o_verts + (he>>1), // current edge vertex
00201                                     half_edges[next].vert_index(), // original vertex
00202                                     num_o_verts + (next>>1) ) ); // next edge vertex
00203     if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_CORNER) {
00204       vcl_cerr << "subdivision of texture coords per corner is not implemented\n";
00205     }
00206   }
00207   if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_CORNER) {
00208     mesh.set_tex_coords(tex_coords);
00209   }
00210 
00211 
00212   mesh.set_faces(vcl_auto_ptr<imesh_face_array_base>(new_faces));
00213   mesh.remove_edge_graph();
00214   if (had_edges)
00215     mesh.build_edge_graph();
00216 }
00217 
00218 
00219 //: Subdivide faces into quadrilaterals (in place)
00220 //  Add a vertex at the center of each edge
00221 //  And a vertex at the center of each face
00222 //  Only subdivide the selected faces
00223 void
00224 imesh_quad_subdivide(imesh_mesh& mesh, const vcl_set<unsigned int>& sel_faces)
00225 {
00226   bool had_edges = mesh.has_half_edges();
00227   if (!had_edges)
00228     mesh.build_edge_graph();
00229 
00230   const imesh_face_array_base& faces = mesh.faces();
00231   imesh_vertex_array_base& verts = mesh.vertices();
00232   const imesh_half_edge_set& half_edges = mesh.half_edges();
00233 
00234   const unsigned int num_o_verts = mesh.num_verts(); // original vertices
00235   const unsigned int num_e = mesh.num_edges(); // edges
00236   const unsigned int num_f = mesh.num_faces(); // faces
00237 
00238   vcl_map<unsigned int,unsigned int> edge_map, face_map;
00239 
00240   // construct vector of indices of vertices to average to create new vertices
00241   vcl_vector<vcl_vector<unsigned int> > merge_idx;
00242   // edge indices
00243   for (unsigned int e=0; e<num_e; ++e) {
00244     if (sel_faces.count(half_edges[2*e].face_index()) +
00245        sel_faces.count(half_edges[2*e+1].face_index()) > 0) {
00246       vcl_vector<unsigned int> new_e_vert;
00247       new_e_vert.push_back(half_edges[2*e].vert_index());
00248       new_e_vert.push_back(half_edges[2*e+1].vert_index());
00249       edge_map[e] = merge_idx.size() + num_o_verts;
00250       merge_idx.push_back(new_e_vert);
00251     }
00252   }
00253   // face indices
00254   for (vcl_set<unsigned int>::const_iterator fi = sel_faces.begin();
00255        fi != sel_faces.end(); ++fi) {
00256     vcl_vector<unsigned int> new_f_vert;
00257     for (unsigned int i=0; i<faces.num_verts(*fi); ++i) {
00258       new_f_vert.push_back(faces(*fi,i));
00259     }
00260     face_map[*fi] = merge_idx.size() + num_o_verts;
00261     merge_idx.push_back(new_f_vert);
00262   }
00263 
00264   // create and append new vertices
00265   switch (verts.dim()) {
00266     case 2:
00267       average_verts_2(verts,merge_idx);
00268       break;
00269     case 3:
00270       average_verts_3(verts,merge_idx);
00271       break;
00272     default:
00273       vcl_cerr << "can not handle vertices of dimension: "
00274                << verts.dim() << '\n';
00275       return;
00276   }
00277 
00278   if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT) {
00279     vcl_vector<vgl_point_2d<double> > tex_coords(mesh.tex_coords());
00280     for (unsigned int i=0; i<merge_idx.size(); ++i) {
00281       const vcl_vector<unsigned int>& new_idx = merge_idx[i];
00282       vgl_point_2d<double> new_tc(0,0);
00283       for (unsigned int j=0; j<new_idx.size(); ++j) {
00284         const vgl_point_2d<double>& v = tex_coords[new_idx[j]];
00285         new_tc.x() += v.x();
00286         new_tc.y() += v.y();
00287       }
00288       new_tc.x() /= new_idx.size();
00289       new_tc.y() /= new_idx.size();
00290       tex_coords.push_back(new_tc);
00291     }
00292     mesh.set_tex_coords(tex_coords);
00293   }
00294 
00295   // construct the new faces
00296   typedef vcl_map<unsigned int,unsigned int>::const_iterator map_itr;
00297   typedef imesh_half_edge_set::f_const_iterator face_itr;
00298   vcl_auto_ptr<imesh_face_array> new_faces(new imesh_face_array);
00299   int group = -1;
00300   if (faces.has_groups())
00301     group = 0;
00302   for (unsigned int f=0; f<num_f; ++f)
00303   {
00304     map_itr i = face_map.find(f);
00305     if (i == face_map.end()){ // don't subdivide face
00306       face_itr fei = half_edges.face_begin(f);
00307       face_itr end = fei;
00308       vcl_vector<unsigned int> new_face;
00309       do{
00310         new_face.push_back(fei->vert_index());
00311         map_itr i2 = edge_map.find(fei->edge_index());
00312         if (i2 != edge_map.end())
00313           new_face.push_back(i2->second);
00314         ++fei;
00315       } while (fei != end);
00316       new_faces->push_back(new_face);
00317     }
00318     else{ // subdivide face
00319       face_itr fei = half_edges.face_begin(f);
00320       face_itr end = fei;
00321       do{
00322         face_itr next = fei;
00323         ++next;
00324         new_faces->push_back(imesh_quad(i->second, // face vertex
00325                                         edge_map[fei->edge_index()], // current edge vertex
00326                                         next->vert_index(), // original vertex
00327                                         edge_map[next->edge_index()] ) ); // next edge vertex
00328         fei = next;
00329       } while (fei != end);
00330     }
00331     if (group >= 0 && f+1 >= faces.groups()[group].second) {
00332       new_faces->make_group(faces.groups()[group++].first);
00333     }
00334   }
00335 
00336 
00337   mesh.set_faces(vcl_auto_ptr<imesh_face_array_base>(new_faces));
00338   mesh.remove_edge_graph();
00339   if (had_edges)
00340     mesh.build_edge_graph();
00341 }
00342 
00343 
00344 //: Extract a sub-mesh containing only the faces listed in sel_faces
00345 imesh_mesh
00346 imesh_submesh_from_faces(const imesh_mesh& mesh, const vcl_set<unsigned int>& sel_faces)
00347 {
00348   const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00349 
00350   vcl_auto_ptr<imesh_face_array> new_faces(new imesh_face_array);
00351   vcl_auto_ptr<imesh_vertex_array<3> > new_verts(new imesh_vertex_array<3>);
00352   vcl_vector<int> vert_map(mesh.num_verts(),-1);
00353 
00354   unsigned int new_count = 0;
00355   vcl_vector<vgl_vector_3d<double> > fnormals;
00356   vcl_vector<vgl_vector_3d<double> > vnormals;
00357   vcl_vector<vgl_point_2d<double> > tex_coords;
00358   const vcl_vector<vcl_pair<vcl_string,unsigned int> >& groups = mesh.faces().groups();
00359   unsigned int group_idx = 0;
00360   for (vcl_set<unsigned int>::const_iterator fi=sel_faces.begin();
00361        fi!=sel_faces.end(); ++fi)
00362   {
00363     const unsigned int num_v = mesh.faces().num_verts(*fi);
00364     vcl_vector<unsigned int> new_face;
00365     for (unsigned int i=0; i<num_v; ++i) {
00366       unsigned int v = mesh.faces()(*fi,i);
00367       int& nv = vert_map[v];
00368       if (nv < 0) {
00369         nv = new_count++;
00370         new_verts->push_back(verts[v]);
00371         if (verts.has_normals())
00372           vnormals.push_back(verts.normal(v));
00373         if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT)
00374           tex_coords.push_back(mesh.tex_coords()[v]);
00375       }
00376       new_face.push_back(nv);
00377     }
00378     if (mesh.faces().has_groups()) {
00379       while (group_idx < groups.size() && groups[group_idx].second <= *fi)
00380       {
00381         new_faces->make_group(groups[group_idx].first);
00382         ++group_idx;
00383       }
00384     }
00385     new_faces->push_back(new_face);
00386     if (mesh.faces().has_normals())
00387       fnormals.push_back(mesh.faces().normal(*fi));
00388   }
00389   if (!fnormals.empty())
00390     new_faces->set_normals(fnormals);
00391   if (!vnormals.empty())
00392     new_verts->set_normals(vnormals);
00393 
00394 
00395   vcl_auto_ptr<imesh_vertex_array_base> nverts(new_verts);
00396   vcl_auto_ptr<imesh_face_array_base> nfaces(new_faces);
00397   imesh_mesh submesh(nverts,nfaces);
00398 
00399   if (mesh.has_tex_coords())
00400     submesh.set_tex_coords(tex_coords);
00401 
00402   return submesh;
00403 }
00404 
00405 
00406 //: Flip the orientation of all mesh faces
00407 void imesh_flip_faces( imesh_mesh& mesh )
00408 {
00409   for (unsigned int f=0; f<mesh.num_faces(); ++f)
00410   {
00411     mesh.faces().flip_orientation(f);
00412   }
00413 }
00414 
00415 
00416 //: Flip the orientation of the selected faces
00417 void imesh_flip_faces( imesh_mesh& mesh, const vcl_set<unsigned int>& sel_faces)
00418 {
00419   for (vcl_set<unsigned int>::const_iterator fi=sel_faces.begin();
00420        fi!=sel_faces.end(); ++fi)
00421   {
00422     mesh.faces().flip_orientation(*fi);
00423   }
00424 }
00425 
00426 
00427 //: Compute the dual mesh using face centroids for vertices
00428 imesh_mesh dual_mesh(const imesh_mesh& mesh)
00429 {
00430   assert(mesh.has_half_edges());
00431   const imesh_half_edge_set& half_edges = mesh.half_edges();
00432   const unsigned int num_verts = mesh.num_verts();
00433   const unsigned int num_faces = mesh.num_faces();
00434 
00435   vcl_auto_ptr<imesh_face_array> new_faces(new imesh_face_array);
00436   vcl_auto_ptr<imesh_vertex_array<3> > new_verts(new imesh_vertex_array<3>);
00437 
00438   for (unsigned int i=0; i<num_faces; ++i)
00439   {
00440     vcl_vector<vgl_point_3d<double> > pts;
00441     for (unsigned int j=0; j<mesh.faces().num_verts(i); ++j)
00442     {
00443       unsigned int v = mesh.faces()(i,j);
00444       pts.push_back(mesh.vertices<3>()[v]);
00445     }
00446     new_verts->push_back(centre(pts));
00447   }
00448   if (mesh.faces().has_normals())
00449     new_verts->set_normals(mesh.faces().normals());
00450 
00451   for (unsigned int i=0; i<num_verts; ++i)
00452   {
00453     typedef imesh_half_edge_set::v_const_iterator vitr;
00454     vcl_vector<unsigned int> face;
00455     vitr end = half_edges.vertex_begin(i), v = end;
00456     face.push_back(v->face_index());
00457     for (++v; v != end; ++v)
00458     {
00459       face.push_back(v->face_index());
00460     }
00461     new_faces->push_back(face);
00462   }
00463   if (mesh.vertices().has_normals())
00464     new_faces->set_normals(mesh.vertices().normals());
00465 
00466   vcl_auto_ptr<imesh_face_array_base> nf(new_faces);
00467   vcl_auto_ptr<imesh_vertex_array_base > nv(new_verts);
00468   return imesh_mesh(nv,nf);
00469 }
00470 
00471 //: Contains a 3d point in convex polygon
00472 bool contains_point(const imesh_mesh& mesh,vgl_point_3d<double> p)
00473 {
00474   vcl_auto_ptr<imesh_face_array> new_faces(new imesh_face_array);
00475   vcl_auto_ptr<imesh_vertex_array<3> > new_verts(new imesh_vertex_array<3>);
00476 
00477   for (unsigned int i=0; i<mesh.num_faces(); ++i)
00478   {
00479     vcl_vector<vgl_point_3d<double> > pts;
00480     for (unsigned int j=0; j<mesh.faces().num_verts(i); ++j)
00481     {
00482       unsigned int v = mesh.faces()(i,j);
00483       pts.push_back(mesh.vertices<3>()[v]);
00484     }
00485     new_verts->push_back(centre(pts));
00486   }
00487   if (mesh.faces().has_normals())
00488     new_verts->set_normals(mesh.faces().normals());
00489   vcl_vector<vgl_vector_3d<double> > normals=  new_verts->normals();
00490   imesh_vertex_array<3>::const_iterator iter=new_verts->begin();
00491   unsigned int i=0;
00492   for (;iter!=new_verts->end();iter++,i++)
00493   {
00494     vgl_point_3d<double> new_vert((*iter)[0],(*iter)[1],(*iter)[2]);
00495     double dotprod=dot_product<double>(new_vert-p,normals[i]);
00496     if (dotprod<0)
00497       return false;
00498   }
00499   return true;
00500 }