2012-02-19 18:31:04 +00:00
|
|
|
/*
|
|
|
|
* ***** 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, Levi Schooley.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/bmesh/intern/bmesh_walkers_impl.c
|
|
|
|
* \ingroup bmesh
|
|
|
|
*
|
|
|
|
* BMesh Walker Code.
|
|
|
|
*/
|
|
|
|
|
2012-03-24 01:24:58 +00:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
|
|
|
#include "bmesh.h"
|
2012-03-08 03:25:53 +00:00
|
|
|
#include "intern/bmesh_private.h"
|
2012-03-24 01:24:58 +00:00
|
|
|
#include "intern/bmesh_walkers_private.h"
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-29 13:09:07 +00:00
|
|
|
static int bmw_mask_check_vert(BMWalker *walker, BMVert *v)
|
|
|
|
{
|
|
|
|
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bmw_mask_check_edge(BMWalker *walker, BMEdge *e)
|
|
|
|
{
|
|
|
|
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bmw_mask_check_face(BMWalker *walker, BMFace *f)
|
|
|
|
{
|
|
|
|
if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Shell Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a vertex on the mesh and walks over the 'shell' it belongs
|
|
|
|
* to via visiting connected edges.
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* \todo Add restriction flag/callback for wire edges.
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_ShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwShellWalker *shellWalk = NULL;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (BLI_ghash_haskey(walker->visithash, e)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-29 13:09:07 +00:00
|
|
|
if (!bmw_mask_check_edge(walker, e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
shellWalk = BMW_state_add(walker);
|
|
|
|
shellWalk->curedge = e;
|
|
|
|
BLI_ghash_insert(walker->visithash, e, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_ShellWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMIter eiter;
|
|
|
|
BMHeader *h = data;
|
|
|
|
BMEdge *e;
|
|
|
|
BMVert *v;
|
|
|
|
|
2012-02-25 20:58:03 +00:00
|
|
|
if (UNLIKELY(h == NULL)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (h->htype) {
|
|
|
|
case BM_VERT:
|
|
|
|
{
|
|
|
|
/* starting the walk at a vert, add all the edges
|
|
|
|
* to the worklist */
|
|
|
|
v = (BMVert *)h;
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
2012-03-02 12:44:34 +00:00
|
|
|
bmw_ShellWalker_visitEdge(walker, e);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case BM_EDGE:
|
|
|
|
{
|
|
|
|
/* starting the walk at an edge, add the single edge
|
|
|
|
* to the worklist */
|
|
|
|
e = (BMEdge *)h;
|
2012-03-02 12:44:34 +00:00
|
|
|
bmw_ShellWalker_visitEdge(walker, e);
|
2012-02-19 18:31:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_ShellWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwShellWalker *shellWalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
return shellWalk->curedge;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_ShellWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwShellWalker *swalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
BMEdge *e, *e2;
|
|
|
|
BMVert *v;
|
|
|
|
BMIter iter;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
e = swalk->curedge;
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
v = i ? e->v2 : e->v1;
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (e2, &iter, v, BM_EDGES_OF_VERT) {
|
2012-03-02 12:44:34 +00:00
|
|
|
bmw_ShellWalker_visitEdge(walker, e2);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_ShellWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMEdge *curedge, *next = NULL;
|
|
|
|
BMVert *ov = NULL;
|
|
|
|
int restrictpass = 1;
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwShellWalker shellWalk = *((BMwShellWalker *)BMW_current_state(walker));
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (!BLI_ghash_haskey(walker->visithash, shellWalk.base)) {
|
|
|
|
BLI_ghash_insert(walker->visithash, shellWalk.base, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
|
|
|
|
/* find the next edge whose other vertex has not been visite */
|
|
|
|
curedge = shellWalk.curedge;
|
|
|
|
do {
|
|
|
|
if (!BLI_ghash_haskey(walker->visithash, curedge)) {
|
|
|
|
if (!walker->restrictflag ||
|
|
|
|
(walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag)))
|
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwShellWalker *newstate;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
ov = BM_edge_other_vert(curedge, shellWalk.base);
|
|
|
|
|
|
|
|
/* push a new state onto the stac */
|
|
|
|
newState = BMW_state_add(walker);
|
|
|
|
BLI_ghash_insert(walker->visithash, curedge, NULL);
|
|
|
|
|
|
|
|
/* populate the new stat */
|
|
|
|
|
|
|
|
newState->base = ov;
|
|
|
|
newState->curedge = curedge;
|
|
|
|
}
|
|
|
|
}
|
2012-02-27 13:47:53 +00:00
|
|
|
curedge = bmesh_disk_edge_next(curedge, shellWalk.base);
|
2012-02-19 18:31:04 +00:00
|
|
|
} while (curedge != shellWalk.curedge);
|
|
|
|
|
|
|
|
return shellWalk.curedge;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Connected Vertex Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Similar to shell walker, but visits vertices instead of edges.
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwConnectedVertexWalker *vwalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (BLI_ghash_haskey(walker->visithash, v)) {
|
|
|
|
/* already visited */
|
|
|
|
return;
|
|
|
|
}
|
2012-03-29 13:09:07 +00:00
|
|
|
|
|
|
|
if (!bmw_mask_check_vert(walker, v)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
/* not flagged for walk */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vwalk = BMW_state_add(walker);
|
|
|
|
vwalk->curvert = v;
|
|
|
|
BLI_ghash_insert(walker->visithash, v, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_ConnectedVertexWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMVert *v = data;
|
2012-03-02 12:44:34 +00:00
|
|
|
bmw_ConnectedVertexWalker_visitVertex(walker, v);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_ConnectedVertexWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwConnectedVertexWalker *vwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
return vwalk->curvert;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwConnectedVertexWalker *vwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
BMVert *v, *v2;
|
|
|
|
BMEdge *e;
|
|
|
|
BMIter iter;
|
|
|
|
|
|
|
|
v = vwalk->curvert;
|
|
|
|
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
|
2012-02-19 18:31:04 +00:00
|
|
|
v2 = BM_edge_other_vert(e, v);
|
|
|
|
if (!BLI_ghash_haskey(walker->visithash, v2)) {
|
2012-03-02 12:44:34 +00:00
|
|
|
bmw_ConnectedVertexWalker_visitVertex(walker, v2);
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Island Boundary Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a edge on the mesh and walks over the boundary of an island it belongs to.
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* \todo Add restriction flag/callback for wire edges.
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
BMLoop *l = data;
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandboundWalker *iwalk = NULL;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
iwalk = BMW_state_add(walker);
|
|
|
|
|
|
|
|
iwalk->base = iwalk->curloop = l;
|
|
|
|
iwalk->lastv = l->v;
|
|
|
|
|
|
|
|
BLI_ghash_insert(walker->visithash, data, NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_IslandboundWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandboundWalker *iwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
return iwalk->curloop;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_IslandboundWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandboundWalker *iwalk = BMW_current_state(walker), owalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMVert *v;
|
|
|
|
BMEdge *e = iwalk->curloop->e;
|
|
|
|
BMFace *f;
|
|
|
|
BMLoop *l = iwalk->curloop;
|
|
|
|
/* int found = 0; */
|
|
|
|
|
|
|
|
owalk = *iwalk;
|
|
|
|
|
2012-03-12 06:53:47 +00:00
|
|
|
v = BM_edge_other_vert(e, iwalk->lastv);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-22 07:53:11 +00:00
|
|
|
if (!BM_vert_is_manifold(v)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_reset(walker);
|
|
|
|
BMO_error_raise(walker->bm, NULL, BMERR_WALKER_FAILED,
|
2012-10-27 11:12:09 +00:00
|
|
|
"Non-manifold vert while searching region boundary");
|
2012-02-19 18:31:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pop off current stat */
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
f = l->f;
|
|
|
|
|
|
|
|
while (1) {
|
2012-03-04 16:36:31 +00:00
|
|
|
l = BM_face_other_edge_loop(f, e, v);
|
2012-03-01 17:13:02 +00:00
|
|
|
if (l != l->radial_next) {
|
|
|
|
l = l->radial_next;
|
2012-02-19 18:31:04 +00:00
|
|
|
f = l->f;
|
|
|
|
e = l->e;
|
2012-03-29 13:09:07 +00:00
|
|
|
|
|
|
|
if (!bmw_mask_check_face(walker, f)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
l = l->radial_next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
f = l->f;
|
|
|
|
e = l->e;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l == owalk.curloop) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (BLI_ghash_haskey(walker->visithash, l)) {
|
|
|
|
return owalk.curloop;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghash_insert(walker->visithash, l, NULL);
|
|
|
|
iwalk = BMW_state_add(walker);
|
|
|
|
iwalk->base = owalk.base;
|
|
|
|
|
|
|
|
//if (!BMO_elem_flag_test(walker->bm, l->f, walker->restrictflag))
|
|
|
|
// iwalk->curloop = l->radial_next;
|
|
|
|
iwalk->curloop = l; //else iwalk->curloop = l;
|
|
|
|
iwalk->lastv = v;
|
|
|
|
|
|
|
|
return owalk.curloop;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Island Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a tool flagged-face and walks over the face region
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* \todo Add restriction flag/callback for wire edges.
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandWalker *iwalk = NULL;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-29 13:09:07 +00:00
|
|
|
if (!bmw_mask_check_face(walker, data)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
iwalk = BMW_state_add(walker);
|
|
|
|
BLI_ghash_insert(walker->visithash, data, NULL);
|
|
|
|
|
|
|
|
iwalk->cur = data;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_IslandWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandWalker *iwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
return iwalk->cur;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_IslandWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwIslandWalker *iwalk = BMW_current_state(walker);
|
|
|
|
/* BMwIslandWalker *owalk = iwalk; */ /* UNUSED */
|
2012-02-19 18:31:04 +00:00
|
|
|
BMIter iter, liter;
|
|
|
|
BMFace *f, *curf = iwalk->cur;
|
|
|
|
BMLoop *l;
|
|
|
|
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
l = BM_iter_new(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
|
|
|
|
for ( ; l; l = BM_iter_step(&liter)) {
|
2012-03-18 07:38:51 +00:00
|
|
|
/* could skip loop here too, but don't add unless we need it */
|
2012-03-29 13:09:07 +00:00
|
|
|
if (!bmw_mask_check_edge(walker, l->e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = BM_iter_new(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
|
|
|
|
for ( ; f; f = BM_iter_step(&iter)) {
|
2012-03-29 13:09:07 +00:00
|
|
|
|
|
|
|
if (!bmw_mask_check_face(walker, f)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
2012-03-01 13:13:08 +00:00
|
|
|
|
|
|
|
if (BLI_ghash_haskey(walker->visithash, f)) {
|
|
|
|
continue;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
iwalk = BMW_state_add(walker);
|
|
|
|
iwalk->cur = f;
|
|
|
|
BLI_ghash_insert(walker->visithash, f, NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return curf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Edge Loop Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a tool-flagged edge and walks over the edge loop
|
2012-02-19 18:31:04 +00:00
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwLoopWalker *lwalk = NULL, owalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMEdge *e = data;
|
|
|
|
BMVert *v;
|
2012-03-13 18:37:31 +00:00
|
|
|
int vert_edge_count[2] = {BM_vert_edge_count_nonwire(e->v1),
|
|
|
|
BM_vert_edge_count_nonwire(e->v2)};
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
v = e->v1;
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
BLI_ghash_insert(walker->visithash, e, NULL);
|
|
|
|
|
|
|
|
lwalk->cur = lwalk->start = e;
|
|
|
|
lwalk->lastv = lwalk->startv = v;
|
2012-03-18 07:38:51 +00:00
|
|
|
lwalk->is_boundary = BM_edge_is_boundary(e);
|
2012-03-13 18:37:31 +00:00
|
|
|
lwalk->is_single = (vert_edge_count[0] == 2 && vert_edge_count[1] == 2);
|
|
|
|
|
|
|
|
/* could also check that vertex*/
|
2012-03-18 07:38:51 +00:00
|
|
|
if ((lwalk->is_boundary == FALSE) &&
|
2012-03-13 18:37:31 +00:00
|
|
|
(vert_edge_count[0] == 3 || vert_edge_count[1] == 3))
|
|
|
|
{
|
|
|
|
BMIter iter;
|
|
|
|
BMFace *f_iter;
|
|
|
|
BMFace *f_best = NULL;
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (f_iter, &iter, e, BM_FACES_OF_EDGE) {
|
2012-03-13 18:37:31 +00:00
|
|
|
if (f_best == NULL || f_best->len < f_iter->len) {
|
|
|
|
f_best = f_iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-21 17:34:31 +00:00
|
|
|
if (f_best) {
|
|
|
|
/* only use hub selection for 5+ sides else this could
|
|
|
|
* conflict with normal edge loop selection. */
|
|
|
|
lwalk->f_hub = f_best->len > 4 ? f_best : NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* edge doesn't have any faces connected to it */
|
|
|
|
lwalk->f_hub = NULL;
|
|
|
|
}
|
2012-03-13 18:37:31 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
lwalk->f_hub = NULL;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 18:37:31 +00:00
|
|
|
/* rewind */
|
2012-02-19 18:31:04 +00:00
|
|
|
while (BMW_current_state(walker)) {
|
2012-03-02 12:44:34 +00:00
|
|
|
owalk = *((BMwLoopWalker *)BMW_current_state(walker));
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_walk(walker);
|
|
|
|
}
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
*lwalk = owalk;
|
|
|
|
|
2012-03-12 06:53:47 +00:00
|
|
|
lwalk->lastv = lwalk->startv = BM_edge_other_vert(owalk.cur, lwalk->lastv);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
BLI_ghash_free(walker->visithash, NULL, NULL);
|
2012-05-16 00:51:36 +00:00
|
|
|
walker->visithash = BLI_ghash_ptr_new("bmesh walkers 2");
|
2012-02-19 18:31:04 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, owalk.cur, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_LoopWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwLoopWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
return lwalk->cur;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_LoopWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwLoopWalker *lwalk = BMW_current_state(walker), owalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMEdge *e = lwalk->cur, *nexte = NULL;
|
2012-03-13 17:13:44 +00:00
|
|
|
BMLoop *l;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMVert *v;
|
2012-10-08 06:28:06 +00:00
|
|
|
int i = 0;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
owalk = *lwalk;
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
l = e->l;
|
|
|
|
|
2012-03-13 18:37:31 +00:00
|
|
|
if (owalk.f_hub) { /* NGON EDGE */
|
|
|
|
int vert_edge_tot;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 18:37:31 +00:00
|
|
|
v = BM_edge_other_vert(e, lwalk->lastv);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 18:37:31 +00:00
|
|
|
vert_edge_tot = BM_vert_edge_count_nonwire(v);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 18:37:31 +00:00
|
|
|
if (vert_edge_tot == 3) {
|
|
|
|
l = BM_face_other_vert_loop(owalk.f_hub, lwalk->lastv, v);
|
|
|
|
nexte = BM_edge_exists(v, l->v);
|
|
|
|
|
2012-03-30 08:43:47 +00:00
|
|
|
if (bmw_mask_check_edge(walker, nexte) &&
|
|
|
|
!BLI_ghash_haskey(walker->visithash, nexte))
|
|
|
|
{
|
2012-03-24 07:36:32 +00:00
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->cur = nexte;
|
|
|
|
lwalk->lastv = v;
|
2012-03-13 18:37:31 +00:00
|
|
|
|
2012-03-24 07:36:32 +00:00
|
|
|
lwalk->is_boundary = owalk.is_boundary;
|
|
|
|
lwalk->is_single = owalk.is_single;
|
|
|
|
lwalk->f_hub = owalk.f_hub;
|
2012-03-13 18:37:31 +00:00
|
|
|
|
2012-03-24 07:36:32 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, nexte, NULL);
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-13 18:37:31 +00:00
|
|
|
else if (l) { /* NORMAL EDGE WITH FACES */
|
2012-03-13 17:13:44 +00:00
|
|
|
int vert_edge_tot;
|
2012-10-08 06:28:06 +00:00
|
|
|
int stopi = 0;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
v = BM_edge_other_vert(e, lwalk->lastv);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
vert_edge_tot = BM_vert_edge_count_nonwire(v);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
if (/* check if we should step, this is fairly involved */
|
2012-03-11 20:45:58 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
/* typical loopiong over edges in the middle of a mesh */
|
|
|
|
/* however, why use 2 here at all? I guess for internal ngon loops it can be useful. Antony R. */
|
2012-03-18 07:38:51 +00:00
|
|
|
((vert_edge_tot == 4 || vert_edge_tot == 2) && owalk.is_boundary == FALSE) ||
|
2012-03-11 21:47:14 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* walk over boundary of faces but stop at corners */
|
2012-06-23 23:22:19 +00:00
|
|
|
(owalk.is_boundary == TRUE && owalk.is_single == FALSE && vert_edge_tot > 2) ||
|
2012-03-11 21:47:14 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* initial edge was a boundary, so is this edge and vertex is only apart of this face
|
|
|
|
* this lets us walk over the the boundary of an ngon which is handy */
|
|
|
|
(owalk.is_boundary == TRUE && owalk.is_single == TRUE && vert_edge_tot == 2 && BM_edge_is_boundary(e)))
|
2012-03-13 17:13:44 +00:00
|
|
|
{
|
|
|
|
i = 0;
|
|
|
|
stopi = vert_edge_tot / 2;
|
|
|
|
while (1) {
|
2012-03-18 07:38:51 +00:00
|
|
|
if ((owalk.is_boundary == FALSE) && (i == stopi)) {
|
2012-03-13 17:13:44 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
l = BM_face_other_edge_loop(l->f, l->e, v);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
if (l == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BMLoop *l_next;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
l_next = l->radial_next;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
if ((l_next == l) || (l_next == NULL)) {
|
|
|
|
break;
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
l = l_next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
if (l != NULL) {
|
2012-03-30 08:43:47 +00:00
|
|
|
if (l != e->l &&
|
|
|
|
bmw_mask_check_edge(walker, l->e) &&
|
|
|
|
!BLI_ghash_haskey(walker->visithash, l->e))
|
|
|
|
{
|
2012-03-18 07:38:51 +00:00
|
|
|
if (!(owalk.is_boundary == FALSE && i != stopi)) {
|
2012-03-13 17:13:44 +00:00
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->cur = l->e;
|
|
|
|
lwalk->lastv = v;
|
2012-03-13 18:37:31 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
lwalk->is_boundary = owalk.is_boundary;
|
2012-03-13 17:13:44 +00:00
|
|
|
lwalk->is_single = owalk.is_single;
|
2012-03-13 18:37:31 +00:00
|
|
|
lwalk->f_hub = owalk.f_hub;
|
|
|
|
|
2012-03-13 17:13:44 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, l->e, NULL);
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
}
|
2012-10-29 15:43:54 +00:00
|
|
|
else { /* WIRE EDGE */
|
2012-03-13 18:37:31 +00:00
|
|
|
BMIter eiter;
|
|
|
|
|
|
|
|
/* match trunk: mark all connected wire edges */
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
v = i ? e->v2 : e->v1;
|
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (nexte, &eiter, v, BM_EDGES_OF_VERT) {
|
2012-03-30 08:43:47 +00:00
|
|
|
if ((nexte->l == NULL) &&
|
|
|
|
bmw_mask_check_edge(walker, nexte) &&
|
|
|
|
!BLI_ghash_haskey(walker->visithash, nexte))
|
|
|
|
{
|
2012-03-13 18:37:31 +00:00
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->cur = nexte;
|
|
|
|
lwalk->lastv = v;
|
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
lwalk->is_boundary = owalk.is_boundary;
|
2012-03-13 18:37:31 +00:00
|
|
|
lwalk->is_single = owalk.is_single;
|
|
|
|
lwalk->f_hub = owalk.f_hub;
|
|
|
|
|
|
|
|
BLI_ghash_insert(walker->visithash, nexte, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
return owalk.cur;
|
|
|
|
}
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Face Loop Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a tool-flagged face and walks over the face loop
|
2012-02-19 18:31:04 +00:00
|
|
|
* Conditions for starting and stepping the face loop have been
|
|
|
|
* tuned in an attempt to match the face loops built by EditMesh
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Check whether the face loop should includes the face specified
|
|
|
|
* by the given BMLoop */
|
2012-03-02 12:44:34 +00:00
|
|
|
static int bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
/* face must have degree 4 */
|
|
|
|
if (l->f->len != 4) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-03-30 09:27:54 +00:00
|
|
|
if (!bmw_mask_check_face(walker, l->f)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
/* the face must not have been already visite */
|
2012-03-21 21:40:42 +00:00
|
|
|
if (BLI_ghash_haskey(walker->visithash, l->f) && BLI_ghash_haskey(walker->secvisithash, l->e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check whether the face loop can start from the given edge */
|
2012-03-02 12:44:34 +00:00
|
|
|
static int bmw_FaceLoopWalker_edge_begins_loop(BMWalker *walker, BMEdge *e)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
|
|
|
/* There is no face loop starting from a wire edge */
|
2012-03-22 07:53:11 +00:00
|
|
|
if (BM_edge_is_wire(e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't start a loop from a boundary edge if it cannot
|
|
|
|
* be extended to cover any faces */
|
2012-04-03 17:09:47 +00:00
|
|
|
if (BM_edge_is_boundary(e)) {
|
2012-03-02 12:44:34 +00:00
|
|
|
if (!bmw_FaceLoopWalker_include_face(walker, e->l)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't start a face loop from non-manifold edges */
|
2012-03-22 07:53:11 +00:00
|
|
|
if (!BM_edge_is_manifold(e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwFaceLoopWalker *lwalk, owalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMEdge *e = data;
|
|
|
|
/* BMesh *bm = walker->bm; */ /* UNUSED */
|
|
|
|
/* int fcount = BM_edge_face_count(e); */ /* UNUSED */
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
if (!bmw_FaceLoopWalker_edge_begins_loop(walker, e))
|
2012-02-19 18:31:04 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->l = e->l;
|
|
|
|
lwalk->nocalc = 0;
|
|
|
|
BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
|
|
|
|
|
|
|
|
/* rewin */
|
|
|
|
while (BMW_current_state(walker)) {
|
2012-03-02 12:44:34 +00:00
|
|
|
owalk = *((BMwFaceLoopWalker *)BMW_current_state(walker));
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_walk(walker);
|
|
|
|
}
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
*lwalk = owalk;
|
|
|
|
lwalk->nocalc = 0;
|
|
|
|
|
2012-03-21 21:40:42 +00:00
|
|
|
BLI_ghash_free(walker->secvisithash, NULL, NULL);
|
2012-05-16 00:51:36 +00:00
|
|
|
walker->secvisithash = BLI_ghash_ptr_new("bmesh walkers 3");
|
2012-03-21 21:40:42 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
|
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
BLI_ghash_free(walker->visithash, NULL, NULL);
|
2012-05-16 00:51:36 +00:00
|
|
|
walker->visithash = BLI_ghash_ptr_new("bmesh walkers 3");
|
2012-02-19 18:31:04 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_FaceLoopWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwFaceLoopWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (!lwalk) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lwalk->l->f;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_FaceLoopWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwFaceLoopWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
BMFace *f = lwalk->l->f;
|
|
|
|
BMLoop *l = lwalk->l, *origl = lwalk->l;
|
|
|
|
|
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
l = l->radial_next;
|
|
|
|
|
2012-03-12 06:53:47 +00:00
|
|
|
if (lwalk->nocalc) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return f;
|
2012-03-12 06:53:47 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
if (!bmw_FaceLoopWalker_include_face(walker, l)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
l = lwalk->l;
|
|
|
|
l = l->next->next;
|
2012-04-18 06:57:28 +00:00
|
|
|
if (!BM_edge_is_manifold(l->e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
l = l->prev->prev;
|
|
|
|
}
|
|
|
|
l = l->radial_next;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
if (bmw_FaceLoopWalker_include_face(walker, l)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->l = l;
|
|
|
|
|
|
|
|
if (l->f->len != 4) {
|
|
|
|
lwalk->nocalc = 1;
|
|
|
|
lwalk->l = origl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lwalk->nocalc = 0;
|
|
|
|
}
|
|
|
|
|
2012-03-21 21:40:42 +00:00
|
|
|
BLI_ghash_insert(walker->secvisithash, l->e, NULL);
|
2012-02-19 18:31:04 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, l->f, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2012-03-03 22:27:34 +00:00
|
|
|
// #define BMW_EDGERING_NGON
|
|
|
|
|
2012-02-28 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Edge Ring Walker:
|
2012-02-19 18:31:04 +00:00
|
|
|
*
|
2012-02-28 18:28:30 +00:00
|
|
|
* Starts at a tool-flagged edge and walks over the edge ring
|
2012-02-19 18:31:04 +00:00
|
|
|
* Conditions for starting and stepping the edge ring have been
|
|
|
|
* tuned in an attempt to match the edge rings built by EditMesh
|
|
|
|
*/
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwEdgeringWalker *lwalk, owalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMEdge *e = data;
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->l = e->l;
|
|
|
|
|
|
|
|
if (!lwalk->l) {
|
|
|
|
lwalk->wireedge = e;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lwalk->wireedge = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
|
|
|
|
|
|
|
|
/* rewin */
|
|
|
|
while (BMW_current_state(walker)) {
|
2012-03-02 12:44:34 +00:00
|
|
|
owalk = *((BMwEdgeringWalker *)BMW_current_state(walker));
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_walk(walker);
|
|
|
|
}
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
*lwalk = owalk;
|
|
|
|
|
2012-03-03 22:27:34 +00:00
|
|
|
#ifdef BMW_EDGERING_NGON
|
2012-02-29 17:23:41 +00:00
|
|
|
if (lwalk->l->f->len % 2 != 0)
|
2012-03-03 22:27:34 +00:00
|
|
|
#else
|
|
|
|
if (lwalk->l->f->len != 4)
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-19 18:31:04 +00:00
|
|
|
lwalk->l = lwalk->l->radial_next;
|
2012-03-03 22:27:34 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
BLI_ghash_free(walker->visithash, NULL, NULL);
|
2012-05-16 00:51:36 +00:00
|
|
|
walker->visithash = BLI_ghash_ptr_new("bmesh walkers 4");
|
2012-02-19 18:31:04 +00:00
|
|
|
BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_EdgeringWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwEdgeringWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (!lwalk) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-06 17:23:26 +00:00
|
|
|
if (lwalk->l) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return lwalk->l->e;
|
2012-03-06 17:23:26 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-02-19 18:31:04 +00:00
|
|
|
return lwalk->wireedge;
|
2012-03-06 17:23:26 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_EdgeringWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwEdgeringWalker *lwalk = BMW_current_state(walker);
|
2012-04-12 12:11:21 +00:00
|
|
|
BMEdge *e, *wireedge = lwalk->wireedge;
|
2012-04-29 15:47:02 +00:00
|
|
|
BMLoop *l = lwalk->l, *origl = lwalk->l;
|
2012-03-03 22:27:34 +00:00
|
|
|
#ifdef BMW_EDGERING_NGON
|
2012-02-29 17:23:41 +00:00
|
|
|
int i, len;
|
2012-03-03 22:27:34 +00:00
|
|
|
#endif
|
2012-02-19 18:31:04 +00:00
|
|
|
|
2012-04-03 17:09:47 +00:00
|
|
|
#define EDGE_CHECK(e) (bmw_mask_check_edge(walker, e) && (BM_edge_is_boundary(e) || BM_edge_is_manifold(e)))
|
2012-03-30 09:27:54 +00:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_state_remove(walker);
|
|
|
|
|
|
|
|
if (!l)
|
2012-04-12 12:11:21 +00:00
|
|
|
return wireedge;
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
e = l->e;
|
2012-03-30 09:27:54 +00:00
|
|
|
if (!EDGE_CHECK(e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
/* walker won't traverse to a non-manifold edge, but may
|
|
|
|
* be started on one, and should not traverse *away* from
|
|
|
|
* a non-manfold edge (non-manifold edges are never in an
|
|
|
|
* edge ring with manifold edges */
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2012-03-03 22:27:34 +00:00
|
|
|
#ifdef BMW_EDGERING_NGON
|
2012-02-19 18:31:04 +00:00
|
|
|
l = l->radial_next;
|
2012-02-29 17:23:41 +00:00
|
|
|
|
|
|
|
i = len = l->f->len;
|
|
|
|
while (i > 0) {
|
|
|
|
l = l->next;
|
|
|
|
i -= 2;
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-04-12 12:11:21 +00:00
|
|
|
if ((len <= 0) || (len % 2 != 0) || !EDGE_CHECK(l->e) ||
|
|
|
|
!bmw_mask_check_face(walker, l->f))
|
|
|
|
{
|
|
|
|
l = origl;
|
2012-02-29 17:23:41 +00:00
|
|
|
i = len;
|
|
|
|
while (i > 0) {
|
|
|
|
l = l->next;
|
|
|
|
i -= 2;
|
|
|
|
}
|
|
|
|
}
|
2012-03-03 22:27:34 +00:00
|
|
|
/* only walk to manifold edge */
|
2012-03-30 09:27:54 +00:00
|
|
|
if ((l->f->len % 2 == 0) && EDGE_CHECK(l->e) &&
|
2012-04-28 06:31:57 +00:00
|
|
|
!BLI_ghash_haskey(walker->visithash, l->e))
|
2012-02-29 17:23:41 +00:00
|
|
|
|
2012-03-03 22:27:34 +00:00
|
|
|
#else
|
2012-02-29 17:23:41 +00:00
|
|
|
|
2012-03-03 22:27:34 +00:00
|
|
|
l = l->radial_next;
|
|
|
|
l = l->next->next;
|
|
|
|
|
2012-04-12 12:03:12 +00:00
|
|
|
if ((l->f->len != 4) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) {
|
2012-04-12 12:11:21 +00:00
|
|
|
l = origl->next->next;
|
2012-03-03 22:27:34 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
/* only walk to manifold edge */
|
2012-03-30 09:27:54 +00:00
|
|
|
if ((l->f->len == 4) && EDGE_CHECK(l->e) &&
|
2012-03-03 22:27:34 +00:00
|
|
|
!BLI_ghash_haskey(walker->visithash, l->e))
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-19 18:31:04 +00:00
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->l = l;
|
|
|
|
lwalk->wireedge = NULL;
|
|
|
|
|
|
|
|
BLI_ghash_insert(walker->visithash, l->e, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return e;
|
2012-03-30 09:27:54 +00:00
|
|
|
|
|
|
|
#undef EDGE_CHECK
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void bmw_UVEdgeWalker_begin(BMWalker *walker, void *data)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwUVEdgeWalker *lwalk;
|
2012-02-19 18:31:04 +00:00
|
|
|
BMLoop *l = data;
|
|
|
|
|
|
|
|
if (BLI_ghash_haskey(walker->visithash, l))
|
|
|
|
return;
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
lwalk->l = l;
|
|
|
|
BLI_ghash_insert(walker->visithash, l, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_UVEdgeWalker_yield(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwUVEdgeWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
if (!lwalk) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lwalk->l;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static void *bmw_UVEdgeWalker_step(BMWalker *walker)
|
2012-02-19 18:31:04 +00:00
|
|
|
{
|
2012-03-02 12:44:34 +00:00
|
|
|
BMwUVEdgeWalker *lwalk = BMW_current_state(walker);
|
2012-02-19 18:31:04 +00:00
|
|
|
BMLoop *l, *l2, *l3, *nl, *cl;
|
|
|
|
BMIter liter;
|
|
|
|
void *d1, *d2;
|
|
|
|
int i, j, rlen, type;
|
|
|
|
|
|
|
|
l = lwalk->l;
|
|
|
|
nl = l->next;
|
|
|
|
type = walker->bm->ldata.layers[walker->layer].type;
|
|
|
|
|
|
|
|
BMW_state_remove(walker);
|
2012-03-29 13:09:07 +00:00
|
|
|
|
|
|
|
if (!bmw_mask_check_edge(walker, l->e)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
return l;
|
2012-03-29 13:09:07 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
|
|
|
|
/* go over loops around l->v and nl->v and see which ones share l and nl's
|
2012-03-01 12:20:18 +00:00
|
|
|
* mloopuv's coordinates. in addition, push on l->next if necessary */
|
2012-02-19 18:31:04 +00:00
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
cl = i ? nl : l;
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (l2, &liter, cl->v, BM_LOOPS_OF_VERT) {
|
2012-02-19 18:31:04 +00:00
|
|
|
d1 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
|
|
|
|
cl->head.data, walker->layer);
|
|
|
|
|
|
|
|
rlen = BM_edge_face_count(l2->e);
|
|
|
|
for (j = 0; j < rlen; j++) {
|
2012-03-29 13:09:07 +00:00
|
|
|
if (BLI_ghash_haskey(walker->visithash, l2)) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
2012-03-29 13:09:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bmw_mask_check_edge(walker, l2->e)) {
|
|
|
|
if (l2->v != cl->v) {
|
2012-02-19 18:31:04 +00:00
|
|
|
continue;
|
2012-03-29 13:09:07 +00:00
|
|
|
}
|
2012-02-19 18:31:04 +00:00
|
|
|
}
|
2012-03-29 13:09:07 +00:00
|
|
|
|
2012-02-19 18:31:04 +00:00
|
|
|
l3 = l2->v != cl->v ? l2->next : l2;
|
|
|
|
d2 = CustomData_bmesh_get_layer_n(&walker->bm->ldata,
|
|
|
|
l3->head.data, walker->layer);
|
|
|
|
|
|
|
|
if (!CustomData_data_equals(type, d1, d2))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
lwalk = BMW_state_add(walker);
|
|
|
|
BLI_ghash_insert(walker->visithash, l2, NULL);
|
|
|
|
|
|
|
|
lwalk->l = l2;
|
|
|
|
|
|
|
|
l2 = l2->radial_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_ShellWalker_Type = {
|
|
|
|
bmw_ShellWalker_begin,
|
|
|
|
bmw_ShellWalker_step,
|
|
|
|
bmw_ShellWalker_yield,
|
|
|
|
sizeof(BMwShellWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_BREADTH_FIRST,
|
|
|
|
BM_EDGE, /* valid restrict masks */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_IslandboundWalker_Type = {
|
|
|
|
bmw_IslandboundWalker_begin,
|
|
|
|
bmw_IslandboundWalker_step,
|
|
|
|
bmw_IslandboundWalker_yield,
|
|
|
|
sizeof(BMwIslandboundWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_DEPTH_FIRST,
|
|
|
|
BM_FACE, /* valid restrict masks */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_IslandWalker_Type = {
|
|
|
|
bmw_IslandWalker_begin,
|
|
|
|
bmw_IslandWalker_step,
|
|
|
|
bmw_IslandWalker_yield,
|
|
|
|
sizeof(BMwIslandWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_BREADTH_FIRST,
|
|
|
|
BM_EDGE | BM_FACE, /* valid restrict masks */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_LoopWalker_Type = {
|
|
|
|
bmw_LoopWalker_begin,
|
|
|
|
bmw_LoopWalker_step,
|
|
|
|
bmw_LoopWalker_yield,
|
|
|
|
sizeof(BMwLoopWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_DEPTH_FIRST,
|
|
|
|
0, /* valid restrict masks */ /* could add flags here but so far none are used */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_FaceLoopWalker_Type = {
|
|
|
|
bmw_FaceLoopWalker_begin,
|
|
|
|
bmw_FaceLoopWalker_step,
|
|
|
|
bmw_FaceLoopWalker_yield,
|
|
|
|
sizeof(BMwFaceLoopWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_DEPTH_FIRST,
|
|
|
|
0, /* valid restrict masks */ /* could add flags here but so far none are used */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_EdgeringWalker_Type = {
|
|
|
|
bmw_EdgeringWalker_begin,
|
|
|
|
bmw_EdgeringWalker_step,
|
|
|
|
bmw_EdgeringWalker_yield,
|
|
|
|
sizeof(BMwEdgeringWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_DEPTH_FIRST,
|
|
|
|
0, /* valid restrict masks */ /* could add flags here but so far none are used */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_UVEdgeWalker_Type = {
|
|
|
|
bmw_UVEdgeWalker_begin,
|
|
|
|
bmw_UVEdgeWalker_step,
|
|
|
|
bmw_UVEdgeWalker_yield,
|
|
|
|
sizeof(BMwUVEdgeWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_DEPTH_FIRST,
|
|
|
|
BM_EDGE, /* valid restrict masks */
|
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
static BMWalker bmw_ConnectedVertexWalker_Type = {
|
|
|
|
bmw_ConnectedVertexWalker_begin,
|
|
|
|
bmw_ConnectedVertexWalker_step,
|
|
|
|
bmw_ConnectedVertexWalker_yield,
|
|
|
|
sizeof(BMwConnectedVertexWalker),
|
2012-02-19 18:31:04 +00:00
|
|
|
BMW_BREADTH_FIRST,
|
|
|
|
BM_VERT, /* valid restrict masks */
|
|
|
|
};
|
|
|
|
|
|
|
|
BMWalker *bm_walker_types[] = {
|
2012-03-02 12:44:34 +00:00
|
|
|
&bmw_ShellWalker_Type, /* BMW_SHELL */
|
|
|
|
&bmw_LoopWalker_Type, /* BMW_LOOP */
|
|
|
|
&bmw_FaceLoopWalker_Type, /* BMW_FACELOOP */
|
|
|
|
&bmw_EdgeringWalker_Type, /* BMW_EDGERING */
|
|
|
|
&bmw_UVEdgeWalker_Type, /* BMW_LOOPDATA_ISLAND */
|
|
|
|
&bmw_IslandboundWalker_Type, /* BMW_ISLANDBOUND */
|
|
|
|
&bmw_IslandWalker_Type, /* BMW_ISLAND */
|
|
|
|
&bmw_ConnectedVertexWalker_Type, /* BMW_CONNECTED_VERTEX */
|
2012-02-19 18:31:04 +00:00
|
|
|
};
|
|
|
|
|
2012-03-02 12:44:34 +00:00
|
|
|
const int bm_totwalkers = sizeof(bm_walker_types) / sizeof(*bm_walker_types);
|