Blender  V3.3
bmesh_mesh_validate.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. All rights reserved. */
3 
10 /* debug builds only */
11 #ifdef DEBUG
12 
13 # include "BLI_edgehash.h"
14 # include "BLI_utildefines.h"
15 
16 # include "bmesh.h"
17 
18 # include "bmesh_mesh_validate.h"
19 
20 /* macro which inserts the function name */
21 # if defined __GNUC__
22 # define ERRMSG(format, args...) \
23  { \
24  fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); \
25  errtot++; \
26  } \
27  (void)0
28 # else
29 # define ERRMSG(format, ...) \
30  { \
31  fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); \
32  errtot++; \
33  } \
34  (void)0
35 # endif
36 
38 {
39  EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
40  int errtot;
41 
42  BMIter iter;
43  BMVert *v;
44  BMEdge *e;
45  BMFace *f;
46 
47  int i, j;
48 
49  errtot = -1; /* 'ERRMSG' next line will set at zero */
50  fprintf(stderr, "\n");
51  ERRMSG("This is a debugging function and not intended for general use, running slow test!");
52 
53  /* force recalc, even if tagged as valid, since this mesh is suspect! */
56 
57  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
60  ERRMSG("vert %d: is hidden and selected", i);
61  }
62 
63  if (v->e) {
64  if (!BM_vert_in_edge(v->e, v)) {
65  ERRMSG("vert %d: is not in its referenced edge: %d", i, BM_elem_index_get(v->e));
66  }
67  }
68  }
69 
70  /* check edges */
71  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
72  void **val_p;
73 
74  if (e->v1 == e->v2) {
75  ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1));
76  }
77 
78  /* build edgehash at the same time */
80  edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) {
81  BMEdge *e_other = *val_p;
82  ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other));
83  }
84  else {
85  *val_p = e;
86  }
87  }
88 
89  /* edge radial structure */
90  BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
93  ERRMSG("edge %d: is hidden and selected", i);
94  }
95 
96  if (e->l) {
97  BMLoop *l_iter;
98  BMLoop *l_first;
99 
100  j = 0;
101 
102  l_iter = l_first = e->l;
103  /* we could do more checks here, but save for face checks */
104  do {
105  if (l_iter->e != e) {
106  ERRMSG("edge %d: has invalid loop, loop is of face %d", i, BM_elem_index_get(l_iter->f));
107  }
108  else if (BM_vert_in_edge(e, l_iter->v) == false) {
109  ERRMSG("edge %d: has invalid loop with vert not in edge, loop is of face %d",
110  i,
111  BM_elem_index_get(l_iter->f));
112  }
113  else if (BM_vert_in_edge(e, l_iter->next->v) == false) {
114  ERRMSG("edge %d: has invalid loop with next vert not in edge, loop is of face %d",
115  i,
116  BM_elem_index_get(l_iter->f));
117  }
118  } while ((l_iter = l_iter->radial_next) != l_first);
119  }
120  }
121 
122  /* face structure */
123  BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
124  BMLoop *l_iter;
125  BMLoop *l_first;
126 
129  ERRMSG("face %d: is hidden and selected", i);
130  }
131 
132  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
133 
134  do {
138  } while ((l_iter = l_iter->next) != l_first);
139 
140  j = 0;
141 
142  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
143  do {
145  ERRMSG("face %d: has duplicate loop at corner: %d", i, j);
146  }
147  if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) {
148  ERRMSG(
149  "face %d: has duplicate vert: %d, at corner: %d", i, BM_elem_index_get(l_iter->v), j);
150  }
151  if (BM_elem_flag_test(l_iter->e, BM_ELEM_INTERNAL_TAG)) {
152  ERRMSG(
153  "face %d: has duplicate edge: %d, at corner: %d", i, BM_elem_index_get(l_iter->e), j);
154  }
155 
156  /* adjacent data checks */
157  if (l_iter->f != f) {
158  ERRMSG("face %d: has loop that points to face: %d at corner: %d",
159  i,
160  BM_elem_index_get(l_iter->f),
161  j);
162  }
163  if (l_iter != l_iter->prev->next) {
164  ERRMSG("face %d: has invalid 'prev/next' at corner: %d", i, j);
165  }
166  if (l_iter != l_iter->next->prev) {
167  ERRMSG("face %d: has invalid 'next/prev' at corner: %d", i, j);
168  }
169  if (l_iter != l_iter->radial_prev->radial_next) {
170  ERRMSG("face %d: has invalid 'radial_prev/radial_next' at corner: %d", i, j);
171  }
172  if (l_iter != l_iter->radial_next->radial_prev) {
173  ERRMSG("face %d: has invalid 'radial_next/radial_prev' at corner: %d", i, j);
174  }
175 
179  j++;
180  } while ((l_iter = l_iter->next) != l_first);
181 
182  if (j != f->len) {
183  ERRMSG("face %d: has length of %d but should be %d", i, f->len, j);
184  }
185 
186  /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */
187  do {
191  } while ((l_iter = l_iter->next) != l_first);
192  }
193 
194  BLI_edgehash_free(edge_hash, NULL);
195 
196  const bool is_valid = (errtot == 0);
197  ERRMSG("Finished - errors %d", errtot);
198  return is_valid;
199 }
200 
201 #endif
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:230
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:307
EdgeHash * BLI_edgehash_new_ex(const char *info, unsigned int nentries_reserve)
Definition: edgehash.c:212
#define BM_ALL
Definition: bmesh_class.h:410
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ 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_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#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.cc:446
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:267
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_prev
Definition: bmesh_class.h:204
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
struct BMEdge * e
Definition: bmesh_class.h:97
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297