Developer Documentation
BoundarySnappingT_impl.hh
1
2/*===========================================================================*\
3 * *
4 * OpenMesh *
5 * Copyright (c) 2001-2015, RWTH-Aachen University *
6 * Department of Computer Graphics and Multimedia *
7 * All rights reserved. *
8 * www.openflipper.org *
9 * *
10 *---------------------------------------------------------------------------*
11 * This file is part of OpenFlipper. *
12 *---------------------------------------------------------------------------*
13 * *
14 * Redistribution and use in source and binary forms, with or without *
15 * modification, are permitted provided that the following conditions *
16 * are met: *
17 * *
18 * 1. Redistributions of source code must retain the above copyright notice, *
19 * this list of conditions and the following disclaimer. *
20 * *
21 * 2. Redistributions in binary form must reproduce the above copyright *
22 * notice, this list of conditions and the following disclaimer in the *
23 * documentation and/or other materials provided with the distribution. *
24 * *
25 * 3. Neither the name of the copyright holder nor the names of its *
26 * contributors may be used to endorse or promote products derived from *
27 * this software without specific prior written permission. *
28 * *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
32 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
33 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
35 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
36 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
40 * *
41 \*===========================================================================*/
42
43/*===========================================================================*\
44 * *
45 * $Revision$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49
53//=============================================================================
54//
55// CLASS MeshFixing - IMPLEMENTATION
56//
57//=============================================================================
58
59#define BOUNDARYSNAPPING_CC
60
61//== INCLUDES =================================================================
62
63#include "BoundarySnappingT.hh"
64
65//== NAMESPACE ===============================================================
66
67
68//== IMPLEMENTATION ==========================================================
69
70
71template<class MeshT>
73mesh_(_mesh)
74{
75}
76
77template<typename MeshT>
78bool sort_less_pair_second(const std::pair<typename MeshT::VertexHandle,double> &lhs,const std::pair<typename MeshT::VertexHandle,double> &rhs)
79{
80 return lhs.second < rhs.second;
81}
82
83template<class MeshT>
84void BoundarySnappingT<MeshT>::snap(double _epsilon)
85{
86 std::vector<typename MeshT::VertexHandle> v_boundary;
87
88 // collect all boundary vertices
89 for (auto v_iter : mesh_.vertices())
90 if (v_iter.is_boundary() && mesh_.status(v_iter).selected())
91 v_boundary.push_back(v_iter);
92
93 //two maps
94 // vertexDistMap saves the vertex and his distances as pairs
95 // vertexVertexMap saves the vertices of a vertex in range and the distances
96 std::vector< std::pair<typename MeshT::VertexHandle,double> > vertexDistMap;
97 std::map<typename MeshT::VertexHandle,std::vector<std::pair<typename MeshT::VertexHandle,double> > > vertexVertexMap;
98
99 // get all boundary vertices in range and save them into the maps
100 for (typename std::vector< typename MeshT::VertexHandle >::iterator oIter = v_boundary.begin(); oIter != v_boundary.end(); ++oIter)
101 {
102 typename MeshT::Point pos = mesh_.point(*oIter);
103 if (!mesh_.status(*oIter).deleted())
104 {
105 std::vector< std::pair<typename MeshT::VertexHandle,double> > verticesInRange;
106
107 //collect all vertices in range
108 for (typename std::vector<typename MeshT::VertexHandle>::iterator cIter = v_boundary.begin(); cIter != v_boundary.end(); ++cIter)
109 {
110 if ( !mesh_.status(*cIter).deleted() && cIter != oIter)
111 {
112 double dist = (pos - mesh_.point(*cIter)).length();
113
114 if ( dist <= _epsilon )
115 verticesInRange.push_back(std::make_pair(*cIter,dist));
116 }
117 }
118
119 // sort them, so nearest vertex is on position 0 (if exist)
120 if (!verticesInRange.empty())
121 {
122 std::sort( verticesInRange.begin(),verticesInRange.end(),&sort_less_pair_second<MeshT> );
123 vertexDistMap.push_back(std::make_pair(*oIter,verticesInRange[0].second));
124 vertexVertexMap[*oIter] = verticesInRange;
125 }
126 }
127 }
128
129 bool finished = false;
130 while(!finished)
131 {
132 finished = true;
133
134 double min = _epsilon;
135 typename MeshT::VertexHandle v_old;//will be replaced by v_new
136 typename MeshT::VertexHandle v_new;
137 typename std::vector<std::pair<typename MeshT::VertexHandle,double> >::iterator v_oldIter = vertexDistMap.end();
138 typename std::vector<std::pair<typename MeshT::VertexHandle,double> >::iterator v_newIter;
139
140 // find next min pair
141 for (typename std::vector<std::pair<typename MeshT::VertexHandle,double> >::iterator vd_iter = vertexDistMap.begin(); vd_iter != vertexDistMap.end(); ++vd_iter)
142 {
143 typename MeshT::VertexHandle v_1 = vd_iter->first;
144 if (v_1.is_valid() && !mesh_.status(v_1).deleted() && vertexVertexMap.find(v_1) != vertexVertexMap.end())
145 {
146 typename MeshT::VertexHandle v_2;
147 std::vector<std::pair<typename MeshT::VertexHandle,double> >& verticesInRange = vertexVertexMap[v_1];
148
149 for (typename std::vector<std::pair<typename MeshT::VertexHandle,double> >::iterator iter = verticesInRange.begin(); iter != verticesInRange.end(); ++iter)
150 {
151 //check if v_2 shares a face with v_1
152 //if so, it is not usable
153 v_2 = iter->first;
154
155 for(typename MeshT::VertexFaceIter vf_iter = mesh_.vf_begin(v_1); vf_iter.is_valid() && v_2.is_valid(); ++vf_iter)
156 for (typename MeshT::FaceVertexIter fv_iter = mesh_.fv_begin(*vf_iter); fv_iter.is_valid() && v_2.is_valid(); ++fv_iter)
157 if (*fv_iter == v_2)
158 v_2 = typename MeshT::VertexHandle();
159
160 const bool validPair = v_2.is_valid() && !mesh_.status(v_2).deleted() && mesh_.is_boundary(v_2);
161
162 //if v_2 is valid, save it, or erase it if not, because v_2 will not be valid in the future
163 if (validPair && iter->second <= min)
164 {
165 //new min pair found
166 min = iter->second;
167 v_old = v_1;
168 v_new = v_2;
169 finished = false;
170 v_oldIter = vd_iter;
171 v_newIter = iter;
172 }
173 }
174 }
175
176 }
177 // merge, if not finished (pair found)
178 if (!finished)
179 {
180 //remove the vertex since we will proceed with it
181 vertexVertexMap[v_old].erase(v_newIter);
182 //save all faces, because faces will be added/deleted
183 std::vector<typename OpenMesh::SmartFaceHandle> faces;
184 for (auto vf_iter : make_smart(v_old, mesh_).faces())
185 if (!mesh_.status(vf_iter).deleted())
186 faces.push_back(vf_iter);
187
188 //replace v_old with v_new by creating new faces with v_new instead of v_old if possible
189 for (auto f_iter : faces)
190 {
191 typename OpenMesh::SmartFaceHandle fHandle = f_iter;
192 if (!fHandle.is_valid() || mesh_.status(fHandle).deleted())
193 continue;
194
195 //get face vertices
196 std::vector<typename MeshT::VertexHandle> f_vertices;
197 for(auto fv_iter : fHandle.vertices())
198 f_vertices.push_back( fv_iter );
199
200 mesh_.delete_face(fHandle,false);
201
202 //try to add new face
203 std::vector<typename MeshT::VertexHandle> newFace_vertices(f_vertices);
204 std::replace(newFace_vertices.begin(),newFace_vertices.end(),v_old,v_new);
205 typename MeshT::FaceHandle faceH = mesh_.add_face(newFace_vertices);
206
207 if (!faceH.is_valid())
208 {
209 //failed, try reverse direction
210 std::reverse(newFace_vertices.begin(),newFace_vertices.end());
211 faceH = mesh_.add_face(newFace_vertices);
212 if (!faceH.is_valid())
213 {
214 //failed, so add the old one
215 mesh_.add_face(f_vertices);
216 }
217 }
218 }
219 }
220 vertexDistMap.erase(v_oldIter);
221
222 //todo: delete vertex before proceed. Now, they will be deleted at the end resulting worse snap
223 }
224 mesh_.delete_isolated_vertices();
225
226 mesh_.garbage_collection();
227
228}
Snaps selected vertices at boundaries.
void snap(double _epsilon)
snaps boundary vertices
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
VectorT< Scalar, DIM > min(const VectorT< Scalar, DIM > &_v1, const VectorT< Scalar, DIM > &_v2)
Definition: Vector11T.hh:797
PolyConnectivity::ConstFaceVertexRange vertices() const
Returns a range of vertices incident to the face (PolyConnectivity::fv_range())