|
| 1 | +from typing import Optional |
| 2 | + |
| 3 | +from pydantic import RootModel |
| 4 | +import os |
| 5 | + |
| 6 | +from ..electronics_model import * |
| 7 | +from .PartsTable import PartsTableRow |
| 8 | +from .PartsTablePart import PartsTableFootprintSelector |
| 9 | + |
| 10 | + |
| 11 | +class FootprintJson(RootModel): # script relpath imports are weird so this is duplicated here |
| 12 | + root: dict[str, float] # footprint name -> area |
| 13 | + |
| 14 | + |
| 15 | +class FootprintAreaTable: |
| 16 | + _table: Optional[FootprintJson] = None |
| 17 | + |
| 18 | + @classmethod |
| 19 | + def area_of(cls, footprint: str) -> float: |
| 20 | + """Returns the area of a footprint, returning infinity if unavailable""" |
| 21 | + if cls._table is None: |
| 22 | + with open(os.path.join(os.path.dirname(__file__), "resources", "kicad_footprints.json"), 'r') as f: |
| 23 | + cls._table = FootprintJson.model_validate_json(f.read()) |
| 24 | + return cls._table.root.get(footprint) or float('inf') |
| 25 | + |
| 26 | + |
| 27 | +@abstract_block |
| 28 | +class SelectorArea(BlockInterfaceMixin[Block]): |
| 29 | + """A base mixin that defines a footprint_area range specification for blocks that automatically select parts. |
| 30 | + Provides no implementation, only defines the specification parameter. |
| 31 | +
|
| 32 | + Some common areas for SMD parts: |
| 33 | + 01005 R=0.72 C=0.72 D=0.72 |
| 34 | + 0201 R=0.98 C=0.98 D=0.98 |
| 35 | + 0402 R=1.7484 C=1.6744 D=1.7484 |
| 36 | + 0603 R=4.3216 C=4.3216 D=4.3216 |
| 37 | + 0805 R=6.384 C=6.664 D=6.384 |
| 38 | + 1206 R=10.2144 C=10.58 D=10.2144 |
| 39 | + 1812 R=23.01 C=23.4 D=23.01 |
| 40 | + 2512 R=29.3376 D=29.3376 |
| 41 | + """ |
| 42 | + @init_in_parent |
| 43 | + def __init__(self, *args, footprint_area: RangeLike = RangeExpr.ALL, **kwargs): |
| 44 | + super().__init__(*args, **kwargs) |
| 45 | + self.footprint_area = self.ArgParameter(footprint_area) |
| 46 | + |
| 47 | + |
| 48 | +@non_library |
| 49 | +class PartsTableAreaSelector(SelectorArea, PartsTableFootprintSelector): |
| 50 | + """Defines an implementation for the area selector using parts tables and KICAD_FOOTPRINT.""" |
| 51 | + def __init__(self, *args, **kwargs): |
| 52 | + super().__init__(*args, **kwargs) |
| 53 | + self.generator_param(self.footprint_area) |
| 54 | + |
| 55 | + def _row_filter(self, row: PartsTableRow) -> bool: |
| 56 | + return super()._row_filter(row) and \ |
| 57 | + (Range.exact(FootprintAreaTable.area_of(row[self.KICAD_FOOTPRINT])).fuzzy_in(self.get(self.footprint_area))) |
0 commit comments