Using the operator "bmesh.ops.similar_faces"

According to the Manual Blender Python API, this operator is used to search for faces that are similar in area, material, perimeter, …
http://www.blender.org/api/blender_python_api_2_75_release/bmesh.ops.html#module-bmesh.ops

It is similar to the “bpy.ops.mesh.select_similar” but instead of selecting the faces, the “bmesh.ops.similar_faces” should return a dictionary with similar faces.

But how to make this possible?

Here’s the source code of the operator:
http://git.blender.org/gitweb/gitweb.cgi/blender.git/blob/HEAD:/source/blender/bmesh/operators/bmo_similar.c

Here’s the code I used to test 100 different combinations:

print('--------------------')
import bpy
import bmesh


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


#face = bm.select_history[0]
index = [0]
list = [bm.faces[i] for i in index]
test = 10


for type in range(test):
    for compare in range(test):
        dict = bmesh.ops.similar_faces(bm, faces = list,
                                           type = type,
                                           thresh = 0.0,
                                           compare = compare
                                           )
        print(dict)
        for f in bm.faces:
            if f.select:
                print(f.index)

Your code is very bad style, you are overwriting a built-in function and two native data types. I would re-write it like:

print('--------------------')
import bpy
import bmesh


ob = bpy.context.object
assert ob is not None
me = ob.data
bm = bmesh.from_edit_mesh(me)


#face = bm.select_history[0]

for i in range(10):
    for j in range(10):
        ret = bmesh.ops.similar_faces(
            bm,
            faces=[bm.faces[0]],
            type=i,
            thresh=0.0,
            compare=j
        )

        print(ret)
        for f in bm.faces:
            if f.select:
                print(f.index)

But you should obviously use the right numbers for type and compare, which are found here:
https://developer.blender.org/diffusion/B/browse/master/source/blender/bmesh/intern/bmesh_operators.h;7380166db2ca0a21511822c33b7751766a5165b1$59

print('--------------------')
import bpy
import bmesh
from enum import IntEnum

class SIM_CMP(IntEnum):
    EQ, GT, LT = range(3)

class SIMFACE(IntEnum):
    MATERIAL = 201
    IMAGE = 202
    AREA = 203
    SIDES = 204
    PERIMETER = 205
    NORMAL = 206
    COPLANAR = 207
    SMOOTH = 208
    FREESTYLE = 209


ob = bpy.context.object
assert ob is not None
me = ob.data
bm = bmesh.from_edit_mesh(me)

ret = bmesh.ops.similar_faces(
    bm,
    faces=[bm.faces.active], #[bm.faces[0]],
    type=SIMFACE.SIDES,
    #thresh=0.0,
    compare=SIM_CMP.EQ
)

for face in ret['faces']:
    print(face)
    face.select_set(True)
bmesh.update_edit_mesh(me)

Thank @CoDEmanX, it worked perfectly :slight_smile:
My first script posted was used only as a quick test. But I would never have advanced to values above 200 (the manual should give at least a tip)

I intend to get all the coplanar faces. But I had given up tinkering with that operator, so I wrote these code lines:

face = bm.faces.active
nn = -face.normal
normals = face.normal.to_tuple(4), nn.to_tuple(4)
m_face = face.calc_center_median()
for f in bm.faces:
    n = f.normal.to_tuple(4)
    if n in normals:
        vec = f.calc_center_median() - m_face
        if abs(vec.dot(n)) < 0.001:
            f.select = True

As that operator ignores coplanar faces with inverted normal, I will continue using these code lines (despite the python be slow).

@CoDEmanX, your script made me curious. Do you really need to import the “IntEnum”??
Why should I use it in python (with its dynamic typing)?

Why not let the bmesh op return all coplanar faces, then filter based on normal to ignore inverted normals?

IntEnum is not really required, but I would consider it good style to use enums since the introduction in v3.4 for cases like this. For motivation, see https://www.python.org/dev/peps/pep-0435/#motivation.

You could supply similar_faces() with the integer values directly of course, but that would result in code that needs explanation. One could use a dict too, but it’s simply easier to use a class, then copy & paste the enum definitions over from C code. You also type less characters later on (SIMFACE[“coplanar”] vs. SIMFACE.coplanar).

The problem is the opposite. I would have to run the operator “bpy.ops.mesh.select_similar” twice. A with the face in the normal position and other with the face reversed. So I would get all the coplanar faces, and not only those with the same Normal.

It would still be faster than using only python without importing operator.

I’m taking a look at the site. thanks

I see, that’s unfortunate. You could ask the devs if they can add the option to include inverted normals. Or use a workaround, like duplicate the source face, flip normal and run similar_faces() again with this face, then remove it again.

I sent a “request” as a Bug (somehow is a bug). I hope to be considered.