/*===========================================================================*\ * * * OpenMesh * * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * * www.openmesh.org * * * *---------------------------------------------------------------------------* * This file is part of OpenMesh. * * * * OpenMesh 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, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenMesh 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 LesserGeneral Public * * License along with OpenMesh. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Date$ * * * \*===========================================================================*/ /** \file BoundarySnappingT.cc */ //============================================================================= // // CLASS MeshFixing - IMPLEMENTATION // //============================================================================= #define BOUNDARYSNAPPING_CC //== INCLUDES ================================================================= #include "BoundarySnappingT.hh" //== NAMESPACE =============================================================== //== IMPLEMENTATION ========================================================== template BoundarySnappingT::BoundarySnappingT(MeshT& _mesh ) : mesh_(_mesh) { } template bool sort_less_pair_second(const std::pair &lhs,const std::pair &rhs) { return lhs.second < rhs.second; } template void BoundarySnappingT::snap(double _epsilon) { std::vector v_boundary; // collect all boundary vertices for (typename MeshT::VertexIter v_iter = mesh_.vertices_begin(); v_iter != mesh_.vertices_end(); ++v_iter) if (mesh_.is_boundary(*v_iter) && mesh_.status(*v_iter).selected()) v_boundary.push_back(*v_iter); //two maps // vertexDistMap saves the vertex and his distances as pairs // vertexVertexMap saves the vertices of a vertex in range and the distances std::vector< std::pair > vertexDistMap; std::map > > vertexVertexMap; // get all boundary vertices in range and save them into the maps for (typename std::vector< typename MeshT::VertexHandle >::iterator oIter = v_boundary.begin(); oIter != v_boundary.end(); ++oIter) { typename MeshT::Point pos = mesh_.point(*oIter); if (!mesh_.status(*oIter).deleted()) { std::vector< std::pair > verticesInRange; //collect all vertices in range for (typename std::vector::iterator cIter = v_boundary.begin(); cIter != v_boundary.end(); ++cIter) { if ( !mesh_.status(*cIter).deleted() && cIter != oIter) { double dist = (pos - mesh_.point(*cIter)).length(); if ( dist <= _epsilon ) verticesInRange.push_back(std::make_pair(*cIter,dist)); } } // sort them, so nearest vertex is on position 0 (if exist) if (!verticesInRange.empty()) { std::sort( verticesInRange.begin(),verticesInRange.end(),&sort_less_pair_second ); vertexDistMap.push_back(std::make_pair(*oIter,verticesInRange[0].second)); vertexVertexMap[*oIter] = verticesInRange; } } } bool finished = false; while(!finished) { finished = true; double min = _epsilon; typename MeshT::VertexHandle v_old;//will be replaced by v_new typename MeshT::VertexHandle v_new; typename std::vector >::iterator v_oldIter = vertexDistMap.end(); typename std::vector >::iterator v_newIter; // find next min pair for (typename std::vector >::iterator vd_iter = vertexDistMap.begin(); vd_iter != vertexDistMap.end(); ++vd_iter) { typename MeshT::VertexHandle v_1 = vd_iter->first; if (v_1.is_valid() && !mesh_.status(v_1).deleted() && vertexVertexMap.find(v_1) != vertexVertexMap.end()) { typename MeshT::VertexHandle v_2; std::vector >& verticesInRange = vertexVertexMap[v_1]; for (typename std::vector >::iterator iter = verticesInRange.begin(); iter != verticesInRange.end(); ++iter) { //check if v_2 shares a face with v_1 //if so, it is not usable v_2 = iter->first; for(typename MeshT::VertexFaceIter vf_iter = mesh_.vf_begin(v_1); vf_iter.is_valid() && v_2.is_valid(); ++vf_iter) for (typename MeshT::FaceVertexIter fv_iter = mesh_.fv_begin(*vf_iter); fv_iter.is_valid() && v_2.is_valid(); ++fv_iter) if (*fv_iter == v_2) v_2 = typename MeshT::VertexHandle(); const bool validPair = v_2.is_valid() && !mesh_.status(v_2).deleted() && mesh_.is_boundary(v_2); //if v_2 is valid, save it, or erase it if not, because v_2 will not be valid in the future if (validPair && iter->second <= min) { //new min pair found min = iter->second; v_old = v_1; v_new = v_2; finished = false; v_oldIter = vd_iter; v_newIter = iter; } } } } // merge, if not finished (pair found) if (!finished) { //remove the vertex since we will proceed with it vertexVertexMap[v_old].erase(v_newIter); //save all faces, because faces will be added/deleted std::vector faces; for (typename MeshT::VertexFaceIter vf_iter = mesh_.vf_begin(v_old); vf_iter.is_valid(); ++vf_iter) if (!mesh_.status(*vf_iter).deleted()) faces.push_back(*vf_iter); //replace v_old with v_new by creating new faces with v_new instead of v_old if possible for (typename std::vector::iterator f_iter = faces.begin(); f_iter !=faces.end(); ++f_iter) { typename MeshT::FaceHandle fHandle = *f_iter; if (!fHandle.is_valid() || mesh_.status(fHandle).deleted()) continue; //get face vertices std::vector f_vertices; for(typename MeshT::FaceVertexIter fv_iter = mesh_.fv_begin(fHandle); fv_iter.is_valid(); ++fv_iter) f_vertices.push_back( *fv_iter ); mesh_.delete_face(fHandle,false); //try to add new face std::vector newFace_vertices(f_vertices); std::replace(newFace_vertices.begin(),newFace_vertices.end(),v_old,v_new); typename MeshT::FaceHandle faceH = mesh_.add_face(newFace_vertices); if (!faceH.is_valid()) { //failed, try reverse direction std::reverse(newFace_vertices.begin(),newFace_vertices.end()); faceH = mesh_.add_face(newFace_vertices); if (!faceH.is_valid()) { //failed, so add the old one mesh_.add_face(f_vertices); } } } } vertexDistMap.erase(v_oldIter); //todo: delete vertex before proceed. Now, they will be deleted at the end resulting worse snap } mesh_.delete_isolated_vertices(); mesh_.garbage_collection(); }