59 lines
2.0 KiB
Python
59 lines
2.0 KiB
Python
|
|
"""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)}")
|