12
$\begingroup$

If I select a face of a cube and switch over to the internal Python console and pass:

bpy.context.selected_objects

I get:

[bpy.data.objects['Cube']]

instead of something like [bpy.data.objects['Cube'].f[1]].

Coming from Maya I was looking for something like:

import pymel.core as pc

print pc.ls(sl=True)

which in the above case would return the face id.

Same thing applies for vertices and edges.

How can I go about getting a detailed selection list programmatically?

| improve this question | | | | |
$\endgroup$
6
$\begingroup$

You may be interested into bmesh module's select_history

import bpy
import bmesh

me = bpy.context.object.data

bm = bmesh.from_edit_mesh(me)

for elem in bm.select_history:
    print(repr(elem))

# Variant 1 - get the active edge
try:
    active_edge = filter(lambda elem: isinstance(elem, bmesh.types.BMEdge), 
        reversed(bm.select_history)).__next__()
except StopIteration:
    active_edge = None


# Variant 2 - same, but less geeky ;)

for elem in reversed(bm.select_history):
    if isinstance(elem, bmesh.types.BMEdge):
        active_edge = elem
        break
else:
    active_edge = None


# Get selected faces in order

for elem in bm.select_history:
    if isinstance(elem, bmesh.types.BMFace):
        print(repr(elem))


# Get all selected faces
# Note: bm.select_history lacks geometry selected via border select, lasso, etc.
#       (mass-selection operators)!

for face in bm.faces:
    if face.select:
        print(repr(face))
| improve this answer | | | | |
$\endgroup$
4
$\begingroup$

PyMEL's ls seems to roll several related functions into one (match by type, name, regexp-pattern, etc.). There's no such function built in to Blender's Python API, so you must create selection list manually.

You have to know what element you need to process. If it's a list of MeshVertex, MeshEdge or MeshPolygon, filter out objects whose type isn't "MESH". It's also possible that edit-mode and object-mode data isn't synced, which will happen if the script is run when the object is in edit-mode (presumably while the user's selecting elements). To make the correct selection list regardless of the object's state, run update_from_editmode beforehand. Then you can create the list:

import bpy

obj = bpy.context.object
mesh = obj.data # Assumed that obj.type == 'MESH'
obj.update_from_editmode() # Loads edit-mode data into object data

selected_polygons = [p for p in mesh.polygons if p.select]
selected_edges = [e for e in mesh.vertices if e.select]
selected_vertices = [v for v in mesh.vertices if v.select]

# ... process selection list...

This also applies to the newer mesh editing API bmesh and also other object types (check the API doc's index if the element needed has a select* attribute), though can be a bit more involving for some types. For example, a curve object can contain more than one spline, so iteration over each splines must be chained in some way to reach all BezierSplinePoint:

import bpy
from itertools import chain

obj = bpy.context.object
curve = obj.data # Assumed that obj.type == 'CURVE'
obj.update_from_editmode() # Loads edit-mode data into object data

selected_cpoints = [p for p in chain(*[s.bezier_points for s in curve.splines])
                    if p.select_control_point]

# ... process selection list...
| improve this answer | | | | |
$\endgroup$
3
$\begingroup$

In blender there is a difference between an object and elements such as faces, edges, and vertices.

I don't know if a collection of selected elements is stored anywhere, but you can iterate through every face and check if it's selected via polygon.select:

import bpy

ob = bpy.data.objects['Cube']

for poly in ob.data.polygons:
    if poly.select == True:
        # Do stuff

Note that you must be in object mode for this to work.

| improve this answer | | | | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.