List of selected faces after shortest_path_select()

How can i retrieve the list of selected verts/edges/faces after selecting the shortest_path_select() ?

I can see in the viewport that the correct faces are being selected, but from code i cannot see them selected, neither from the bmesh neither from the mesh itself.

As you can see in the image, after the call to bpy.ops.mesh.shortest_path_select() i see the faces selected in the viewport, but from code only the face 655 of the mesh results selected.

After calling the function i DO call bmesh.update_edit_mesh(me) but still it seems not to work as wanted.

Here a snippet of code driving this example

bpy.ops.mesh.shortest_path_select()

                bmesh.update_edit_mesh(me)

                self.report({"INFO"}, f"me 655: {me.polygons[655].select}")
                self.report({"INFO"}, f"me 380: {me.polygons[380].select}")
                self.report({"INFO"}, f"me 372: {me.polygons[372].select}")
                self.report({"INFO"}, f"me 947: {me.polygons[947].select}")
                self.report({"INFO"}, f"me 2200: {me.polygons[2200].select}")
                self.report({"INFO"}, f"")

                self.report({"INFO"}, f"bm 655: {bm.faces[655].select}")
                self.report({"INFO"}, f"bm 380: {bm.faces[380].select}")
                self.report({"INFO"}, f"bm 372: {bm.faces[372].select}")
                self.report({"INFO"}, f"bm 947: {bm.faces[947].select}")
                self.report({"INFO"}, f"bm 2200: {bm.faces[2200].select}")
                self.report({"INFO"}, f"")

I don’t know how to get the list of selected faces after the shortest path calculation. Any hep?

the most straightforward way to determine this would be to create two sets and then get the difference between them.

before_selection = {v for v in bm.verts if v.select}
bpy.ops.mesh.shortest_path_select()
after_selection = {v for v in bm.verts if v.select}

shortest_path_verts = after_selection.difference(before_selection)

it’s worth pointing out that this will not give you the path that was selected in the sense that it is sequential, it’s just going to be a chunk of verts in whatever order Blender decided to return them in. If you need a shortest path that is actually in sequential order you’d be better off writing your own pathfinding algorithm, which by the way is not as hard as it sounds. With a python Queue object you can write an A* function in about 20 lines of code.

I dont get how to use this function.

This is the class i am using to test right now.

class MESH_OT_path_test(bpy.types.Operator):
    """test shortest path"""
    bl_idname = "mesh.path_test"
    bl_label = "path_test"
    bl_options = {'REGISTER'}

    @classmethod
    def poll(cls, context):
        active_object = context.active_object
        return active_object is not None and active_object.type == 'MESH' or active_object.select_get() and context.area.type == "VIEW_3D"

    def execute(self, context):

        # Get the active mesh
        me = context.object.data

        # Get a BMesh representation
        bm = bmesh.new()   # create an empty BMesh
        bm.from_mesh(me)   # fill it in from a Mesh

        # Modify the BMesh, can do anything here...
        if hasattr(bm.verts, "ensure_lookup_table"):
            bm.verts.ensure_lookup_table()
            bm.edges.ensure_lookup_table()
            bm.faces.ensure_lookup_table()

        bpy.ops.object.mode_set(mode="EDIT")
        bpy.ops.mesh.select_all(action='DESELECT')
        bpy.ops.object.mode_set(mode="EDIT")

        bm.faces[655].select = True
        bm.faces[5071].select = True

        before_selection = {f for f in bm.faces if f.select}

        bpy.ops.mesh.shortest_path_select()

        after_selection = {f for f in bm.faces if f.select}

        shortest_path_faces = after_selection.difference(before_selection)

        self.report({"INFO"}, f"len bef {len(before_selection)}")
        self.report({"INFO"}, f"len aft {len(after_selection)}")
        self.report({"INFO"}, f"spf {len(shortest_path_faces)}")

        for f in shortest_path_faces:
            bm.faces[f.index].select = True
            me.polygons[f.index].select = True

        bpy.ops.object.mode_set(mode="OBJECT")
        bm.to_mesh(me)
        bm.free()
        bpy.ops.object.mode_set(mode="EDIT")

        return {'FINISHED'}

and this is the output:
Screenshot 2021-02-15 163034

The only faces selected are the ones i do from code.
What am i doing wrong?

The problem is that you’re creating a bmesh from scratch and then giving it data from object mode- which means the select_shortest_path operator’s changes aren’t reflected. If you need to use a bmesh object in this way you’ll need to force the bmesh data to be updated each time you make a change to it.

Far easier to just run the operator from edit mode and then create your bmesh object from the edit mesh.

import bpy, bmesh

obj = bpy.context.active_object
bm = bmesh.from_edit_mesh(obj.data)

#selected_faces = {f for f in bm.faces if f.select}
#print(selected_faces)

before_selection = {f for f in bm.faces if f.select}
bpy.ops.mesh.shortest_path_select()
after_selection = {f for f in bm.faces if f.select}
shortest_path_faces = after_selection.difference(before_selection)

print([f.index for f in shortest_path_faces])

output: [39, 40, 41, 42, 43, 34, 35, 44, 46, 45, 36, 37, 38]