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::HalfedgeHandle hstart, hhh;
149 size_t n_halfedges = 2*mesh_.n_edges();
150
151 for (const auto hh: mesh_.halfedges())
152 {
153 if (!hh.to().halfedge().is_valid()) {
154 _os << "MeshChecker: vertex " << hh.from()
155 << " has no outgoing halfedge, but it is not isolated.\n";
156 ok = false;
157 }
158 // degenerated halfedge ?
159 if (mesh_.from_vertex_handle(hh) == mesh_.to_vertex_handle(hh))
160 {
161 _os << "MeshChecker: halfedge " << hh
162 << ": to-vertex == from-vertex\n";
163 ok = false;
164 }
165
166
167 // next <-> prev check
168 if (mesh_.next_halfedge_handle(mesh_.prev_halfedge_handle(hh)) != hh)
169 {
170 _os << "MeshChecker: halfedge " << hh
171 << ": prev->next != this\n";
172 ok = false;
173 }
174
175 // heh.to == heh.next.from?
176 if (mesh_.to_vertex_handle(hh) != mesh_.from_vertex_handle(
177 mesh_.next_halfedge_handle(hh)))
178 {
179 _os << "MeshChecker: halfedge " << hh
180 << ".to != he.next.from\n";
181 ok = false;
182 }
183 // heh.from == heh.prev.to?
184 if (mesh_.from_vertex_handle(hh) != mesh_.to_vertex_handle(
185 mesh_.prev_halfedge_handle(hh)))
186 {
187 _os << "MeshChecker: halfedge " << hh
188 << ".from != he.prev.to\n";
189 ok = false;
190 }
191
192
193 // halfedges should form a cycle
194 size_t count=0; hstart=hhh=hh;
195 do
196 {
197 hhh = mesh_.next_halfedge_handle(hhh);
198 ++count;
199 } while (hhh != hstart && count < n_halfedges);
200
201 if (count == n_halfedges)
202 {
203 _os << "MeshChecker: halfedges starting from " << hh
204 << " do not form a cycle\n";
205 ok = false;
206 }
207 }
208 }
209
210
211
212 //--- face checks ---
213
214 if (_targets & CHECK_FACES)
215 {
216 typename Mesh::ConstFaceHalfedgeIter fh_it;
217
218 for(const auto fh: mesh_.faces()) {
219 for(const auto heh: fh.halfedges()) {
220 if (heh.face() != fh) {
221 _os << "MeshChecker: face " << fh
222 << ": its halfedge " << heh << " references a different face: "
223 << heh.face()
224 << ".\n";
225 ok = false;
226 }
227 }
228 }
229 }
230
231
232
233 return ok;
234}
235
236
237//=============================================================================
238} // naespace Utils
239} // namespace OpenMesh
240//=============================================================================
Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...
Definition: MeshItems.hh:59
Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:178
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 .