From 958b47ab471053798ff55194c4aff4cf52f7602a Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 26 Apr 2023 23:37:38 +0200 Subject: Speed up protoboard generation --- gerbonara/apertures.py | 5 ++++- gerbonara/cad/kicad/footprints.py | 17 ++++++++++++++++- gerbonara/cad/primitives.py | 20 +++++++++++++++++++- gerbonara/cad/protoboard.py | 2 +- gerbonara/cad/protoserve_data/protoserve.html | 4 +++- gerbonara/graphic_objects.py | 13 ++++++------- gerbonara/utils.py | 5 +++++ 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/gerbonara/apertures.py b/gerbonara/apertures.py index feccb7f..73a6e9c 100644 --- a/gerbonara/apertures.py +++ b/gerbonara/apertures.py @@ -20,7 +20,7 @@ import math from dataclasses import dataclass, replace, field, fields, InitVar from .aperture_macros.parse import GenericMacros -from .utils import MM, Inch +from .utils import MM, Inch, sum_bounds from . import graphic_primitives as gp @@ -118,6 +118,9 @@ class Aperture: """ return self._primitives(x, y, unit, polarity_dark) + def bounding_box(self, unit=None): + return sum_bounds((prim.bounding_box() for prim in self.flash(0, 0, unit, True))) + def equivalent_width(self, unit=None): """ Get the width of a line interpolated using this aperture in the given :py:class:`~.LengthUnit`. diff --git a/gerbonara/cad/kicad/footprints.py b/gerbonara/cad/kicad/footprints.py index 86ba254..428d5ea 100644 --- a/gerbonara/cad/kicad/footprints.py +++ b/gerbonara/cad/kicad/footprints.py @@ -23,8 +23,9 @@ from ..primitives import Positioned from ... import graphic_primitives as gp from ... import graphic_objects as go from ... import apertures as ap +from ...layers import LayerStack from ...newstroke import Newstroke -from ...utils import MM, rotate_point +from ...utils import MM, rotate_point, offset_bounds, sum_bounds from ...aperture_macros.parse import GenericMacros, ApertureMacro from ...aperture_macros import primitive as amp @@ -591,6 +592,7 @@ class Footprint: models: List(Model) = field(default_factory=list) _ : SEXP_END = None original_filename: str = None + _bounding_box: tuple = None @property def version(self): @@ -701,6 +703,16 @@ class Footprint: layer_stack.drill_npth.append(fe) else: layer_stack.drill_pth.append(fe) + + def bounding_box(self, unit=MM): + if not self._bounding_box: + stack = LayerStack() + layer_map = {kc_id: gn_id for kc_id, gn_id in LAYER_MAP_K2G.items() if gn_id in stack} + self.render(stack, layer_map, x=0, y=0, rotation=0, side='top', text=False, variables={}) + self._bounding_box = stack.bounding_box(unit) + return self._bounding_box + + LAYER_MAP_K2G = { 'F.Cu': ('top', 'copper'), @@ -752,6 +764,9 @@ class FootprintInstance(Positioned): side=self.side, text=(not self.hide_text), variables=variables) + + def bounding_box(self, unit=MM): + return offset_bounds(self.sexp.bounding_box(unit), unit(self.x, self.unit), unit(self.y, self.unit)) if __name__ == '__main__': import sys diff --git a/gerbonara/cad/primitives.py b/gerbonara/cad/primitives.py index 80373c6..ce69bae 100644 --- a/gerbonara/cad/primitives.py +++ b/gerbonara/cad/primitives.py @@ -7,7 +7,7 @@ from itertools import zip_longest, chain from dataclasses import dataclass, field, KW_ONLY from collections import defaultdict -from ..utils import LengthUnit, MM, rotate_point, svg_arc, sum_bounds, bbox_intersect, Tag +from ..utils import LengthUnit, MM, rotate_point, svg_arc, sum_bounds, bbox_intersect, Tag, offset_bounds from ..layers import LayerStack from ..graphic_objects import Line, Arc, Flash from ..apertures import Aperture, CircleAperture, ObroundAperture, RectangleAperture, ExcellonTool @@ -215,6 +215,24 @@ class ObjectGroup(Positioned): fe.offset(x, y, self.unit) target.objects.append(fe) + def bounding_box(self, unit=MM): + if math.isclose(self.rotation, 0, abs_tol=1e-3): + return offset_bounds(sum_bounds((obj.bounding_box(unit=unit) for obj in chain( + self.top_copper, + self.top_mask, + self.top_silk, + self.top_paste, + self.bottom_copper, + self.bottom_mask, + self.bottom_silk, + self.bottom_paste, + self.drill_npth, + self.drill_pth, + self.objects, + ))), unit(self.x, self.unit), unit(self.y, self.unit)) + else: + return super().bounding_box(unit) + @property def single_sided(self): any_top = self.top_copper or self.top_mask or self.top_paste or self.top_silk diff --git a/gerbonara/cad/protoboard.py b/gerbonara/cad/protoboard.py index 2acc0f2..741d8a9 100644 --- a/gerbonara/cad/protoboard.py +++ b/gerbonara/cad/protoboard.py @@ -549,7 +549,7 @@ def _demo(): #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()) - pb = ProtoBoard(30, 30, pattern1, mounting_hole_dia=3.2, mounting_hole_offset=5) + pb = ProtoBoard(50, 50, pattern1, mounting_hole_dia=3.2, mounting_hole_offset=5) print(pb.pretty_svg()) pb.layer_stack().save_to_directory('/tmp/testdir') diff --git a/gerbonara/cad/protoserve_data/protoserve.html b/gerbonara/cad/protoserve_data/protoserve.html index 98a2192..215f3b7 100644 --- a/gerbonara/cad/protoserve_data/protoserve.html +++ b/gerbonara/cad/protoserve_data/protoserve.html @@ -598,7 +598,9 @@ input {