diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 60ebb99ce05..2284e183d97 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -762,6 +762,19 @@ int BM_edge_is_manifold(BMEdge *e) } #endif +/** + * Tests that the edge is manifold and + * that both its faces point the same way. + */ +bool BM_edge_is_contiguous(BMEdge *e) +{ + const BMLoop *l = e->l; + const BMLoop *l_other = l->radial_next; + return (l && (l_other != l) && /* not 0 or 1 face users */ + (l_other->radial_next == l) && /* 2 face users */ + (l_other->v != l->v)); +} + /** * Tests whether or not an edge is on the boundary * of a shell (has one face associated with it) diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index b285c531bb5..7cb5749a4bf 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -61,6 +61,7 @@ bool BM_edge_is_wire(BMEdge *e); bool BM_vert_is_manifold(BMVert *v); bool BM_edge_is_manifold(BMEdge *e); bool BM_edge_is_boundary(BMEdge *e); +bool BM_edge_is_contiguous(BMEdge *e); bool BM_loop_is_convex(BMLoop *l); diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 202d1964bd6..a573c4ae75f 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -412,6 +412,14 @@ static PyObject *bpy_bmedge_is_manifold_get(BPy_BMEdge *self) return PyBool_FromLong(BM_edge_is_manifold(self->e)); } +PyDoc_STRVAR(bpy_bmedge_is_contiguous_doc, +"True when this edge is manifold, between two faces with the same winding (read-only).\n\n:type: boolean" +); +static PyObject *bpy_bmedge_is_contiguous_get(BPy_BMEdge *self) +{ + BPY_BM_CHECK_OBJ(self); + return PyBool_FromLong(BM_edge_is_contiguous(self->e)); +} PyDoc_STRVAR(bpy_bmedge_is_wire_doc, "True when this edge is not connected to any faces (read-only).\n\n:type: boolean" @@ -678,10 +686,11 @@ static PyGetSetDef bpy_bmedge_getseters[] = { {(char *)"link_loops", (getter)bpy_bmelemseq_elem_get, (setter)NULL, (char *)bpy_bmedge_link_loops_doc, (void *)BM_LOOPS_OF_EDGE}, /* readonly checks */ - {(char *)"is_manifold", (getter)bpy_bmedge_is_manifold_get, (setter)NULL, (char *)bpy_bmedge_is_manifold_doc, NULL}, - {(char *)"is_wire", (getter)bpy_bmedge_is_wire_get, (setter)NULL, (char *)bpy_bmedge_is_wire_doc, NULL}, + {(char *)"is_manifold", (getter)bpy_bmedge_is_manifold_get, (setter)NULL, (char *)bpy_bmedge_is_manifold_doc, NULL}, + {(char *)"is_contiguous", (getter)bpy_bmedge_is_contiguous_get, (setter)NULL, (char *)bpy_bmedge_is_contiguous_doc, NULL}, + {(char *)"is_wire", (getter)bpy_bmedge_is_wire_get, (setter)NULL, (char *)bpy_bmedge_is_wire_doc, NULL}, {(char *)"is_boundary", (getter)bpy_bmedge_is_boundary_get, (setter)NULL, (char *)bpy_bmedge_is_boundary_doc, NULL}, - {(char *)"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, (char *)bpy_bm_is_valid_doc, NULL}, + {(char *)"is_valid", (getter)bpy_bm_is_valid_get, (setter)NULL, (char *)bpy_bm_is_valid_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ };