Compare commits
15 commits
915d4981bd
...
c1194ecee0
Author | SHA1 | Date | |
---|---|---|---|
|
c1194ecee0 | ||
|
cfc3370ad8 | ||
|
613f959781 | ||
|
e81979ad84 | ||
|
ad679b9ae6 | ||
|
f5d3e26a0b | ||
|
d17d97f678 | ||
|
c66b554b46 | ||
|
f1d2800354 | ||
|
09a2daf427 | ||
|
527d493c1b | ||
|
b5a1e8c71d | ||
|
caa3225ef8 | ||
|
e05f3f6a3c | ||
|
8c41e66a1a |
9 changed files with 175 additions and 48 deletions
|
@ -2,6 +2,7 @@ import FreeCAD as App
|
|||
import FreeCADGui as Gui
|
||||
|
||||
from kipy import KiCad
|
||||
from kipy.proto.common.types import DocumentType
|
||||
|
||||
from . import settings
|
||||
from .bases import BaseObject, BaseViewProvider
|
||||
|
@ -14,6 +15,7 @@ class APIObject(BaseObject):
|
|||
|
||||
feature.addProperty('App::PropertyFile', 'Socket', 'KiConnect', 'Path to the KiCAD Socket File').Socket = '/tmp/kicad/api.lock'
|
||||
feature.addProperty('App::PropertyBool', 'Connected', 'KiConnect', 'Is socket connected')
|
||||
feature.addProperty('App::PropertyInteger', 'DocumentCount', 'KiConnect', 'Count of open Documnets')
|
||||
|
||||
self.onDocumentRestored(feature)
|
||||
|
||||
|
@ -26,23 +28,49 @@ class APIObject(BaseObject):
|
|||
parent = feature.getParent()
|
||||
if not parent: return
|
||||
|
||||
# XXX This gets all of the KiConnect::Board features but then does nothing with them
|
||||
# future multi-board support?
|
||||
boards = [ board for board in parent.Group if hasattr(board, 'Type') and board.Type == 'KiConnect::Board' ]
|
||||
|
||||
|
||||
@property
|
||||
def is_connected(self):
|
||||
'''
|
||||
Returns connection status
|
||||
'''
|
||||
|
||||
return self.feature.Connected
|
||||
|
||||
def ping_connection(self, feature):
|
||||
'''
|
||||
Ping the KiCAD API to determine if it's connected
|
||||
'''
|
||||
|
||||
connection_status = 'Disconnected'
|
||||
document_status = 'No Documents'
|
||||
|
||||
try:
|
||||
self.kicad.ping()
|
||||
|
||||
feature.Connected = True
|
||||
feature.Label2 = 'Connected'
|
||||
connection_status = 'Connected'
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
feature.Connected = False
|
||||
feature.Label2 = 'Disconnected'
|
||||
pass
|
||||
connection_status = 'Disconnected'
|
||||
|
||||
if feature.Connected:
|
||||
try:
|
||||
docs = self.kicad.get_open_documents(DocumentType.DOCTYPE_PCB)
|
||||
document_status = f'{len(docs)} Documents'
|
||||
feature.DocumentCount = len(docs)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
feature.DocumentCount = 0
|
||||
|
||||
feature.Label2 = f'{connection_status} ({document_status})'
|
||||
|
||||
return feature.Connected
|
||||
|
||||
|
||||
class APIViewProvider(BaseViewProvider):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class BaseObject:
|
||||
EXTENSIONS = []
|
||||
TYPE = None
|
||||
|
||||
def __init__(self, feature):
|
||||
|
@ -13,7 +14,8 @@ class BaseObject:
|
|||
|
||||
def execute(self, feature):
|
||||
# TODO this might not be the right move
|
||||
self.onDocumentRestored(feature)
|
||||
print(self, 'BaseObject.execute')
|
||||
#self.onDocumentRestored(feature)
|
||||
|
||||
def get_api(self):
|
||||
p = self.feature
|
||||
|
@ -25,6 +27,16 @@ class BaseObject:
|
|||
|
||||
return None
|
||||
|
||||
def isChildOf(self, parent):
|
||||
p = self.feature
|
||||
|
||||
while p:
|
||||
if p == parent:
|
||||
return True
|
||||
p = p.getParent()
|
||||
|
||||
return False
|
||||
|
||||
def onBeforeChange(self, feature, prop):
|
||||
pass
|
||||
|
||||
|
@ -42,5 +54,11 @@ class BaseObject:
|
|||
def setup_properties(self, feature):
|
||||
feature.addProperty('App::PropertyString', 'Type', 'KiConnect', 'Internatl KiConnect Type', read_only=True, hidden=True)
|
||||
|
||||
def sync_from(self):
|
||||
pass
|
||||
|
||||
def sync_to(self):
|
||||
pass
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
|
|
@ -7,10 +7,11 @@ from .. import settings
|
|||
class BaseViewProvider:
|
||||
ICON = None
|
||||
TYPE = None
|
||||
VIEWPROVIDER_EXTENSIONS = []
|
||||
EXTENSIONS = []
|
||||
|
||||
def __init__(self, viewprovider):
|
||||
self.viewprovider = viewprovider
|
||||
self.feature = viewprovider.Object.Proxy.feature
|
||||
|
||||
self.icon = ''
|
||||
|
||||
|
@ -22,8 +23,8 @@ class BaseViewProvider:
|
|||
self.setup_extensions()
|
||||
|
||||
def setup_extensions(self):
|
||||
if hasattr(self, 'VIEWPROVIDER_EXTENSIONS'):
|
||||
for ext in self.VIEWPROVIDER_EXTENSIONS:
|
||||
if hasattr(self, 'EXTENSIONS'):
|
||||
for ext in self.EXTENSIONS:
|
||||
self.feature.addExtension(ext)
|
||||
|
||||
def attach(self, vobj):
|
||||
|
|
|
@ -19,23 +19,57 @@ class BoardObject(BaseObject):
|
|||
super(BoardObject, self).__init__(feature)
|
||||
|
||||
self.kicad_board = None
|
||||
self.substrate_body = None
|
||||
self.substrate_sketch = None
|
||||
self.via_sketch = None
|
||||
|
||||
feature.addProperty('App::PropertyPlacement', 'BoardOffset', 'KiConnect', 'Internal offset for zeroing out Footprint offset', hidden=True, read_only=True)
|
||||
|
||||
def onDocumentRestored(self, feature):
|
||||
|
||||
def execute(self, feature):
|
||||
super(BoardObject, self).execute(feature)
|
||||
|
||||
if self.kicad_board is None:
|
||||
self.kicad_board = self.get_api().kicad.get_board()
|
||||
|
||||
if self.substrate_body is None:
|
||||
self.extrude_substrate(feature)
|
||||
self.sketch_outline(feature)
|
||||
if not self.substrate_body:
|
||||
self.create_substrate_body()
|
||||
|
||||
if not self.substrate_sketch:
|
||||
self.create_substrate_sketch()
|
||||
self.sketch_outline()
|
||||
|
||||
def onDocumentRestored(self, feature):
|
||||
super(BoardObject, self).onDocumentRestored(feature)
|
||||
|
||||
self.kicad_board = self.get_api().kicad.get_board()
|
||||
|
||||
@property
|
||||
def substrate_body(self):
|
||||
return self.feature.getObject('Substrate')
|
||||
|
||||
@property
|
||||
def substrate_sketch(self):
|
||||
return self.substrate_body.getObject('Sketch')
|
||||
|
||||
def create_substrate_body(self):
|
||||
substrate_body = App.ActiveDocument.addObject('PartDesign::Body', 'Substrate')
|
||||
|
||||
substrate_body.addProperty('App::PropertyString', 'Type', 'KiConnect', 'KiConnect specific Type', read_only=True, hidden=True)
|
||||
substrate_body.Type = 'KiConnect::BoardBody'
|
||||
|
||||
self.feature.addObject(substrate_body)
|
||||
|
||||
def create_substrate_sketch(self):
|
||||
substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch')
|
||||
substrate_sketch.Visibility = False
|
||||
|
||||
self.substrate_body.addObject(substrate_sketch)
|
||||
|
||||
pad = self.substrate_body.newObject('PartDesign::Pad', 'Outline')
|
||||
|
||||
pad.Profile = substrate_sketch
|
||||
pad.Length = 1.6
|
||||
pad.Midplane = True
|
||||
|
||||
if len(self.kicad_board.get_vias()) > 0 and self.via_sketch is None:
|
||||
self.setup_vias()
|
||||
self.pocket_vias()
|
||||
|
||||
def extrude_substrate(self, feature):
|
||||
self.substrate_sketch = App.ActiveDocument.addObject('Sketcher::SketchObject', 'Sketch')
|
||||
|
@ -95,7 +129,14 @@ class BoardObject(BaseObject):
|
|||
via_pocket.Midplane = True
|
||||
via_pocket.Type = 1
|
||||
|
||||
def sketch_outline(self, feature):
|
||||
def sketch_outline(self, do_offset=True):
|
||||
'''
|
||||
Draws the Board outline fetched from the API
|
||||
|
||||
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]
|
||||
|
||||
|
@ -104,13 +145,15 @@ class BoardObject(BaseObject):
|
|||
self.feature.PolygonId = boardpoly.id.value
|
||||
|
||||
# this offset centers the board to 0,0
|
||||
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
|
||||
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 Geometry
|
||||
# reset Sketch Constraints and Geometry
|
||||
self.substrate_sketch.Constraints = []
|
||||
self.substrate_sketch.Geometry = []
|
||||
|
||||
# sketch outline
|
||||
|
@ -136,7 +179,11 @@ class BoardObject(BaseObject):
|
|||
Part.LineSegment(start, begin)
|
||||
)
|
||||
|
||||
def sync(self):
|
||||
def sync_from(self):
|
||||
self.sketch_outline()
|
||||
self.substrate_body.recompute(True)
|
||||
|
||||
def sync_to(self):
|
||||
board = self.kicad_board
|
||||
|
||||
commit = board.begin_commit()
|
||||
|
|
43
freecad/kiconnect/commands/Syncable.py
Normal file
43
freecad/kiconnect/commands/Syncable.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
import FreeCADGui as Gui
|
||||
|
||||
class Syncable:
|
||||
SYNCABLES = [ 'KiConnect::Project', 'KiConnect::Board', 'KiConnect::Parts', 'KiConnect::BoardBody', ]
|
||||
|
||||
def IsActive(self):
|
||||
sel = Gui.Selection.getSelection()
|
||||
|
||||
if len(sel) == 0: return False
|
||||
|
||||
for obj in sel:
|
||||
if obj.Type not in self.SYNCABLES:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
selection = [ sel for sel in Gui.Selection.getSelection() if sel.Type in self.SYNCABLES ]
|
||||
syncables = []
|
||||
|
||||
if len(selection) == 1:
|
||||
syncables = selection
|
||||
else:
|
||||
syncables = []
|
||||
|
||||
for i in selection:
|
||||
for j in selection:
|
||||
print(selection)
|
||||
if i == j: continue
|
||||
|
||||
if i in j.OutList:
|
||||
break
|
||||
else:
|
||||
syncables.append(i)
|
||||
|
||||
for s in syncables:
|
||||
if not hasattr(s, 'Proxy'): continue
|
||||
|
||||
feature = s.Proxy
|
||||
if hasattr(feature, self.method):
|
||||
getattr(feature, self.method)()
|
||||
|
||||
s.recompute()
|
|
@ -8,7 +8,7 @@ from ..project import Project
|
|||
|
||||
class Reload:
|
||||
def GetResources(self):
|
||||
tooltip = '<p>Reload KiConnect Workbench for development.</p>'
|
||||
tooltip = '<p>Reload KiConnect Workbench for development.\nNOTE: Does not reload toolbars.</p>'
|
||||
iconFile = os.path.join(settings.ICONPATH, 'kiconnect.svg')
|
||||
|
||||
return {
|
||||
|
@ -19,15 +19,14 @@ class Reload:
|
|||
|
||||
def Activated(self):
|
||||
try:
|
||||
Gui.activateWorkbench('Part')
|
||||
Gui.activateWorkbench('PartWorkbench')
|
||||
except:
|
||||
print('failed to switch to Part WB')
|
||||
except: pass
|
||||
|
||||
try:
|
||||
Gui.removeWorkbench('KiConnect')
|
||||
except:
|
||||
print('failed to remove KiConnect')
|
||||
pass
|
||||
|
||||
for mod in [mod for mod in sys.modules if 'kicon' in mod]:
|
||||
print(f'Reloading {mod}')
|
||||
|
|
|
@ -7,7 +7,11 @@ import sys
|
|||
from .. import settings
|
||||
from ..project import Project
|
||||
|
||||
class Sync:
|
||||
from .Syncable import Syncable
|
||||
|
||||
class SyncFrom(Syncable):
|
||||
method = 'sync_from'
|
||||
|
||||
def GetResources(self):
|
||||
tooltip = '<p>Reload Board from KiCAD.</p>'
|
||||
iconFile = os.path.join(settings.ICONPATH, 'import_brd_file.svg')
|
||||
|
@ -18,12 +22,4 @@ class Sync:
|
|||
'Pixmap' : iconFile
|
||||
}
|
||||
|
||||
def Activated(self):
|
||||
boards = [ sel for sel in Gui.Selection.getSelection() if sel.Type == 'KiConnect::Board' ]
|
||||
|
||||
for board in boards:
|
||||
board.KiConnBoard.sketch_outline()
|
||||
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
Gui.addCommand('kiconn_sync_from', Sync())
|
||||
Gui.addCommand('kiconn_sync_from', SyncFrom())
|
||||
|
|
|
@ -6,7 +6,11 @@ import sys
|
|||
from .. import settings
|
||||
from ..project import Project
|
||||
|
||||
class Sync:
|
||||
from .Syncable import Syncable
|
||||
|
||||
class SyncTo(Syncable):
|
||||
method = 'sync_to'
|
||||
|
||||
def GetResources(self):
|
||||
tooltip = '<p>Update Board in KiCAD.</p>'
|
||||
iconFile = os.path.join(settings.ICONPATH, 'export_to_pcbnew.svg')
|
||||
|
@ -17,13 +21,4 @@ class Sync:
|
|||
'Pixmap' : iconFile
|
||||
}
|
||||
|
||||
def Activated(self):
|
||||
boards = [ sel for sel in Gui.Selection.getSelection() if sel.Type == 'KiConnect::Board' ]
|
||||
|
||||
for board in boards:
|
||||
board.KiConnBoard.sync()
|
||||
|
||||
|
||||
|
||||
|
||||
Gui.addCommand('kiconn_sync_to', Sync())
|
||||
Gui.addCommand('kiconn_sync_to', SyncTo())
|
||||
|
|
|
@ -28,7 +28,7 @@ class Project:
|
|||
|
||||
self.API = api.makeAPI(self.feature)
|
||||
|
||||
if self.API.Proxy.is_connected:
|
||||
if self.API.Proxy.is_connected and self.API.DocumentCount > 0:
|
||||
kicad_board = self.API.Proxy.kicad.get_board()
|
||||
|
||||
self.board = Board(kicad_board, self.feature)
|
||||
|
|
Loading…
Add table
Reference in a new issue