Blender  V2.93
bmesh_mesh_validate.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 /* debug builds only */
27 #ifdef DEBUG
28 
29 # include "BLI_edgehash.h"
30 # include "BLI_utildefines.h"
31 
32 # include "bmesh.h"
33 
34 # include "bmesh_mesh_validate.h"
35 
36 /* macro which inserts the function name */
37 # if defined __GNUC__
38 # define ERRMSG(format, args...) \
39  { \
40  fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); \
41  errtot++; \
42  } \
43  (void)0
44 # else
45 # define ERRMSG(format, ...) \
46  { \
47  fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); \
48  errtot++; \
49  } \
50  (void)0
51 # endif
52 
60 {
61  EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
62  int errtot;
63 
64  BMIter iter;
65  BMVert *v;
66  BMEdge *e;
67  BMFace *f;
68 
69  int i, j;
70 
71  errtot = -1; /* 'ERRMSG' next line will set at zero */
72  fprintf(stderr, "\n");
73  ERRMSG("This is a debugging function and not intended for general use, running slow test!");
74 
75  /* force recalc, even if tagged as valid, since this mesh is suspect! */
78 
79  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
82  ERRMSG("vert %d: is hidden and selected", i);
83  }
84 
85  if (v->e) {
86  if (!BM_vert_in_edge(v->e, v)) {
87  ERRMSG("vert %d: is not in its referenced edge: %d", i, BM_elem_index_get(v->e));
88  }
89  }
90  }
91 
92  /* check edges */
93  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
94  void **val_p;
95 
96  if (e->v1 == e->v2) {
97  ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1));
98  }
99 
100  /* build edgehash at the same time */
102  edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) {
103  BMEdge *e_other = *val_p;
104  ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other));
105  }
106  else {
107  *val_p = e;
108  }
109  }
110 
111  /* edge radial structure */
112  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
115  ERRMSG("edge %d: is hidden and selected", i);
116  }
117 
118  if (e->l) {
119  BMLoop *l_iter;
120  BMLoop *l_first;
121 
122  j = 0;
123 
124  l_iter = l_first = e->l;
125  /* we could do more checks here, but save for face checks */
126  do {
127  if (l_iter->e != e) {
128  ERRMSG("edge %d: has invalid loop, loop is of face %d", i, BM_elem_index_get(l_iter->f));
129  }
130  else if (BM_vert_in_edge(e, l_iter->v) == false) {
131  ERRMSG("edge %d: has invalid loop with vert not in edge, loop is of face %d",
132  i,
133  BM_elem_index_get(l_iter->f));
134  }
135  else if (BM_vert_in_edge(e, l_iter->next->v) == false) {
136  ERRMSG("edge %d: has invalid loop with next vert not in edge, loop is of face %d",
137  i,
138  BM_elem_index_get(l_iter->f));
139  }
140  } while ((l_iter = l_iter->radial_next) != l_first);
141  }
142  }
143 
144  /* face structure */
145  BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
146  BMLoop *l_iter;
147  BMLoop *l_first;
148 
151  ERRMSG("face %d: is hidden and selected", i);
152  }
153 
154  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
155 
156  do {
160  } while ((l_iter = l_iter->next) != l_first);
161 
162  j = 0;
163 
164  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
165  do {
167  ERRMSG("face %d: has duplicate loop at corner: %d", i, j);
168  }
169  if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) {
170  ERRMSG(
171  "face %d: has duplicate vert: %d, at corner: %d", i, BM_elem_index_get(l_iter->v), j);
172  }
173  if (BM_elem_flag_test(l_iter->e, BM_ELEM_INTERNAL_TAG)) {
174  ERRMSG(
175  "face %d: has duplicate edge: %d, at corner: %d", i, BM_elem_index_get(l_iter->e), j);
176  }
177 
178  /* adjacent data checks */
179  if (l_iter->f != f) {
180  ERRMSG("face %d: has loop that points to face: %d at corner: %d",
181  i,
182  BM_elem_index_get(l_iter->f),
183  j);
184  }
185  if (l_iter != l_iter->prev->next) {
186  ERRMSG("face %d: has invalid 'prev/next' at corner: %d", i, j);
187  }
188  if (l_iter != l_iter->next->prev) {
189  ERRMSG("face %d: has invalid 'next/prev' at corner: %d", i, j);
190  }
191  if (l_iter != l_iter->radial_prev->radial_next) {
192  ERRMSG("face %d: has invalid 'radial_prev/radial_next' at corner: %d", i, j);
193  }
194  if (l_iter != l_iter->radial_next->radial_prev) {
195  ERRMSG("face %d: has invalid 'radial_next/radial_prev' at corner: %d", i, j);
196  }
197 
201  j++;
202  } while ((l_iter = l_iter->next) != l_first);
203 
204  if (j != f->len) {
205  ERRMSG("face %d: has length of %d but should be %d", i, f->len, j);
206  }
207 
208  /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */
209  do {
213  } while ((l_iter = l_iter->next) != l_first);
214  }
215 
216  BLI_edgehash_free(edge_hash, NULL);
217 
218  const bool is_valid = (errtot == 0);
219  ERRMSG("Finished - errors %d", errtot);
220  return is_valid;
221 }
222 
223 #endif
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:244
EdgeHash * BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve)
Definition: edgehash.c:226
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:355
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_INTERNAL_TAG
Definition: bmesh_class.h:496
#define BM_ALL
Definition: bmesh_class.h:410
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
bool BM_mesh_validate(BMesh *bm)
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool is_valid
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_prev
Definition: bmesh_class.h:216
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMEdge * e
Definition: bmesh_class.h:109
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297