From 0a059353d707df91f71bdb6be976546089e01488 Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 5 Apr 2023 18:56:16 +0200 Subject: Improve protoboard row/column numbering --- gerbonara/cad/protoboard.py | 122 ++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 51 deletions(-) diff --git a/gerbonara/cad/protoboard.py b/gerbonara/cad/protoboard.py index 4a66b67..81b31dd 100644 --- a/gerbonara/cad/protoboard.py +++ b/gerbonara/cad/protoboard.py @@ -38,7 +38,7 @@ class ProtoBoard(Board): def generate(self, unit=MM): bbox = ((self.margin, self.margin), (self.w-self.margin, self.h-self.margin)) bbox = unit.convert_bounds_from(self.unit, bbox) - for obj in self.content.generate(bbox, unit): + for obj in self.content.generate(bbox, (True, True, True, True), unit): self.add(obj, keepout_errors='skip') @@ -52,9 +52,16 @@ class PropLayout: if len(content) != len(proportions): raise ValueError('proportions and content must have same length') - def generate(self, bbox, unit=MM): - for bbox, child in self.layout_2d(bbox, unit): - yield from child.generate(bbox, unit) + def generate(self, bbox, border_text, unit=MM): + for i, (bbox, child) in enumerate(self.layout_2d(bbox, unit)): + first = bool(i == 0) + last = bool(i == len(self.content)-1) + yield from child.generate(bbox, ( + border_text[0] and (first or self.direction == 'h'), + border_text[1] and (last or self.direction == 'v'), + border_text[2] and (last or self.direction == 'h'), + border_text[3] and (first or self.direction == 'v'), + ), unit) def fit_size(self, w, h, unit=MM): widths = [] @@ -132,9 +139,9 @@ class TwoSideLayout: return w1, h1 return max(w1, w2), max(h1, h2) - def generate(self, bbox, unit=MM): - yield from self.top.generate(bbox, unit) - for obj in self.bottom.generate(bbox, unit): + def generate(self, bbox, border_text, unit=MM): + yield from self.top.generate(bbox, border_text, unit) + for obj in self.bottom.generate(bbox, border_text, unit): obj.side = 'bottom' yield obj @@ -158,16 +165,21 @@ def alphabetic(case='upper'): nonlocal index for i in itertools.count(): - out = '' - mod = 26 + if i<26: + yield index[i] + continue - while i > 0: - rem = i % mod - i //= mod - mod *= 26 - out = index[rem] + out + i -= 26 + if i<26*26: + yield index[i//26] + index[i%26] + continue - yield out + i -= 26*26 + if i<26*26*26: + yield index[i//(26*26)] + index[(i//26)%26] + index[i%26] + + else: + raise ValueError('row/column index out of range') return gen @@ -179,10 +191,10 @@ class PatternProtoArea: self.obj = obj self.unit = unit self.numbers = numbers - self.font_size = font_size or unit(1.5, MM) + self.font_size = font_size or unit(1.0, MM) self.font_stroke = font_stroke or unit(0.2, MM) self.interval_x = interval_x - self.interval_y = interval_y or (1 if self.pitch_y > self.font_size*1.2 else 5) + self.interval_y = interval_y or (1 if MM(self.pitch_y, unit) >= 2.0 else 5) self.number_x_gen, self.number_y_gen = number_x_gen, number_y_gen def fit_size(self, w, h, unit=MM): @@ -201,45 +213,47 @@ class PatternProtoArea: y = y + (h-h_fit)/2 return (x, y), (x+w_fit, y+h_fit) - def generate(self, bbox, unit=MM): + def generate(self, bbox, border_text, unit=MM): (x, y), (w, h) = bbox w, h = w-x, h-y - if self.numbers: - x += self.font_size - y += self.font_size - w -= 2*self.font_size - h -= 2*self.font_size - n_x = int(w//unit(self.pitch_x, self.unit)) n_y = int(h//unit(self.pitch_y, self.unit)) off_x = (w % unit(self.pitch_x, self.unit)) / 2 off_y = (h % unit(self.pitch_y, self.unit)) / 2 if self.numbers: - for i, lno_i in zip(range(n_y), self.number_x_gen()): - if (i+1) % self.interval_y == 0: - t_y = off_y + y + (i + 0.5) * self.pitch_y - - t_x = x - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'right', 'middle', unit=self.unit) - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'right', 'middle', side='bottom', unit=self.unit) - - t_x = x + w - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'left', 'middle', unit=self.unit) - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'left', 'middle', side='bottom', unit=self.unit) - - for i, lno_i in zip(range(n_x), self.number_y_gen()): - if (i+1) % self.interval_x == 0: + for i, lno_i in list(zip(range(n_y), self.number_y_gen())): + if i == 0 or i == n_y - 1 or (i+1) % self.interval_y == 0: + t_y = off_y + y + (n_y - 1 - i + 0.5) * self.pitch_y + + if border_text[3]: + t_x = x + 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: + yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'right', 'middle', side='bottom', unit=self.unit) + + if border_text[1]: + t_x = x + w - 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: + yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'left', 'middle', side='bottom', unit=self.unit) + + for i, lno_i in zip(range(n_x), self.number_x_gen()): + if i == 0 or i == n_x - 1 or (i+1) % self.interval_x == 0: t_x = off_x + x + (i + 0.5) * self.pitch_x - t_y = y - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'top', unit=self.unit) - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'top', side='bottom', unit=self.unit) + if border_text[2]: + t_y = y + 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: + yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'top', side='bottom', unit=self.unit) - t_y = y + h - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'bottom', unit=self.unit) - yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'bottom', side='bottom', unit=self.unit) + if border_text[0]: + t_y = y + h - 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: + yield Text(t_x, t_y, lno_i, self.font_size, self.font_stroke, 'center', 'bottom', side='bottom', unit=self.unit) for i in range(n_x): @@ -267,7 +281,7 @@ class EmptyProtoArea: def fit_size(self, w, h, unit=MM): return w, h - def generate(self, bbox, unit=MM): + def generate(self, bbox, border_text, unit=MM): if self.copper: (min_x, min_y), (max_x, max_y) = bbox yield ObjectGroup(top_copper=[Region([(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_x, max_y)], @@ -477,17 +491,17 @@ def eval_value(value, total_length=None): def _demo(): - #pattern1 = PatternProtoArea(2.54, obj=THTPad.circle(0, 0, 0.9, 1.8, paste=False)) - #pattern2 = PatternProtoArea(1.2, 2.0, obj=SMDPad.rect(0, 0, 1.0, 1.8, paste=False)) - #pattern3 = PatternProtoArea(2.54, 1.27, obj=SMDPad.rect(0, 0, 2.3, 1.0, paste=False)) - #stack = TwoSideLayout(pattern2, pattern3) - #layout = PropLayout([pattern1, stack], 'h', [0.5, 0.5]) + pattern1 = PatternProtoArea(2.54, obj=THTPad.circle(0, 0, 0.9, 1.8, paste=False)) + pattern2 = PatternProtoArea(1.2, 2.0, obj=SMDPad.rect(0, 0, 1.0, 1.8, paste=False)) + pattern3 = PatternProtoArea(2.54, 1.27, obj=SMDPad.rect(0, 0, 2.3, 1.0, paste=False)) + stack = TwoSideLayout(pattern2, pattern3) + pattern = PropLayout([pattern1, stack], 'h', [0.5, 0.5]) #pattern = PatternProtoArea(2.54, obj=ManhattanPads(2.54)) #pattern = PatternProtoArea(2.54, obj=PoweredProto()) #pattern = PatternProtoArea(2.54, obj=RFGroundProto()) #pattern = PatternProtoArea(2.54*1.5, obj=THTFlowerProto()) #pattern = PatternProtoArea(2.54, obj=THTPad.circle(0, 0, 0.9, 1.8, paste=False)) - pattern = PatternProtoArea(2.54, obj=PoweredProto()) + #pattern = PatternProtoArea(2.54, obj=PoweredProto()) pb = ProtoBoard(100, 80, pattern, mounting_hole_dia=3.2, mounting_hole_offset=5) print(pb.pretty_svg()) pb.layer_stack().save_to_directory('/tmp/testdir') @@ -495,3 +509,9 @@ def _demo(): if __name__ == '__main__': _demo() + #cnt = alphabetic()() + #for _ in range(32): + # for _ in range(26): + # print(f'{next(cnt):>2}', end=' ', file=sys.stderr) + # print(file=sys.stderr) + -- cgit