2
$\begingroup$

Is there a way in Python to get a list of faces that are coplanar to a particular face similar to the way the command "Select Linked Flat Faces" works, but without actually requiring me to change the selection.

I think it might be possible to use Python to call the aforementioned command to select coplanar faces, and then store the selected faces in a list, but this seems really inefficient as I will be iterating over a lot of faces, so I'm wondering if there is a command in the Python API that I can send a face index and angle tolerance and it will just return a list of coplanar faces.

$\endgroup$
  • 1
    $\begingroup$ there is a function that gives the angle between 2 vectors, you get the face normal then loop through the faces list and calculate the angle difference with their normals and use your threshold to decide which go in $\endgroup$ – Chebhou May 29 '16 at 7:19
3
$\begingroup$

There is also built in bpy.ops.mesh.select_similar(type='COPLANAR', threshold=0)

$\endgroup$
2
$\begingroup$

As an alternative to bpy.ops.mesh.select_similar(type='COPLANAR')

Select all faces with normals within angle tolerance of face.normal, then check if the convex hull, made from the verts of each of these faces with those of selected face, volume is zero (or within some tolerance). If so it must be on same plane.

Quick script to test. Runs thru all mesh objects in the scene each face in the objects mesh and the coplanar list of the indices of faces coplanar to that face.

import bpy
import bmesh
from mathutils import Vector

def coplanar_list(bm, index, TOL=0.001):
    bm.faces.ensure_lookup_table()
    face = bm.faces[index]
    coplanar = []
    # narrow down selection based on normals
    faces = [f for f in bm.faces if f.normal.angle(face.normal) < TOL]
    # list of faces with same normal
    bm2 = bmesh.new()
    for f in faces:
        verts = [v.co for v in face.verts]
        if f.index != face.index:
            verts.extend(v.co for v in f.verts)
        # make a dummy bmesh with verts of each face
        o = sum(verts, Vector((0,0,0))) / len(verts)
        for v in verts:
            bm2.verts.new(v - o)
        #calculate a convex hull
        bmesh.ops.convex_hull(bm2, input=bm2.verts)
        # if the convex hull has no volume its on same plane.
        volume = bm2.calc_volume()
        if volume < 0.001:
            coplanar.append(f.index)
        bm2.clear()
    bm2.free()
    return coplanar

context = bpy.context
scene = context.scene
meshobjs = [o for o in scene.objects if o.type == 'MESH']
print("-" * 72)
for o in meshobjs:
    print("Object", o.name)
    if o == context.edit_object:
        bm = bmesh.from_edit_mesh(o.data)
    else:
        bm = bmesh.new()
        bm.from_mesh(o.data)
    for f in bm.faces:
        print("\tface %3d " % (f.index), coplanar_list(bm, f.index))

Output for default Cube subdivided once.

Object Cube.016
    face   0  [0, 21, 22, 23]
    face   1  [1, 18, 19, 20]
    face   2  [2, 15, 16, 17]
    face   3  [3, 12, 13, 14]
    face   4  [4, 9, 10, 11]
    face   5  [5, 6, 7, 8]
    face   6  [5, 6, 7, 8]
    face   7  [5, 6, 7, 8]
    face   8  [5, 6, 7, 8]
    face   9  [4, 9, 10, 11]
    ...
    face  17  [2, 15, 16, 17]
    face  18  [1, 18, 19, 20]
    face  19  [1, 18, 19, 20]
    face  20  [1, 18, 19, 20]
    face  21  [0, 21, 22, 23]
    face  22  [0, 21, 22, 23]
    face  23  [0, 21, 22, 23]
$\endgroup$
0
$\begingroup$

In edit mode, Having your face of comparison selected, you can use Shift+G >> Co-planar. You must be in Face selection mode for this to work though, otherwise you will get a different context for verts/edges respectively.

This equates to the same answer given by JuhaW from the Python perspective.

bpy.ops.mesh.select_similar(type='COPLANAR', threshold=0.01)

The limitations to this is that everything that you are looking for must be in one object reference.

To overcome this limitation, I would recommend (with Object Mode active):

  1. Create a full copy of your current scene.

Create a copy of the scene

  1. Within the copied scene, Select all your mesh objects, and join them into ONE object by hitting Ctrl+J.

  2. Delete the other objects that are not important for this operation.

  3. Go into edit mode.

  4. run your python function: bpy.ops.mesh.select_similar(type='COPLANAR', threshold=0.01)

$\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.