main
ae007 Project page: AFS_Adom rev A (Rice Eclipse AFS clean-room AI redesign): highlight reel and narrated process video with… cbe460e 7d ago
"""AI-created placeholder bodies as valid STEP AP214 solids (axis-aligned boxes, Z up, seated on z=0, centred on the
footprint origin). Labelled AI-generated; dimensions from the datasheet drawings cited in the provenance JSON written beside
each file. Used only for parts with no manufacturer or KiCad packages3D model."""
import json, hashlib, os, sys
sys.path.insert(0, '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad/gen')


def box_step(name, lx, ly, lz, x0=0.0, y0=0.0, z0=0.0, color=(0.2, 0.2, 0.2)):
    """Return STEP text for one box solid from (x0,y0,z0) to (x0+lx, y0+ly, z0+lz) in mm."""
    e = []            # entity lines
    def add(s):
        e.append(s); return len(e)
    # geometry context
    n_len = add("LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.)")
    n_ang = add("NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.)")
    n_sol = add("NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT()")
    n_unc = add(f"UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-06),#{n_len},'distance_accuracy_value','')")
    n_ctx = add(f"GEOMETRIC_REPRESENTATION_CONTEXT(3) GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#{n_unc})) GLOBAL_UNIT_ASSIGNED_CONTEXT((#{n_len},#{n_ang},#{n_sol})) REPRESENTATION_CONTEXT('','')")
    x1, y1, z1 = x0 + lx, y0 + ly, z0 + lz
    P = [(x0, y0, z0), (x1, y0, z0), (x1, y1, z0), (x0, y1, z0), (x0, y0, z1), (x1, y0, z1), (x1, y1, z1), (x0, y1, z1)]
    vp = [add(f"CARTESIAN_POINT('',({p[0]:.4f},{p[1]:.4f},{p[2]:.4f}))") for p in P]
    vx = [add(f"VERTEX_POINT('',#{cp})") for cp in vp]
    # edges: bottom 0-1,1-2,2-3,3-0 ; top 4-5,5-6,6-7,7-4 ; verticals 0-4,1-5,2-6,3-7
    E = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)]
    ed = []
    for a, b in E:
        pa, pb = P[a], P[b]
        d = (pb[0] - pa[0], pb[1] - pa[1], pb[2] - pa[2])
        L = (d[0] ** 2 + d[1] ** 2 + d[2] ** 2) ** 0.5
        dirn = add(f"DIRECTION('',({d[0]/L:.4f},{d[1]/L:.4f},{d[2]/L:.4f}))")
        vec = add(f"VECTOR('',#{dirn},1.)")
        line = add(f"LINE('',#{vp[a]},#{vec})")
        ed.append(add(f"EDGE_CURVE('',#{vx[a]},#{vx[b]},#{line},.T.)"))
    # faces: (edge indices with orientation), plane origin point, normal, ref dir
    F = [([(0, False), (3, False), (2, False), (1, False)], 0, (0, 0, -1), (1, 0, 0)),   # bottom (z0), outward -z
         ([(4, True), (5, True), (6, True), (7, True)], 4, (0, 0, 1), (1, 0, 0)),         # top
         ([(0, True), (9, True), (4, False), (8, False)], 0, (0, -1, 0), (1, 0, 0)),      # front y0
         ([(2, False), (10, True), (6, True), (11, False)], 2, (0, 1, 0), (-1, 0, 0)),    # back y1
         ([(3, True), (8, True), (7, False), (11, False)], 3, (-1, 0, 0), (0, -1, 0)),    # left x0
         ([(1, True), (10, True), (5, False), (9, False)], 1, (1, 0, 0), (0, 1, 0))]      # right x1
    faces = []
    for loop, pidx, nrm, ref in F:
        oes = [add(f"ORIENTED_EDGE('',*,*,#{ed[i]},{'.T.' if o else '.F.'})") for i, o in loop]
        el = add(f"EDGE_LOOP('',({','.join('#%d' % o for o in oes)}))")
        fb = add(f"FACE_OUTER_BOUND('',#{el},.T.)")
        nd = add(f"DIRECTION('',({nrm[0]:.1f},{nrm[1]:.1f},{nrm[2]:.1f}))")
        rd = add(f"DIRECTION('',({ref[0]:.1f},{ref[1]:.1f},{ref[2]:.1f}))")
        ax = add(f"AXIS2_PLACEMENT_3D('',#{vp[pidx]},#{nd},#{rd})")
        pl = add(f"PLANE('',#{ax})")
        faces.append(add(f"ADVANCED_FACE('',(#{fb}),#{pl},.T.)"))
    shell = add(f"CLOSED_SHELL('',({','.join('#%d' % f for f in faces)}))")
    solid = add(f"MANIFOLD_SOLID_BREP('{name}',#{shell})")
    # colour
    rgb = add(f"COLOUR_RGB('',{color[0]:.3f},{color[1]:.3f},{color[2]:.3f})")
    fsa = add(f"FILL_AREA_STYLE_COLOUR('',#{rgb})")
    fas = add(f"FILL_AREA_STYLE('',(#{fsa}))")
    sfs = add(f"SURFACE_STYLE_FILL_AREA(#{fas})")
    sss = add(f"SURFACE_SIDE_STYLE('',(#{sfs}))")
    ssu = add(f"SURFACE_STYLE_USAGE(.BOTH.,#{sss})")
    pst = add(f"PRESENTATION_STYLE_ASSIGNMENT((#{ssu}))")
    sti = add(f"STYLED_ITEM('',(#{pst}),#{solid})")
    o = add("CARTESIAN_POINT('',(0.,0.,0.))"); dz = add("DIRECTION('',(0.,0.,1.))"); dx = add("DIRECTION('',(1.,0.,0.))")
    ax0 = add(f"AXIS2_PLACEMENT_3D('',#{o},#{dz},#{dx})")
    sr = add(f"ADVANCED_BREP_SHAPE_REPRESENTATION('{name}',(#{ax0},#{solid}),#{n_ctx})")
    mdi = add(f"MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#{sti}),#{n_ctx})")
    app = add("APPLICATION_CONTEXT('core data for automotive mechanical design processes')")
    apd = add(f"APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#{app})")
    pc = add(f"PRODUCT_CONTEXT('',#{app},'mechanical')")
    prod = add(f"PRODUCT('{name}','{name}','AI-created placeholder body',(#{pc}))")
    pdc = add(f"PRODUCT_DEFINITION_CONTEXT('part definition',#{app},'design')")
    pdf = add(f"PRODUCT_DEFINITION_FORMATION('','',#{prod})")
    pd = add(f"PRODUCT_DEFINITION('design','',#{pdf},#{pdc})")
    pds = add(f"PRODUCT_DEFINITION_SHAPE('','',#{pd})")
    add(f"SHAPE_DEFINITION_REPRESENTATION(#{pds},#{sr})")
    prpc = add("PRODUCT_RELATED_PRODUCT_CATEGORY('part','',(#%d))" % prod)
    body = '\n'.join(f"#{i+1}={s};" for i, s in enumerate(e))
    return f"""ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('AI-created placeholder body {name}'),'2;1');
FILE_NAME('{name}.step','2026-10-15T00:00:00',('AFS_Adom generator'),('Adom'),'mkstep.py','mkstep.py','');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN {{ 1 0 10303 214 1 1 1 1 }}'));
ENDSEC;
DATA;
{body}
ENDSEC;
END-ISO-10303-21;
"""


OUT = '/tmp/claude-1001/-home-adom-project/8819fb5f-c2c6-4524-9528-99428cd6b88e/scratchpad/AFS_Adom/3d'
parts = [
    # name, lx, ly, lz, x0, y0, color, provenance
    ('QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm', 10.0, 10.0, 0.9, -5.0, -5.0, (0.15, 0.15, 0.15),
     dict(source='RP2350 datasheet, QFN-80 package drawing (10.0 x 10.0 mm body, 0.9 mm max height), via the KiCad footprint Package_DFN_QFN:QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm',
          dims_mm=dict(body=[10.0, 10.0], height=0.9), simplifications='single box, no leads, no pin-1 chamfer', used_for='RP2350B (U1) body envelope on the board only')),
    ('Kionix_LGA-12_2x2mm_P0.5mm_LayoutBorder2x4y', 2.0, 2.0, 0.9, -1.0, -1.0, (0.2, 0.2, 0.2),
     dict(source='KX134-1211 specification rev 4.0, Package Dimensions: 2 x 2 x 0.9 mm LGA 12-pin',
          dims_mm=dict(body=[2.0, 2.0], height=0.9), simplifications='single box, no pads, no pin-1 dot', used_for='KX134-1211 (U9) body envelope')),
    ('AMASS_XT30PW-M_1x02_P2.50mm_Horizontal', 13.3, 9.0, 8.3, -9.15, -13.1, (0.85, 0.75, 0.1),
     dict(source='KiCad footprint Connector_AMASS:AMASS_XT30PW-M_1x02_P2.50mm_Horizontal F.Fab outline (x -9.15..4.15, y -13.1..-4.1) and the Amass XT30PW-M drawing height (8.3 mm, approximate)',
          dims_mm=dict(body=[13.3, 9.0], height=8.3), simplifications='single box over the fab outline; the real part has a mating shroud and two pins', used_for='XT30PW-M (J1) body envelope')),
]
os.makedirs(OUT, exist_ok=True)
for name, lx, ly, lz, x0, y0, color, prov in parts:
    txt = box_step(name, lx, ly, lz, x0, y0, 0.0, color)
    path = os.path.join(OUT, name + '.step')
    open(path, 'w').write(txt)
    sha = hashlib.sha256(txt.encode()).hexdigest()
    json.dump(dict(file=name + '.step', authoring='AI-created placeholder body (axis-aligned box), not a manufacturer model', generator='gen/mkstep.py (AFS_Adom)',
                   sha256=sha, units='mm', frame='Z up, seated on z=0, centred on the footprint origin', **prov), open(os.path.join(OUT, name + '.provenance.json'), 'w'), indent=1)
    print('wrote', path, len(txt), 'bytes')