# blender -b file.blend -P stretch_blend.py -- Action "label:cond;cond|..." [nframes]
import bpy, sys
a=sys.argv[sys.argv.index("--")+1:]; name,spec=a[0],a[1]; nf=int(a[2]) if len(a)>2 else 12
arm=[o for o in bpy.context.scene.objects if o.type=="ARMATURE"][0]; me=[o for o in bpy.context.scene.objects if o.type=="MESH"][0]
def coords():
    dg=bpy.context.evaluated_depsgraph_get(); e=me.evaluated_get(dg); m=e.to_mesh(); c=[e.matrix_world@v.co for v in m.vertices]; e.to_mesh_clear(); return c
arm.animation_data_create(); arm.animation_data.action=None; arm.data.pose_position="REST"; bpy.context.view_layer.update(); rest=coords(); arm.data.pose_position="POSE"
act=bpy.data.actions[name]; arm.animation_data.action=act
if act.slots: arm.animation_data.action_slot=act.slots[0]
f0,f1=act.frame_range; edges=[tuple(e.vertices) for e in me.data.edges]; regions=[]
for part in spec.split("|"):
    label,conds=part.split(":",1); conds=conds.split(";")
    sel=[all(eval(c,{"x":p.x,"y":p.y,"z":p.z,"abs":abs}) for c in conds) for p in rest]
    es=[(i,j,(rest[i]-rest[j]).length) for i,j in edges if sel[i] and sel[j]]; es=[t for t in es if t[2]>1e-5]
    regions.append((label,es,[]))
for k in range(nf):
    bpy.context.scene.frame_set(int(round(f0+(f1-f0)*k/max(1,nf-1)))); c=coords()
    for label,es,acc in regions: acc.extend(abs((c[i]-c[j]).length-l)/l for i,j,l in es)
for label,es,acc in regions:
    acc.sort(); n=len(acc)
    if not n: print("STRETCH %-9s none"%label); continue
    q=lambda t: acc[min(n-1,int(t*n))]
    print("STRETCH %-9s %-6s edges=%5d median=%5.1f%% p90=%6.1f%% p99=%6.1f%% >10%%:%5.1f%%"%(name,label,len(es),100*q(.5),100*q(.9),100*q(.99),100*sum(1 for x in acc if x>.1)/n))
