by adom
0603 SMD Green LED · 3.2 V drop · 25 mA max
master
John Lauer
Datasheet-true STEP height (0.55 mm), side MPN mark re-applied; GLBs, hero rebuilt without Z stretch
2e9a25d
20d ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
#!/usr/bin/env python3
"""Pick the face region a SIDE laser-etch mark must stay inside (Z-up STEP, already turned so the chosen side
faces +Z). Candidates: planar faces lying flat at the model's top Z (the turned side's outermost plane). Of the
candidates with at least a quarter of the largest candidate's area, take the one furthest along --up (the
part's original +Z expressed in this frame): the moulded body/lens band above a PCB substrate or the leads,
never the seam between them. Prints JSON: region bbox, z, face colour (linear RGB) and the candidate list.
Usage: side_region.py in.step --up ux,uy,uz"""
import sys, json, argparse
from OCP.STEPCAFControl import STEPCAFControl_Reader
from OCP.TDocStd import TDocStd_Document
from OCP.TCollection import TCollection_ExtendedString
from OCP.XCAFDoc import XCAFDoc_DocumentTool, XCAFDoc_ColorType
from OCP.TDF import TDF_ChildIterator, TDF_Label
from OCP.TopLoc import TopLoc_Location
from OCP.TopExp import TopExp_Explorer
from OCP.TopAbs import TopAbs_FACE
from OCP.Bnd import Bnd_Box
from OCP.BRepBndLib import BRepBndLib
from OCP.GProp import GProp_GProps
from OCP.BRepGProp import BRepGProp
from OCP.Quantity import Quantity_Color
ap = argparse.ArgumentParser(); ap.add_argument('src'); ap.add_argument('--up', required=True); ap.add_argument('--pick', default='high', choices=['high', 'low']); a = ap.parse_args()
up = [float(v) for v in a.up.split(',')]
doc = TDocStd_Document(TCollection_ExtendedString("d"))
r = STEPCAFControl_Reader(); r.SetColorMode(True); r.SetNameMode(True); r.ReadFile(a.src); r.Transfer(doc)
st = XCAFDoc_DocumentTool.ShapeTool_s(doc.Main()); ct = XCAFDoc_DocumentTool.ColorTool_s(doc.Main())
faces = []
def colour(lab, f):
c = Quantity_Color()
for t in (XCAFDoc_ColorType.XCAFDoc_ColorSurf, XCAFDoc_ColorType.XCAFDoc_ColorGen):
if ct.GetColor(f, t, c): return [c.Red(), c.Green(), c.Blue()]
for t in (XCAFDoc_ColorType.XCAFDoc_ColorSurf, XCAFDoc_ColorType.XCAFDoc_ColorGen):
if ct.GetColor_s(lab, t, c): return [c.Red(), c.Green(), c.Blue()]
return None
def walk(l, loc):
if st.IsReference_s(l):
ref = TDF_Label(); st.GetReferredShape_s(l, ref); return walk(ref, loc.Multiplied(st.GetLocation_s(l)))
if st.IsAssembly_s(l):
it = TDF_ChildIterator(l, False)
while it.More(): c = it.Value(); it.Next(); walk(c, loc)
return
ex = TopExp_Explorer(st.GetShape_s(l), TopAbs_FACE)
while ex.More():
f = ex.Current(); ex.Next(); fw = f.Moved(loc)
b = Bnd_Box(); BRepBndLib.Add_s(fw, b); mn, mx = b.CornerMin(), b.CornerMax()
g = GProp_GProps(); BRepGProp.SurfaceProperties_s(fw, g)
faces.append(dict(bbox=[mn.X(), mn.Y(), mn.Z(), mx.X(), mx.Y(), mx.Z()], area=g.Mass(), rgb=colour(l, f)))
it = TDF_ChildIterator(st.Label(), False)
while it.More():
l = it.Value(); it.Next()
if st.IsFree_s(l) and st.IsTopLevel(l): walk(l, TopLoc_Location())
top = max(f['bbox'][5] for f in faces)
cand = [f for f in faces if f['bbox'][5] - f['bbox'][2] < 2e-3 and top - f['bbox'][5] < 2e-3 and f['area'] > 1e-6]
big = max(f['area'] for f in cand)
cand = [f for f in cand if f['area'] >= 0.25 * big]
cen = lambda f: [(f['bbox'][0] + f['bbox'][3]) / 2, (f['bbox'][1] + f['bbox'][4]) / 2, (f['bbox'][2] + f['bbox'][5]) / 2]
pick = (max if a.pick == 'high' else min)(cand, key=lambda f: sum(c * u for c, u in zip(cen(f), up))) # --pick low: the body band under a window that runs the full length (WS2812B-2020)
print(json.dumps(dict(region=[pick['bbox'][0], pick['bbox'][1], pick['bbox'][3], pick['bbox'][4]], z=top, area=pick['area'], rgb=pick['rgb'],
candidates=[dict(region=[round(f['bbox'][0], 4), round(f['bbox'][1], 4), round(f['bbox'][3], 4), round(f['bbox'][4], 4)], area=round(f['area'], 4)) for f in cand])))