bmesh py api, new functions:

* bmesh.utils.face_vert_rip(f, v)
* bmesh.utils.loop_rip(l)
This commit is contained in:
Campbell Barton 2012-03-08 20:00:37 +00:00
parent 284fcd2df2
commit c82c456247
10 changed files with 146 additions and 43 deletions

@ -1930,7 +1930,7 @@ static int bm_edge_cut(BMesh *bm, BMEdge *e, BMLoop *cutl)
* *
* \return The newly created BMVert * \return The newly created BMVert
*/ */
static BMVert *bm_urmv_loop(BMesh *bm, BMLoop *sl) BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl)
{ {
BMVert **vtar; BMVert **vtar;
int len, i; int len, i;
@ -2007,20 +2007,6 @@ static BMVert *bm_urmv_loop(BMesh *bm, BMLoop *sl)
*/ */
BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv) BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
{ {
BMLoop *l_first; BMLoop *l = BM_face_vert_share_loop(sf, sv);
BMLoop *l_iter; return bmesh_urmv_loop(bm, l);
l_iter = l_first = BM_FACE_FIRST_LOOP(sf);
do {
if (l_iter->v == sv) {
break;
}
} while ((l_iter = l_iter->next) != l_first);
if (l_iter->v != sv) {
/* sv is not part of sf */
return NULL;
}
return bm_urmv_loop(bm, l_iter);
} }

@ -60,5 +60,6 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
BMEdge *bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv, const short check_edge_splice); BMEdge *bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv, const short check_edge_splice);
BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e); BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv); BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv);
BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl);
#endif /* __BMESH_CORE_H__ */ #endif /* __BMESH_CORE_H__ */

@ -1073,7 +1073,17 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const short ccw, const short check_
/** /**
* \brief Rip a single face from a vertex fan * \brief Rip a single face from a vertex fan
*/ */
BMVert *BM_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv) BMVert *BM_face_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv)
{ {
return bmesh_urmv(bm, sf, sv); return bmesh_urmv(bm, sf, sv);
} }
/**
* \brief Rip a single face from a vertex fan
*
* \note same as #BM_face_vert_rip but faster (avoids a loop lookup)
*/
BMVert *BM_face_loop_rip(BMesh *bm, BMLoop *sl)
{
return bmesh_urmv_loop(bm, sl);
}

@ -77,6 +77,7 @@ enum {
}; };
BMVert *BM_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv); BMVert *BM_face_vert_rip(BMesh *bm, BMFace *sf, BMVert *sv);
BMVert *BM_face_loop_rip(BMesh *bm, BMLoop *sl);
#endif /* __BMESH_MODS_H__ */ #endif /* __BMESH_MODS_H__ */

@ -556,6 +556,29 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
} }
} }
/**
* \brief Radial Find a Vertex Loop in Face
*
* Finds the loop used which uses \a v in face loop \a l
*
* \note currenly this just uses simple loop in future may be speeded up
* using radial vars
*/
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
{
BMLoop *l_first;
BMLoop *l_iter;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (l_iter->v == v) {
return l_iter;
}
} while ((l_iter = l_iter->next) != l_first);
return NULL;
}
/** /**
* Returns the verts of an edge as used in a face * Returns the verts of an edge as used in a face
* if used in a face at all, otherwise just assign as used in the edge. * if used in a face at all, otherwise just assign as used in the edge.

@ -72,6 +72,7 @@ int BM_edge_share_face_count(BMEdge *e1, BMEdge *e2);
int BM_edge_share_vert_count(BMEdge *e1, BMEdge *e2); int BM_edge_share_vert_count(BMEdge *e1, BMEdge *e2);
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2); BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2);
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v);
void BM_edge_ordered_verts(BMEdge *edge, BMVert **r_v1, BMVert **r_v2); void BM_edge_ordered_verts(BMEdge *edge, BMVert **r_v1, BMVert **r_v2);

@ -450,27 +450,6 @@ BMLoop *bmesh_radial_faceloop_find_next(BMLoop *l, BMVert *v)
return l; return l;
} }
/* NOTE: this function has not been used or tested - so take care but it should work ok,
* I wrote it for some tool that ended up not using it, however this seems like a reasonable
* thing to be able to find the loop between a vertex and a face so keeping - campbell */
/**
* \brief Radial Find a Vertex Loop in Face
*
* Finds the loop used which uses \a v in face loop \a l
*/
BMLoop *bmesh_radial_faceloop_find_vert(BMFace *f, BMVert *v) /* name is a bit awkward */
{
BMLoop *l_iter, *l_first;
if (v->e && (l_iter = l_first = v->e->l)) {
do {
if (l_iter->v == v && l_iter->f == f) {
return l_iter;
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
return NULL;
}
int bmesh_radial_length(BMLoop *l) int bmesh_radial_length(BMLoop *l)
{ {
BMLoop *l_iter = l; BMLoop *l_iter = l;

@ -2409,7 +2409,7 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
/* rip two adjacent edges */ /* rip two adjacent edges */
if (BM_edge_face_count(e2) == 1 || BM_vert_face_count(v) == 2) { if (BM_edge_face_count(e2) == 1 || BM_vert_face_count(v) == 2) {
l = e2->l; l = e2->l;
ripvert = BM_vert_rip(bm, l->f, v); ripvert = BM_face_vert_rip(bm, l->f, v);
BLI_assert(ripvert); BLI_assert(ripvert);
if (!ripvert) { if (!ripvert) {

@ -961,7 +961,7 @@ static PyObject *bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value)
BPY_BM_CHECK_OBJ(value); BPY_BM_CHECK_OBJ(value);
if (self->bm != value->bm) { if (self->bm != value->bm) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_ValueError,
"BMEdge.other_vert(vert): vert is from another mesh"); "BMEdge.other_vert(vert): vert is from another mesh");
return NULL; return NULL;
} }
@ -2625,7 +2625,7 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
/* trick so we can ensure all items have the same mesh, /* trick so we can ensure all items have the same mesh,
* and allows us to pass the 'bm' as NULL. */ * and allows us to pass the 'bm' as NULL. */
else if (do_bm_check && (bm && bm != item->bm)) { else if (do_bm_check && (bm && bm != item->bm)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_ValueError,
"%s: %d %s is from another mesh", "%s: %d %s is from another mesh",
error_prefix, i, type->tp_name); error_prefix, i, type->tp_name);
goto err_cleanup; goto err_cleanup;

@ -417,6 +417,68 @@ static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *value)
} }
PyDoc_STRVAR(bpy_bm_utils_face_vert_rip_doc,
".. method:: face_vert_rip(face, vert)\n"
"\n"
" Rip a vertex in a face away and add a new vertex.\n"
"\n"
" :arg face: The face to rip.\n"
" :type face: :class:`BMFace`\n"
" :arg vert: A vertex in the face to rip.\n"
" :type vert: :class:`BMVert`\n"
" :return vert: The newly created vertex or None of failure.\n"
" :rtype vert: :class:`BMVert`\n"
"\n"
" .. note::\n"
"\n"
" This is the same as loop_rip, and has only been added for convenience.\n"
);
static PyObject *bpy_bm_utils_face_vert_rip(PyObject *UNUSED(self), PyObject *args)
{
BPy_BMFace *py_face;
BPy_BMVert *py_vert;
BMesh *bm;
BMLoop *l;
BMVert *v_new;
if (!PyArg_ParseTuple(args, "O!O!:face_vert_rip",
&BPy_BMFace_Type, &py_face,
&BPy_BMVert_Type, &py_vert))
{
return NULL;
}
BPY_BM_CHECK_OBJ(py_face);
BPY_BM_CHECK_OBJ(py_vert);
bm = py_face->bm;
if (bm != py_vert->bm) {
PyErr_SetString(PyExc_ValueError,
"mesh elements are from different meshes");
return NULL;
}
l = BM_face_vert_share_loop(py_face->f, py_vert->v);
if (l == NULL) {
PyErr_SetString(PyExc_ValueError,
"vertex not found in face");
return NULL;
}
v_new = BM_face_loop_rip(bm, l);
if (v_new != l->v) {
return BPy_BMVert_CreatePyObject(bm, v_new);
}
else {
Py_RETURN_NONE;
}
}
PyDoc_STRVAR(bpy_bm_utils_face_flip_doc, PyDoc_STRVAR(bpy_bm_utils_face_flip_doc,
".. method:: face_flip(faces)\n" ".. method:: face_flip(faces)\n"
"\n" "\n"
@ -442,6 +504,44 @@ static PyObject *bpy_bm_utils_face_flip(PyObject *UNUSED(self), BPy_BMFace *valu
} }
PyDoc_STRVAR(bpy_bm_utils_loop_rip_doc,
".. method:: loop_rip(loop)\n"
"\n"
" Rip a vertex in a face away and add a new vertex.\n"
"\n"
" :arg loop: The to rip.\n"
" :type loop: :class:`BMFace`\n"
" :return vert: The newly created vertex or None of failure.\n"
" :rtype vert: :class:`BMVert`\n"
);
static PyObject *bpy_bm_utils_loop_rip(PyObject *UNUSED(self), BPy_BMLoop *value)
{
BMesh *bm;
BMVert *v_new;
if (!BPy_BMLoop_Check(value)) {
PyErr_Format(PyExc_TypeError,
"loop_rip(loop): BMLoop expected, not '%.200s'",
Py_TYPE(value)->tp_name);
return NULL;
}
BPY_BM_CHECK_OBJ(value);
bm = value->bm;
v_new = BM_face_loop_rip(bm, value->l);
if (v_new != value->l->v) {
return BPy_BMVert_CreatePyObject(bm, v_new);
}
else {
Py_RETURN_NONE;
}
}
static struct PyMethodDef BPy_BM_utils_methods[] = { static struct PyMethodDef BPy_BM_utils_methods[] = {
{"vert_collapse_edge", (PyCFunction)bpy_bm_utils_vert_collapse_edge, METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc}, {"vert_collapse_edge", (PyCFunction)bpy_bm_utils_vert_collapse_edge, METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
{"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc}, {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
@ -450,7 +550,9 @@ static struct PyMethodDef BPy_BM_utils_methods[] = {
{"edge_rotate", (PyCFunction)bpy_bm_utils_edge_rotate, METH_VARARGS, bpy_bm_utils_edge_rotate_doc}, {"edge_rotate", (PyCFunction)bpy_bm_utils_edge_rotate, METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
{"face_split", (PyCFunction)bpy_bm_utils_face_split, METH_VARARGS, bpy_bm_utils_face_split_doc}, {"face_split", (PyCFunction)bpy_bm_utils_face_split, METH_VARARGS, bpy_bm_utils_face_split_doc},
{"face_join", (PyCFunction)bpy_bm_utils_face_join, METH_O, bpy_bm_utils_face_join_doc}, {"face_join", (PyCFunction)bpy_bm_utils_face_join, METH_O, bpy_bm_utils_face_join_doc},
{"face_vert_rip", (PyCFunction)bpy_bm_utils_face_vert_rip, METH_VARARGS, bpy_bm_utils_face_vert_rip_doc},
{"face_flip", (PyCFunction)bpy_bm_utils_face_flip, METH_O, bpy_bm_utils_face_flip_doc}, {"face_flip", (PyCFunction)bpy_bm_utils_face_flip, METH_O, bpy_bm_utils_face_flip_doc},
{"loop_rip", (PyCFunction)bpy_bm_utils_loop_rip, METH_O, bpy_bm_utils_loop_rip_doc},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };