BMesh: minor optimization counting adjacent data

add BM_***_count_is_over(), _count_is_equal()

Useful if we only want to know if the count is a smaller value.
This commit is contained in:
Campbell Barton 2015-04-12 15:21:40 +10:00
parent 6d2c3a2456
commit 690b90f1e2
14 changed files with 161 additions and 41 deletions

@ -369,6 +369,7 @@ static BMFace *pbvh_bmesh_face_create(
}
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
BMIter bm_iter;
@ -376,12 +377,33 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
int count = 0;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
PBVHNode *f_node;
f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node == node)
PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node == node) {
count++;
}
}
return count;
}
#endif
#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
(pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n)
static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
{
BMIter bm_iter;
BMFace *f;
int count = 0;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
break;
}
}
}
return count;
@ -484,13 +506,13 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) {
if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
BLI_assert(new_node || BM_vert_face_count(v) == 1);
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
@ -810,13 +832,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_face_kill(bvh->bm, f_adj);
/* Ensure new vertex is in the node */
if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new) &&
!BLI_gset_haskey(bvh->nodes[ni].bm_other_verts, v_new))
{
BLI_gset_insert(bvh->nodes[ni].bm_other_verts, v_new);
if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
}
if (BM_vert_edge_count(v_opp) >= 9) {
if (BM_vert_edge_count_is_over(v_opp, 8)) {
BMIter bm_iter;
BMEdge *e2;
@ -945,10 +965,8 @@ static void pbvh_bmesh_collapse_edge(
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
if (!BLI_gset_haskey(n->bm_unique_verts, v_conn) &&
!BLI_gset_haskey(n->bm_other_verts, v_conn))
{
BLI_gset_insert(n->bm_other_verts, v_conn);
if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
BLI_gset_add(n->bm_other_verts, v_conn);
}
}
@ -973,7 +991,7 @@ static void pbvh_bmesh_collapse_edge(
/* Check if any of the face's vertices are now unused, if so
* remove them from the PBVH */
for (j = 0; j < 3; j++) {
if (v_tri[j] != v_del && BM_vert_face_count(v_tri[j]) == 1) {
if (v_tri[j] != v_del && BM_vert_face_count_is_equal(v_tri[j], 1)) {
BLI_gset_insert(deleted_verts, v_tri[j]);
pbvh_bmesh_vert_remove(bvh, v_tri[j]);
}
@ -1010,7 +1028,7 @@ static void pbvh_bmesh_collapse_edge(
}
/* Delete v_del */
BLI_assert(BM_vert_face_count(v_del) == 0);
BLI_assert(!BM_vert_face_check(v_del));
BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
BM_vert_kill(bvh->bm, v_del);
@ -1641,7 +1659,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
BLI_assert(BM_vert_face_count(v) > 0);
BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}

@ -1111,7 +1111,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
* else this will remove the face as well - campbell */
if (BM_edge_face_count(l_iter->e) <= 2) {
if (!BM_edge_face_count_is_over(l_iter->e, 3)) {
if (do_del) {
BLI_array_append(deledges, l_iter->e);
}

@ -72,7 +72,8 @@
*/
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
const int len = BM_vert_edge_count(v);
/* logic for 3 or more is identical */
const int len = BM_vert_edge_count_ex(v, 3);
if (len == 1) {
BM_vert_kill(bm, v); /* will kill edges too */
@ -97,7 +98,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return false;
}
}
else if (len == 2 && BM_vert_face_count(v) == 1) {
else if (len == 2 && BM_vert_face_count_is_equal(v, 1)) {
/* boundary vertex on a face */
return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}

@ -54,6 +54,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
int bmesh_disk_count_ex(const BMVert *v, const int count_max);
int bmesh_disk_count(const BMVert *v);
/**

@ -750,6 +750,11 @@ int BM_vert_edge_count(const BMVert *v)
return bmesh_disk_count(v);
}
int BM_vert_edge_count_ex(const BMVert *v, const int count_max)
{
return bmesh_disk_count_ex(v, count_max);
}
int BM_vert_edge_count_nonwire(const BMVert *v)
{
int count = 0;
@ -770,11 +775,9 @@ int BM_edge_face_count(const BMEdge *e)
int count = 0;
if (e->l) {
BMLoop *l_iter;
BMLoop *l_first;
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
count++;
} while ((l_iter = l_iter->radial_next) != l_first);
@ -783,6 +786,25 @@ int BM_edge_face_count(const BMEdge *e)
return count;
}
int BM_edge_face_count_ex(const BMEdge *e, const int count_max)
{
int count = 0;
if (e->l) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
count++;
if (count == count_max) {
break;
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
return count;
}
/**
* Returns the number of faces around this vert
* length matches #BM_LOOPS_OF_VERT iterator
@ -792,6 +814,21 @@ int BM_vert_face_count(const BMVert *v)
return bmesh_disk_facevert_count(v);
}
int BM_vert_face_count_ex(const BMVert *v, int count_max)
{
return bmesh_disk_facevert_count_ex(v, count_max);
}
/**
* Return true if the vertex is connected to _any_ faces.
*
* same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
*/
bool BM_vert_face_check(BMVert *v)
{
return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
}
/**
* Tests whether or not the vertex is part of a wire edge.
* (ie: has no faces attached to it)

@ -65,12 +65,22 @@ BMFace *BM_vert_pair_share_face_by_angle(
const bool allow_adjacent) ATTR_NONNULL();
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == n)
#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == (n) + 1)
int BM_vert_edge_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_ex(e, (n) + 1) == n)
#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_ex(e, (n) + 1) == (n) + 1)
int BM_edge_face_count_ex(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_ex(v, (n) + 1) == n)
#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_ex(v, (n) + 1) == (n) + 1)
int BM_vert_face_count_ex(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();

@ -206,6 +206,22 @@ int bmesh_disk_count(const BMVert *v)
return count;
}
int bmesh_disk_count_ex(const BMVert *v, const int count_max)
{
int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
e_iter = e_first = v->e;
do {
count++;
if (count == count_max) {
break;
}
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
return count;
}
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
{
BMEdge *e_iter;
@ -236,9 +252,9 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
int count = 0;
/* first, loop around edge */
e_first = e_iter = v->e;
@ -247,11 +263,29 @@ int bmesh_disk_facevert_count(const BMVert *v)
count += bmesh_radial_facevert_count(e_iter->l, v);
}
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
return count;
}
else {
return 0;
return count;
}
int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
{
/* is there an edge on this vert at all */
int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
/* first, loop around edge */
e_first = e_iter = v->e;
do {
if (e_iter->l) {
count += bmesh_radial_facevert_count_ex(e_iter->l, v, count_max - count);
if (count == count_max) {
break;
}
}
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
return count;
}
/**
@ -456,6 +490,23 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
return count;
}
int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max)
{
const BMLoop *l_iter;
int count = 0;
l_iter = l;
do {
if (l_iter->v == v) {
count++;
if (count == count_max) {
break;
}
}
} while ((l_iter = l_iter->radial_next) != l);
return count;
}
/**
* \brief RADIAL CHECK FACE VERT
*

@ -49,6 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) A
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@ -60,6 +61,7 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();

@ -333,7 +333,7 @@ static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_
BLI_assert(e->l->f->len == 3 &&
e->l->radial_next->f->len == 3);
BLI_assert(BM_edge_face_count(e) == 2);
BLI_assert(BM_edge_face_count_is_equal(e, 2));
for (i = 0; i < 4; i++) {
bm_edge_update_beauty_cost_single(
@ -389,11 +389,11 @@ void BM_mesh_beautify_fill(
i = BM_elem_index_get(e);
eheap_table[i] = NULL;
BLI_assert(BM_edge_face_count(e) == 2);
BLI_assert(BM_edge_face_count_is_equal(e, 2));
e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
BLI_assert(e == NULL || BM_edge_face_count(e) == 2);
BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
if (LIKELY(e)) {
GSet *e_state_set = edge_state_arr[i];

@ -2778,7 +2778,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k);
}
if (BM_vert_face_count(bv->v) == 0) {
if (BM_vert_face_check(bv->v) == false) {
e_eg = bv->edges[0].e;
BLI_assert(e_eg != NULL);
for (k = 0; k < ns; k++) {

@ -587,8 +587,8 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* if we are ripping a single vertex from 3 faces,
* then measure the distance to the face corner as well as the edge */
if (BM_vert_face_count(v) == 3 &&
BM_vert_edge_count(v) == 3)
if (BM_vert_face_count_is_equal(v, 3) &&
BM_vert_edge_count_is_equal(v, 3))
{
BMEdge *e_all[3];
BMLoop *l_all[3];
@ -735,7 +735,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
* but both allocate fill */
/* rip two adjacent edges */
if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) {
if (BM_edge_is_boundary(e2) || BM_vert_face_count_is_equal(v, 2)) {
/* Don't run the edge split operator in this case */
BMVert *v_rip;

@ -2042,7 +2042,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
ok = true;
BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
if (BM_edge_face_count(eed) < 3) {
if (!BM_edge_face_count_is_over(eed, 2)) {
ok = false;
break;
}
@ -2938,7 +2938,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
if ((use_wire && BM_edge_is_wire(e)) ||
(use_boundary && BM_edge_is_boundary(e)) ||
(use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
(use_multi_face && (BM_edge_face_count(e) > 2)))
(use_multi_face && (BM_edge_face_count_is_over(e, 2))))
{
/* check we never select perfect edge (in test above) */
BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));

@ -68,7 +68,7 @@
#include <float.h>
#include <math.h>
// #define DEBUG_TIME
#define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"

@ -84,7 +84,7 @@ static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObjec
return NULL;
}
if (BM_vert_edge_count(py_vert->v) > 2) {
if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
return NULL;
@ -150,7 +150,7 @@ static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObje
return NULL;
}
if (BM_vert_edge_count(py_vert->v) > 2) {
if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
return NULL;