major flow rearrangement, better separation of syncing from KiCAD and FreeCAD executing/drawing. still more to go

This commit is contained in:
Morgan 'ARR\!' Allen 2025-05-16 17:52:17 -07:00
parent 6d6ccadccf
commit 961b0b44f3

View file

@ -10,32 +10,54 @@ from kipy.proto.common.types import KiCadObjectType
from kipy.util.board_layer import BoardLayer from kipy.util.board_layer import BoardLayer
from .bases import BaseObject, BaseViewProvider from .bases import BaseObject, BaseViewProvider
from . import parts from . import parts as Parts
class BoardObject(BaseObject): class BoardObject(BaseObject):
TYPE = 'KiConnect::Board' TYPE = 'KiConnect::Board'
def __init__(self, feature): def __init__(self, feature, kicad_board, board_polygon):
super(BoardObject, self).__init__(feature) self.feature = feature
self.kicad_board = kicad_board
# TODO add this to FreeCAD Preferences and Property?
self.do_offset = True
# TODO needs to be resotred in onDocumentRestored
#self.board_polygon = board_polygon
self.polygon_id = board_polygon.id.value
self.kicad_board = None
self.via_sketch = None self.via_sketch = None
feature.addProperty('App::PropertyPlacement', 'BoardOffset', 'KiConnect', 'Internal offset for zeroing out Footprint offset', hidden=True, read_only=True) super(BoardObject, self).__init__(feature)
self.feature.PolygonId = board_polygon.id.value
@property
def board_polygon(self):
print(self.polygon_id)
print([ poly for poly in extract_polygons(self.kicad_board) if poly.id.value == self.polygon_id ][0])
return [ poly for poly in extract_polygons(self.kicad_board) if poly.id.value == self.polygon_id ][0]
def execute(self, feature): def execute(self, feature):
super(BoardObject, self).execute(feature) begin = None
start = None
if self.kicad_board is None: sketch = self.substrate_sketch
self.kicad_board = self.get_api().kicad.get_board()
if not self.substrate_body: # this probably needs a bit more control..
self.create_substrate_body() sketch.Constraints = []
sketch.Geometry = []
if not self.substrate_sketch: for vector in self.feature.Vectors:
self.create_substrate_sketch() if not start:
self.sketch_outline() start = vector
begin = vector
continue
sketch.addGeometry(Part.LineSegment(start, vector))
start = vector
sketch.addGeometry(Part.LineSegment(start, begin))
def onDocumentRestored(self, feature): def onDocumentRestored(self, feature):
super(BoardObject, self).onDocumentRestored(feature) super(BoardObject, self).onDocumentRestored(feature)
@ -44,11 +66,21 @@ class BoardObject(BaseObject):
@property @property
def substrate_body(self): def substrate_body(self):
return self.feature.getObject('Substrate') body = self.feature.getObject('Substrate')
if not body:
body = self.create_substrate_body()
return body
@property @property
def substrate_sketch(self): def substrate_sketch(self):
return self.substrate_body.getObject('Sketch') sketch = self.substrate_body.getObject('Sketch')
if not sketch:
sketch = self.create_substrate_sketch()
return sketch
def create_substrate_body(self): def create_substrate_body(self):
substrate_body = App.ActiveDocument.addObject('PartDesign::Body', 'Substrate') substrate_body = App.ActiveDocument.addObject('PartDesign::Body', 'Substrate')
@ -58,6 +90,8 @@ class BoardObject(BaseObject):
self.feature.addObject(substrate_body) self.feature.addObject(substrate_body)
return substrate_body
def create_substrate_sketch(self): def create_substrate_sketch(self):
substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch') substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch')
substrate_sketch.Visibility = False substrate_sketch.Visibility = False
@ -70,6 +104,7 @@ class BoardObject(BaseObject):
pad.Length = 1.6 pad.Length = 1.6
pad.Midplane = True pad.Midplane = True
return substrate_sketch
def extrude_substrate(self, feature): def extrude_substrate(self, feature):
self.substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch') self.substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch')
@ -87,6 +122,7 @@ class BoardObject(BaseObject):
self.substrate_body.addObject(self.substrate_sketch) self.substrate_body.addObject(self.substrate_sketch)
def get_boardpoly(self): def get_boardpoly(self):
# TODO remove in favor of extract_polygons class method
board = self.kicad_board board = self.kicad_board
# find polygons of Edge Cuts # find polygons of Edge Cuts
@ -129,59 +165,32 @@ class BoardObject(BaseObject):
via_pocket.Midplane = True via_pocket.Midplane = True
via_pocket.Type = 1 via_pocket.Type = 1
def sketch_outline(self, do_offset=True): def point_to_vector(self, point, offset=True):
''' return (
Draws the Board outline fetched from the API App.Vector(point.x,
-point.y
)) / 1000000.0 - (self.feature.BoardOffset.Base if offset else 0)
Parameters:
do_offset (bool): If offset should be recalcualted, typically this is undesired after calculated the first time. (Default: True)
'''
boardpoly = self.get_boardpoly()
poly = boardpoly.polygons[0]
# track KIID
# TODO FeaturePython objects interacting with kipy objects should inherit common parent class
self.feature.PolygonId = boardpoly.id.value
# this offset centers the board to 0,0
if do_offset:
bb = boardpoly.bounding_box()
self.feature.BoardOffset.Base = (App.Vector(bb.pos.x, -bb.pos.y) + App.Vector(bb.size.x, -bb.size.y) / 2) / 1000000.0
begin = None
start = None
# reset Sketch Constraints and Geometry
self.substrate_sketch.Constraints = []
self.substrate_sketch.Geometry = []
# sketch outline
for segment in poly.outline:
if not start:
start = (App.Vector(segment.point.x, -segment.point.y)) / 1000000.0 - self.feature.BoardOffset.Base
# needs to remain to connect the last segment
begin = start
continue
end = (App.Vector(segment.point.x, -segment.point.y)) / 1000000.0 - self.feature.BoardOffset.Base
self.substrate_sketch.addGeometry(
Part.LineSegment(start, end)
)
start = end
# make final connection
self.substrate_sketch.addGeometry(
Part.LineSegment(start, begin)
)
def sync_from(self): def sync_from(self):
self.sketch_outline() '''
self.substrate_body.recompute(True) Pulls outline from KiCAD PolygonBoard and saves points as Vectors
'''
if self.do_offset:
bb = self.board_polygon.bounding_box()
self.feature.BoardOffset.Base = (App.Vector(bb.pos.x, -bb.pos.y) + App.Vector(bb.size.x, -bb.size.y) / 2) / 1000000.0
vectors = []
for node in self.board_polygon.polygons[0].outline:
vectors.append(self.point_to_vector(node.point))
print(self.feature.Vectors == vectors)
self.feature.Vectors = vectors
print(self.feature.Vectors == vectors)
App.ActiveDocument.recompute()
def sync_to(self): def sync_to(self):
board = self.kicad_board board = self.kicad_board
@ -231,18 +240,22 @@ class BoardViewProvider(BaseViewProvider):
TYPE = 'KiConnect::Board' TYPE = 'KiConnect::Board'
ICON = 'board.svg' ICON = 'board.svg'
class Board: def makeBoard(parent, kicad_board, polygon):
def __init__(self, kicad_board, parent):
feature = App.ActiveDocument.addObject('App::DocumentObjectGroupPython', 'Board') feature = App.ActiveDocument.addObject('App::DocumentObjectGroupPython', 'Board')
parent.addObject(feature) parent.addObject(feature)
self.feature = feature
BoardObject(feature) BoardObject(feature, kicad_board, polygon)
BoardViewProvider(feature.ViewObject) BoardViewProvider(feature.ViewObject)
# TODO move into BoardObject Parts.makeParts(feature)
feature.addProperty('App::PropertyString', 'Doc', 'KiConnect', 'Doc in project to sync with', read_only=True).Doc = kicad_board.name
feature.addProperty('App::PropertyString', 'PolygonId', 'KiConnect', 'Polygon ID for the original outline', hidden=True, read_only=True)
parts.makeParts(feature) return feature
def extract_polygons(board):
# find polygons of Edge Cuts
edge_cuts = [ edge for edge in board.get_shapes() if edge.layer == BoardLayer.BL_Edge_Cuts ]
polygons = [ edge for edge in edge_cuts if isinstance(edge, BoardPolygon) ]
# XXX only single board supported at the moment
return polygons