1 // This is brl/bbas/imesh/imesh_mesh.cxx
2 #include <iostream>
3 #include "imesh_mesh.h"
4 //:
5 // \file
6 
7 #include "vgl/vgl_polygon.h"
8 #include "vgl/vgl_area.h"
9 
10 #ifdef _MSC_VER
11 #  include "vcl_msvc_warnings.h"
12 #endif
13 
14 //: Copy Constructor
imesh_mesh(const imesh_mesh & other)15 imesh_mesh::imesh_mesh(const imesh_mesh& other)
16   : vbl_ref_count(),
17     verts_((other.verts_.get()) ? other.verts_->clone() : nullptr),
18     faces_((other.faces_.get()) ? other.faces_->clone() : nullptr),
19     half_edges_(other.half_edges_),
20     tex_coords_(other.tex_coords_),
21     tex_source_(other.tex_source_),
22     valid_tex_faces_(other.valid_tex_faces_),
23     tex_coord_status_(other.tex_coord_status_)
24 {
25 }
26 
27 
28 //: Assignment operator
operator =(imesh_mesh const & other)29 imesh_mesh& imesh_mesh::operator=(imesh_mesh const& other)
30 {
31   if (this != &other) {
32     verts_ = std::unique_ptr<imesh_vertex_array_base>((other.verts_.get()) ?
33                                                    other.verts_->clone() : nullptr);
34     faces_ = std::unique_ptr<imesh_face_array_base>((other.faces_.get()) ?
35                                                  other.faces_->clone() : nullptr);
36     half_edges_ = other.half_edges_;
37     tex_coords_ = other.tex_coords_;
38     valid_tex_faces_ = other.valid_tex_faces_;
39     tex_coord_status_ = other.tex_coord_status_;
40   }
41   return *this;
42 }
43 
44 
45 //: Merge the data from another mesh into this one
46 //  Duplicates are not removed
merge(const imesh_mesh & other)47 void imesh_mesh::merge(const imesh_mesh& other)
48 {
49   const unsigned num_v = this->num_verts();
50   const unsigned num_e = this->num_edges();
51   faces_ = imesh_merge(*this->faces_,*other.faces_,verts_->size());
52   verts_->append(*other.verts_);
53 
54   if (this->has_tex_coords() == TEX_COORD_NONE)
55   {
56     std::vector<vgl_point_2d<double> > tex;
57     if (other.has_tex_coords() == TEX_COORD_ON_VERT) {
58       tex = std::vector<vgl_point_2d<double> >(num_v, vgl_point_2d<double>(0,0));
59     }
60     else if (other.has_tex_coords() == TEX_COORD_ON_CORNER) {
61       tex = std::vector<vgl_point_2d<double> >(2*num_e, vgl_point_2d<double>(0,0));
62     }
63 
64     tex.insert(tex.end(), other.tex_coords().begin(), other.tex_coords().end());
65     this->set_tex_coords(tex);
66   }
67   else if (this->has_tex_coords() == other.has_tex_coords())
68   {
69     this->tex_coords_.insert(this->tex_coords_.end(),
70                              other.tex_coords().begin(),
71                              other.tex_coords().end());
72   }
73 
74   if (this->has_half_edges() && other.has_half_edges())
75     this->build_edge_graph();
76   else
77     this->half_edges_.clear();
78 }
79 
80 
81 //: Set the texture coordinates
set_tex_coords(const std::vector<vgl_point_2d<double>> & tc)82 void imesh_mesh::set_tex_coords(const std::vector<vgl_point_2d<double> >& tc)
83 {
84   if (tc.size() == this->num_verts())
85     tex_coord_status_ = TEX_COORD_ON_VERT;
86   else if (tc.size() == 2*this->num_edges())
87     tex_coord_status_ = TEX_COORD_ON_CORNER;
88   else
89     tex_coord_status_ = TEX_COORD_NONE;
90 
91   tex_coords_ = tc;
92 }
93 
94 
95 //: Construct the half edges graph structure
build_edge_graph()96 void imesh_mesh::build_edge_graph()
97 {
98   const imesh_face_array_base& faces = this->faces();
99   std::vector<std::vector<unsigned int> > face_list(faces.size());
100   for (unsigned int f=0; f<faces.size(); ++f) {
101     face_list[f].resize(faces.num_verts(f));
102     for (unsigned int v=0; v<faces.num_verts(f); ++v)
103       face_list[f][v] =  faces(f,v);
104   }
105 
106   half_edges_.build_from_ifs(face_list);
107 }
108 
109 
110 //: Compute vertex normals
compute_vertex_normals()111 void imesh_mesh::compute_vertex_normals()
112 {
113   if (!this->has_half_edges())
114     this->build_edge_graph();
115 
116   const imesh_half_edge_set& half_edges = this->half_edges();
117   imesh_vertex_array<3>& verts = this->vertices<3>();
118 
119   std::vector<vgl_vector_3d<double> > normals(this->num_verts(),
120                                              vgl_vector_3d<double>(0,0,0));
121   std::vector<unsigned int> f_count(this->num_verts(),0);
122 
123   for (unsigned int he=0; he < half_edges.size(); ++he) {
124     imesh_half_edge_set::f_const_iterator fi(he,half_edges);
125     if (fi->is_boundary())
126       continue;
127     unsigned int vp = fi->vert_index();
128     unsigned int v = (++fi)->vert_index();
129     unsigned int vn = (++fi)->vert_index();
130     normals[v] += normalized(imesh_tri_normal(verts[v],verts[vn],verts[vp]));
131     ++f_count[v];
132   }
133 
134   for (unsigned v=0; v<verts.size(); ++v)
135   {
136     normals[v] /= f_count[v];
137     normalize(normals[v]);
138     if (normals[v].length() < 0.5)
139       std::cout << "normal "<<v<<" is "<<normals[v] <<std::endl;
140   }
141 
142   verts.set_normals(normals);
143 }
144 
145 
146 //: Compute vertex normals using face normals
compute_vertex_normals_from_faces()147 void imesh_mesh::compute_vertex_normals_from_faces()
148 {
149   if (!this->has_half_edges())
150     this->build_edge_graph();
151 
152   if (!this->faces_->has_normals())
153     this->compute_face_normals();
154 
155   const std::vector<vgl_vector_3d<double> >& fnormals = faces_->normals();
156 
157   const imesh_half_edge_set& half_edges = this->half_edges();
158   imesh_vertex_array<3>& verts = this->vertices<3>();
159 
160   std::vector<vgl_vector_3d<double> > normals(this->num_verts(),
161                                              vgl_vector_3d<double>(0,0,0));
162   std::vector<unsigned int> f_count(this->num_verts(),0);
163 
164   for (unsigned int he=0; he < half_edges.size(); ++he) {
165     const imesh_half_edge& half_edge = half_edges[he];
166     if (half_edge.is_boundary())
167       continue;
168     unsigned int v = half_edge.vert_index();
169     normals[v] += normalized(fnormals[half_edge.face_index()]);
170     ++f_count[v];
171   }
172 
173   for (unsigned v=0; v<verts.size(); ++v)
174   {
175     normals[v] /= f_count[v];
176     normalize(normals[v]);
177     if (normals[v].length() < 0.5)
178       std::cout << "normal "<<v<<" is "<<normals[v] <<std::endl;
179   }
180 
181   verts.set_normals(normals);
182 }
183 
184 
185 //: Compute face normals
compute_face_normals(bool norm)186 void imesh_mesh::compute_face_normals(bool norm)
187 {
188   imesh_face_array_base& faces = this->faces();
189   const imesh_vertex_array<3>& verts = this->vertices<3>();
190 
191   std::vector<vgl_vector_3d<double> > normals(this->num_faces(),
192                                              vgl_vector_3d<double>(0,0,0));
193 
194   for (unsigned int i=0; i<faces.size(); ++i) {
195     const unsigned int num_v = faces.num_verts(i);
196     vgl_vector_3d<double>& n = normals[i];
197     for (unsigned int j=2; j<num_v; ++j) {
198       n += imesh_tri_normal(verts[faces(i,0)],
199                             verts[faces(i,j-1)],
200                             verts[faces(i,j)]);
201     }
202     if (norm)
203       normalize(n);
204   }
205 
206   faces.set_normals(normals);
207 }
208 
209 
210 //: Map a barycentric coordinate (u,v) on triangle \param tri into texture space
texture_map(unsigned int tri,double u,double v) const211 vgl_point_2d<double> imesh_mesh::texture_map(unsigned int tri,
212                                              double u, double v) const
213 {
214   vgl_point_2d<double> tex(0,0);
215   if (this->tex_coord_status_ == TEX_COORD_ON_VERT)
216   {
217     unsigned int v1 = (*faces_)(tri,0);
218     unsigned int v2 = (*faces_)(tri,1);
219     unsigned int v3 = (*faces_)(tri,2);
220     tex += (1-u-v)*vgl_vector_2d<double>(tex_coords_[v1].x(),tex_coords_[v1].y());
221     tex += u*vgl_vector_2d<double>(tex_coords_[v2].x(),tex_coords_[v2].y());
222     tex += v*vgl_vector_2d<double>(tex_coords_[v3].x(),tex_coords_[v3].y());
223   }
224   return tex;
225 }
226 
227 
228 //: Set the vector indicating which faces have texture
set_valid_tex_faces(const std::vector<bool> & valid)229 void imesh_mesh::set_valid_tex_faces(const std::vector<bool>& valid)
230 {
231   if (valid.size() == this->num_faces() && has_tex_coords())
232     valid_tex_faces_ = valid;
233 }
234 
235 
236 //: Label all faces with positive (counter clockwise orientation) area as valid
237 //  This requirement refers to the texture map coordinates
label_ccw_tex_faces_valid()238 void imesh_mesh::label_ccw_tex_faces_valid()
239 {
240   switch (tex_coord_status_)
241   {
242     case TEX_COORD_ON_VERT:
243     {
244       valid_tex_faces_.resize(this->num_faces());
245       vgl_polygon<double> face(1);
246       imesh_face_array_base& faces = this->faces();
247       for (unsigned int f=0; f<num_faces(); ++f)
248       {
249         const unsigned int num_v = faces.num_verts(f);
250         for (unsigned int i=0; i<num_v; ++i) {
251           face.push_back(tex_coords_[faces(f,i)]);
252         }
253         valid_tex_faces_[f] = vgl_area_signed(face) > 0;
254       }
255       break;
256     }
257     case TEX_COORD_ON_CORNER:
258       std::cerr << "imesh_mesh::label_ccw_tex_faces_valid()"
259                << " not implemented for TEX_COORD_ON_CORNER\n";
260       break;
261     default:
262       break;
263   }
264 }
265 
266 //Smart Pointer IO
vsl_b_write(vsl_b_ostream &,imesh_mesh_sptr &)267 void vsl_b_write(vsl_b_ostream& /*os*/, imesh_mesh_sptr&) {}
vsl_b_write(vsl_b_ostream &,imesh_mesh_sptr const &)268 void vsl_b_write(vsl_b_ostream& /*os*/, imesh_mesh_sptr const&) {}
269 
270 //: Binary load boxm scene from stream.
vsl_b_read(vsl_b_istream &,imesh_mesh_sptr &)271 void vsl_b_read(vsl_b_istream& /*is*/, imesh_mesh_sptr&) {}
vsl_b_read(vsl_b_istream &,imesh_mesh_sptr const &)272 void vsl_b_read(vsl_b_istream& /*is*/, imesh_mesh_sptr const&) {}
273