"""Critique 1: count the sides of round parts (distinct angles of the outermost ring of vertices about the part axis). Read-only; writes crit1_segments.json.""" import bpy, json, os, math from mathutils import Vector HERE = os.path.dirname(os.path.abspath(__file__)) U = Vector((-0.7997, 0, 0.6003)) CHECK = { # mesh: [(part id prefix, axis)] "DoorArm | lower arm": [("L01", "Y"), ("L07", "Y"), ("L15", "Y"), ("L06", "Y"), ("L11", "Y")], "DoorArm | upper arm": [("U01", "Y"), ("U03", "Y"), ("U11", "Y"), ("U05", "Y")], "DoorArm | turret": [("T01", "Z"), ("T04a", "Y"), ("T12", "Y"), ("T06", "Y"), ("T08", "X"), ("T05", "Y")], "DoorArm | carriage": [("C13", "Z"), ("C07", "Y"), ("C08", "Y")], "DoorArm | forearm": [("F01", "X"), ("F04", "Y"), ("F14", "Y"), ("F07", "X")], "DoorArm | tool A hub": [("A01", "X")], "DoorArm | tool B": [("B01", "X")], "DoorArm | J3 cylinder": [("R01", "U"), ("R03", "U")], "DoorArm | J3 piston": [("R05", "U"), ("R06", "Y")], "DoorArm | wrist head": [("W01", "Y")], "DoorArm | flange": [("FL1", "X"), ("FL2", "X")], "DoorArm_AFT | door fixture A": [("DA3", "N"), ("DA4", "N")], } N = Vector((0, 0.9089, 0.4171)) def basis(ax): if ax == "X": return Vector((1, 0, 0)) if ax == "Y": return Vector((0, 1, 0)) if ax == "Z": return Vector((0, 0, 1)) if ax == "U": return U.normalized() if ax == "N": return N.normalized() out = {} for mname, items in CHECK.items(): me = bpy.data.meshes.get(mname) if me is None: out[mname] = "missing"; continue ids = list(me.get("parts", [])) lay = me.attributes.get('part') res = {} for pref, ax in items: idx = [i for i, p in enumerate(ids) if p == pref or p.startswith(pref + ".") or p.startswith(pref)] if not idx: res[pref] = "no part"; continue a = basis(ax) # build two perpendicular vectors t = Vector((1, 0, 0)) if abs(a.x) < 0.9 else Vector((0, 1, 0)) e1 = a.cross(t).normalized(); e2 = a.cross(e1).normalized() for k in idx[:2]: vs = set() for poly in me.polygons: if lay.data[poly.index].value == k: vs.update(poly.vertices) if not vs: continue pts = [me.vertices[i].co for i in vs] c = sum(pts, Vector()) / len(pts) # centre in the plane: average of extreme points r = [] for p in pts: d = p - c x, y = d.dot(e1), d.dot(e2) r.append((math.hypot(x, y), math.atan2(y, x))) rmax = max(q[0] for q in r) ring = sorted(set(round(math.degrees(q[1]) % 360, 1) for q in r if q[0] > rmax * 0.985)) res[ids[k]] = dict(r_max=round(rmax, 4), sides_at_rim=len(ring)) out[mname] = res json.dump(out, open(os.path.join(HERE, "crit1_segments.json"), "w"), indent=1) print("[crit1] segments done", flush=True)