From 6f8d4bb999e780f38776938599dab4b9b7ed8403 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 7 Jul 2024 17:08:06 +0200 Subject: protoboard: Finish up sides of Alio better --- gerbonara/cad/protoboard.py | 42 ++++++++++++++++++--------- gerbonara/cad/protoserve.py | 2 ++ gerbonara/cad/protoserve_data/protoserve.html | 6 ++++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/gerbonara/cad/protoboard.py b/gerbonara/cad/protoboard.py index 5c424ef..7e43945 100644 --- a/gerbonara/cad/protoboard.py +++ b/gerbonara/cad/protoboard.py @@ -49,7 +49,7 @@ class ProtoBoard(Board): bbox = ((self.margin, self.margin), (self.w-self.margin, self.h-self.margin)) bbox = unit.convert_bounds_from(self.unit, bbox) hole_bboxes = [hole.bounding_box(unit) for hole in self.mounting_holes] - for obj in self.content.generate(bbox, (True, True, True, True), self.keepouts, self.margin, unit): + for obj in self.content.generate(bbox, (True, True, True, True), self.keepouts, self.margin, True, unit): if isinstance(obj, Text): # It's okay for the text to go into the mounting hole keepouts, we just don't want it to overlap with # the actual mounting holes. @@ -81,7 +81,7 @@ class PropLayout: else: return max(obj.increment_y() for obj in self.content) - def generate(self, bbox, border_text, keepouts, text_margin, unit=MM): + def generate(self, bbox, border_text, keepouts, text_margin, two_sided, unit=MM): for i, (bbox, child) in enumerate(self.layout_2d(bbox, unit)): first = bool(i == 0) last = bool(i == len(self.content)-1) @@ -90,7 +90,7 @@ class PropLayout: border_text[1] and (last or self.direction == 'v'), border_text[2] and (first or self.direction == 'h'), border_text[3] and (first or self.direction == 'v'), - ), keepouts, text_margin, unit) + ), keepouts, text_margin, two_sided, unit) def fit_size(self, w, h, unit=MM): widths = [] @@ -207,9 +207,9 @@ class TwoSideLayout: return w1, h1 return max(w1, w2), max(h1, h2) - def generate(self, bbox, border_text, keepouts, text_margin, unit=MM): - yield from self.top.generate(bbox, border_text, keepouts, text_margin, unit) - for obj in self.bottom.generate(bbox, border_text, keepouts, text_margin, unit): + def generate(self, bbox, border_text, keepouts, text_margin, two_sided, unit=MM): + yield from self.top.generate(bbox, border_text, keepouts, text_margin, False, unit) + for obj in self.bottom.generate(bbox, border_text, keepouts, text_margin, False, unit): obj.flip = not obj.flip yield obj @@ -289,7 +289,7 @@ class PatternProtoArea: y = y + (h-h_fit)/2 return (x, y), (x+w_fit, y+h_fit) - def generate(self, bbox, border_text, keepouts, text_margin, unit=MM): + def generate(self, bbox, border_text, keepouts, text_margin, two_sided, unit=MM): (x, y), (w, h) = bbox w, h = w-x, h-y @@ -326,13 +326,13 @@ class PatternProtoArea: if border_text[3]: t_x = x + off_x - text_off_x yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'right', 'middle', unit=self.unit) - if not self.single_sided: + if two_sided: yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'right', 'middle', flip=True, unit=self.unit) if border_text[1]: t_x = x + w - off_x + text_off_x yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'left', 'middle', unit=self.unit) - if not self.single_sided: + if two_sided: yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'left', 'middle', flip=True, unit=self.unit) for i, lno_i in zip(range(n_x), self.number_x_gen()): @@ -346,13 +346,13 @@ class PatternProtoArea: if border_text[2]: t_y = y + off_y - text_off_y yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'top', unit=self.unit) - if not self.single_sided: + if two_sided: yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'top', flip=True, unit=self.unit) if border_text[0]: t_y = y + h - off_y + text_off_y yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'bottom', unit=self.unit) - if not self.single_sided: + if two_sided: yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'bottom', flip=True, unit=self.unit) @@ -394,6 +394,8 @@ class PatternProtoArea: px = self.unit(off_x + x, unit) + (i + 0.5) * self.pitch_x py = self.unit(off_y + y, unit) + (j + 0.5) * self.pitch_y yield Pad(px, py, pad_stack=obj, unit=self.unit) + if two_sided and self.single_sided: + yield Pad(px, py, pad_stack=obj, flip=True, unit=self.unit) continue elif hasattr(self.obj, 'inst'): @@ -407,6 +409,11 @@ class PatternProtoArea: inst.y = inst.unit(off_y + y, unit) + (j + 0.5) * inst.unit(self.pitch_y, self.unit) yield inst + if two_sided and self.single_sided: + inst = copy(inst) + inst.flip = not inst.flip + yield inst + @property def single_sided(self): return self.obj.single_sided @@ -425,11 +432,13 @@ class EmptyProtoArea: def fit_size(self, w, h, unit=MM): return w, h - def generate(self, bbox, border_text, keepouts, text_margin, unit=MM): + def generate(self, bbox, border_text, keepouts, text_margin, two_sided, unit=MM): if self.copper_fill: (min_x, min_y), (max_x, max_y) = bbox group = ObjectGroup(0, 0, top_copper=[Region([(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_x, max_y)], unit=unit, polarity_dark=True)]) + if two_sided: + group.bottom_copper = group.top_copper group.bounding_box = lambda *args, **kwargs: None yield group @@ -829,16 +838,23 @@ class AlioCell(Positioned): corner_radius, # 4 rotation+90), unit=MM) # 5 + end_pad = RectangleAperture(self.link_trace_width, self.pitch - 2*self.clearance - self.link_pad_width, unit=self.unit) + end_pad_90 = end_pad.rotated(math.pi/2) + # all layers are identical here for side, use in (('top', 'copper'), ('top', 'mask'), ('bottom', 'copper'), ('bottom', 'mask')): if side == 'top': layer_stack[side, use].objects.insert(0, xf(Flash(0, 0, aperture=main_ap, unit=self.unit))) if not self.border_s and not self.border_e: layer_stack[side, use].objects.append(xf(Flash(self.pitch/2, self.pitch/2, aperture=alio_dark, unit=self.unit))) + if self.border_e and not self.border_s: + layer_stack[side, use].objects.append(xf(Flash(0, self.pitch/2, aperture=end_pad_90, unit=self.unit))) else: layer_stack[side, use].objects.insert(0, xf(Flash(0, 0, aperture=main_ap_90, unit=self.unit))) - if not self.border_e and not self.border_n: + if not self.border_e and not self.border_s: layer_stack[side, use].objects.append(xf(Flash(self.pitch/2, self.pitch/2, aperture=alio_dark_90, unit=self.unit))) + if self.border_s and not self.border_e: + layer_stack[side, use].objects.append(xf(Flash(self.pitch/2, 0, aperture=end_pad, unit=self.unit))) layer_stack.drill_pth.append(Flash(x, y, aperture=main_drill, unit=self.unit)) if not (self.border_e or self.border_s): diff --git a/gerbonara/cad/protoserve.py b/gerbonara/cad/protoserve.py index c3224e3..a2aa7d6 100644 --- a/gerbonara/cad/protoserve.py +++ b/gerbonara/cad/protoserve.py @@ -141,6 +141,7 @@ def to_board(obj): w = float(obj.get('width', unit(100, MM))) h = float(obj.get('height', unit(80, MM))) corner_radius = float(obj.get('round_corners', {}).get('radius', unit(1.5, MM))) + margin = float(obj.get('margin', unit(2.0, MM))) holes = obj.get('mounting_holes', {}) mounting_hole_dia = float(holes.get('diameter', unit(3.2, MM))) mounting_hole_offset = float(holes.get('offset', unit(5, MM))) @@ -157,6 +158,7 @@ def to_board(obj): corner_radius=corner_radius, mounting_hole_dia=mounting_hole_dia, mounting_hole_offset=mounting_hole_offset, + margin=margin, unit=unit) @app.route('/preview_.svg', methods=['POST']) diff --git a/gerbonara/cad/protoserve_data/protoserve.html b/gerbonara/cad/protoserve_data/protoserve.html index 7a11626..e1d00b3 100644 --- a/gerbonara/cad/protoserve_data/protoserve.html +++ b/gerbonara/cad/protoserve_data/protoserve.html @@ -283,6 +283,12 @@ input[type="text"]:focus:valid { inch + +