I've got a non flat and non regular surface with three selected faces. Is there a way to get the smallest angle between these with python?

enter image description here

  • $\begingroup$ Is it related to camera space at all? Like, are the lines meant to be contained within the same plane? $\endgroup$ – someonewithpc Feb 26 '16 at 0:39
  • $\begingroup$ No there is no relation. Just the smallest angle would be great. $\endgroup$ – Basti Feb 26 '16 at 11:14

Here's a slightly different approach.

enter image description here

The solution below treats the three faces as a triangle. The script calculates all 3 triangle angles, then sums the two smaller angles to find the answer.

As shown in the image below, they are equal to the angle between the edges of the larger angle within the triangle.

enter image description here

import bpy, bmesh
from mathutils import Vector
from math import degrees, acos

bm = bmesh.from_edit_mesh( bpy.context.object.data )
centers = [ f.calc_center_median() * bpy.context.object.matrix_world for f in bm.faces if f.select ]

if len( centers ) == 3:
    # Face centers as triangle vertices
    A, B, C = centers

    # Triangle edges (sides)
    AB = B - A
    AC = C - A
    BC = C - B

    # Triangle angles
    a =       degrees( acos( ( AB.dot( AC ) ) / ( AB.length * AC.length ) ) )
    b = 180 - degrees( acos( ( AB.dot( BC ) ) / ( AB.length * BC.length ) ) )
    c =       degrees( acos( ( BC.dot( AC ) ) / ( BC.length * AC.length ) ) )

    # The smallest angle between the two triangle edge vectors equals
    # To the sum of the two smallest angles within the triangle
    angles = sorted( [ a, b, c ] )
    print( angles )
    print( "All: ", sum( angles ) )
    print( "Two smaller: ", sum( angles[:2] ) )

    print( "Invalid number of selected faces" )

This is what I have so far. It doesn't seem to quite work, but I have to go and don't want to waste my efforts. There is one problem with it: to know which vector to use as the center, it calculates the distance to the object center, instead of the (intended) median selection point.

Feel free to use this code to make your own answer.

import bmesh
import bpy
import mathutils

bm = bmesh.new()
obj = bpy.context.object
zero = mathutils.Vector((0, 0, 0))

vec = None
minSq = 0
vec_list = list()
for f in bm.faces:
    if f.select:
        center = f.calc_center_median()
        distSq = (center - obj.location).dot(center - obj.location)

        if vec == None:
            vec = center
            minSq = distSq

        if distSq < minSq:
            vec = center

for f in bm.faces:
    if f.select:
        if (f.calc_center_median() - vec) != zero:
            vec_list.append(f.calc_center_median() - vec)

if len(vec_list) != 3:
    print("Select only three faces")


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.