I have this simple setup:

enter image description here

I'd like to walk this perimeter and find the total length of every side, so as to find which side is longer:

enter image description here

How can I do that with a python script? Thank you EDIT: added a clearer picture


2 Answers 2


Co linear Edges

below is a script that returns all co linear edges from a set of input edges. Two edges are colinear if they share a vertex and the edge vectors are parallel (dot product of normalized vectors is one)

The method edge_line_segments(...) takes as its arguments, the bmesh, a list of edges from that bmesh and a tolerance angle for how far from parallel the edges can be.

The return dictionary has a key "segments" which is a list of edges in each line segment.

import bpy
import bmesh
from math import sin, radians

def tag(iterable, value):
    for x in iterable:
        x.tag = value    

def vec(e):
    v0, v1 = e.verts
    return (v1.co - v0.co).normalized()

def parallel(e1, e2, tol_angle=0):
    return abs(vec(e1).dot(vec(e2)) - 1) <= sin(tol_angle)

def line_select_extend(edge, v, tol_angle=0):  
    edges = []
    while v:
        segments = [e for e in v.link_edges
                if not e is edge
                and e.tag
                and parallel(e, edge, tol_angle)]
        if segments:
            edge = segments[0]
            v = edge.other_vert(v)
            v = None  
    return edges     

def select_segment(edge, tol_angle=0):
    v0, v1 = edge.verts
    edges = line_select_extend(edge, v0, tol_angle)
    edges.extend(line_select_extend(edge, v1, tol_angle))
    return edges

def edge_line_segments(bm, edges=[], tol_angle=0):
    ret = {"segments" : []}
    tag(bm.edges, False)
    tag(edges, True)
    edges = set(edges)
    while edges:
        segments = select_segment(next(iter(edges)))
        edges -= set(segments)
    tag(bm.edges, False)
    return ret

To use.

Test script below to run in edit mode. Calls method with boundary (perimeter edges), sorts the segments by length, selects the edges of the longest segment and writes a report to system console.

context = bpy.context
ob = context.object
me = ob.data

bm = bmesh.from_edit_mesh(me)    
perimeter = [e for e in bm.edges if e.is_boundary]  
ret = edge_line_segments(bm, edges=perimeter, tol_angle=radians(5))
segments = [(sum(e.calc_length() for e in s), s)
        for s in ret["segments"]]
segments.sort(key=lambda s: s[0])

for i, (length, edges) in enumerate(segments):
    print("linked segment %d edges length %.3f" % (len(edges), length))

    for e in edges:
        e.select = i == len(segments) - 1 
        print("\t edge %d len %.2f" % (e.index, e.calc_length())) 
  • $\begingroup$ This puts me on the right way, thank you very much. $\endgroup$
    – Kabu
    May 22, 2018 at 8:31

With the following script you're able to find the indexnumber of the corner vertices. Just put the object in editmode and select all corner vertices. The script will print a list for the second script.

import bpy
import bmesh

obj = bpy.context.active_object

mesh = obj.data

bm = bmesh.from_edit_mesh(mesh)

vertices = bm.faces[0].verts

corner_verts =[]
for v in vertices:
    if v.select:



Replace the corner_verts array with the output from the first script.

import bpy
import bmesh

obj = bpy.context.active_object

mesh = obj.data


bm = bmesh.from_edit_mesh(mesh)

corner_verts = [3, 11, 10, 1, 6, 5, 0, 15, 14, 2, 13, 12]
len_corner_verts = len(corner_verts)

for i in range(0, len_corner_verts):
    v1 = bm.verts[corner_verts[i % len_corner_verts]].co
    v2 = bm.verts[corner_verts[(i + 1) % len_corner_verts]].co
    dv = v2 -v1  
    print('from {0} to {1}, length: {2}'.format(v1, v2, dv.length))



You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .