4

Suppose I want to select the entire mesh boundary. Alt + RMB on a boundary edge would select one edge loop (left image), while Alt + double RMB yields the desired result (right image).

edge loop select

How would I achieve this result by scripting? Assume the user first selects one boundary edge manually. I reckon it is buried somewhere in this function:

bpy.ops.mesh.loop_select(extend=False, deselect=False, toggle=False, ring=False)

But I can't quite understand how to use this function. Examples on how to do this would be very much welcome.

Niels
  • 324
  • 1
  • 8

1 Answers1

6

Bmesh script.

With a single boundary edge selected in edit mode, the LHS of question images can be achieved calling bpy.ops.mesh.loop_multi_select() directly from the python console.

>>> bpy.ops.mesh.loop_multi_select(
loop_multi_select()
bpy.ops.mesh.loop_multi_select(ring=False)
Select a loop of connected edges by connection type
>>> bpy.ops.mesh.loop_multi_select()
{'FINISHED'}

enter image description here

The mesh.loop_select operator is a different kettle of fish and requires context override if called from outside the 3D view.

This is a matter of giving the context override dictionary a 3d view "area", "space_data" and "region"

However even then, with all combos of options it still did not perform as did the alt double click on my test mesh.

Use bmesh.

IMO edit mode mesh operators can become mind-numbingly annoying to code when they cannot be "made to perform" as desired

Touched on some other reasons to avoid operators Element indices messed up after switching from Edit to Object Mode

Can instead create our own methods

The boundary select function below takes an edge, tags it, looks at all untagged boundary edges linked to its two end verts, tags them and so on until it can go no further, then returns the edges.

Test script, run in edit mode with a single boundary edge selected.

import bpy
import bmesh
from collections import defaultdict

context = bpy.context

ob = context.edit_object me = ob.data

bm = bmesh.from_edit_mesh(me)

edge = bm.select_history.active

assert isinstance(edge, bmesh.types.BMEdge), "Select an Edge"

def boundary_select(edge): tag = defaultdict(bool) tag[edge] = True grow = True edges = [edge] while grow: more = [ el for es in edges for v in es.verts for el in v.link_edges if not tag[el] and el.is_boundary ] edges.extend(more) for e in more: tag[e] = True grow = bool(more) return edges

for e in boundary_select(edge): e.select_set(True) bmesh.update_edit_mesh(me)

Persistence of element tag and select using bound bmesh

How to detect disconnected parts within a selection?

p2or
  • 15,860
  • 10
  • 83
  • 143
batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Alright this has answered my question. Hoped it would be easier to use the bpy operator instead of recreating the method. Does context override have disadvantages? When would you use override instead of creating your own method? – Niels Mar 01 '21 at 09:01
  • Chances are can use the operator, couldn't crack it, but am slowly learning not to bother if can do it with bmesh. (in less time). Re overriding context, would make a good question (may be one IIRC) I am of the view that if you make a method like above, it takes context out of equation. All that matters is a valid bmesh. (btw have another similar answer re this somewhere that orders edges --> slice n feed into bmesh grid fill for instance) Possibly most important is what you wish to achieve via scripting. Covered some of this in prior answers to your questions. Started coding blender – batFINGER Mar 01 '21 at 09:39
  • in 2.49, then 2.5 brought in bpy with no bmesh. Used to write all mesh manipulation either via ops or manipulating mesh data. Had no idea how to use bmesh for a long while, after it arrived, and was all the rage. (similarly with cycles and material nodes lol) . When it twigs, its nigh on impossible to look back . .. tho, to reiterate, depends on your use case. – batFINGER Mar 01 '21 at 09:51