/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2012 Blender Foundation. * All rights reserved. * * Contributor(s): Campbell Barton * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/bmesh/intern/bmesh_mesh_validate.c * \ingroup bmesh * * BM mesh validation function. */ /* debug builds only */ #ifdef DEBUG #include "BLI_utildefines.h" #include "BLI_edgehash.h" #include "bmesh.h" #include "bmesh_mesh_validate.h" /* macro which inserts the function name */ #if defined __GNUC__ || defined __sun # define ERRMSG(format, args...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, ##args); errtot++; } (void)0 #else # define ERRMSG(format, ...) { fprintf(stderr, "%s: " format ", " AT "\n", __func__, __VA_ARGS__); errtot++; } (void)0 #endif /** * Check of this BMesh is valid, this function can be slow since its intended to help with debugging. * * \return true when the mesh is valid. */ bool BM_mesh_validate(BMesh *bm) { EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge); int errtot; BMIter iter; BMVert *v; BMEdge *e; BMFace *f; int i, j; errtot = -1; /* 'ERRMSG' next line will set at zero */ fprintf(stderr, "\n"); ERRMSG("This is a debugging function and not intended for general use, running slow test!"); /* force recalc, even if tagged as valid, since this mesh is suspect! */ bm->elem_index_dirty |= BM_ALL; BM_mesh_elem_index_ensure(bm, BM_ALL); BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(v, BM_ELEM_SELECT | BM_ELEM_HIDDEN) == (BM_ELEM_SELECT | BM_ELEM_HIDDEN)) { ERRMSG("vert %d: is hidden and selected", i); } if (v->e) { if (!BM_vert_in_edge(v->e, v)) { ERRMSG("vert %d: is not in its referenced edge: %d", i, BM_elem_index_get(v->e)); } } } /* check edges */ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { void **val_p; if (e->v1 == e->v2) { ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1)); } /* build edgehash at the same time */ if (BLI_edgehash_ensure_p(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) { BMEdge *e_other = *val_p; ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other)); } else { *val_p = e; } } /* edge radial structure */ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { if (BM_elem_flag_test(e, BM_ELEM_SELECT | BM_ELEM_HIDDEN) == (BM_ELEM_SELECT | BM_ELEM_HIDDEN)) { ERRMSG("edge %d: is hidden and selected", i); } if (e->l) { BMLoop *l_iter; BMLoop *l_first; j = 0; l_iter = l_first = e->l; /* we could do more checks here, but save for face checks */ do { if (l_iter->e != e) { ERRMSG("edge %d: has invalid loop, loop is of face %d", i, BM_elem_index_get(l_iter->f)); } else if (BM_vert_in_edge(e, l_iter->v) == false) { ERRMSG("edge %d: has invalid loop with vert not in edge, loop is of face %d", i, BM_elem_index_get(l_iter->f)); } else if (BM_vert_in_edge(e, l_iter->next->v) == false) { ERRMSG("edge %d: has invalid loop with next vert not in edge, loop is of face %d", i, BM_elem_index_get(l_iter->f)); } } while ((l_iter = l_iter->radial_next) != l_first); } } /* face structure */ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { BMLoop *l_iter; BMLoop *l_first; if (BM_elem_flag_test(f, BM_ELEM_SELECT | BM_ELEM_HIDDEN) == (BM_ELEM_SELECT | BM_ELEM_HIDDEN)) { ERRMSG("face %d: is hidden and selected", i); } l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); } while ((l_iter = l_iter->next) != l_first); j = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { if (BM_elem_flag_test(l_iter, BM_ELEM_INTERNAL_TAG)) { ERRMSG("face %d: has duplicate loop at corner: %d", i, j); } if (BM_elem_flag_test(l_iter->v, BM_ELEM_INTERNAL_TAG)) { ERRMSG("face %d: has duplicate vert: %d, at corner: %d", i, BM_elem_index_get(l_iter->v), j); } if (BM_elem_flag_test(l_iter->e, BM_ELEM_INTERNAL_TAG)) { ERRMSG("face %d: has duplicate edge: %d, at corner: %d", i, BM_elem_index_get(l_iter->e), j); } /* adjacent data checks */ if (l_iter->f != f) { ERRMSG("face %d: has loop that points to face: %d at corner: %d", i, BM_elem_index_get(l_iter->f), j); } if (l_iter != l_iter->prev->next) { ERRMSG("face %d: has invalid 'prev/next' at corner: %d", i, j); } if (l_iter != l_iter->next->prev) { ERRMSG("face %d: has invalid 'next/prev' at corner: %d", i, j); } if (l_iter != l_iter->radial_prev->radial_next) { ERRMSG("face %d: has invalid 'radial_prev/radial_next' at corner: %d", i, j); } if (l_iter != l_iter->radial_next->radial_prev) { ERRMSG("face %d: has invalid 'radial_next/radial_prev' at corner: %d", i, j); } BM_elem_flag_enable(l_iter, BM_ELEM_INTERNAL_TAG); BM_elem_flag_enable(l_iter->v, BM_ELEM_INTERNAL_TAG); BM_elem_flag_enable(l_iter->e, BM_ELEM_INTERNAL_TAG); j++; } while ((l_iter = l_iter->next) != l_first); if (j != f->len) { ERRMSG("face %d: has length of %d but should be %d", i, f->len, j); } /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */ do { BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); } while ((l_iter = l_iter->next) != l_first); } BLI_edgehash_free(edge_hash, NULL); const bool is_valid = (errtot == 0); ERRMSG("Finished - errors %d", errtot); return is_valid; } #endif