Integrate Measured ESP32 PCB Geometry
- Add measured F.Fab bounds and USB mouth markers - Add guarded preservation and regression validation - Refresh review exports and remove draft presentation labels
This commit is contained in:
@@ -10,6 +10,7 @@ import uuid
|
||||
import pcbnew as p
|
||||
from shapely.geometry import LineString, Point, box
|
||||
from shapely.ops import unary_union, polygonize
|
||||
from update_u1_graphics import verify
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
PCB = ROOT / "serial-carrier.kicad_pcb"
|
||||
@@ -38,6 +39,7 @@ def outline_lines(shape):
|
||||
|
||||
|
||||
def add_outlines(board):
|
||||
verify(board)
|
||||
owned = {str(uuid.uuid5(NS, str(i))) for i in range(4096)}
|
||||
for drawing in list(board.GetDrawings()):
|
||||
if drawing.m_Uuid.AsString() in owned:
|
||||
@@ -82,8 +84,11 @@ def add_outlines(board):
|
||||
board.Add(shape)
|
||||
count+=1
|
||||
|
||||
def line(a,b):
|
||||
clipped=LineString([a,b]).intersection(silk_area).difference(blocked)
|
||||
def line(a,b,width=WIDTH):
|
||||
extra = max(0, (width-WIDTH)/2)
|
||||
area = silk_area.buffer(-extra) if extra else silk_area
|
||||
obstacles = blocked.buffer(extra) if extra else blocked
|
||||
clipped=LineString([a,b]).intersection(area).difference(obstacles)
|
||||
pieces=list(clipped.geoms) if hasattr(clipped,"geoms") else [clipped]
|
||||
for piece in pieces:
|
||||
if piece.geom_type!="LineString" or piece.length < 0.25:
|
||||
@@ -91,7 +96,7 @@ def add_outlines(board):
|
||||
shape=p.PCB_SHAPE(board)
|
||||
shape.SetShape(p.SHAPE_T_SEGMENT)
|
||||
shape.SetStart(vec(piece.coords[0])); shape.SetEnd(vec(piece.coords[-1]))
|
||||
shape.SetWidth(p.FromMM(WIDTH))
|
||||
shape.SetWidth(p.FromMM(width))
|
||||
add(shape)
|
||||
|
||||
for ref in ("DS1","U2"):
|
||||
@@ -137,22 +142,19 @@ def add_outlines(board):
|
||||
distance+=1.3
|
||||
else:
|
||||
line(edge.coords[0],edge.coords[-1])
|
||||
# These are pad-row guides, not inferred socket/body or ESP32 PCB dimensions.
|
||||
fp=footprints["U1"]
|
||||
assert fp.GetOrientationDegrees()==0, "Review guide construction for rotated U1"
|
||||
pads={pad.GetNumber():xy(pad.GetPosition()) for pad in fp.Pads()}
|
||||
for first,last in (("1","22"),("23","44")):
|
||||
x,ytop=pads[first]; _,ybottom=pads[last]
|
||||
corners=[(x-1.2,ytop-1.2),(x+1.2,ytop-1.2),(x+1.2,ybottom+1.2),(x-1.2,ybottom+1.2)]
|
||||
for a,b in zip(corners,corners[1:]+corners[:1]):
|
||||
line(a,b)
|
||||
label=p.PCB_TEXT(board)
|
||||
label.SetText("HEADER GUIDES")
|
||||
a,b=pads["1"],pads["23"]
|
||||
label.SetPosition(vec(((a[0]+b[0])/2,a[1]+28)))
|
||||
label.SetTextSize(p.VECTOR2I(p.FromMM(0.85),p.FromMM(0.85)))
|
||||
label.SetTextThickness(p.FromMM(0.12))
|
||||
add(label)
|
||||
# Union removes the shared body/antenna edge duplication. Mouth spans replace
|
||||
# the coincident bottom-edge strokes, with their measured library line weight;
|
||||
# this marks width only, without inventing connector depth or an RF keepout.
|
||||
sources=[g for g in footprints["U1"].GraphicalItems()
|
||||
if isinstance(g,p.PCB_SHAPE) and g.GetLayer()==p.F_Fab]
|
||||
mouths=[g for g in sources if g.GetShape()==p.SHAPE_T_SEGMENT]
|
||||
mouth_lines=unary_union([edge for g in mouths for edge in outline_lines(g)])
|
||||
perimeter=unary_union([edge for g in sources if g.GetShape()==p.SHAPE_T_RECT
|
||||
for edge in outline_lines(g)]).difference(mouth_lines)
|
||||
for edge in perimeter.geoms:
|
||||
line(edge.coords[0],edge.coords[-1])
|
||||
for mouth in mouths:
|
||||
line(xy(mouth.GetStart()),xy(mouth.GetEnd()),p.ToMM(mouth.GetWidth()))
|
||||
return count
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user