OpenMesh
MeshCheckerT_impl.hh
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2023, 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
45#define OPENMESH_MESHCHECKER_C
46
47
48//== INCLUDES =================================================================
49
50
51#include <OpenMesh/Tools/Utils/MeshCheckerT.hh>
52
53
54//== NAMESPACES ==============================================================
55
56
57namespace OpenMesh {
58namespace Utils {
59
60//== IMPLEMENTATION ==========================================================
61
62
63template <class Mesh>
64bool
66check(unsigned int _targets, std::ostream& _os)
67{
68 bool ok(true);
69
70
71
72 //--- vertex checks ---
73
74 if (_targets & CHECK_VERTICES)
75 {
76 unsigned int count;
77 const unsigned int max_valence(10000);
78
79
80 for (const auto vh: mesh_.vertices())
81 {
82 /* The outgoing halfedge of a boundary vertex has to be a boundary halfedge */
83 auto heh = vh.halfedge();
84 if (heh.is_valid() && !mesh_.is_boundary(heh))
85 {
86 for (typename Mesh::ConstVertexOHalfedgeIter vh_it(mesh_, vh);
87 vh_it.is_valid(); ++vh_it)
88 {
89 if (mesh_.is_boundary(*vh_it))
90 {
91 _os << "MeshChecker: vertex " << vh
92 << ": outgoing halfedge not on boundary error\n";
93 ok = false;
94 }
95 }
96 }
97 if (heh.is_valid()) {
98 if (heh.idx() < -1 || heh.idx() >= (int)mesh_.n_halfedges()) {
99 _os << "MeshChecker: vertex " << vh
100 << " has out-of-bounds outgoing HE: " << heh;
101 ok = false;
102 }
103 if (is_deleted(heh.edge())) {
104 _os << "MeshChecker: vertex " << vh
105 << " has deleted outgoing HE: " << heh;
106 ok = false;
107 }
108 }
109
110
111
112 // outgoing halfedge has to refer back to vertex
113 if (mesh_.halfedge_handle(vh).is_valid() &&
114 mesh_.from_vertex_handle(mesh_.halfedge_handle(vh)) != vh)
115 {
116 _os << "MeshChecker: vertex " << vh
117 << ": outgoing halfedge does not reference vertex\n";
118 ok = false;
119 }
120
121
122 // check whether circulators are still in order
123 auto vv_it = mesh_.cvv_cwiter(vh);
124 for (count=0; vv_it.is_valid() && (count < max_valence); ++vv_it, ++count) {};
125 if (count == max_valence)
126 {
127 _os << "MeshChecker: vertex " << vh
128 << ": ++circulator problem, one ring corrupt\n";
129 ok = false;
130 }
131 vv_it = mesh_.cvv_cwiter(vh);
132 for (count=0; vv_it.is_valid() && (count < max_valence); --vv_it, ++count) {};
133 if (count == max_valence)
134 {
135 _os << "MeshChecker: vertex " << vh
136 << ": --circulator problem, one ring corrupt\n";
137 ok = false;
138 }
139 }
140 }
141
142
143
144 //--- halfedge checks ---
145
146 if (_targets & CHECK_EDGES)
147 {
148 typename Mesh::ConstHalfedgeIter h_it(mesh_.halfedges_begin()),
149 h_end(mesh_.halfedges_end());
150 typename Mesh::HalfedgeHandle hstart, hhh;
151 size_t n_halfedges = 2*mesh_.n_edges();
152
153 for (const auto hh: mesh_.halfedges())
154 {
155 if (!hh.to().halfedge().is_valid()) {
156 _os << "MeshChecker: vertex " << hh.from()
157 << " has no outgoing halfedge, but it is not isolated.\n";
158 ok = false;
159 }
160 // degenerated halfedge ?
161 if (mesh_.from_vertex_handle(hh) == mesh_.to_vertex_handle(hh))
162 {
163 _os << "MeshChecker: halfedge " << hh
164 << ": to-vertex == from-vertex\n";
165 ok = false;
166 }
167
168
169 // next <-> prev check
170 if (mesh_.next_halfedge_handle(mesh_.prev_halfedge_handle(hh)) != hh)
171 {
172 _os << "MeshChecker: halfedge " << hh
173 << ": prev->next != this\n";
174 ok = false;
175 }
176
177 // heh.to == heh.next.from?
178 if (mesh_.to_vertex_handle(hh) != mesh_.from_vertex_handle(
179 mesh_.next_halfedge_handle(hh)))
180 {
181 _os << "MeshChecker: halfedge " << hh
182 << ".to != he.next.from\n";
183 ok = false;
184 }
185 // heh.from == heh.prev.to?
186 if (mesh_.from_vertex_handle(hh) != mesh_.to_vertex_handle(
187 mesh_.prev_halfedge_handle(hh)))
188 {
189 _os << "MeshChecker: halfedge " << hh
190 << ".from != he.prev.to\n";
191 ok = false;
192 }
193
194
195 // halfedges should form a cycle
196 size_t count=0; hstart=hhh=hh;
197 do
198 {
199 hhh = mesh_.next_halfedge_handle(hhh);
200 ++count;
201 } while (hhh != hstart && count < n_halfedges);
202
203 if (count == n_halfedges)
204 {
205 _os << "MeshChecker: halfedges starting from " << hh
206 << " do not form a cycle\n";
207 ok = false;
208 }
209 }
210 }
211
212
213
214 //--- face checks ---
215
216 if (_targets & CHECK_FACES)
217 {
218 typename Mesh::ConstFaceIter f_it(mesh_.faces_begin()),
219 f_end(mesh_.faces_end());
220 typename Mesh::ConstFaceHalfedgeIter fh_it;
221
222 for(const auto fh: mesh_.faces()) {
223 for(const auto heh: fh.halfedges()) {
224 if (heh.face() != fh) {
225 _os << "MeshChecker: face " << fh
226 << ": its halfedge " << heh << " references a different face: "
227 << heh.face()
228 << ".\n";
229 ok = false;
230 }
231 }
232 }
233 }
234
235
236
237 return ok;
238}
239
240
241//=============================================================================
242} // naespace Utils
243} // namespace OpenMesh
244//=============================================================================
Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...
Definition: MeshItems.hh:59
Kernel::ConstFaceIter ConstFaceIter
Scalar type.
Definition: PolyMeshT.hh:151
Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:178
Kernel::ConstHalfedgeIter ConstHalfedgeIter
Scalar type.
Definition: PolyMeshT.hh:149
Kernel::HalfedgeHandle HalfedgeHandle
Scalar type.
Definition: PolyMeshT.hh:137
Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:173
bool check(unsigned int _targets=CHECK_ALL, std::ostream &_os=omerr())
check it, return true iff ok
Definition: MeshCheckerT_impl.hh:66

Project OpenMesh, ©  Visual Computing Institute, RWTH Aachen. Documentation generated using doxygen .