From e3d8c3a063e2e1e10dd65453db6204d85c4294f8 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 19 Jun 2022 21:02:47 +0200 Subject: protoboard: add mounting holes --- gerbolyze/protoboard.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gerbolyze/protoboard.py b/gerbolyze/protoboard.py index b2e9d95..f7603ad 100644 --- a/gerbolyze/protoboard.py +++ b/gerbolyze/protoboard.py @@ -19,11 +19,11 @@ class Pattern: {svg_str(self.content)} ''') -def make_rect(svg_id, x, y, w, h): +def make_rect(svg_id, x, y, w, h, clip=''): #import random #c = random.randint(0, 2**24) #return f'' - return f'' + return f'' class CirclePattern(Pattern): def __init__(self, d, w, h=None): @@ -92,22 +92,22 @@ class THTProtoAreaCircles(PatternProtoArea): self.plated = plated self.sides = sides - def generate(self, x, y, w, h, center=True): + def generate(self, x, y, w, h, center=True, clip=''): x, y, w, h = self.fit_rect(x, y, w, h, center) drill = 'plated drill' if self.plated else 'nonplated drill' pad_id = str(uuid.uuid4()) drill_id = str(uuid.uuid4()) - d = { drill: make_rect(drill_id, x, y, w, h), + d = { drill: make_rect(drill_id, x, y, w, h, clip), 'defs': [ self.pad_pattern.svg_def(pad_id, x, y), self.drill_pattern.svg_def(drill_id, x, y)]} if self.sides in ('top', 'both'): - d['top copper'] = make_rect(pad_id, x, y, w, h) + d['top copper'] = make_rect(pad_id, x, y, w, h, clip) if self.sides in ('bottom', 'both'): - d['bottom copper'] = make_rect(pad_id, x, y, w, h) + d['bottom copper'] = make_rect(pad_id, x, y, w, h, clip) return d @@ -129,20 +129,31 @@ LAYERS = [ ] class ProtoBoard: - def __init__(self, defs, expr): + def __init__(self, defs, expr, mounting_holes=None): self.defs = eval_defs(defs) self.layout = parse_layout(expr) + self.mounting_holes = mounting_holes def generate(self, w, h): svg_defs = [] + clip = '' + + if self.mounting_holes: + d, o, k = self.mounting_holes # diameter, offset from edge, keepout to proto area + q = o + k + clip_d = f'M 0 {q} L {q} {q} L {q} 0 L {w-q} 0 L {w-q} {q} L {w} {q} L {w} {h-q} L {w-q} {h-q} L {w-q} {h} L {q} {h} L {q} {h-q} L 0 {h-q} Z' + svg_defs.append(f'') + clip = 'clip-path="url(#hole-clip)"' out = {l: [] for l in LAYERS} - for layer_dict in self.layout.generate(0, 0, w, h, self.defs): + for layer_dict in self.layout.generate(0, 0, w, h, self.defs, clip): for l in LAYERS: if l in layer_dict: out[l].append(layer_dict[l]) svg_defs += layer_dict.get('defs', []) + out['outline'] = f'' + layers = [ make_layer(l, out[l]) for l in LAYERS ] return svg_template.format(w=w, h=h, defs='\n'.join(svg_defs), layers='\n'.join(layers)) @@ -176,13 +187,13 @@ class PropLayout: if len(content) != len(proportions): raise ValueError('proportions and content must have same length') - def generate(self, x, y, w, h, defs): + def generate(self, x, y, w, h, defs, clip=''): for (c_x, c_y, c_w, c_h), child in self.layout_2d(x, y, w, h): if isinstance(child, str): - yield defs[child].generate(c_x, c_y, c_w, c_h, defs) + yield defs[child].generate(c_x, c_y, c_w, c_h, defs, clip) else: - yield from child.generate(c_x, c_y, c_w, c_h, defs) + yield from child.generate(c_x, c_y, c_w, c_h, defs, clip) def layout_2d(self, x, y, w, h): for l, child in zip(self.layout(w if self.direction == 'h' else h), self.content): @@ -341,5 +352,5 @@ if __name__ == '__main__': # print(line, '->', eval_defs(line)) # print() # print('===== Proto board =====') - b = ProtoBoard('tht = THTCircles()', 'tht@1in|(tht@2/tht@1)') + b = ProtoBoard('tht = THTCircles()', 'tht@1in|(tht@2/tht@1)', mounting_holes=(3.2, 5.0, 5.0)) print(b.generate(80, 60)) -- cgit