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