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