component
150060VS75000 - Wurth WL-SMCW 0603 Bright Green Chip LED
Public Made by Adomby adom
Wurth Elektronik 150060VS75000: WL-SMCW 0603 SMD chip LED, bright green (570 nm), water-clear lens, 2.0 V typ at 20 mA, 30 mA max.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
#!/usr/bin/env python3
"""Build the 150060VS75000 (Wurth WL-SMCW 0603) 3D model from the datasheet as an AP214 STEP.
No CAD kernel needed: every solid is a planar-faced prism (an extruded or lofted polygon), written
straight to STEP with colours (STYLED_ITEM per solid). Adom frame: Z-up, millimetres, seated on z = 0,
origin = footprint origin (pad-pattern centre), pin 1 (cathode) toward -X.
Dimensions: Wurth Elektronik datasheet 150060VS75000, revision 002.009 (2019-02-26), p.1 "Dimensions":
body 1.6 +/-0.1 x 0.8 +/-0.1, total height 0.7 +/-0.1, substrate 0.3 +/-0.1, lens 1.1 +/-0.1 long,
bottom terminals 0.7 typ wide with a 0.7 +/-0.1 gap, castellation R 0.175 typ, polarity marks.
Appearance (colours, wrap-around gold ends, green underside triangle): the Wurth WL-SMCW 0603 product
photo used on distributor listings. See provenance/3d-model.json.
usage: build_step.py OUT.step [--lens off|on] [--segs 12] [--no-die] [--no-marks] [--name NAME]
"""
import argparse, math
COL = {
"substrate": (0.90, 0.90, 0.88),
"terminal": (0.85, 0.68, 0.35),
"mark": (0.10, 0.65, 0.25),
"die": (0.15, 0.15, 0.17),
"lens_off": (0.86, 0.92, 0.93), # water-clear epoxy, unlit
"lens_on": (0.62, 0.95, 0.10), # 570 nm dominant (bright green), lit
}
L, W = 1.6, 0.8 # body length (x), width (y)
H_SUB = 0.30 # substrate top
H_TOT = 0.70 # lens top
LENS_L = 1.10 # lens length at its base
LENS_TOP_INSET = 0.02 # draft seen on p.1 side and end views
END = (L - LENS_L) / 2 # 0.25 mm end blocks (gold wrap-around terminals)
PAD_GAP = 0.70 # bottom terminal gap
PAD_W = 0.70 # bottom terminal width (typ)
R_CAST = 0.175
PLATE = 0.02 # bottom pad / plating thickness
TOP_PLATE = 0.01 # terminal stands proud of the substrate top
def end_block_outline(sign, segs):
"""CCW outline of one end block (x from 0.55 to 0.8 on the +X end), castellation notch at the end face."""
xi, xo = LENS_L / 2, L / 2
pts = [(xi, -W / 2), (xo, -W / 2), (xo, -R_CAST)]
for k in range(1, segs):
t = -math.pi / 2 + math.pi * k / segs
pts.append((xo - R_CAST * math.cos(t), R_CAST * math.sin(t)))
pts += [(xo, R_CAST), (xo, W / 2), (xi, W / 2)]
if sign < 0:
pts = [(-x, y) for x, y in pts][::-1]
return pts
def rect(x0, y0, x1, y1):
return [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
class Step:
def __init__(self):
self.lines = []
self.n = 0
self.vcache = {}
self.dcache = {}
def add(self, s):
self.n += 1
self.lines.append("#%d = %s;" % (self.n, s))
return "#%d" % self.n
def pt(self, p):
return self.add("CARTESIAN_POINT('',(%s))" % ",".join("%.6f" % c for c in p))
def dir(self, d):
k = tuple(round(c, 9) for c in d)
if k not in self.dcache:
self.dcache[k] = self.add("DIRECTION('',(%s))" % ",".join("%.9f" % c for c in d))
return self.dcache[k]
def sub(a, b): return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
def cross(a, b): return (a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0])
def norm(a):
m = math.sqrt(sum(c * c for c in a)); return tuple(c / m for c in a)
def newell(poly):
n = [0.0, 0.0, 0.0]
for i, p in enumerate(poly):
q = poly[(i + 1) % len(poly)]
n[0] += (p[1] - q[1]) * (p[2] + q[2]); n[1] += (p[2] - q[2]) * (p[0] + q[0]); n[2] += (p[0] - q[0]) * (p[1] + q[1])
return norm(n)
def solid(st, name, bottom, top, z0, z1):
"""Loft polygon `bottom` at z0 to polygon `top` at z1 (same vertex count, both CCW from +Z, planar sides)."""
nb = len(bottom)
V = [(x, y, z0) for x, y in bottom] + [(x, y, z1) for x, y in top]
faces = [list(range(nb))[::-1], [nb + i for i in range(nb)]]
for i in range(nb):
j = (i + 1) % nb
faces.append([i, j, nb + j, nb + i])
vp = {}
for i, p in enumerate(V):
vp[i] = st.add("VERTEX_POINT('',%s)" % st.pt(p))
edges = {}
def edge(a, b):
k = (min(a, b), max(a, b))
if k not in edges:
p, q = V[k[0]], V[k[1]]
d = sub(q, p); ln = math.sqrt(sum(c * c for c in d))
line = st.add("LINE('',%s,%s)" % (st.pt(p), st.add("VECTOR('',%s,%.6f)" % (st.dir(norm(d)), ln))))
edges[k] = st.add("EDGE_CURVE('',%s,%s,%s,.T.)" % (vp[k[0]], vp[k[1]], line))
return edges[k], (a, b) == (min(a, b), max(a, b))
fids = []
for f in faces:
poly = [V[i] for i in f]
n = newell(poly)
ref = norm(sub(poly[1], poly[0]))
ax = st.add("AXIS2_PLACEMENT_3D('',%s,%s,%s)" % (st.pt(poly[0]), st.dir(n), st.dir(ref)))
plane = st.add("PLANE('',%s)" % ax)
oes = []
for i in range(len(f)):
e, fwd = edge(f[i], f[(i + 1) % len(f)])
oes.append(st.add("ORIENTED_EDGE('',*,*,%s,%s)" % (e, ".T." if fwd else ".F.")))
loop = st.add("EDGE_LOOP('',(%s))" % ",".join(oes))
bound = st.add("FACE_OUTER_BOUND('',%s,.T.)" % loop)
fids.append(st.add("ADVANCED_FACE('',(%s),%s,.T.)" % (bound, plane)))
shell = st.add("CLOSED_SHELL('',(%s))" % ",".join(fids))
return st.add("MANIFOLD_SOLID_BREP('%s',%s)" % (name, shell))
def build(out, lens="off", segs=12, die=True, marks=True, name="150060VS75000"):
st = Step()
parts = [] # (solid id, colour key)
# substrate (white PCB) between the end blocks, bottom at the plating height
parts.append((solid(st, "substrate", rect(-LENS_L / 2, -W / 2, LENS_L / 2, W / 2), rect(-LENS_L / 2, -W / 2, LENS_L / 2, W / 2), PLATE, H_SUB), "substrate"))
for s, tag in ((-1, "K"), (1, "A")):
o = end_block_outline(s, segs)
parts.append((solid(st, "terminal_%s_end" % tag, o, o, 0.0, H_SUB + TOP_PLATE), "terminal"))
x0, x1 = sorted((s * PAD_GAP / 2, s * LENS_L / 2))
r = rect(x0, -PAD_W / 2, x1, PAD_W / 2)
parts.append((solid(st, "terminal_%s_bottom" % tag, r, r, 0.0, PLATE), "terminal"))
# lens: 1.1 x 0.8 at its base, slight draft to the top (p.1 side and end views)
lb = rect(-LENS_L / 2, -W / 2, LENS_L / 2, W / 2)
lt = rect(-LENS_L / 2 + LENS_TOP_INSET, -W / 2 + LENS_TOP_INSET, LENS_L / 2 - LENS_TOP_INSET, W / 2 - LENS_TOP_INSET)
parts.append((solid(st, "lens", lb, lt, H_SUB, H_TOT), "lens_" + lens))
if die:
d = rect(-0.12, -0.12, 0.12, 0.12)
parts.append((solid(st, "die", d, d, H_SUB, H_SUB + 0.10), "die"))
if marks:
# underside: triangle between the pads, tip toward pin 1 (cathode), p.1 bottom view
tri = [(-0.16, 0.0), (0.16, -0.175), (0.16, 0.175)]
parts.append((solid(st, "polarity_mark_bottom", tri, tri, PLATE * 0.4, PLATE), "mark"))
# top: corner wedge on the pin-1 end, p.1 top view ("Polarity Mark")
wedge = [(-L / 2, W / 2), (-LENS_L / 2, W / 2 - 0.10), (-LENS_L / 2, W / 2)]
parts.append((solid(st, "polarity_mark_top", wedge, wedge, H_SUB + TOP_PLATE, H_SUB + TOP_PLATE + 0.005), "mark"))
# product structure + units
ctx_app = st.add("APPLICATION_CONTEXT('automotive_design')")
st.add("APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,%s)" % ctx_app)
pctx = st.add("PRODUCT_CONTEXT('',%s,'mechanical')" % ctx_app)
prod = st.add("PRODUCT('%s','%s','',(%s))" % (name, name, pctx))
st.add("PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(%s))" % prod)
pdf = st.add("PRODUCT_DEFINITION_FORMATION('','',%s)" % prod)
pdctx = st.add("PRODUCT_DEFINITION_CONTEXT('part definition',%s,'design')" % ctx_app)
pd = st.add("PRODUCT_DEFINITION('design','',%s,%s)" % (pdf, pdctx))
pds = st.add("PRODUCT_DEFINITION_SHAPE('','',%s)" % pd)
lu = st.add("( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) )")
au = st.add("( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) )")
su = st.add("( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() )")
unc = st.add("UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),%s,'distance_accuracy_value','confusion accuracy')" % lu)
gctx = st.add("( GEOMETRIC_REPRESENTATION_CONTEXT(3) GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((%s)) GLOBAL_UNIT_ASSIGNED_CONTEXT((%s,%s,%s)) REPRESENTATION_CONTEXT('Context #1','3D Context with UNIT and UNCERTAINTY') )" % (unc, lu, au, su))
origin = st.add("AXIS2_PLACEMENT_3D('',%s,%s,%s)" % (st.pt((0, 0, 0)), st.dir((0, 0, 1)), st.dir((1, 0, 0))))
rep = st.add("ADVANCED_BREP_SHAPE_REPRESENTATION('',(%s),%s)" % (",".join([origin] + [p[0] for p in parts]), gctx))
st.add("SHAPE_DEFINITION_REPRESENTATION(%s,%s)" % (pds, rep))
styled = []
for sid, ck in parts:
r, g, b = COL[ck]
c = st.add("COLOUR_RGB('%s',%.4f,%.4f,%.4f)" % (ck, r, g, b))
fa = st.add("FILL_AREA_STYLE('',(%s))" % st.add("FILL_AREA_STYLE_COLOUR('',%s)" % c))
sss = st.add("SURFACE_SIDE_STYLE('',(%s))" % st.add("SURFACE_STYLE_FILL_AREA(%s)" % fa))
psa = st.add("PRESENTATION_STYLE_ASSIGNMENT((%s))" % st.add("SURFACE_STYLE_USAGE(.BOTH.,%s)" % sss))
styled.append(st.add("STYLED_ITEM('color',(%s),%s)" % (psa, sid)))
st.add("MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(%s),%s)" % (",".join(styled), gctx))
hdr = ["ISO-10303-21;", "HEADER;",
"FILE_DESCRIPTION(('%s, Wurth Elektronik WL-SMCW 0603 chip LED, built from datasheet rev 002.009 p.1'),'2;1');" % name,
"FILE_NAME('%s','2026-10-21T00:00:00',('Adom'),('Adom'),'adom build_step.py 1.0','adom build_step.py 1.0','');" % out.split('/')[-1],
"FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));", "ENDSEC;", "DATA;"]
open(out, "w").write("\n".join(hdr + st.lines + ["ENDSEC;", "END-ISO-10303-21;", ""]))
return len(parts)
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("out"); ap.add_argument("--lens", default="off", choices=["off", "on"])
ap.add_argument("--segs", type=int, default=12); ap.add_argument("--no-die", action="store_true")
ap.add_argument("--no-marks", action="store_true"); ap.add_argument("--name", default="150060VS75000")
a = ap.parse_args()
n = build(a.out, a.lens, a.segs, not a.no_die, not a.no_marks, a.name)
print("OK: %d solids -> %s" % (n, a.out))