contrib/brl/bbas/imesh/imesh_mesh.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/imesh_mesh.cxx
00002 #include "imesh_mesh.h"
00003 //:
00004 // \file
00005 
00006 #include <vgl/vgl_polygon.h>
00007 #include <vgl/vgl_area.h>
00008 
00009 #include <vcl_iostream.h>
00010 
00011 //: Copy Constructor
00012 imesh_mesh::imesh_mesh(const imesh_mesh& other)
00013   : vbl_ref_count(),
00014     verts_((other.verts_.get()) ? other.verts_->clone() : 0),
00015     faces_((other.faces_.get()) ? other.faces_->clone() : 0),
00016     half_edges_(other.half_edges_),
00017     tex_coords_(other.tex_coords_),
00018     tex_source_(other.tex_source_),
00019     valid_tex_faces_(other.valid_tex_faces_),
00020     tex_coord_status_(other.tex_coord_status_)
00021 {
00022 }
00023 
00024 
00025 //: Assignment operator
00026 imesh_mesh& imesh_mesh::operator=(imesh_mesh const& other)
00027 {
00028   if (this != &other) {
00029     verts_ = vcl_auto_ptr<imesh_vertex_array_base>((other.verts_.get()) ?
00030                                                    other.verts_->clone() : 0);
00031     faces_ = vcl_auto_ptr<imesh_face_array_base>((other.faces_.get()) ?
00032                                                  other.faces_->clone() : 0);
00033     half_edges_ = other.half_edges_;
00034     tex_coords_ = other.tex_coords_;
00035     valid_tex_faces_ = other.valid_tex_faces_;
00036     tex_coord_status_ = other.tex_coord_status_;
00037   }
00038   return *this;
00039 }
00040 
00041 
00042 //: Merge the data from another mesh into this one
00043 //  Duplicates are not removed
00044 void imesh_mesh::merge(const imesh_mesh& other)
00045 {
00046   const unsigned num_v = this->num_verts();
00047   const unsigned num_e = this->num_edges();
00048   faces_ = imesh_merge(*this->faces_,*other.faces_,verts_->size());
00049   verts_->append(*other.verts_);
00050 
00051   if (this->has_tex_coords() == TEX_COORD_NONE)
00052   {
00053     vcl_vector<vgl_point_2d<double> > tex;
00054     if (other.has_tex_coords() == TEX_COORD_ON_VERT) {
00055       tex = vcl_vector<vgl_point_2d<double> >(num_v, vgl_point_2d<double>(0,0));
00056     }
00057     else if (other.has_tex_coords() == TEX_COORD_ON_CORNER) {
00058       tex = vcl_vector<vgl_point_2d<double> >(2*num_e, vgl_point_2d<double>(0,0));
00059     }
00060 
00061     tex.insert(tex.end(), other.tex_coords().begin(), other.tex_coords().end());
00062     this->set_tex_coords(tex);
00063   }
00064   else if (this->has_tex_coords() == other.has_tex_coords())
00065   {
00066     this->tex_coords_.insert(this->tex_coords_.end(),
00067                              other.tex_coords().begin(),
00068                              other.tex_coords().end());
00069   }
00070 
00071   if (this->has_half_edges() && other.has_half_edges())
00072     this->build_edge_graph();
00073   else
00074     this->half_edges_.clear();
00075 }
00076 
00077 
00078 //: Set the texture coordinates
00079 void imesh_mesh::set_tex_coords(const vcl_vector<vgl_point_2d<double> >& tc)
00080 {
00081   if (tc.size() == this->num_verts())
00082     tex_coord_status_ = TEX_COORD_ON_VERT;
00083   else if (tc.size() == 2*this->num_edges())
00084     tex_coord_status_ = TEX_COORD_ON_CORNER;
00085   else
00086     tex_coord_status_ = TEX_COORD_NONE;
00087 
00088   tex_coords_ = tc;
00089 }
00090 
00091 
00092 //: Construct the half edges graph structure
00093 void imesh_mesh::build_edge_graph()
00094 {
00095   const imesh_face_array_base& faces = this->faces();
00096   vcl_vector<vcl_vector<unsigned int> > face_list(faces.size());
00097   for (unsigned int f=0; f<faces.size(); ++f) {
00098     face_list[f].resize(faces.num_verts(f));
00099     for (unsigned int v=0; v<faces.num_verts(f); ++v)
00100       face_list[f][v] =  faces(f,v);
00101   }
00102 
00103   half_edges_.build_from_ifs(face_list);
00104 }
00105 
00106 
00107 //: Compute vertex normals
00108 void imesh_mesh::compute_vertex_normals()
00109 {
00110   if (!this->has_half_edges())
00111     this->build_edge_graph();
00112 
00113   const imesh_half_edge_set& half_edges = this->half_edges();
00114   imesh_vertex_array<3>& verts = this->vertices<3>();
00115 
00116   vcl_vector<vgl_vector_3d<double> > normals(this->num_verts(),
00117                                              vgl_vector_3d<double>(0,0,0));
00118   vcl_vector<unsigned int> f_count(this->num_verts(),0);
00119 
00120   for (unsigned int he=0; he < half_edges.size(); ++he) {
00121     imesh_half_edge_set::f_const_iterator fi(he,half_edges);
00122     if (fi->is_boundary())
00123       continue;
00124     unsigned int vp = fi->vert_index();
00125     unsigned int v = (++fi)->vert_index();
00126     unsigned int vn = (++fi)->vert_index();
00127     normals[v] += normalized(imesh_tri_normal(verts[v],verts[vn],verts[vp]));
00128     ++f_count[v];
00129   }
00130 
00131   for (unsigned v=0; v<verts.size(); ++v)
00132   {
00133     normals[v] /= f_count[v];
00134     normalize(normals[v]);
00135     if (normals[v].length() < 0.5)
00136       vcl_cout << "normal "<<v<<" is "<<normals[v] <<vcl_endl;
00137   }
00138 
00139   verts.set_normals(normals);
00140 }
00141 
00142 
00143 //: Compute vertex normals using face normals
00144 void imesh_mesh::compute_vertex_normals_from_faces()
00145 {
00146   if (!this->has_half_edges())
00147     this->build_edge_graph();
00148 
00149   if (!this->faces_->has_normals())
00150     this->compute_face_normals();
00151 
00152   const vcl_vector<vgl_vector_3d<double> >& fnormals = faces_->normals();
00153 
00154   const imesh_half_edge_set& half_edges = this->half_edges();
00155   imesh_vertex_array<3>& verts = this->vertices<3>();
00156 
00157   vcl_vector<vgl_vector_3d<double> > normals(this->num_verts(),
00158                                              vgl_vector_3d<double>(0,0,0));
00159   vcl_vector<unsigned int> f_count(this->num_verts(),0);
00160 
00161   for (unsigned int he=0; he < half_edges.size(); ++he) {
00162     const imesh_half_edge& half_edge = half_edges[he];
00163     if (half_edge.is_boundary())
00164       continue;
00165     unsigned int v = half_edge.vert_index();
00166     normals[v] += normalized(fnormals[half_edge.face_index()]);
00167     ++f_count[v];
00168   }
00169 
00170   for (unsigned v=0; v<verts.size(); ++v)
00171   {
00172     normals[v] /= f_count[v];
00173     normalize(normals[v]);
00174     if (normals[v].length() < 0.5)
00175       vcl_cout << "normal "<<v<<" is "<<normals[v] <<vcl_endl;
00176   }
00177 
00178   verts.set_normals(normals);
00179 }
00180 
00181 
00182 //: Compute face normals
00183 void imesh_mesh::compute_face_normals(bool norm)
00184 {
00185   imesh_face_array_base& faces = this->faces();
00186   const imesh_vertex_array<3>& verts = this->vertices<3>();
00187 
00188   vcl_vector<vgl_vector_3d<double> > normals(this->num_faces(),
00189                                              vgl_vector_3d<double>(0,0,0));
00190 
00191   for (unsigned int i=0; i<faces.size(); ++i) {
00192     const unsigned int num_v = faces.num_verts(i);
00193     vgl_vector_3d<double>& n = normals[i];
00194     for (unsigned int j=2; j<num_v; ++j) {
00195       n += imesh_tri_normal(verts[faces(i,0)],
00196                             verts[faces(i,j-1)],
00197                             verts[faces(i,j)]);
00198     }
00199     if (norm)
00200       normalize(n);
00201   }
00202 
00203   faces.set_normals(normals);
00204 }
00205 
00206 
00207 //: Map a barycentric coordinate (u,v) on triangle \param tri into texture space
00208 vgl_point_2d<double> imesh_mesh::texture_map(unsigned int tri,
00209                                              double u, double v) const
00210 {
00211   vgl_point_2d<double> tex(0,0);
00212   if (this->tex_coord_status_ == TEX_COORD_ON_VERT)
00213   {
00214     unsigned int v1 = (*faces_)(tri,0);
00215     unsigned int v2 = (*faces_)(tri,1);
00216     unsigned int v3 = (*faces_)(tri,2);
00217     tex += (1-u-v)*vgl_vector_2d<double>(tex_coords_[v1].x(),tex_coords_[v1].y());
00218     tex += u*vgl_vector_2d<double>(tex_coords_[v2].x(),tex_coords_[v2].y());
00219     tex += v*vgl_vector_2d<double>(tex_coords_[v3].x(),tex_coords_[v3].y());
00220   }
00221   return tex;
00222 }
00223 
00224 
00225 //: Set the vector indicating which faces have texture
00226 void imesh_mesh::set_valid_tex_faces(const vcl_vector<bool>& valid)
00227 {
00228   if (valid.size() == this->num_faces() && has_tex_coords())
00229     valid_tex_faces_ = valid;
00230 }
00231 
00232 
00233 //: Label all faces with positive (counter clockwise orientation) area as valid
00234 //  This requirement refers to the texture map coordinates
00235 void imesh_mesh::label_ccw_tex_faces_valid()
00236 {
00237   switch (tex_coord_status_)
00238   {
00239     case TEX_COORD_ON_VERT:
00240     {
00241       valid_tex_faces_.resize(this->num_faces());
00242       vgl_polygon<double> face(1);
00243       imesh_face_array_base& faces = this->faces();
00244       for (unsigned int f=0; f<num_faces(); ++f)
00245       {
00246         const unsigned int num_v = faces.num_verts(f);
00247         for (unsigned int i=0; i<num_v; ++i) {
00248           face.push_back(tex_coords_[faces(f,i)]);
00249         }
00250         valid_tex_faces_[f] = vgl_area_signed(face) > 0;
00251       }
00252       break;
00253     }
00254     case TEX_COORD_ON_CORNER:
00255       vcl_cerr << "imesh_mesh::label_ccw_tex_faces_valid()"
00256                << " not implemented for TEX_COORD_ON_CORNER\n";
00257       break;
00258     default:
00259       break;
00260   }
00261 }
00262 
00263 //Smart Pointer IO
00264 void vsl_b_write(vsl_b_ostream& /*os*/, imesh_mesh_sptr&) {}
00265 void vsl_b_write(vsl_b_ostream& /*os*/, imesh_mesh_sptr const&) {}
00266 
00267 //: Binary load boxm scene from stream.
00268 void vsl_b_read(vsl_b_istream& /*is*/, imesh_mesh_sptr&) {}
00269 void vsl_b_read(vsl_b_istream& /*is*/, imesh_mesh_sptr const&) {}