Developer Documentation
MeshFixingT_impl.hh
1/*===========================================================================*\
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42/*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $Date$ *
46 * *
47 \*===========================================================================*/
48
52//=============================================================================
53//
54// CLASS MeshFixing - IMPLEMENTATION
55//
56//=============================================================================
57
58#define OPENMESH_MESHFIXING_CC
59
60//== INCLUDES =================================================================
61
62#include "MeshFixingT.hh"
63
64//== NAMESPACE ===============================================================
65
66
67//== IMPLEMENTATION ==========================================================
68
69
71 epsilon_(_epsilon * _epsilon)
72{
73}
74
75bool CompareVectors::operator()(const ACG::Vec3d& _v0, const ACG::Vec3d& _v1) const
76{
77 if ((_v0 - _v1).sqrnorm() <= epsilon_)
78 return false;
79 else
80 return _v0 < _v1;
81}
82
83template<class MeshT>
84MeshFixing<MeshT>::MeshFixing(MeshT& _mesh, double _epsilon ) :
85mesh_(_mesh),
86vmap_(CompareVectors(_epsilon))
87{
88}
89
90
91template<class MeshT>
93 vertices_.push_back( Vertex(_p) );
94 return vertices_.size()-1;
95}
96
97template<class MeshT>
98void MeshFixing<MeshT>::add_face(const ACG::Vec3d& _p0, const ACG::Vec3d& _p1, const ACG::Vec3d& _p2) {
99 ACG::Vec3d p[3] = {_p0, _p1, _p2 };
100 int v[3];
101 MapIter it;
102
103
104 // map points to vertices
105 for (unsigned int i=0; i<3; ++i) {
106
107 // Try to find the vertex in the map
108 it = vmap_.find(p[i]);
109
110 // Add the vertex to the map, if it is new
111 // (Out of the epsilon range! )
112 if ( it == vmap_.end() ) {
113 v[i] = add_vertex( p[i] );
114 vmap_[p[i]] = v[i];
115 } else
116 v[i] = it->second;
117 }
118
119
120 // Don't add degenerate faces, as we could already skip them here
121 if (v[0]==v[1] || v[0]==v[2] || v[1]==v[2])
122 return;
123
124
125 // add face
126 faces_.push_back( Face(v[0], v[1], v[2]) );
127
128 unsigned int newFace = faces_.size()- 1;
129 for (unsigned int i = 0; i < 3; ++i)
130 vertices_[v[i]].faces.push_back( newFace );
131
132}
133
140template<class MeshT>
142{
143 int component;
144
145 const unsigned int numberOfVertices = vertices_.size();
146
147 // Iterate over all vertices
148 for (unsigned int v = 0; v < numberOfVertices; ++v) {
149
150 // Get reference to the vector of associated faces at the current vertex
151 const std::vector<unsigned int>& vfaces = vertices_[v].faces;
152 std::vector<unsigned int>::const_iterator f_it, f_end(vfaces.end());
153 std::vector<unsigned int> todo;
154
155 todo.reserve(vfaces.size());
156
157 // Reset components to which each face connected to this vertex belongs
158 for (auto f_it : vfaces)
159 faces_[f_it].component = -1;
160
161 // Find the components
162 for (component = 0;; ++component) {
163
164 // Find one face, that is not yet flagged with a component
165 for (auto f_it : vfaces) {
166
167 if (faces_[f_it].component == -1) {
168
169 // Add component as seed to the list
170 todo.push_back(f_it);
171
172 // Mark the current face with the right component
173 faces_[f_it].component = component;
174
175 // Found, so don't continue
176 break;
177 }
178
179 }
180
181 // No components found anymore
182 if (f_it == f_end)
183 break;
184
185 // Grow from the seed face until no more connected faces where found
186 while (!todo.empty()) {
187
188 // Get next element from the todo list
189 const unsigned int currentFace = todo.back();
190 todo.pop_back();
191
192 // Go over all vertices of the current face
193 for (unsigned int i = 0; i < 3; ++i) {
194
195 // If the vertex of the face is not equal to the current iteration vertex
196 if (faces_[currentFace].v[i] != v) {
197
198 // Found neighbor?
199 const int neighbourFace = neighbor(currentFace, v, faces_[currentFace].v[i]);
200 if ( neighbourFace != -1) {
201
202 // Tag it with the right component and push it to the list of todos
203 if (faces_[neighbourFace].component == -1) {
204 faces_[neighbourFace].component = component;
205 todo.push_back(neighbourFace);
206 }
207
208 }
209 }
210 }
211 }
212 }
213
214 // Now we separate the components at the current vertex
215 for (int c = 1; c < component; ++c) {
216
217 // Duplicate the point to achieve the separation
218 const ACG::Vec3d p = vertices_[v].p;
219 unsigned int newVertex = add_vertex(p);
220
221 // Possible relocation of vertices_ so we need to update the references!
222 std::vector<unsigned int>& vfaces = vertices_[v].faces;
223 std::vector<unsigned int>::iterator f_it, f_end(vfaces.end());
224
225 // Update the face indices of the current component
226 bool finished = false;
227 while (!finished) {
228 finished = true;
229
230 for (f_it = vfaces.begin(), f_end = vfaces.end(); f_it != f_end; ++f_it) {
231
232 // If the face belongs to the current component
233
234 if (faces_[*f_it].component == c) {
235
236 // Iterate over its vertices
237 for (unsigned int i = 0; i < 3; ++i) {
238
239 // Relink to the new vertex by updating the face and pushing it in as new
240 if (faces_[*f_it].v[i] == v) {
241 faces_[*f_it].v[i] = newVertex;
242 vertices_[newVertex].faces.push_back(*f_it);
243 finished = false;
244 }
245
246 }
247
248 // Erase the old one
249 vfaces.erase(f_it);
250 break;
251 }
252 }
253 }
254 }
255
256 }
257}
258
259//-----------------------------------------------------------------------------
260
261
269template<class MeshT>
270int MeshFixing<MeshT>::neighbor(unsigned int _f, unsigned int _v0, unsigned int _v1)
271{
272 // Get the list of faces at vertex _v0
273 const std::vector<unsigned int>& v0faces = vertices_[_v0].faces;
274
275 int neighborFace = -1;
276
277 // Iterate over all associated faces at the current vertex
278 for (auto f_it : v0faces) {
279
280 // if the face associated at this vertex is not equal to the face we are analyzing
281 if (f_it != _f) {
282
283 // Iterate over all vertices of this face
284 for (unsigned int j = 0; j < 3; ++j)
285
286 // If this face is adjacent to the vertex we are analyzing
287 if (faces_[f_it].v[j] == _v1) {
288
289 if (neighborFace != -1)
290 return -1;
291 else
292 neighborFace = f_it;
293
294 }
295 }
296 }
297
298 return neighborFace;
299}
300
304template<class MeshT>
306{
307 // We need faces to work on!
308 if (faces_.empty()) return;
309
310 int fh = 0;
311
312 std::vector<int> todo;
313 todo.reserve( (int) sqrt( (double) faces_.size()) );
314
315 const unsigned int faceCount = faces_.size();
316
317 // Reset components of all faces
318 for (unsigned int i = 0; i < faceCount; ++i)
319 faces_[i].component = -1;
320
321
322 // Iterate over all components
323 for (int component = 0;; ++component) {
324
325 unsigned int start = 0 ;
326
327 // Find one seed triangle in this component
328 for (; start < faceCount; ++start) {
329
330 // Found an untagged face == new component?
331 if (faces_[start].component == -1) {
332 fh = start;
333 todo.push_back(fh);
334 faces_[fh].component = component;
335 break;
336 }
337
338 }
339
340 // No more Components!
341 if (start == faceCount)
342 break;
343
344 // Flood fill the current component, while fixing the orientation
345 while (!todo.empty()) {
346
347 // Get the next face to work on
348 fh = todo.back();
349 todo.pop_back();
350
351 // Find neighbors of the current face
352 for (unsigned int i = 0; i < 3; ++i) {
353 unsigned int i0 = faces_[fh].v[i];
354 unsigned int i1 = faces_[fh].v[(i + 1) % 3];
355
356 int neighborFace = neighbor(fh, i0, i1);
357 if (neighborFace != -1 && faces_[neighborFace].component == -1) {
358
359 int nextVertex = 0;
360 for (nextVertex = 0; nextVertex < 3; ++nextVertex)
361 if (faces_[neighborFace].v[nextVertex] == i1)
362 break;
363
364 // If the orientation is incorrect, we have to flip it!
365 if (faces_[neighborFace].v[(nextVertex + 2) % 3] == i0)
366 std::swap(faces_[neighborFace].v[1], faces_[neighborFace].v[2]);
367
368 faces_[neighborFace].component = component;
369 todo.push_back(neighborFace);
370 }
371 }
372
373 }
374 }
375}
376
377template<class MeshT>
379{
380
381 // Maximal number of steps:
382 // _mesh.n_faces() + // add face
383 // (_fix_topology ? _mesh.n_vertices() : 0) + // non-manifold
384 // (_fix_orientation ? _mesh.n_faces() : 0) + // orientation
385 // _mesh.n_faces(), // copy output
386
387
388 typename MeshT::FaceVertexIter fv_it;
389
390 std::cerr << "Setup data structure" << std::endl;
391
392 // add faces
393 for (auto f_it : mesh_.faces())
394 {
395 fv_it = mesh_.fv_iter(f_it);
396 const ACG::Vec3d p0 = mesh_.point( *(fv_it) );
397 const ACG::Vec3d p1 = mesh_.point(*(++fv_it));
398 const ACG::Vec3d p2 = mesh_.point(*(++fv_it));
399
400 add_face(p0, p1, p2);
401
402 }
403
404
405
406 std::cerr << "Fix topology" << std::endl;
407 //fix_topology();
408
409 std::cerr << "Fix orientation" << std::endl;
410
411 fix_orientation();
412
413 std::cerr << "Copy back to mesh" << std::endl;
414
415 // Remove all primitives but keep the properties
416 mesh_.clean();
417
418 // Copy back to the target mesh
419 unsigned int vertexCount(vertices_.size());
420 unsigned int faceCount(faces_.size());
421
422
423 std::vector<typename MeshT::VertexHandle> vh;
424 typename MeshT::VertexHandle v0, v1, v2;
425 typename MeshT::FaceHandle fh;
426 bool ok = true;
427
428
429 // Add all vertices back to the mesh
430 vh.resize(vertexCount);
431 for (unsigned int i = 0; i < vertexCount; ++i)
432 vh[i] = mesh_.add_vertex((typename TriMesh::Point) vertices_[i].p);
433
434 // Add all faces back to mesh
435 for (unsigned int i = 0; i < faceCount; ++i) {
436
437 // try to add face
438 if (!(fh = mesh_.add_face(vh[faces_[i].v[0]], vh[faces_[i].v[1]], vh[faces_[i].v[2]])).is_valid()) {
439 // fails -> add isolated face
440 v0 = mesh_.add_vertex((typename MeshT::Point) vertices_[faces_[i].v[0]].p);
441 v1 = mesh_.add_vertex((typename MeshT::Point) vertices_[faces_[i].v[1]].p);
442 v2 = mesh_.add_vertex((typename MeshT::Point) vertices_[faces_[i].v[2]].p);
443 fh = mesh_.add_face(v0, v1, v2);
444 ok = false;
445 }
446
447 }
448
449 return ok;
450}
Compare two vectors.
Definition: MeshFixingT.hh:71
CompareVectors(double _eps=FLT_MIN)
Constructor.
bool operator()(const ACG::Vec3d &_v0, const ACG::Vec3d &_v1) const
comparison operator
Fix a mesh.
Definition: MeshFixingT.hh:89
int neighbor(unsigned int _f, unsigned int _v0, unsigned int _v1)
void fix_topology()
Fix the mesh topology.
void fix_orientation()
int add_vertex(const ACG::Vec3d &_p)
void add_face(const ACG::Vec3d &_p0, const ACG::Vec3d &_p1, const ACG::Vec3d &_p2)
Add a face to the fixing data.
SmartVertexHandle add_vertex(const Point _p)
Definition: PolyMeshT.hh:255
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
Internal face type.
Definition: MeshFixingT.hh:132
Internal vertex type.
Definition: MeshFixingT.hh:122