#!/usr/bin/env python3 """按"查看器标签"缩放 GLB 中某个零件的几何体(绕其包围盒中心)。 默认:长度 = 平面内最长的轴,宽度 = 第二长的轴。缩放以中心为基准, 所以 width=3 表示两边各 +100%(总宽变 3 倍),length=1.5 表示两边各 +25%。 用法: python3 viewer/tools/scale_part.py --input a.glb --label 区域_143 --width 3 --length 1.5 --inplace """ import argparse, os, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from split_glb import read_glb, write_glb, NCOMP, COMP_DTYPE, COMP_SIZE import numpy as np def viewer_labels(gltf): used, labels = {}, {} for i, n in enumerate(gltf["nodes"]): nm = n.get("name", "") if not nm: continue if nm in used: used[nm] += 1 labels[i] = f"{nm}_{used[nm]}" else: used[nm] = 0 labels[i] = nm return labels def main(): ap = argparse.ArgumentParser() ap.add_argument("--input", required=True) ap.add_argument("--label", required=True, help="查看器标签,如 区域_143") ap.add_argument("--width", type=float, default=1.0, help="宽度方向缩放倍数(最短的平面轴)") ap.add_argument("--length", type=float, default=1.0, help="长度方向缩放倍数(最长的平面轴)") ap.add_argument("--output") ap.add_argument("--inplace", action="store_true") args = ap.parse_args() gltf, bin_ = read_glb(args.input) labels = viewer_labels(gltf) node_idx = next((i for i, l in labels.items() if l == args.label), None) if node_idx is None: print(f"未找到标签 {args.label!r}") return node = gltf["nodes"][node_idx] mesh = gltf["meshes"][node["mesh"]] changed = 0 for pr in mesh["primitives"]: ai = pr["attributes"]["POSITION"] acc = gltf["accessors"][ai] if acc["componentType"] != 5126 or acc["type"] != "VEC3": print("仅支持 float VEC3 的 POSITION") return bv = gltf["bufferViews"][acc["bufferView"]] base = bv.get("byteOffset", 0) + acc.get("byteOffset", 0) n = acc["count"] arr = np.frombuffer(bin_, dtype="