From ce25779b5db0a66111c0197100a1f7b9ff9648d2 Mon Sep 17 00:00:00 2001 From: "Morgan 'ARR\\!' Allen" Date: Tue, 8 Apr 2025 12:10:36 -0700 Subject: [PATCH] major rework of parts, somewhat handles updates from KiCAD via recompute, needs Live switch to enable/disable --- freecad/kiconnect/parts.py | 68 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/freecad/kiconnect/parts.py b/freecad/kiconnect/parts.py index 09ad44a..a87a1b3 100644 --- a/freecad/kiconnect/parts.py +++ b/freecad/kiconnect/parts.py @@ -15,28 +15,35 @@ from .bases import BaseObject, BaseViewProvider class PartsObject(BaseObject): TYPE = 'KiConnect::Parts' -class PartsViewProvider(BaseViewProvider): - ICON = 'icon_footprint_browser.svg' - TYPE = 'KiConnect::Parts' - -class Parts(): - def __init__(self, kicad_board, kiconn_board): - self.kicad_board = kicad_board - self.kiconn_board = kiconn_board - - feature = App.ActiveDocument.addObject('App::DocumentObjectGroupPython', 'Parts') - - PartsObject(self, feature) - PartsViewProvider(self, feature.ViewObject) - - self.feature = feature + def execute(self, feature): + super(PartsObject, self).execute(feature) self.import_footprints() def import_footprints(self): - for footprint in self.kicad_board.get_footprints(): + kiconn_board = self.feature.getParentGroup() + kicad_board = self.get_api().kicad.get_board() + + existing_footprints_by_ref = { part.KiCadRef: part for part in self.feature.Group } + + for footprint in kicad_board.get_footprints(): # NOTE this doesn't handle footprints that have been removed - if App.ActiveDocument.getObjectsByLabel(footprint.reference_field.text.value): continue + reference = footprint.reference_field.text.value + + if reference in existing_footprints_by_ref: + model = existing_footprints_by_ref[reference] + + placement = App.Placement() + placement.Base.x = (footprint.position.x / 1000000.0) - kiconn_board.BoardOffset.Base.x + placement.Base.y = (-footprint.position.y / 1000000.0) - kiconn_board.BoardOffset.Base.y + # TODO get from kicad board settings + placement.Base.z = 0.8 + placement.Rotation.Angle = footprint.orientation.to_radians() + + if model.Placement != placement: + model.Placement = placement + + continue for item in [item for item in footprint.definition.items if isinstance(item, Footprint3DModel)]: filename = item.filename.replace('${KICAD9_3DMODEL_DIR}', settings.KICAD9_3DMODEL_DIR).replace('wrl', 'step') @@ -45,15 +52,34 @@ class Parts(): # simply grabs the last object in the document, probably need to figure out a safer way to handle model = App.ActiveDocument.findObjects()[-1] - model.Label = footprint.reference_field.text.value + model.Label = reference + model.Label2 = reference model.addProperty('App::PropertyPlacement', 'BoardOffset', 'Base', 'Internal offset for zeroing out Footprint offset', hidden=True, read_only=True) + model.addProperty('App::PropertyString', 'KiCadRef', 'KiConnect', 'Original KiCAD REF', hidden=True, read_only=True) + model.KiCadRef = reference + self.feature.addObject(model) - model.Placement.Base.x = (footprint.position.x / 1000000.0) - self.kiconn_board.offset.x - model.Placement.Base.y = (-footprint.position.y / 1000000.0) - self.kiconn_board.offset.y + model.Placement.Base.x = (footprint.position.x / 1000000.0) - kiconn_board.BoardOffset.Base.x + model.Placement.Base.y = (-footprint.position.y / 1000000.0) - kiconn_board.BoardOffset.Base.y + # TODO get from kicad board settings model.Placement.Base.z = 0.8 model.Placement.Rotation.Angle = footprint.orientation.to_radians() model.BoardOffset = model.Placement - except: + except Exception as e: print('failed to load', filename) + print(e) + +class PartsViewProvider(BaseViewProvider): + ICON = 'icon_footprint_browser.svg' + TYPE = 'KiConnect::Parts' + +def makeParts(parent): + feature = App.ActiveDocument.addObject('App::DocumentObjectGroupPython', 'Parts') + parent.addObject(feature) + + PartsObject(feature) + PartsViewProvider(feature.ViewObject) + + return feature