"""Edge-stretch fin detector (pure python): posed OBJ edge lengths vs rest OBJ.""" import sys, os, math def load_obj(path): vs, faces = [], [] with open(path) as f: for line in f: if line.startswith('v '): p = line.split() vs.append((float(p[1]), float(p[2]), float(p[3]))) elif line.startswith('f '): idx = [int(tok.split('/')[0]) - 1 for tok in line.split()[1:]] for i in range(1, len(idx) - 1): faces.append((idx[0], idx[i], idx[i + 1])) return vs, faces def edge_set(faces): es = set() for a, b, c in faces: for u, v in ((a, b), (b, c), (c, a)): es.add((u, v) if u < v else (v, u)) return sorted(es) def dist(p, q): return math.sqrt((p[0]-q[0])**2 + (p[1]-q[1])**2 + (p[2]-q[2])**2) d = sys.argv[1] for hand in ('l', 'r'): rest_v, rest_f = load_obj(os.path.join(d, f'rest_hand_{hand}.obj')) edges = edge_set(rest_f) rest_len = [dist(rest_v[a], rest_v[b]) for a, b in edges] for pose in ('flat', 'fist', 'grip'): v, _ = load_obj(os.path.join(d, f'{pose}_hand_{hand}.obj')) if len(v) != len(rest_v): print(f'{pose}_hand_{hand}: VERTEX COUNT MISMATCH {len(v)} vs {len(rest_v)}') continue ratios = [] for (a, b), rl in zip(edges, rest_len): if rl <= 1e-9: continue ratios.append((dist(v[a], v[b]) / rl, a, b)) ratios.sort(key=lambda t: t[0]) n = len(ratios) mx = ratios[-1][0] p999 = ratios[int(n * 0.999)][0] n2 = sum(1 for r, _, _ in ratios if r > 2) n3 = sum(1 for r, _, _ in ratios if r > 3) n5 = sum(1 for r, _, _ in ratios if r > 5) print(f'{pose}_hand_{hand}: edges={n} max={mx:.2f}x p99.9={p999:.2f}x >2x={n2} >3x={n3} >5x={n5}') for r, a, b in ratios[-min(max(n3, 3), 8):][::-1]: pa = [c * 100 for c in v[a]] rl = dist(rest_v[a], rest_v[b]) * 100 print(f' {r:7.1f}x rest {rl:5.2f}cm -> {r*rl:7.1f}cm at posed ({pa[0]:.1f}, {pa[1]:.1f}, {pa[2]:.1f}) cm')