//============================================================================= // // OpenMesh // Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen // www.openmesh.org // //----------------------------------------------------------------------------- // // License // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, version 2.1. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // //----------------------------------------------------------------------------- // // $Revision: 1802 $ // $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $ // //============================================================================= /** \file SmootherT.cc */ //============================================================================= // // CLASS SmootherT - IMPLEMENTATION // //============================================================================= #define OPENMESH_SMOOTHERT_C //== INCLUDES ================================================================= #include #include //== NAMESPACES =============================================================== namespace OpenMesh { namespace Smoother { //== IMPLEMENTATION ========================================================== template SmootherT:: SmootherT(Mesh& _mesh) : mesh_(_mesh) { // request properties mesh_.request_vertex_status(); mesh_.request_face_normals(); mesh_.request_vertex_normals(); // custom properties mesh_.add_property(original_positions_); mesh_.add_property(original_normals_); mesh_.add_property(new_positions_); mesh_.add_property(is_active_); // default settings component_ = Tangential_and_Normal; continuity_ = C0; tolerance_ = -1.0; } //----------------------------------------------------------------------------- template SmootherT:: ~SmootherT() { // free properties mesh_.release_vertex_status(); mesh_.release_face_normals(); mesh_.release_vertex_normals(); // free custom properties mesh_.remove_property(original_positions_); mesh_.remove_property(original_normals_); mesh_.remove_property(new_positions_); mesh_.remove_property(is_active_); } //----------------------------------------------------------------------------- template void SmootherT:: initialize(Component _comp, Continuity _cont) { typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); // store smoothing settings component_ = _comp; continuity_ = _cont; // update normals mesh_.update_face_normals(); mesh_.update_vertex_normals(); // store original points & normals for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) { mesh_.property(original_positions_, v_it) = mesh_.point(v_it); mesh_.property(original_normals_, v_it) = mesh_.normal(v_it); } } //----------------------------------------------------------------------------- template void SmootherT:: set_active_vertices() { typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); // is something selected? bool nothing_selected(true); for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) if (mesh_.status(v_it).selected()) { nothing_selected = false; break; } // tagg all active vertices bool active; for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) { active = ((nothing_selected || mesh_.status(v_it).selected()) && !mesh_.is_boundary(v_it) && !mesh_.status(v_it).locked()); mesh_.property(is_active_, v_it) = active; } // C1: remove one ring of boundary vertices if (continuity_ == C1) { typename Mesh::VVIter vv_it; for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) if (mesh_.is_boundary(v_it)) for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) mesh_.property(is_active_, vv_it) = false; } // C2: remove two rings of boundary vertices if (continuity_ == C2) { typename Mesh::VVIter vv_it; for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) { mesh_.status(v_it).set_tagged(false); mesh_.status(v_it).set_tagged2(false); } for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) if (mesh_.is_boundary(v_it)) for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) mesh_.status(v_it).set_tagged(true); for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) if (mesh_.status(v_it).tagged()) for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) mesh_.status(v_it).set_tagged2(true); for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) { if (mesh_.status(v_it).tagged2()) mesh_.property(is_active_, vv_it) = false; mesh_.status(v_it).set_tagged(false); mesh_.status(v_it).set_tagged2(false); } } } //----------------------------------------------------------------------------- template void SmootherT:: set_relative_local_error(Scalar _err) { if (!mesh_.vertices_empty()) { typename Mesh::VertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end()); // compute bounding box Point bb_min, bb_max; bb_min = bb_max = mesh_.point(v_it); for (++v_it; v_it!=v_end; ++v_it) { bb_min.minimize(mesh_.point(v_it)); bb_max.minimize(mesh_.point(v_it)); } // abs. error = rel. error * bounding-diagonal set_absolute_error(_err * (bb_max-bb_min).norm()); } } //----------------------------------------------------------------------------- template void SmootherT:: set_absolute_local_error(Scalar _err) { tolerance_ = _err; } //----------------------------------------------------------------------------- template void SmootherT:: disable_local_error_check() { tolerance_ = -1.0; } //----------------------------------------------------------------------------- template void SmootherT:: smooth(unsigned int _n) { // mark active vertices set_active_vertices(); // smooth _n iterations while (_n--) { compute_new_positions(); if (component_ == Tangential) project_to_tangent_plane(); else if (tolerance_ >= 0.0) local_error_check(); move_points(); } } //----------------------------------------------------------------------------- template void SmootherT:: compute_new_positions() { switch (continuity_) { case C0: compute_new_positions_C0(); break; case C1: compute_new_positions_C1(); break; case C2: break; } } //----------------------------------------------------------------------------- template void SmootherT:: project_to_tangent_plane() { typename Mesh::VertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end()); // Normal should be a vector type. In some environment a vector type // is different from point type, e.g. OpenSG! typename Mesh::Normal translation, normal; for (; v_it != v_end; ++v_it) { if (is_active(v_it)) { translation = new_position(v_it)-orig_position(v_it); normal = orig_normal(v_it); normal *= dot(translation, normal); translation -= normal; translation += vector_cast(orig_position(v_it)); set_new_position(v_it, translation); } } } //----------------------------------------------------------------------------- template void SmootherT:: local_error_check() { typename Mesh::VertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end()); typename Mesh::Normal translation; typename Mesh::Scalar s; for (; v_it != v_end; ++v_it) { if (is_active(v_it)) { translation = new_position(v_it) - orig_position(v_it); s = fabs(dot(translation, orig_normal(v_it))); if (s > tolerance_) { translation *= (tolerance_ / s); translation += vector_cast(orig_position(v_it)); set_new_position(v_it, translation); } } } } //----------------------------------------------------------------------------- template void SmootherT:: move_points() { typename Mesh::VertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end()); for (; v_it != v_end; ++v_it) if (is_active(v_it)) mesh_.set_point(v_it, mesh_.property(new_positions_, v_it)); } //============================================================================= } // namespace Smoother } // namespace OpenMesh //=============================================================================