4
$\begingroup$

I get geometry from bisecting some mesh bm_tmp by a plane and I want to copy/append the resulting geometry r['geom_cut'] (only the edges and vertices of bisection) to another bmesh bm. I solved it by the following snippet, but I was wondering if there is a better and more efficient way to copy geometry to another bmesh

import bpy
import bmesh

bm_tmp = bmesh.new()
bmesh.ops.create_monkey(bm_tmp)

geom = bm_tmp.verts[:] + bm_tmp.edges[:] + bm_tmp.faces[:]
r = bmesh.ops.bisect_plane(bm_tmp, geom=geom, 
    plane_co=(0, 0, 0), plane_no=(0, 0, 1))

# Get all the vertices and edges
verts = [v for v in r['geom_cut'] if isinstance(v, bmesh.types.BMVert)]
edges = [e for e in r['geom_cut'] if isinstance(e, bmesh.types.BMEdge)]

# Copy geometry
bm = bmesh.new()
vertmap = {}
for v in verts:
    new_vert = bm.verts.new(v.co)
    vertmap[v.index] = new_vert

for e in edges:
    idx0, idx1 = e.verts[0].index, e.verts[1].index
    bm.edges.new([vertmap[idx0], vertmap[idx1]])

I tried bmesh.ops.duplicate(bm_tmp, geom=r['geom_cut'], dest=bm) but it is not implemented yet: NotImplementedError: duplicate: keyword "dest" type 4 not working yet! for Blender 2.79.

$\endgroup$
1

2 Answers 2

4
$\begingroup$

Your bmesh is just a python representation of the mesh thats in your scene. As long as you don't write your bmesh back into the mesh-datablock (bm.to_mesh(me)), you can use it for anything you want to do with it.

This means you can create a new mesh datablock and then use

bm.to_mesh(new_mesh)

since it's just a python object, you can copy it with a python copy method:

bm2 = bm.copy()

Which will give you a fully editable bmesh that is disconnected from your first bmesh. So you don't have to copy every vert & edge manually.

edit: this is how you seperate the mesh into two halfs that were split. You can then write it back into the edit mesh and separate the loose parts which will give you two objects. Because with your current code you get vertices and edges that define where your mesh is being cut, and not the actual geometry. -> your result:

enter image description here

My code example:

import bpy
import bmesh

bm_tmp = bmesh.new()
bmesh.ops.create_monkey(bm_tmp)

geom = bm_tmp.verts[:] + bm_tmp.edges[:] + bm_tmp.faces[:]
r = bmesh.ops.bisect_plane(bm_tmp, geom=geom, 
    plane_co=(0, 0, 0), plane_no=(0, 0, 1))

bmesh.ops.split_edges(bm_tmp, edges=[e for e in r['geom_cut'] if isinstance(e, bmesh.types.BMEdge)])

bm_tmp.to_mesh(bpy.context.selected_objects[0].data)
bpy.ops.mesh.separate(type='LOOSE')

Visual result from this code: enter image description here

Edit 2: in that case, that you want to slice it multiple times - instead of writing it to a new bmesh after each bisect, do this:

bmesh.ops.split_edges(bm_tmp, edges=[e for e in r['geom_cut'] if isinstance(e, bmesh.types.BMEdge)])

to apply the bisection to your bmesh and actually separating it by parts. In the end you can write it to a actual mesh. Only then i would combine it with your other bmesh. You can't simply add two bmesh together. so i'd suggest combining them like this, because it is the simplest way:

bm = bmesh.new()

bm.from_mesh( m1 ) # Add mesh 1 to bmesh
bm.from_mesh( m2 ) # Add mesh 2 to bmesh
$\endgroup$
4
  • $\begingroup$ Thank you for the tip with bm.copy(). I'm sorry I was not clear enough with the question, I did mean the edges and vertices of the bisection which I want to copy/append to another bmesh. Is there an efficient way to do this, or is it better to remove the geometry that I don't need? $\endgroup$ Sep 21, 2017 at 8:41
  • $\begingroup$ i don't see a use case of transferring a bisection to another bmesh, unless it's a copy of the exact same one. Why not just bisect again. Maybe you need to tell me more about what you want to to with this $\endgroup$ Sep 21, 2017 at 9:04
  • $\begingroup$ My goal is to have a function for an input bmesh which I slice multiple times and then add the sliced geometry to another existing bmesh. But this problem would also apply for the use case of adding a list of faces, edges or vertices from one bmesh to another bmesh. $\endgroup$ Sep 21, 2017 at 10:00
  • $\begingroup$ in that case, i would slice your bmesh multiple times and between each slice use bmesh.ops.split_edges(bm_tmp, edges=[e for e in r['geom_cut'] if isinstance(e, bmesh.types.BMEdge)]) to apply the slice and actually seperate your bmesh. instead of writing it to a new bmesh every time. In the end you can write it to a actual mesh. Only then i would combine it with your other bmesh. You can't simply add two bmesh together, so i'd suggest combining them like this (see edit 2 of my answer) $\endgroup$ Sep 21, 2017 at 11:00
1
$\begingroup$

to apply it to the active object (not necessarily a suzane):

import bpy
import bmesh

obj = bpy.context.object
me=obj.data
bm_tmp = bmesh.new()
bm_tmp.from_mesh(me)

geom = bm_tmp.verts[:] + bm_tmp.edges[:] + bm_tmp.faces[:]
r = bmesh.ops.bisect_plane(bm_tmp, geom=geom, 
    plane_co=(0, 0, 0), plane_no=(0, 0, 1))

bmesh.ops.split_edges(bm_tmp, edges=[e for e in r['geom_cut'] if isinstance(e, bmesh.types.BMEdge)])

bm_tmp.to_mesh(me)
bpy.ops.mesh.separate(type='LOOSE')
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .