This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/bmesh/intern/bmesh_iterators.c

549 lines
12 KiB
C

/*
* ***** 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.
*
* Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_iterators.c
* \ingroup bmesh
*
* Functions to abstract looping over bmesh data structures.
*
* See: bmesh_iterators_inlin.c too, some functions are here for speed reasons.
*/
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
'\0',
BM_VERT, /* BM_VERTS_OF_MESH */
BM_EDGE, /* BM_EDGES_OF_MESH */
BM_FACE, /* BM_FACES_OF_MESH */
BM_EDGE, /* BM_EDGES_OF_VERT */
BM_FACE, /* BM_FACES_OF_VERT */
BM_LOOP, /* BM_LOOPS_OF_VERT */
BM_VERT, /* BM_VERTS_OF_EDGE */
BM_FACE, /* BM_FACES_OF_EDGE */
BM_VERT, /* BM_VERTS_OF_FACE */
BM_EDGE, /* BM_EDGES_OF_FACE */
BM_LOOP, /* BM_LOOPS_OF_FACE */
BM_LOOP, /* BM_ALL_LOOPS_OF_FACE */
BM_LOOP, /* BM_LOOPS_OF_LOOP */
BM_LOOP /* BM_LOOPS_OF_EDGE */
};
/**
* \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
*/
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
{
BMIter iter;
void *val;
int i;
/* sanity check */
if (index < 0) {
return NULL;
}
val = BM_iter_new(&iter, bm, itype, data);
i = 0;
while (i < index) {
val = BM_iter_step(&iter);
i++;
}
return val;
}
/**
* \brief Iterator as Array
*
* Sometimes its convenient to get the iterator as an array
* to avoid multiple calls to #BM_iter_at_index.
*/
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
{
int i = 0;
/* sanity check */
if (len > 0) {
BMIter iter;
void *ele;
for (ele = BM_iter_new(&iter, bm, itype, data); ele; ele = BM_iter_step(&iter)) {
array[i] = ele;
i++;
if (i == len) {
return len;
}
}
}
return i;
}
/**
* \brief Iterator as Array
*
* Allocates a new array, has the advantage that you dont need to know the size ahead of time.
*
* Takes advantage of less common iterator usage to avoid counting twice,
* which you might end up doing when #BM_iter_as_array is used.
*
* Caller needs to free the array.
*/
void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
/* optional args to avoid an alloc (normally stack array) */
void **stack_array, int stack_array_size)
{
BMIter iter;
BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
/* we can't rely on coun't being set */
switch (itype) {
case BM_VERTS_OF_MESH:
iter.count = bm->totvert;
break;
case BM_EDGES_OF_MESH:
iter.count = bm->totedge;
break;
case BM_FACES_OF_MESH:
iter.count = bm->totface;
break;
default:
break;
}
if (BM_iter_init(&iter, bm, itype, data) && iter.count > 0) {
BMElem *ele;
BMElem **array = iter.count > stack_array_size ?
MEM_mallocN(sizeof(ele) * iter.count, __func__) :
stack_array;
int i = 0;
*r_len = iter.count; /* set before iterating */
while ((ele = BM_iter_step(&iter))) {
array[i++] = ele;
}
return array;
}
else {
*r_len = 0;
return NULL;
}
}
/**
* \brief Elem Iter Flag Count
*
* Counts how many flagged / unflagged items are found in this element.
*/
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
{
BMIter iter;
BMElem *ele;
int count = 0;
for (ele = BM_iter_new(&iter, NULL, itype, data); ele; ele = BM_iter_step(&iter)) {
if (BM_elem_flag_test_bool(ele, hflag) == value) {
count++;
}
}
return count;
}
/**
* \brief Mesh Iter Flag Count
*
* Counts how many flagged / unflagged items are found in this mesh.
*/
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
{
BMIter iter;
BMElem *ele;
int count = 0;
for (ele = BM_iter_new(&iter, bm, itype, NULL); ele; ele = BM_iter_step(&iter)) {
if (BM_elem_flag_test_bool(ele, hflag) == value) {
count++;
}
}
return count;
}
/**
* \brief Init Iterator
*
* Clears the internal state of an iterator for begin() callbacks.
*/
static void init_iterator(BMIter *iter)
{
// iter->v_first = iter->v_next = NULL; // UNUSED
iter->e_first = iter->e_next = NULL;
iter->l_first = iter->l_next = NULL;
// iter->f_first = iter->f_next = NULL; // UNUSED
iter->ldata = NULL;
}
/**
* Notes on iterator implementation:
*
* Iterators keep track of the next element in a sequence.
* When a step() callback is invoked the current value of 'next'
* is stored to be returned later and the next variable is incremented.
*
* When the end of a sequence is reached, next should always equal NULL
*
* The 'bmiter__' prefix is used because these are used in
* bmesh_iterators_inine.c but should otherwise be seen as
* private.
*/
/*
* VERT OF MESH CALLBACKS
*/
void bmiter__vert_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter);
}
void *bmiter__vert_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
void bmiter__edge_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->epool, &iter->pooliter);
iter->count = iter->bm->totedge; /* */
}
void *bmiter__edge_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
void bmiter__face_of_mesh_begin(BMIter *iter)
{
BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter);
}
void *bmiter__face_of_mesh_step(BMIter *iter)
{
return BLI_mempool_iterstep(&iter->pooliter);
}
/*
* EDGE OF VERT CALLBACKS
*/
void bmiter__edge_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
if (iter->vdata->e) {
iter->e_first = iter->vdata->e;
iter->e_next = iter->vdata->e;
}
}
void *bmiter__edge_of_vert_step(BMIter *iter)
{
BMEdge *current = iter->e_next;
if (iter->e_next)
iter->e_next = bmesh_disk_edge_next(iter->e_next, iter->vdata);
if (iter->e_next == iter->e_first) iter->e_next = NULL;
return current;
}
/*
* FACE OF VERT CALLBACKS
*/
void bmiter__face_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
iter->count = 0;
if (iter->vdata->e)
iter->count = bmesh_disk_facevert_count(iter->vdata);
if (iter->count) {
iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
iter->e_next = iter->e_first;
iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
}
void *bmiter__face_of_vert_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->count && iter->l_next) {
iter->count--;
iter->l_next = bmesh_radial_faceloop_find_next(iter->l_next, iter->vdata);
if (iter->l_next == iter->l_first) {
iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
iter->l_first = bmesh_radial_faceloop_find_first(iter->e_next->l, iter->vdata);
iter->l_next = iter->l_first;
}
}
if (!iter->count) iter->l_next = NULL;
return current ? current->f : NULL;
}
/*
* LOOP OF VERT CALLBACKS
*
*/
void bmiter__loop_of_vert_begin(BMIter *iter)
{
init_iterator(iter);
iter->count = 0;
if (iter->vdata->e)
iter->count = bmesh_disk_facevert_count(iter->vdata);
if (iter->count) {
iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata);
iter->e_next = iter->e_first;
iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata);
iter->l_next = iter->l_first;
}
}
void *bmiter__loop_of_vert_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->count) {
iter->count--;
iter->l_next = bmesh_radial_faceloop_find_next(iter->l_next, iter->vdata);
if (iter->l_next == iter->l_first) {
iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
iter->l_first = bmesh_radial_faceloop_find_first(iter->e_next->l, iter->vdata);
iter->l_next = iter->l_first;
}
}
if (!iter->count) iter->l_next = NULL;
if (current) {
return current;
}
return NULL;
}
void bmiter__loops_of_edge_begin(BMIter *iter)
{
BMLoop *l;
l = iter->edata->l;
/* note sure why this sets ldata ... */
init_iterator(iter);
iter->l_first = iter->l_next = l;
}
void *bmiter__loops_of_edge_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) {
iter->l_next = iter->l_next->radial_next;
}
if (iter->l_next == iter->l_first) {
iter->l_next = NULL;
}
if (current) {
return current;
}
return NULL;
}
void bmiter__loops_of_loop_begin(BMIter *iter)
{
BMLoop *l;
l = iter->ldata;
/* note sure why this sets ldata ... */
init_iterator(iter);
iter->l_first = l;
iter->l_next = iter->l_first->radial_next;
if (iter->l_next == iter->l_first)
iter->l_next = NULL;
}
void *bmiter__loops_of_loop_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) {
iter->l_next = iter->l_next->radial_next;
}
if (iter->l_next == iter->l_first) {
iter->l_next = NULL;
}
if (current) {
return current;
}
return NULL;
}
/*
* FACE OF EDGE CALLBACKS
*/
void bmiter__face_of_edge_begin(BMIter *iter)
{
init_iterator(iter);
if (iter->edata->l) {
iter->l_first = iter->edata->l;
iter->l_next = iter->edata->l;
}
}
void *bmiter__face_of_edge_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) {
iter->l_next = iter->l_next->radial_next;
}
if (iter->l_next == iter->l_first) iter->l_next = NULL;
return current ? current->f : NULL;
}
/*
* VERTS OF EDGE CALLBACKS
*/
void bmiter__vert_of_edge_begin(BMIter *iter)
{
init_iterator(iter);
iter->count = 0;
}
void *bmiter__vert_of_edge_step(BMIter *iter)
{
iter->count++;
switch (iter->count) {
case 1:
return iter->edata->v1;
case 2:
return iter->edata->v2;
default:
return NULL;
}
}
/*
* VERT OF FACE CALLBACKS
*/
void bmiter__vert_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__vert_of_face_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) iter->l_next = iter->l_next->next;
if (iter->l_next == iter->l_first) iter->l_next = NULL;
return current ? current->v : NULL;
}
/*
* EDGE OF FACE CALLBACKS
*/
void bmiter__edge_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__edge_of_face_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) iter->l_next = iter->l_next->next;
if (iter->l_next == iter->l_first) iter->l_next = NULL;
return current ? current->e : NULL;
}
/*
* LOOP OF FACE CALLBACKS
*/
void bmiter__loop_of_face_begin(BMIter *iter)
{
init_iterator(iter);
iter->l_first = iter->l_next = BM_FACE_FIRST_LOOP(iter->pdata);
}
void *bmiter__loop_of_face_step(BMIter *iter)
{
BMLoop *current = iter->l_next;
if (iter->l_next) iter->l_next = iter->l_next->next;
if (iter->l_next == iter->l_first) iter->l_next = NULL;
return current;
}