Developer Documentation
SmootherT.cc
Go to the documentation of this file.
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.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
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 
53 //=============================================================================
54 //
55 // CLASS SmootherT - IMPLEMENTATION
56 //
57 //=============================================================================
58 
59 #define OPENMESH_SMOOTHERT_C
60 
61 //== INCLUDES =================================================================
62 
63 #include <OpenMesh/Core/Utils/vector_cast.hh>
65 
66 //== NAMESPACES ===============================================================
67 
68 
69 namespace OpenMesh {
70 namespace Smoother {
71 
72 
73 //== IMPLEMENTATION ==========================================================
74 
75 
76 template <class Mesh>
78 SmootherT(Mesh& _mesh)
79  : mesh_(_mesh),
80  skip_features_(false)
81 {
82  // request properties
83  mesh_.request_vertex_status();
84  mesh_.request_face_normals();
85  mesh_.request_vertex_normals();
86 
87  // custom properties
88  mesh_.add_property(original_positions_);
89  mesh_.add_property(original_normals_);
90  mesh_.add_property(new_positions_);
91  mesh_.add_property(is_active_);
92 
93 
94  // default settings
95  component_ = Tangential_and_Normal;
96  continuity_ = C0;
97  tolerance_ = -1.0;
98 }
99 
100 
101 //-----------------------------------------------------------------------------
102 
103 
104 template <class Mesh>
106 ~SmootherT()
107 {
108  // free properties
109  mesh_.release_vertex_status();
110  mesh_.release_face_normals();
111  mesh_.release_vertex_normals();
112 
113  // free custom properties
114  mesh_.remove_property(original_positions_);
115  mesh_.remove_property(original_normals_);
116  mesh_.remove_property(new_positions_);
117  mesh_.remove_property(is_active_);
118 }
119 
120 
121 //-----------------------------------------------------------------------------
122 
123 
124 template <class Mesh>
125 void
127 initialize(Component _comp, Continuity _cont)
128 {
129  typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
130 
131 
132  // store smoothing settings
133  component_ = _comp;
134  continuity_ = _cont;
135 
136 
137  // update normals
138  mesh_.update_face_normals();
139  mesh_.update_vertex_normals();
140 
141 
142  // store original points & normals
143  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
144  {
145  mesh_.property(original_positions_, *v_it) = mesh_.point(*v_it);
146  mesh_.property(original_normals_, *v_it) = mesh_.normal(*v_it);
147  }
148 }
149 
150 
151 //-----------------------------------------------------------------------------
152 
153 
154 template <class Mesh>
155 void
158 {
159  typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
160 
161 
162  // is something selected?
163  bool nothing_selected(true);
164  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
165  if (mesh_.status(*v_it).selected())
166  { nothing_selected = false; break; }
167 
168 
169  // tagg all active vertices
170  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
171  {
172  bool active = ((nothing_selected || mesh_.status(*v_it).selected())
173  && !mesh_.is_boundary(*v_it)
174  && !mesh_.status(*v_it).locked());
175 
176  if ( skip_features_ ) {
177 
178  active = active && !mesh_.status(*v_it).feature();
179 
180  typename Mesh::VertexOHalfedgeIter voh_it(mesh_,*v_it);
181  for ( ; voh_it.is_valid() ; ++voh_it ) {
182 
183  // If the edge is a feature edge, skip the current vertex while smoothing
184  if ( mesh_.status(mesh_.edge_handle(*voh_it)).feature() )
185  active = false;
186 
187  typename Mesh::FaceHandle fh1 = mesh_.face_handle(*voh_it );
188  typename Mesh::FaceHandle fh2 = mesh_.face_handle(mesh_.opposite_halfedge_handle(*voh_it ) );
189 
190  // If one of the faces is a feature, lock current vertex
191  if ( fh1.is_valid() && mesh_.status( fh1 ).feature() )
192  active = false;
193  if ( fh2.is_valid() && mesh_.status( fh2 ).feature() )
194  active = false;
195 
196  }
197  }
198 
199  mesh_.property(is_active_, *v_it) = active;
200  }
201 
202 
203  // C1: remove one ring of boundary vertices
204  if (continuity_ == C1)
205  {
206  typename Mesh::VVIter vv_it;
207 
208  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
209  if (mesh_.is_boundary(*v_it))
210  for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
211  mesh_.property(is_active_, *vv_it) = false;
212  }
213 
214 
215  // C2: remove two rings of boundary vertices
216  if (continuity_ == C2)
217  {
218  typename Mesh::VVIter vv_it;
219 
220  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
221  {
222  mesh_.status(*v_it).set_tagged(false);
223  mesh_.status(*v_it).set_tagged2(false);
224  }
225 
226  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
227  if (mesh_.is_boundary(*v_it))
228  for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
229  mesh_.status(*v_it).set_tagged(true);
230 
231  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
232  if (mesh_.status(*v_it).tagged())
233  for (vv_it=mesh_.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
234  mesh_.status(*v_it).set_tagged2(true);
235 
236  for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it)
237  {
238  if (mesh_.status(*v_it).tagged2())
239  mesh_.property(is_active_, *vv_it) = false;
240  mesh_.status(*v_it).set_tagged(false);
241  mesh_.status(*v_it).set_tagged2(false);
242  }
243  }
244 }
245 
246 
247 //-----------------------------------------------------------------------------
248 
249 
250 template <class Mesh>
251 void
254 {
255  if (!mesh_.vertices_empty())
256  {
257  typename Mesh::VertexIter v_it(mesh_.vertices_begin()),
258  v_end(mesh_.vertices_end());
259 
260 
261  // compute bounding box
262  Point bb_min, bb_max;
263  bb_min = bb_max = mesh_.point(*v_it);
264  for (++v_it; v_it!=v_end; ++v_it)
265  {
266  bb_min.minimize(mesh_.point(*v_it));
267  bb_max.maximize(mesh_.point(*v_it));
268  }
269 
270 
271  // abs. error = rel. error * bounding-diagonal
272  set_absolute_local_error(_err * (bb_max-bb_min).norm());
273  }
274 }
275 
276 
277 //-----------------------------------------------------------------------------
278 
279 
280 template <class Mesh>
281 void
284 {
285  tolerance_ = _err;
286 }
287 
288 
289 //-----------------------------------------------------------------------------
290 
291 
292 template <class Mesh>
293 void
296 {
297  tolerance_ = -1.0;
298 }
299 
300 
301 //-----------------------------------------------------------------------------
302 
303 
304 template <class Mesh>
305 void
307 smooth(unsigned int _n)
308 {
309  // mark active vertices
311 
312  // smooth _n iterations
313  while (_n--)
314  {
315  compute_new_positions();
316 
317  if (component_ == Tangential)
318  project_to_tangent_plane();
319 
320  else if (tolerance_ >= 0.0)
321  local_error_check();
322 
323  move_points();
324  }
325 }
326 
327 
328 //-----------------------------------------------------------------------------
329 
330 
331 template <class Mesh>
332 void
335 {
336  switch (continuity_)
337  {
338  case C0:
339  compute_new_positions_C0();
340  break;
341 
342  case C1:
343  compute_new_positions_C1();
344  break;
345 
346  case C2:
347  break;
348  }
349 }
350 
351 
352 //-----------------------------------------------------------------------------
353 
354 
355 template <class Mesh>
356 void
359 {
360  typename Mesh::VertexIter v_it(mesh_.vertices_begin()),
361  v_end(mesh_.vertices_end());
362  // Normal should be a vector type. In some environment a vector type
363  // is different from point type, e.g. OpenSG!
364  typename Mesh::Normal translation, normal;
365 
366 
367  for (; v_it != v_end; ++v_it)
368  {
369  if (is_active(*v_it))
370  {
371  translation = new_position(*v_it)-orig_position(*v_it);
372  normal = orig_normal(*v_it);
373  normal *= dot(translation, normal);
374  translation -= normal;
375  translation += vector_cast<typename Mesh::Normal>(orig_position(*v_it));
376  set_new_position(*v_it, translation);
377  }
378  }
379 }
380 
381 
382 //-----------------------------------------------------------------------------
383 
384 
385 template <class Mesh>
386 void
389 {
390  typename Mesh::VertexIter v_it(mesh_.vertices_begin()),
391  v_end(mesh_.vertices_end());
392 
393  typename Mesh::Normal translation;
394  typename Mesh::Scalar s;
395 
396 
397  for (; v_it != v_end; ++v_it)
398  {
399  if (is_active(*v_it))
400  {
401  translation = new_position(*v_it) - orig_position(*v_it);
402 
403  s = fabs(dot(translation, orig_normal(*v_it)));
404 
405  if (s > tolerance_)
406  {
407  translation *= (tolerance_ / s);
408  translation += vector_cast<NormalType>(orig_position(*v_it));
409  set_new_position(*v_it, translation);
410  }
411  }
412  }
413 }
414 
415 
416 //-----------------------------------------------------------------------------
417 
418 
419 template <class Mesh>
420 void
422 move_points()
423 {
424  typename Mesh::VertexIter v_it(mesh_.vertices_begin()),
425  v_end(mesh_.vertices_end());
426 
427  for (; v_it != v_end; ++v_it)
428  if (is_active(*v_it))
429  mesh_.set_point(*v_it, mesh_.property(new_positions_, *v_it));
430 }
431 
432 
433 //=============================================================================
434 } // namespace Smoother
435 } // namespace OpenMesh
436 //=============================================================================
void vector_cast(const src_t &_src, dst_t &_dst, GenProg::Int2Type< n >)
Cast vector type to another vector type by copying the vector elements.
Definition: vector_cast.hh:86
void disable_local_error_check()
Disable error control of the smoother.
Definition: SmootherT.cc:295
void set_relative_local_error(Scalar _err)
Set local error relative to bounding box.
Definition: SmootherT.cc:253
void set_absolute_local_error(Scalar _err)
Set local error as an absolute value.
Definition: SmootherT.cc:283
virtual void smooth(unsigned int _n)
Do _n smoothing iterations.
Definition: SmootherT.cc:307
Kernel::Normal Normal
Normal type.
Definition: PolyMeshT.hh:117
Smooth tangential and normal direction.
Definition: SmootherT.hh:95
Smooth tangential direction.
Definition: SmootherT.hh:93
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
void update_face_normals()
Update normal vectors for all faces.
Definition: PolyMeshT.cc:259
Kernel::VertexOHalfedgeIter VertexOHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:166
void set_active_vertices()
Find active vertices. Resets tagged status !
Definition: SmootherT.cc:157
void update_vertex_normals()
Update normal vectors for all vertices.
Definition: PolyMeshT.cc:448
void initialize(Component _comp, Continuity _cont)
Definition: SmootherT.cc:127
Kernel::Scalar Scalar
Scalar type.
Definition: PolyMeshT.hh:113
SmootherT(Mesh &_mesh)
constructor & destructor
Definition: SmootherT.cc:78