# -*- coding: utf-8 -*- """ 生成占位数模 (每系列一个通用的"待补数模"方块)。 用途: 为「参数组合补齐」生成的型号提供占位 STEP —— 构建器要求每个型号必须有数模文件。 真实数模后续由 AI 参照同系列已有型号补出, 覆盖同名文件即可。 产出: catalog/step/PLACEHOLDER.step 通用的方块 (ISO-10303-21, 标准 B-rep) catalog/step/_placeholder/<系列>.step 每系列一份 (便于按系列替换/识别) 方块边长 60mm, 居中于原点。 用法: PYTHONUTF8=1 python gen-placeholder-step.py """ import os CAT = r'D:/开发/OnebotCatalog/onebot-data/catalog' STEP_DIR = os.path.join(CAT, 'step') # 方块尺寸 (mm) SX, SY, SZ = 60.0, 60.0, 60.0 HX, HY, HZ = SX / 2, SY / 2, SZ / 2 def build_step(label): """生成一个合法的 STEP 文件内容: 单位立方体 B-rep。""" L = [] L.append('ISO-10303-21;') L.append('HEADER;') L.append("FILE_DESCRIPTION(('PLACEHOLDER - real CAD model pending'),'2;1');") L.append("FILE_NAME('%s','2026-01-01T00:00:00',('ONEBOT'),('ONEBOT')," "'gen-placeholder-step.py','ONEBOT Catalog','');" % label) L.append("FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));") L.append('ENDSEC;') L.append('DATA;') L.append("#1=APPLICATION_CONTEXT('core data for automotive mechanical design processes');") L.append("#2=APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#1);") L.append("#3=PRODUCT_CONTEXT('',#1,'mechanical');") L.append("#4=PRODUCT_DEFINITION_CONTEXT('part definition',#1,'design');") L.append("#5=PRODUCT('%s','PLACEHOLDER',$,(#3));" % label) L.append("#6=PRODUCT_DEFINITION_FORMATION('','',#5);") L.append("#7=PRODUCT_DEFINITION('design','',#6,#4);") L.append("#8=PRODUCT_DEFINITION_SHAPE('','',#7);") L.append("#9=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));") L.append("#10=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));") L.append("#11=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());") L.append("#12=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.001),#9," "'distance_accuracy_value','');") L.append("#13=(GEOMETRIC_REPRESENTATION_CONTEXT(3)" "GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#12))" "GLOBAL_UNIT_ASSIGNED_CONTEXT((#9,#10,#11))REPRESENTATION_CONTEXT('',''));") # 8 个顶点坐标 corners = [ (-HX, -HY, -HZ), (HX, -HY, -HZ), (HX, HY, -HZ), (-HX, HY, -HZ), (-HX, -HY, HZ), (HX, -HY, HZ), (HX, HY, HZ), (-HX, HY, HZ), ] eid = 20 pt_ids, vx_ids = [], [] for (x, y, z) in corners: L.append('#%d=CARTESIAN_POINT('',(%.3f,%.3f,%.3f));' % (eid, x, y, z)) pt_ids.append(eid); eid += 1 L.append('#%d=DIRECTION('',(0.,0.,1.));' % eid); dz = eid; eid += 1 L.append('#%d=DIRECTION('',(1.,0.,0.));' % eid); dx = eid; eid += 1 for pid in pt_ids: L.append('#%d=VERTEX_POINT('',#%d);' % (eid, pid)) vx_ids.append(eid); eid += 1 # 12 条棱 edges = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)] edge_ids = [] for (a, b) in edges: L.append('#%d=LINE('',#%d,#%d);' % (eid, pt_ids[a], pt_ids[b])) ln = eid; eid += 1 L.append('#%d=VECTOR('',#%d,1.0);' % (eid, dx)); vc = eid; eid += 1 L.append('#%d=EDGE_CURVE('',#%d,#%d,#%d,.T.);' % (eid, vx_ids[a], vx_ids[b], ln)) ec = eid; eid += 1 L.append('#%d=ORIENTED_EDGE('',*,*,#%d,.T.);' % (eid, ec)) edge_ids.append(eid); eid += 1 # 6 个面 faces = [ [0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7], ] normals = [(0, 0, -1), (0, 0, 1), (0, -1, 0), (1, 0, 0), (0, 1, 0), (-1, 0, 0)] face_ids = [] for fi, f in enumerate(faces): loops = [] for k in range(4): loops.append(edge_ids[f[k]]) L.append('#%d=EDGE_LOOP('',(%s));' % (eid, ','.join('#%d' % x for x in loops))) el = eid; eid += 1 nx, ny, nz = normals[fi] L.append('#%d=DIRECTION('',(%.1f,%.1f,%.1f));' % (eid, nx, ny, nz)) nd = eid; eid += 1 L.append("#%d=AXIS2_PLACEMENT_3D('',#%d,#%d,$);" % (eid, pt_ids[f[0]], nd)) ax = eid; eid += 1 L.append('#%d=PLANE(\'\',#%d);' % (eid, ax)) pl = eid; eid += 1 L.append('#%d=ADVANCED_FACE(\'\',(#%d),#%d,.T.);' % (eid, el, pl)) face_ids.append(eid); eid += 1 L.append('#%d=CLOSED_SHELL(\'\',(%s));' % (eid, ','.join('#%d' % x for x in face_ids))) sh = eid; eid += 1 L.append("#%d=MANIFOLD_SOLID_BREP('PLACEHOLDER',#%d);" % (eid, sh)) msb = eid; eid += 1 L.append('#%d=ADVANCED_BREP_SHAPE_REPRESENTATION(\'PLACEHOLDER\',(#%d,#%d),#13);' % (eid, msb, eid + 1)) abr = eid; eid += 1 L.append("#%d=AXIS2_PLACEMENT_3D('',#%d,#%d,#%d);" % (eid, pt_ids[0], dz, dx)) ax2 = eid; eid += 1 L.append("#%d=SHAPE_DEFINITION_REPRESENTATION(#8,#%d);" % (eid, abr)) L.append('ENDSEC;') L.append('END-ISO-10303-21;') return '\n'.join(L) + '\n' def main(): os.makedirs(STEP_DIR, exist_ok=True) content = build_step('PLACEHOLDER') p = os.path.join(STEP_DIR, 'PLACEHOLDER.step') with open(p, 'w', encoding='ascii', newline='\r\n') as f: f.write(content) print(f'写入 {p} ({os.path.getsize(p)} 字节)') if __name__ == '__main__': main()