contrib/brl/bbas/imesh/algo/imesh_operations.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/algo/imesh_operations.cxx
00002 #include "imesh_operations.h"
00003 //:
00004 // \file
00005 
00006 #include <vgl/vgl_plane_3d.h>
00007 #include <vgl/vgl_area.h>
00008 #include <vgl/vgl_polygon.h>
00009 #include <vgl/vgl_triangle_test.h>
00010 #include <vnl/vnl_matrix.h>
00011 #include <vnl/vnl_double_3.h>
00012 #include <vnl/algo/vnl_svd.h>
00013 #include <vcl_cassert.h>
00014 #include <vcl_list.h>
00015 
00016 #include <vcl_iostream.h>
00017 
00018 
00019 //: Compute the dual mesh using vertex normals to compute dual vertices
00020 imesh_mesh dual_mesh_with_normals(const imesh_mesh& mesh,
00021                                   const imesh_vertex_array_base& old_verts,
00022                                   double tau)
00023 {
00024   assert(mesh.has_half_edges());
00025   const imesh_half_edge_set& half_edges = mesh.half_edges();
00026   const imesh_vertex_array<3>& init_verts =
00027       static_cast<const imesh_vertex_array<3>&>(old_verts);
00028   const unsigned int num_verts = mesh.num_verts();
00029   const unsigned int num_faces = mesh.num_faces();
00030 
00031   vcl_auto_ptr<imesh_face_array> new_faces(new imesh_face_array);
00032   vcl_auto_ptr<imesh_vertex_array<3> > new_verts(new imesh_vertex_array<3>);
00033 
00034   for (unsigned int i=0; i<num_verts; ++i)
00035   {
00036     typedef imesh_half_edge_set::v_const_iterator vitr;
00037     vcl_vector<unsigned int> face;
00038     vitr end = half_edges.vertex_begin(i), v = end;
00039     face.push_back(v->face_index());
00040     for (++v; v != end; ++v)
00041     {
00042       face.push_back(v->face_index());
00043     }
00044     new_faces->push_back(face);
00045   }
00046   new_faces->set_normals(mesh.vertices().normals());
00047 
00048 
00049   for (unsigned int i=0; i<num_faces; ++i)
00050   {
00051     const unsigned int num_planes = mesh.faces().num_verts(i);
00052     vgl_point_3d<double> p0(init_verts[i]);
00053     vgl_vector_3d<double> v0(p0.x(), p0.y(), p0.z());
00054     vnl_matrix<double> A(num_planes, 3);
00055     vnl_vector<double> b(num_planes);
00056     for (unsigned int j=0; j<num_planes; ++j)
00057     {
00058       unsigned int v = mesh.faces()(i,j);
00059       vgl_point_3d<double> c(mesh.vertices<3>()[v]);
00060       c -= v0;
00061       vgl_plane_3d<double> p(mesh.vertices().normal(v), c);
00062       A(j,0) = p.nx();
00063       A(j,1) = p.ny();
00064       A(j,2) = p.nz();
00065       b(j)   = -p.d();
00066     }
00067 
00068     vnl_svd<double> svd(A);
00069     svd.zero_out_relative(tau);
00070     vgl_point_3d<double> p1(svd.solve(b).begin());
00071     p1 += v0;
00072     new_verts->push_back(p1);
00073   }
00074 
00075   vcl_auto_ptr<imesh_face_array_base> nf(new_faces);
00076   vcl_auto_ptr<imesh_vertex_array_base > nv(new_verts);
00077   return imesh_mesh(nv,nf);
00078 }
00079 
00080 
00081 //: triangulate the 2-d polygon and add triangles to \a tris
00082 void imesh_triangulate_face(const vcl_vector<vgl_point_2d<double> >& face_v,
00083                             const vcl_vector<unsigned int>& face_i,
00084                             imesh_regular_face_array<3>& tris)
00085 {
00086   const unsigned int numv = face_v.size();
00087   bool ccw = vgl_area_signed(vgl_polygon<double>(face_v)) > 0;
00088   vcl_vector<bool> concave_vert(numv,false);
00089   vcl_list<unsigned int> remain;
00090   // determine the concavity of each polygon vertex
00091   for (unsigned int i1=numv-2, i2=numv-1, i3=0; i3<numv; i1=i2, i2=i3++)
00092   {
00093     concave_vert[i2] = ccw != (signed_angle(face_v[i2]-face_v[i1],
00094                                             face_v[i3]-face_v[i2]) > 0);
00095     remain.push_back(i3);
00096   }
00097 
00098   typedef vcl_list<unsigned int>::iterator ritr;
00099   unsigned int remain_size = 0;
00100   while (remain.size() > 2 && remain_size != remain.size()) {
00101     remain_size = remain.size();
00102     ritr curr = remain.end(), prev = --curr;
00103     --prev;
00104     for (ritr next=remain.begin(); next!=remain.end(); prev=curr, curr=next++)
00105     {
00106       if (concave_vert[*curr])
00107         continue;
00108 
00109       // test for an ear (a triangle completely contained in the polygon)
00110       bool inside = false;
00111       for (ritr itr=remain.begin(); itr!=remain.end(); ++itr)
00112       {
00113         if (!concave_vert[*itr] || itr==curr || itr==prev || itr==next)
00114           continue;
00115         inside = vgl_triangle_test_inside(face_v[*prev].x(),face_v[*prev].y(),
00116                                           face_v[*curr].x(),face_v[*curr].y(),
00117                                           face_v[*next].x(),face_v[*next].y(),
00118                                           face_v[*itr ].x(),face_v[*itr ].y());
00119         if (inside)
00120           break;
00121       }
00122       if (inside)
00123         continue;
00124 
00125       //found an ear, remove it
00126       tris.push_back(imesh_tri(face_i[*prev],face_i[*curr],face_i[*next]));
00127       remain.erase(curr);
00128       if (remain.size() < 3)
00129         break;
00130 
00131       // get the indices before previous and after next
00132       ritr pprev = prev;
00133       if (pprev == remain.begin())
00134         pprev = remain.end();
00135       --pprev;
00136       ritr nnext = next;
00137       ++nnext;
00138       if (nnext == remain.end())
00139         nnext = remain.begin();
00140       // update the concavities
00141       vgl_vector_2d<double> v1 = face_v[*prev]-face_v[*pprev];
00142       vgl_vector_2d<double> v2 = face_v[*next]-face_v[*prev];
00143       vgl_vector_2d<double> v3 = face_v[*nnext]-face_v[*next];
00144       concave_vert[*prev] = ccw != (signed_angle(v1,v2) > 0);
00145       concave_vert[*next] = ccw != (signed_angle(v2,v3) > 0);
00146       curr = prev;
00147       prev = pprev;
00148     }
00149   }
00150 
00151   // This case should never happen
00152   if (remain_size == remain.size())
00153     vcl_cout << "error: "<<remain.size()<<" vertices remaining and no more ears"<<vcl_endl;
00154 }
00155 
00156 
00157 //: Triangulate the faces of the mesh (in place)
00158 //  Uses mesh geometry to handle nonconvex faces
00159 void
00160 imesh_triangulate_nonconvex(imesh_mesh& mesh)
00161 {
00162   const imesh_face_array_base& faces = mesh.faces();
00163   assert(mesh.vertices().dim() == 3);
00164   const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00165 
00166   vcl_auto_ptr<imesh_face_array_base> tris_base(new imesh_regular_face_array<3>);
00167   imesh_regular_face_array<3>* tris =
00168       static_cast<imesh_regular_face_array<3>*> (tris_base.get());
00169   int group = -1;
00170   if (faces.has_groups())
00171     group = 0;
00172   for (unsigned int f=0; f<faces.size(); ++f) {
00173     const unsigned int numv = faces.num_verts(f);
00174     if (numv == 3)
00175     {
00176       tris->push_back(imesh_tri(faces(f,0),faces(f,1),faces(f,2)));
00177       continue;
00178     }
00179 
00180     // find the best planar projection of the face
00181     // to apply 2-d nonconvex polygon triangulation
00182     vnl_matrix<double> M(3,numv);
00183     vnl_vector<double> mean(3,0.0);
00184     for (unsigned i=0; i<numv; ++i)
00185     {
00186       const imesh_vertex<3>& v = verts[faces(f,i)];
00187       mean[0] += M(0,i) = v[0];
00188       mean[1] += M(1,i) = v[1];
00189       mean[2] += M(2,i) = v[2];
00190     }
00191     mean /= numv;
00192     for (unsigned i=0; i<numv; ++i)
00193     {
00194       M(0,i) -= mean[0];
00195       M(1,i) -= mean[1];
00196       M(2,i) -= mean[2];
00197     }
00198     vnl_svd<double> svd_M(M);
00199     vnl_matrix<double> P = svd_M.U().extract(3,2).transpose();
00200 
00201     vcl_vector<vgl_point_2d<double> > face_v;
00202     vcl_vector<unsigned int> face_i;
00203     for (unsigned i=0; i<numv; ++i)
00204     {
00205       const imesh_vertex<3>& v = verts[faces(f,i)];
00206       vnl_vector<double> p3 = vnl_double_3(v[0],v[1],v[2])-mean;
00207       vnl_vector<double> p2 = P*p3;
00208       face_v.push_back(vgl_point_2d<double>(p2[0],p2[1]));
00209       face_i.push_back(faces(f,i));
00210     }
00211     imesh_triangulate_face(face_v, face_i, *tris);
00212     if (group >= 0 && f+1 >= faces.groups()[group].second) {
00213       tris->make_group(faces.groups()[group++].first);
00214     }
00215   }
00216 
00217   mesh.set_faces(tris_base);
00218 }