Initial placement generation for svg-pcb backend#413
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR enhances the SVG-PCB backend by adding a hierarchical initial placement algorithm, moving and extending footprint metadata (area and bounding box), updating example outputs with concrete placement coordinates, and bundling the full SVG-PCB code block.
- Introduces
arrange_netlist/flatten_packed_blockfor recursive placement and generates complete PCB code including outline and rendering. - Moves footprint area/bbox JSON handling into
FootprintDataTableunderelectronics_model, replacing scatteredFootprintAreaTablereferences. - Updates all example
.svgpcb.jsfiles with generated translation coordinates instead of stacked defaults.
Reviewed Changes
Copilot reviewed 17 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/.../*.svgpcb.js | Replace default translate: pt(0,0) with computed coordinates from the new placer |
| edg/parts/JlcPart.py & JlcOscillator.py & JlcPartsBase.py | Swap FootprintAreaTable.area_of calls for new _row_area helper in sorting lambdas |
| edg/parts/Generic*.py | Switch to internal _footprint_area for fuzzy-in footprint filtering |
| edg/electronics_model/KicadFootprintData.py | New FootprintDataTable class providing area + bbox lookup |
| edg/electronics_model/resources/...build_kicad_footprint_table.py | Expanded footprint extractor to compute both area and bbox, output JSON with full data |
| edg/electronics_model/SvgPcbBackend.py | Integrates placement, generates full SVG-PCB code, and updates backend signatures |
| edg/abstract_parts/SelectorArea.py | Removes local footprint-area table, uses FootprintDataTable, adds _row_area helper |
Comments suppressed due to low confidence (2)
edg/electronics_model/SvgPcbBackend.py:17
- TransformUtil is referenced here but not imported in this module, leading to a NameError at runtime. Add
from .TransformUtil import TransformUtilat the top.
elts: Dict[str, Tuple[Union['PlacedBlock', TransformUtil.Path], Tuple[float, float]]] # name -> elt, (x, y)
edg/abstract_parts/SelectorArea.py:26
- Ensure that the new
_footprint_areaand_row_areamethods are correctly indented inside theSelectorAreaclass to match existing method definitions and avoid indentation errors.
@classmethod
|
|
||
| return cls._jlc_table().map_new_columns(parse_row).sort_by( # TODO dedup w/ JlcTableSelector._row_sort_by | ||
| lambda row: [row[cls.BASIC_PART_HEADER], FootprintAreaTable.area_of(row[cls.KICAD_FOOTPRINT]), row[cls.COST]] | ||
| lambda row: [row[cls.BASIC_PART_HEADER], cls._row_area(row), row[cls.COST]] |
There was a problem hiding this comment.
[nitpick] This sorting lambda duplicates logic found in JlcTableSelector._row_sort_by. Extract the sort key into a shared helper to reduce duplication and ensure consistency.
| for subdir in os.listdir(kicad_dir): | ||
| if not subdir.endswith('.pretty') or not os.path.isdir(os.path.join(kicad_dir, subdir)): | ||
| continue | ||
| lib_name = subdir.split('.pretty')[0] | ||
| for file in os.listdir(os.path.join(kicad_dir, subdir)): | ||
| if not file.endswith('.kicad_mod'): | ||
| continue | ||
| fp_filename = file.split('.kicad_mod')[0] | ||
|
|
||
| with open(os.path.join(kicad_dir, subdir, file)) as f: | ||
| fp_data = f.read() | ||
| fp_area = calculate_area(fp_data) | ||
| fp_bbox = calculate_bbox(fp_data) | ||
| if fp_area is None and fp_bbox is not None: | ||
| fp_area = (fp_bbox[2] - fp_bbox[0]) * (fp_bbox[3] - fp_bbox[1]) | ||
|
|
||
| fp_name = lib_name + ":" + fp_filename | ||
| if fp_area is not None and fp_bbox is not None: | ||
| fp_data_dict[fp_name] = FootprintData( | ||
| area=fp_area, | ||
| bbox=fp_bbox | ||
| ) | ||
| print(f" {fp_name} -> {fp_area:.3g}, {fp_bbox}") | ||
| else: | ||
| print(f"skip {fp_name} {fp_area} {fp_bbox}") |
There was a problem hiding this comment.
[nitpick] Consider using os.walk or a recursive directory traversal to capture footprints in nested .pretty directories or subfolders, ensuring no valid footprints are missed.
Changes to the experimental svg-pcb backend. Adds a better initial placement, instead of all components stacked, tries to pack components with a fixed aspect ratio, recursively by group bottom-up. Also now generates the entire svg-pcb code block instead of just snippets.
Also adds svgpcb backend to unit test outputs.
Changes the footprint data json to store area and bounding box. Moves the FootprintDataTable into electronics_model, where the svg-pcb backend and the footprint data generation is now.