bmesh py api (some api changes and doc additions)
authorCampbell Barton <ideasman42@gmail.com>
Fri, 24 Feb 2012 05:56:06 +0000 (05:56 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 24 Feb 2012 05:56:06 +0000 (05:56 +0000)
* remove 'select' and 'hide' from BMLoop
* remove BMesh.update
* add BMesh.normal_update(skip_hidden=False)
* add BMElemSet.index_update(), eg: bm.verts.index_update()

bmesh api
* BM_mesh_normals_update() now takes skip_hidden as an argument
(previously this was default behavior), however this isnt good when
using BMesh modifiers, where you want all normals to be recalculated.
* add bm_iter_itype_htype_map[], to get the iter type from a BMesh
iterator.

13 files changed:
source/blender/bmesh/bmesh.h
source/blender/bmesh/bmesh_iterators.h
source/blender/bmesh/intern/bmesh_iterators.c
source/blender/bmesh/intern/bmesh_mesh.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/bmesh_selecthistory.c
source/blender/editors/mesh/bmesh_tools.c
source/blender/editors/mesh/bmesh_utils.c
source/blender/editors/space_view3d/view3d_snap.c
source/blender/modifiers/intern/MOD_bevel.c
source/blender/modifiers/intern/MOD_edgesplit.c
source/blender/python/bmesh/bmesh_py_types.c
source/blender/python/bmesh/bmesh_py_types.h

index 4535e7b8c581d7b3ca3b7150bcc3b2d63ca59363..dab70ac35bffc9af655735af223da62345bec964 100644 (file)
@@ -123,7 +123,7 @@ void   BM_mesh_free(BMesh *bm);
 
 /* frees mesh, but not actual BMesh struct */
 void BM_mesh_data_free(BMesh *bm);
-void BM_mesh_normals_update(BMesh *bm);
+void BM_mesh_normals_update(BMesh *bm, const short skip_hidden);
 
 /* Construction */
 BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example);
index 08da4f9a949eab59c7377ac4a8cc5eef4d61d00f..ccbed3ecd01fadf7ef7668557537eade3c67913d 100644 (file)
@@ -49,7 +49,9 @@
  */
 
 /* these iterator over all elements of a specific
- * type in the mesh.*/
+ * type in the mesh.
+ *
+ * be sure to keep 'bm_iter_itype_htype_map' in sync with any changes */
 typedef enum BMIterType {
        BM_VERTS_OF_MESH = 1,
        BM_EDGES_OF_MESH = 2,
@@ -74,6 +76,11 @@ typedef enum BMIterType {
        BM_LOOPS_OF_EDGE = 14
 } BMIterType;
 
+#define BM_ITYPE_MAX 15
+
+/* the iterator htype for each iterator */
+extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
+
 
 #define BM_ITER(ele, iter, bm, itype, data)                                   \
        ele = BM_iter_new(iter, bm, itype, data);                                 \
index 281f42300ff7525bbe0d2920f152907c68649a25..fb63ab36ef52496147634f0068749a026f003d49 100644 (file)
 #include "bmesh.h"
 #include "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, we have BM_vert_at_index/BM_edge_at_index/BM_face_at_index for arrays
  */
index a378ddaeabb03bce3f6605071d7e347a585a91bf..9621e593f3a62cf9e2c1af955d761f3128332899 100644 (file)
@@ -208,7 +208,7 @@ void BM_mesh_free(BMesh *bm)
  *
  */
 
-void BM_mesh_normals_update(BMesh *bm)
+void BM_mesh_normals_update(BMesh *bm, const short skip_hidden)
 {
        BMVert *v;
        BMFace *f;
@@ -225,7 +225,7 @@ void BM_mesh_normals_update(BMesh *bm)
 
        /* first, find out the largest face in mesh */
        BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
-               if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+               if (skip_hidden && BM_elem_flag_test(f, BM_ELEM_HIDDEN))
                        continue;
 
                if (f->len > maxlength) maxlength = f->len;
@@ -239,7 +239,7 @@ void BM_mesh_normals_update(BMesh *bm)
        
        /* calculate all face normals */
        BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
-               if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+               if (skip_hidden && BM_elem_flag_test(f, BM_ELEM_HIDDEN))
                        continue;
 #if 0  /* UNUSED */
                if (f->head.flag & BM_NONORMCALC)
@@ -251,7 +251,7 @@ void BM_mesh_normals_update(BMesh *bm)
        
        /* Zero out vertex normals */
        BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
-               if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+               if (skip_hidden && BM_elem_flag_test(v, BM_ELEM_HIDDEN))
                        continue;
 
                zero_v3(v->no);
@@ -280,7 +280,7 @@ void BM_mesh_normals_update(BMesh *bm)
        /* add weighted face normals to vertices */
        BM_ITER(f, &faces, bm, BM_FACES_OF_MESH, NULL) {
 
-               if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+               if (skip_hidden && BM_elem_flag_test(f, BM_ELEM_HIDDEN))
                        continue;
 
                BM_ITER(l, &loops, bm, BM_LOOPS_OF_FACE, f) {
@@ -310,7 +310,7 @@ void BM_mesh_normals_update(BMesh *bm)
        
        /* normalize the accumulated vertex normals */
        BM_ITER(v, &verts, bm, BM_VERTS_OF_MESH, NULL) {
-               if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+               if (skip_hidden && BM_elem_flag_test(v, BM_ELEM_HIDDEN))
                        continue;
 
                if (normalize_v3(v->no) == 0.0f) {
@@ -473,7 +473,7 @@ void bmesh_end_edit(BMesh *bm, int flag)
        bm->opflag = 0;
 
        /* compute normals, clear temp flags and flush selections */
-       BM_mesh_normals_update(bm);
+       BM_mesh_normals_update(bm, TRUE);
        BM_mesh_select_mode_flush(bm);
 }
 
index 2d4e267ba80140411793816d8fdc91e40c1d2aed..9ef4bc1cbd558c40cea91857431100229c495cdb 100644 (file)
@@ -157,7 +157,7 @@ void ED_view3d_global_to_vector(struct RegionView3D *rv3d, const float coord[3],
 
 /**
  * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivilent to RegionView3D.viewinv
+ * The resulting matrix is equivalent to RegionView3D.viewinv
  * @param mat The view 4x4 transformation matrix to calculate.
  * @param ofs The view offset, normally from RegionView3D.ofs.
  * @param quat The view rotation, quaternion normally from RegionView3D.viewquat.
index a242356f1abbf2f63d7438fbf0561e74bd6d71dd..ed3bd0c8a8770579f659dd0c9149c8076057ac9f 100644 (file)
@@ -30,7 +30,7 @@
 #include "BKE_tessmesh.h"
 
 
-/* these wrap equivilent bmesh functions.  I'm in two minds of it we should
+/* these wrap equivalent bmesh functions.  I'm in two minds of it we should
  * just use the bm functions directly; on the one hand, there's no real
  * need (at the moment) to wrap them, but on the other hand having these
  * wrapped avoids a confusing mess of mixing BM_ and EDBM_ namespaces. */
index 5225b704a7f5f3aa69ea03b182d3aa6c9cbb3fd4..972236ab411c748f3368be506ed242543428be3b 100644 (file)
@@ -3262,7 +3262,7 @@ static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmO
 
        EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS);
 
-       BM_mesh_normals_update(bmnew);
+       BM_mesh_normals_update(bmnew, TRUE);
        BMO_op_callf(bmnew, "bmesh_to_mesh mesh=%p object=%p notesselation=%b",
                     basenew->object->data, basenew->object, TRUE);
                
index 0f49ffa78e823e87eac6c78bba282f3716cee0bf..da1904cf11a5b3de89e83d1bdc8631c0c427621c 100644 (file)
@@ -50,7 +50,7 @@
 
 void EDBM_RecalcNormals(BMEditMesh *em)
 {
-       BM_mesh_normals_update(em->bm);
+       BM_mesh_normals_update(em->bm, TRUE);
 }
 
 void EDBM_ClearMesh(BMEditMesh *em)
index 978d32be48a1f48005d9ea0af01f7cdfe0c36775..c5e0572154a445752cc203516f9dacac75854c9e 100644 (file)
@@ -102,7 +102,7 @@ static void special_transvert_update(Object *obedit)
                
                if (obedit->type==OB_MESH) {
                        Mesh *me= obedit->data;
-                       BM_mesh_normals_update(me->edit_btmesh->bm);    // does face centers too
+                       BM_mesh_normals_update(me->edit_btmesh->bm, TRUE);      // does face centers too
                }
                else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
                        Curve *cu= obedit->data;
index 8aefd9288582c9217d90e008c094558ad61aa695..92584800f9853175da3f6427370239b84f73e353 100644 (file)
@@ -121,7 +121,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
        em = DM_to_editbmesh(ob, dm, NULL, FALSE);
        bm = em->bm;
 
-       BM_mesh_normals_update(bm);
+       BM_mesh_normals_update(bm, FALSE);
        BMO_push(bm, NULL);
 
        if (bmd->lim_flags & BME_BEVEL_ANGLE) {
index 14b54be8be1cf66685d03b0070e6e6e9c4271397..1e275862b5c072b302fe41d8f03181ee32f85e11 100644 (file)
@@ -69,7 +69,7 @@ static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Obj
        em = DM_to_editbmesh(ob, dm, NULL, FALSE);
        bm = em->bm;
 
-       BM_mesh_normals_update(bm);     
+       BM_mesh_normals_update(bm, FALSE);
        BMO_push(bm, NULL);
        
        if (emd->flags & MOD_EDGESPLIT_FROMANGLE) {
index 08097a2dc5746b25e4e685d23ad01297a57167c4..22eded1d11b0350c76bd285c0d437041bcc21314 100644 (file)
@@ -159,7 +159,7 @@ static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *UNUSED
                return -1;
        }
        else {
-               BM_elem_index_set(self->ele, param);
+               BM_elem_index_set(self->ele, param); /* set_dirty! */
 
                /* when setting the index assume its set invalid */
                if (self->ele->htype & (BM_VERT | BM_EDGE | BM_FACE)) {
@@ -474,8 +474,9 @@ static PyGetSetDef bpy_bmface_getseters[] = {
 
 static PyGetSetDef bpy_bmloop_getseters[] = {
     /* generic */
-    {(char *)"select", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_select_doc, (void *)BM_ELEM_SELECT},
-    {(char *)"hide",   (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_hide_doc,   (void *)BM_ELEM_SELECT},
+    // flags are available but not used for loops.
+    // {(char *)"select", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_select_doc, (void *)BM_ELEM_SELECT},
+    // {(char *)"hide",   (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_hide_doc,   (void *)BM_ELEM_SELECT},
     {(char *)"tag",    (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_tag_doc,    (void *)BM_ELEM_TAG},
     {(char *)"index",  (getter)bpy_bm_elem_index_get, (setter)bpy_bm_elem_index_set, (char *)bpy_bm_elem_index_doc,  NULL},
 
@@ -535,49 +536,27 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
        Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(bpy_bmesh_update_doc,
-".. method:: update(index=False, normals=False)\n"
+PyDoc_STRVAR(bpy_bmesh_normal_update_doc,
+".. method:: normal_update(skip_hidden=False)\n"
 "\n"
-"   Update mesh data.\n"
+"   Update mesh normals.\n"
 "\n"
-"   :arg normals: When True will re-calculate normals for verts and faces.\n"
-"   :type normals: boolean\n"
+"   :arg skip_hidden: When True hidden elements are ignored.\n"
+"   :type skip_hidden: boolean\n"
 
 );
-static PyObject *bpy_bmesh_update(BPy_BMElem *self, PyObject *args, PyObject *kw)
+static PyObject *bpy_bmesh_normal_update(BPy_BMElem *self, PyObject *args)
 {
-       static const char *kwlist[] = {"normals", "index", NULL};
 
-       int do_normals = FALSE;
-
-       PyObject *index_flags = NULL;
-       int do_index_hflag = 0;
+       int skip_hidden = FALSE;
 
        BPY_BM_CHECK_OBJ(self);
 
-       if (!PyArg_ParseTupleAndKeywords(args, kw,
-                                        "|iO:update",
-                                        (char **)kwlist,
-                                        &do_normals, &index_flags))
-       {
+       if (!PyArg_ParseTuple(args, "|i:normal_update", &skip_hidden)) {
                return NULL;
        }
 
-       if (index_flags) {
-               if (PyC_FlagSet_ToBitfield(bpy_bm_htype_vert_edge_face_flags, index_flags,
-                                          &do_index_hflag, "bm.update(index=...)") == -1)
-               {
-                       return NULL;
-               }
-       }
-
-       if (do_normals) {
-               BM_mesh_normals_update(self->bm);
-       }
-
-       if (do_index_hflag) {
-               BM_mesh_elem_index_ensure(self->bm, (char)do_index_hflag);
-       }
+       BM_mesh_normals_update(self->bm, skip_hidden);
 
        Py_RETURN_NONE;
 }
@@ -589,7 +568,7 @@ PyDoc_STRVAR(bpy_bmesh_transform_doc,
 "   Transform the mesh (optionally filtering flagged data only).\n"
 "\n"
 "   :arg matrix: transform matrix.\n"
-"   :type matrix: 4x4 :class:`mathutils.Matrix`"
+"   :type matrix: 4x4 :class:`mathutils.Matrix`\n"
 "   :arg filter: set of values in ('SELECT', 'HIDE', 'SEAM', 'SMOOTH', 'TAG').\n"
 "   :type filter: set\n"
 );
@@ -1195,7 +1174,7 @@ static PyObject *bpy_bmface_seq_remove(BPy_BMElemSeq *self, BPy_BMFace *value)
 
 
 PyDoc_STRVAR(bpy_bmelemseq_remove_doc,
-".. method:: remove()\n"
+".. method:: remove(elem)\n"
 "\n"
 "   Remove a vert/edge/face.\n"
 );
@@ -1215,10 +1194,69 @@ static PyObject *bpy_bmelemseq_remove(BPy_BMElemSeq *self, PyObject *value)
        }
 }
 
+PyDoc_STRVAR(bpy_bmelemseq_index_update_doc,
+".. method:: index_update()\n"
+"\n"
+"   Initialize the index values of this sequence.\n"
+"\n"
+"   This is the equivalent of looping over all elements and assigning the index values.\n"
+"\n"
+"   .. code-block:: python\n"
+"\n"
+"      for index, ele in enumerate(sequence):\n"
+"          ele.index = index\n"
+"\n"
+"   .. note::\n"
+"\n"
+"      Running this on sequences besides :class:`BMesh.verts`, :class:`BMesh.edges`, :class:`BMesh.faces`\n"
+"      works but wont result in each element having a valid index, insted its order in the sequence will be set.\n"
+);
+static PyObject *bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
+{
+       BMesh *bm = self->bm;
+
+       BPY_BM_CHECK_OBJ(self);
+
+       switch ((BMIterType)self->itype) {
+               case BM_VERTS_OF_MESH:
+                       BM_mesh_elem_index_ensure(self->bm, BM_VERT);
+                       break;
+               case BM_EDGES_OF_MESH:
+                       BM_mesh_elem_index_ensure(self->bm, BM_EDGE);
+                       break;
+               case BM_FACES_OF_MESH:
+                       BM_mesh_elem_index_ensure(self->bm, BM_FACE);
+                       break;
+               default:
+               {
+                       BMIter iter;
+                       BMHeader *ele;
+                       int index = 0;
+                       const char htype = bm_iter_itype_htype_map[self->itype];
+
+                       BM_ITER_BPY_BM_SEQ(ele, &iter, self) {
+                               BM_elem_index_set(ele, index); /* set_dirty! */
+                               index++;
+                       }
+
+                       if (htype & (BM_VERT | BM_EDGE | BM_FACE)) {
+                               /* since this isnt the normal vert/edge/face loops,
+                                * we're setting dirty values here. so tag as dirty. */
+                               bm->elem_index_dirty |= htype;
+                       }
+
+                       break;
+               }
+       }
+
+       Py_RETURN_NONE;
+}
+
+
 static struct PyMethodDef bpy_bmesh_methods[] = {
     {"select_flush_mode", (PyCFunction)bpy_bmesh_select_flush_mode, METH_NOARGS, bpy_bmesh_select_flush_mode_doc},
     {"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc},
-    {"update", (PyCFunction)bpy_bmesh_update, METH_VARARGS|METH_KEYWORDS, bpy_bmesh_update_doc},
+    {"normal_update", (PyCFunction)bpy_bmesh_normal_update, METH_VARARGS, bpy_bmesh_normal_update_doc},
     {"transform", (PyCFunction)bpy_bmesh_transform, METH_VARARGS|METH_KEYWORDS, bpy_bmesh_transform_doc},
     {NULL, NULL, 0, NULL}
 };
@@ -1263,17 +1301,15 @@ static struct PyMethodDef bpy_bmloop_methods[] = {
 static struct PyMethodDef bpy_bmelemseq_methods[] = {
     {"new", (PyCFunction)bpy_bmelemseq_new, METH_VARARGS, bpy_bmelemseq_new_doc},
     {"remove", (PyCFunction)bpy_bmelemseq_remove, METH_O, bpy_bmelemseq_remove_doc},
+
+    /* odd function, initializes index values */
+    {"index_update", (PyCFunction)bpy_bmelemseq_index_update, METH_NOARGS, bpy_bmelemseq_index_update_doc},
     {NULL, NULL, 0, NULL}
 };
 
 /* Sequences
  * ========= */
 
-#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq) \
-       BM_ITER(ele, iter, (bpy_bmelemseq)->bm, (bpy_bmelemseq)->itype,\
-       (bpy_bmelemseq)->py_ele ? ((BPy_BMElem *)(bpy_bmelemseq)->py_ele)->ele : NULL)
-
-
 static PyTypeObject *bpy_bm_itype_as_pytype(const char itype)
 {
        /* should cover all types */
index 67a276f3f809fc9e0ebbc2b15cb84e2ec23d2065..05a36ee9897e8645110a63af2e62ea698caaa1e0 100644 (file)
@@ -140,4 +140,8 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
 #define BPY_BM_CHECK_OBJ(obj) if (bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1) { return NULL; } (void)NULL
 #define BPY_BM_CHECK_INT(obj) if (bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1) { return -1; }   (void)NULL
 
+#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq) \
+       BM_ITER(ele, iter, (bpy_bmelemseq)->bm, (bpy_bmelemseq)->itype,\
+       (bpy_bmelemseq)->py_ele ? ((BPy_BMElem *)(bpy_bmelemseq)->py_ele)->ele : NULL)
+
 #endif /* __BMESH_TYPES_H__ */