Crash when passing geom and context to bmesh.ops.delete when all is selected #50920

Closed
opened 2017-03-11 10:07:05 +01:00 by Shane Ambler · 10 comments

This started from a question at [BSE ]]. The example file can be found [ https:*drive.google.com/open?id=0B9DFPZBPKp6AdERZTmJWeGE0RFE | here (google drive 500k)

The file contains a single mesh object made of two cubes and a plane and has the following script -


mesh = bpy.context.edit_object.data
bm = bmesh.from_edit_mesh(mesh)

delete_first = []
for f in bm.faces:

if f.calc_center_bounds().y < 0:
delete_first.append(f)


bmesh.ops.delete(bm, geom=delete_first, context=5)
# Note: if the above line is commented out, there is no error.

- bmesh.update_edit_mesh(mesh, True)
- bpy.ops.object.editmode_toggle()
- bpy.ops.object.editmode_toggle()
- bm = bmesh.from_edit_mesh(mesh)

geom = [e for e in bm.verts- [x]+bm.edges- [x]+bm.faces- [x] if e.select]

for i in range(10):

vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces)
ret = bmesh.ops.bisect_plane(bm, geom=geom, plane_co=(0,i,0), plane_no=(0,1,0))
geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:]

    - Note: ret["geom"] unfortunately does not provide all the geometry I need for the next cut, so I have to collect the new geometry this way.
    - Note: Also it is required that ONLY the selected geometry is cut, nothing else.

bmesh.update_edit_mesh(mesh)

The script expects to start with the object in edit mode and the sample file has all mesh components selected. When the script is run the error ValueError: geom: found the same (BMVert/BMEdge/BMFace) used multiple times is given and then when the 3d view is updated blender crashes.

The problem comes from the call to bmesh.ops.delete and would appear to be caused by both geom and context parameters being passed, while all components are selected.

If context is removed or changed (values of 1,2 and 4 works) or if everything is deselected before running the script there is no problem. I think the enum for the context value should be defined in python and to me it looks like it should match the enum in https://developer.blender.org/diffusion/B/browse/master/source/blender/bmesh/intern/bmesh_operator_api.h;f667593b6a1325c62a89a6ae1ae4718833dca4d0$340 .

Also having only the listed items selected works, so you can also change the first loop to -

for f in bm.faces:
    f.select = False
    if f.calc_center_bounds().y < 0:
        delete_first.append(f)
        f.select = True

Related to this - the python docs for bmesh.ops.delete could be improved. Some clarification for the context and/or geom parameter could be added, is context meant to delete selected items or does it have to match (or subset of) the type of items in the geom list?

This started from a question at [BSE ]]. The example file can be found [[ https:*drive.google.com/open?id=0B9DFPZBPKp6AdERZTmJWeGE0RFE | here ](http:*blender.stackexchange.com/q/75335/935) (google drive 500k) The file contains a single mesh object made of two cubes and a plane and has the following script - ```import bpy, bmesh mesh = bpy.context.edit_object.data bm = bmesh.from_edit_mesh(mesh) delete_first = [] for f in bm.faces: ``` if f.calc_center_bounds().y < 0: delete_first.append(f) ``` bmesh.ops.delete(bm, geom=delete_first, context=5) # Note: if the above line is commented out, there is no error. - bmesh.update_edit_mesh(mesh, True) - bpy.ops.object.editmode_toggle() - bpy.ops.object.editmode_toggle() - bm = bmesh.from_edit_mesh(mesh) geom = [e for e in bm.verts- [x]+bm.edges- [x]+bm.faces- [x] if e.select] for i in range(10): ``` vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces) ret = bmesh.ops.bisect_plane(bm, geom=geom, plane_co=(0,i,0), plane_no=(0,1,0)) geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:] ``` - Note: ret["geom"] unfortunately does not provide all the geometry I need for the next cut, so I have to collect the new geometry this way. - Note: Also it is required that ONLY the selected geometry is cut, nothing else. bmesh.update_edit_mesh(mesh) ``` The script expects to start with the object in edit mode and the sample file has all mesh components selected. When the script is run the error `ValueError: geom: found the same (BMVert/BMEdge/BMFace) used multiple times` is given and then when the 3d view is updated blender crashes. The problem comes from the call to `bmesh.ops.delete` and would appear to be caused by both `geom` and `context` parameters being passed, while all components are selected. If context is removed or changed (values of 1,2 and 4 works) or if everything is deselected before running the script there is no problem. I think the enum for the context value should be defined in python and to me it looks like it should match the enum in [[ https://developer.blender.org/diffusion/B/browse/master/source/blender/bmesh/intern/bmesh_operator_api.h;f667593b6a1325c62a89a6ae1ae4718833dca4d0$340 | bmesh_operator_api.h ]]. Also having only the listed items selected works, so you can also change the first loop to - ```delete_first = [] for f in bm.faces: f.select = False if f.calc_center_bounds().y < 0: delete_first.append(f) f.select = True ``` Related to this - the python docs for `bmesh.ops.delete` could be improved. Some clarification for the context and/or geom parameter could be added, is context meant to delete selected items or does it have to match (or subset of) the type of items in the geom list?
Author

Changed status to: 'Open'

Changed status to: 'Open'
Author

Added subscriber: @sambler

Added subscriber: @sambler

Added subscriber: @mano-wii

Added subscriber: @mano-wii

Changed status from 'Open' to: 'Archived'

Changed status from 'Open' to: 'Archived'
Germano Cavalcante self-assigned this 2017-03-12 00:50:21 +01:00

Actually the crash occurs because the execution of the script is being interrupted before the bmesh.update_edit_mesh(mesh).

Remember that the new elements created are not necessarily at the end of the array. So your code is actually repeating elements in the list.

Unfortunately the return of the bmesh.ops.bisect_plane does not inform the new index of the cut edges :
This return is a matter for discussion... In another report.

Actually the crash occurs because the execution of the script is being interrupted before the `bmesh.update_edit_mesh(mesh)`. Remember that the new elements created are not necessarily at the end of the array. So your code is actually repeating elements in the list. Unfortunately the return of the `bmesh.ops.bisect_plane` does not inform the new index of the cut edges :\ This return is a matter for discussion... In another report.

Added subscriber: @hedgehog90-3

Added subscriber: @hedgehog90-3

I posted the question on BSE.

I've seen the editmode_toggle trick used in other addons as a flush to ensure everything is as it seems. But without it, it seems bmesh.ops.bisect_plane is filling gaps in bm.verts/edges/faces that resulted from the deletion op.
Thus:

vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces)
op()
geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:]

Will catch some repeated elements due to the initial deletion making Swiss cheese of my geometry.

Shouldn't there be an additional op that ensures that new geometry is appended?
(along with documentation and something in the Gotchas section)

Surely it's just a matter of removing secret gaps in the BMElemSeqs and updating indices.

Unless I'm terribly mistaken, could someone explain why this wouldn't be a welcome addition to the bmesh module?

I posted the question on BSE. I've seen the editmode_toggle trick used in other addons as a flush to ensure everything is as it seems. But without it, it seems bmesh.ops.bisect_plane is filling gaps in bm.verts/edges/faces that resulted from the deletion op. Thus: ``` vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces) op() geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:] ``` Will catch some repeated elements due to the initial deletion making Swiss cheese of my geometry. Shouldn't there be an additional op that ensures that new geometry is appended? (along with documentation and something in the Gotchas section) Surely it's just a matter of removing *secret* gaps in the BMElemSeqs and updating indices. Unless I'm terribly mistaken, could someone explain why this wouldn't be a welcome addition to the bmesh module?

In #50920#422339, @hedgehog90-3 wrote:
Thus:

vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces)
op()
geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:]

This takes repetitive elements because the new elements are added in the middle of the list (not at the end).

Unfortunately the return of the bmesh.ops.bisect_plane operator is currently limited. So to get around this limitation in python is necessary to make a hack that unfortunately makes your code less efficient :\

Here is the hack:

import bpy, bmesh

mesh = bpy.context.edit_object.data
bm = bmesh.from_edit_mesh(mesh)

delete_first = []
for f in bm.faces:
    if f.calc_center_bounds().y < 0:
        delete_first.append(f)

bmesh.ops.delete(bm, geom=delete_first, context=5)

geom = [e for e in bm.verts[:]+bm.edges[:]+bm.faces[:] if e.select]

edges = set(bm.edges)

for i in range(10):
    ret = bmesh.ops.bisect_plane(bm, geom=geom, plane_co=(0,i,0), plane_no=(0,1,0))
    
    if ret["geom_cut"]: # Had cut
        geom = ret["geom"]
        new_edges = edges.symmetric_difference(bm.edges)
        edges.update(new_edges)
        geom.extend(e for e in new_edges if e not in ret["geom_cut"])

bmesh.update_edit_mesh(mesh)
> In #50920#422339, @hedgehog90-3 wrote: > Thus: > ``` > vn, en, fn = len(bm.verts), len(bm.edges), len(bm.faces) > op() > geom += bm.verts[vn:] + bm.edges[en:] + bm.faces[fn:] > ``` This takes repetitive elements because the new elements are added in the middle of the list (not at the end). Unfortunately the return of the `bmesh.ops.bisect_plane` operator is currently limited. So to get around this limitation in python is necessary to make a hack that unfortunately makes your code less efficient :\ Here is the hack: ``` import bpy, bmesh mesh = bpy.context.edit_object.data bm = bmesh.from_edit_mesh(mesh) delete_first = [] for f in bm.faces: if f.calc_center_bounds().y < 0: delete_first.append(f) bmesh.ops.delete(bm, geom=delete_first, context=5) geom = [e for e in bm.verts[:]+bm.edges[:]+bm.faces[:] if e.select] edges = set(bm.edges) for i in range(10): ret = bmesh.ops.bisect_plane(bm, geom=geom, plane_co=(0,i,0), plane_no=(0,1,0)) if ret["geom_cut"]: # Had cut geom = ret["geom"] new_edges = edges.symmetric_difference(bm.edges) edges.update(new_edges) geom.extend(e for e in new_edges if e not in ret["geom_cut"]) bmesh.update_edit_mesh(mesh) ```

This issue was referenced by blender/blender@2b3cc24388

This issue was referenced by blender/blender@2b3cc24388202d222e2f342badef6879bc2c6432

Changed status from 'Archived' to: 'Resolved'

Changed status from 'Archived' to: 'Resolved'
Sign in to join this conversation.
No Milestone
No project
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#50920
No description provided.