Files
animation/tools/obj_slice_components.py
T

59 lines
2.0 KiB
Python
Raw Normal View History

"""Count connected components in a slab of an OBJ, to tell separated digits from a fused
mitt. Slice just past the knuckles: 4 components = separate fingers, 1 = fused paddle.
usage: obj_slice_components.py mesh.obj AXIS LO HI (axis x|y|z, bounds in metres)
"""
import sys
from pathlib import Path
from collections import defaultdict, deque
path, axis, lo, hi = sys.argv[1], sys.argv[2], float(sys.argv[3]), float(sys.argv[4])
ai = {"x": 0, "y": 1, "z": 2}[axis]
vs, faces = [], []
for line in Path(path).read_text().splitlines():
if line.startswith("v "):
p = line.split()
vs.append((float(p[1]), float(p[2]), float(p[3])))
elif line.startswith("f "):
faces.append([int(t.split("/")[0]) - 1 for t in line.split()[1:]])
inslab = [i for i, v in enumerate(vs) if lo <= v[ai] <= hi]
sel = set(inslab)
adj = defaultdict(set)
kept = 0
for f in faces:
if all(k in sel for k in f):
kept += 1
for a in f:
for b in f:
if a != b:
adj[a].add(b)
seen = set()
comps = []
for v in inslab:
if v in seen:
continue
q = deque([v]); seen.add(v); c = []
while q:
u = q.popleft(); c.append(u)
for w in adj.get(u, ()):
if w not in seen:
seen.add(w); q.append(w)
comps.append(c)
comps.sort(key=len, reverse=True)
print(f"{Path(path).name} slab {axis} in [{lo}, {hi}]")
print(f" verts in slab {len(inslab)}, faces kept {kept}, components {len(comps)}")
for n, c in enumerate(comps[:10]):
if len(c) < 4:
continue
ext = [(min(vs[k][d] for k in c) * 100, max(vs[k][d] for k in c) * 100) for d in range(3)]
span = [f"{e[1]-e[0]:.1f}" for e in ext]
ctr = [f"{(e[0]+e[1])/2:.1f}" for e in ext]
print(f" comp{n}: {len(c):5d} verts span(cm) x{span[0]} y{span[1]} z{span[2]}"
f" centre({ctr[0]}, {ctr[1]}, {ctr[2]})")
big = [c for c in comps if len(c) >= 20]
print(f" components with >=20 verts: {len(big)}")