Compare commits
9 commits
polygon_he
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
|
934aaaf354 | ||
|
7ee3ed89c6 | ||
|
b19c95cd2e | ||
|
205254a4f3 | ||
|
6137b50208 | ||
|
0a95b5529e | ||
|
a162b98000 | ||
|
c61020242d | ||
|
638fda2daf |
10 changed files with 241 additions and 23 deletions
|
@ -54,7 +54,7 @@ class BaseObject:
|
||||||
self.feature.addExtension(ext)
|
self.feature.addExtension(ext)
|
||||||
|
|
||||||
def setup_properties(self, feature):
|
def setup_properties(self, feature):
|
||||||
feature.addProperty('App::PropertyString', 'Type', 'KiConnect', 'Internal KiConnect Type', read_only=True, hidden=True)
|
feature.addProperty('App::PropertyString', 'Type', 'KiConnect', 'Internal KiConnect Type', hidden=True)
|
||||||
|
|
||||||
def sync_from(self):
|
def sync_from(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -19,6 +19,7 @@ class BoardObject(BaseObject):
|
||||||
def __init__(self, feature, kicad_board, board_polygon):
|
def __init__(self, feature, kicad_board, board_polygon):
|
||||||
self.feature = feature
|
self.feature = feature
|
||||||
self.kicad_board = kicad_board
|
self.kicad_board = kicad_board
|
||||||
|
self.board_sketch = None
|
||||||
# TODO add this to FreeCAD Preferences and Property?
|
# TODO add this to FreeCAD Preferences and Property?
|
||||||
self.do_offset = True
|
self.do_offset = True
|
||||||
# TODO needs to be resotred in onDocumentRestored
|
# TODO needs to be resotred in onDocumentRestored
|
||||||
|
@ -72,7 +73,10 @@ class BoardObject(BaseObject):
|
||||||
|
|
||||||
return self.board_sketch
|
return self.board_sketch
|
||||||
|
|
||||||
def get_boardpoly(self, polygon_id=None):
|
def get_polygon(self, kiid):
|
||||||
|
return [ s for s in self.kicad_board.get_shapes() if s.id.value == kiid ][0]
|
||||||
|
|
||||||
|
def get_boardpoly(self):
|
||||||
# TODO remove in favor of extract_polygons class method
|
# TODO remove in favor of extract_polygons class method
|
||||||
board = self.kicad_board
|
board = self.kicad_board
|
||||||
|
|
||||||
|
@ -80,10 +84,8 @@ class BoardObject(BaseObject):
|
||||||
edge_cuts = [ edge for edge in board.get_shapes() if edge.layer == BoardLayer.BL_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) ]
|
polygons = [ edge for edge in edge_cuts if isinstance(edge, BoardPolygon) ]
|
||||||
|
|
||||||
if polygon_id:
|
# XXX only single board supported at the moment
|
||||||
return [ p for p in polygons if p.id.value == polygon_id ][0]
|
return polygons[0]
|
||||||
else:
|
|
||||||
return polygons
|
|
||||||
|
|
||||||
def pocket_vias(self):
|
def pocket_vias(self):
|
||||||
board = self.kicad_board
|
board = self.kicad_board
|
||||||
|
@ -130,17 +132,8 @@ class BoardObject(BaseObject):
|
||||||
Pulls outline from KiCAD PolygonBoard and saves points as Vectors
|
Pulls outline from KiCAD PolygonBoard and saves points as Vectors
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# bit of a quick hack to keep the board in one place, needs more testing
|
if self.board_sketch:
|
||||||
if self.do_offset and not self.feature.BoardOffset:
|
self.board_sketch.Proxy.sync_from()
|
||||||
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))
|
|
||||||
|
|
||||||
self.feature.Vectors = vectors
|
|
||||||
|
|
||||||
def sync_to(self):
|
def sync_to(self):
|
||||||
board = self.kicad_board
|
board = self.kicad_board
|
||||||
|
|
|
@ -23,6 +23,12 @@ class BoardSketchObject(BaseObject):
|
||||||
def execute(self, feature):
|
def execute(self, feature):
|
||||||
feature.recompute()
|
feature.recompute()
|
||||||
|
|
||||||
|
def get_parent_board(self):
|
||||||
|
try:
|
||||||
|
return self.feature.getParent().getParent().Proxy
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
def point_to_vector(self, point, offset=True):
|
def point_to_vector(self, point, offset=True):
|
||||||
return (
|
return (
|
||||||
App.Vector(point.x,
|
App.Vector(point.x,
|
||||||
|
@ -39,6 +45,11 @@ class BoardSketchObject(BaseObject):
|
||||||
feature = self.feature
|
feature = self.feature
|
||||||
vectors = []
|
vectors = []
|
||||||
|
|
||||||
|
board = self.get_parent_board()
|
||||||
|
if board:
|
||||||
|
self.board_polygon = board.get_polygon(board.polygon_id)
|
||||||
|
|
||||||
|
# board.get_shapes needs to be called to ensure polygons are actually up to date
|
||||||
for node in self.board_polygon.polygons[0].outline:
|
for node in self.board_polygon.polygons[0].outline:
|
||||||
vectors.append(self.point_to_vector(node.point))
|
vectors.append(self.point_to_vector(node.point))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import FreeCAD as App
|
||||||
import FreeCADGui as Gui
|
import FreeCADGui as Gui
|
||||||
|
|
||||||
class Syncable:
|
class Syncable:
|
||||||
SYNCABLES = [ 'KiConnect::Project', 'KiConnect::Board', 'KiConnect::Parts', 'KiConnect::BoardBody', ]
|
SYNCABLES = [ 'KiConnect::Project', 'KiConnect::Board', 'KiConnect::Parts', 'KiConnect::BoardBody', 'KiConnect::BoardSketch' ]
|
||||||
|
|
||||||
def IsActive(self):
|
def IsActive(self):
|
||||||
sel = Gui.Selection.getSelection()
|
sel = Gui.Selection.getSelection()
|
||||||
|
@ -41,3 +42,5 @@ class Syncable:
|
||||||
getattr(feature, self.method)()
|
getattr(feature, self.method)()
|
||||||
|
|
||||||
s.recompute()
|
s.recompute()
|
||||||
|
|
||||||
|
App.ActiveDocument.recompute()
|
||||||
|
|
24
freecad/kiconnect/commands/cmd_edit_prefs.py
Normal file
24
freecad/kiconnect/commands/cmd_edit_prefs.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import importlib
|
||||||
|
import FreeCADGui as Gui
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
|
from ..project import Project
|
||||||
|
|
||||||
|
class EditPrefs:
|
||||||
|
def GetResources(self):
|
||||||
|
tooltip = '<p>EditPrefs KiConnect Workbench for development.\nNOTE: Does not reload toolbars.</p>'
|
||||||
|
iconFile = 'preferences-system.svg'
|
||||||
|
|
||||||
|
return {
|
||||||
|
'MenuText': 'Edit Preferences',
|
||||||
|
'ToolTip': tooltip,
|
||||||
|
'Pixmap' : iconFile
|
||||||
|
}
|
||||||
|
|
||||||
|
def Activated(self):
|
||||||
|
Gui.showPreferences("KiConnect")
|
||||||
|
|
||||||
|
|
||||||
|
Gui.addCommand('cmd_edit_prefs', EditPrefs())
|
|
@ -7,7 +7,7 @@ sys.path.insert(1, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..
|
||||||
import FreeCADGui as Gui
|
import FreeCADGui as Gui
|
||||||
import FreeCAD as App
|
import FreeCAD as App
|
||||||
|
|
||||||
from .commands import cmd_new_pcb, cmd_reload, cmd_sync_from, cmd_sync_to
|
from .commands import cmd_edit_prefs, cmd_new_pcb, cmd_reload, cmd_sync_from, cmd_sync_to
|
||||||
from . import settings
|
from . import settings
|
||||||
|
|
||||||
translate=App.Qt.translate
|
translate=App.Qt.translate
|
||||||
|
@ -19,12 +19,18 @@ TRANSLATIONSPATH = os.path.join(os.path.dirname(__file__), "resources", "transla
|
||||||
Gui.addLanguagePath(TRANSLATIONSPATH)
|
Gui.addLanguagePath(TRANSLATIONSPATH)
|
||||||
Gui.updateLocale()
|
Gui.updateLocale()
|
||||||
|
|
||||||
|
default_preferences = [
|
||||||
|
('Bool', 'debug_reload', True),
|
||||||
|
('Bool', 'prefs_toolbar', True),
|
||||||
|
('Float', 'default_thickness', 1.6),
|
||||||
|
]
|
||||||
|
|
||||||
class KiConnect(Gui.Workbench):
|
class KiConnect(Gui.Workbench):
|
||||||
MenuText = translate("Workbench", "KiConnect")
|
MenuText = translate("Workbench", "KiConnect")
|
||||||
ToolTip = translate("Workbench", "KiConnect PCB Workbench")
|
ToolTip = translate("Workbench", "KiConnect PCB Workbench")
|
||||||
Icon = os.path.join(settings.ICONPATH, "kiconnect.svg")
|
Icon = os.path.join(settings.ICONPATH, "kiconnect.svg")
|
||||||
|
|
||||||
toolbox = [ 'kiconn_new', 'kiconn_reload', 'kiconn_sync_to', 'kiconn_sync_from' ]
|
toolbox = [ 'kiconn_new', 'kiconn_sync_to', 'kiconn_sync_from' ]
|
||||||
|
|
||||||
def GetClassName(self):
|
def GetClassName(self):
|
||||||
return "Gui::PythonWorkbench"
|
return "Gui::PythonWorkbench"
|
||||||
|
@ -35,11 +41,27 @@ class KiConnect(Gui.Workbench):
|
||||||
here is the place to import all the commands
|
here is the place to import all the commands
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# setup default preferences on first load
|
||||||
|
if settings.preferences.IsEmpty():
|
||||||
|
for pref in default_preferences:
|
||||||
|
print('setting pref: ', f'Set{pref[0]}', pref[1], pref[2])
|
||||||
|
getattr(settings.preferences, f'Set{pref[0]}')(pref[1], pref[2])
|
||||||
|
|
||||||
|
# add debug reload button if enabled
|
||||||
|
if settings.preferences.GetBool('debug_reload'):
|
||||||
|
self.toolbox.append('kiconn_reload')
|
||||||
|
|
||||||
|
if settings.preferences.GetBool('prefs_toolbar'):
|
||||||
|
self.toolbox.append('cmd_edit_prefs')
|
||||||
|
|
||||||
print('setting up toolbar')
|
print('setting up toolbar')
|
||||||
# NOTE: Context for this commands must be "Workbench"
|
# NOTE: Context for this commands must be "Workbench"
|
||||||
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
|
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
|
||||||
self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
|
self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "KiConnect"), self.toolbox)
|
||||||
|
|
||||||
|
Gui.addPreferencePage(os.path.join(settings.UIPATH, 'preferences.ui'), 'KiConnect')
|
||||||
|
|
||||||
|
|
||||||
def Activated(self):
|
def Activated(self):
|
||||||
App.Console.PrintMessage(translate("Log", "Workbench KiConnect activated.") + "\n")
|
App.Console.PrintMessage(translate("Log", "Workbench KiConnect activated.") + "\n")
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,13 @@ from .bases import BaseObject, BaseViewProvider
|
||||||
class PartsObject(BaseObject):
|
class PartsObject(BaseObject):
|
||||||
TYPE = 'KiConnect::Parts'
|
TYPE = 'KiConnect::Parts'
|
||||||
|
|
||||||
|
def __init__(self, feature):
|
||||||
|
super(PartsObject, self).__init__(feature)
|
||||||
|
|
||||||
def execute(self, feature):
|
def execute(self, feature):
|
||||||
super(PartsObject, self).execute(feature)
|
super(PartsObject, self).execute(feature)
|
||||||
|
|
||||||
self.import_footprints()
|
def sync_from(self):
|
||||||
|
|
||||||
def import_footprints(self):
|
|
||||||
kiconn_board = self.feature.getParentGroup()
|
kiconn_board = self.feature.getParentGroup()
|
||||||
kicad_board = self.get_api().kicad.get_board()
|
kicad_board = self.get_api().kicad.get_board()
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Project:
|
||||||
kicad_board = self.API.Proxy.kicad.get_board()
|
kicad_board = self.API.Proxy.kicad.get_board()
|
||||||
|
|
||||||
polygons = Board.extract_polygons(kicad_board)
|
polygons = Board.extract_polygons(kicad_board)
|
||||||
|
|
||||||
for polygon in polygons:
|
for polygon in polygons:
|
||||||
self.board = Board.makeBoard(self.feature, kicad_board, polygon)
|
self.board = Board.makeBoard(self.feature, kicad_board, polygon)
|
||||||
|
|
||||||
|
|
158
freecad/kiconnect/resources/ui/preferences.ui
Normal file
158
freecad/kiconnect/resources/ui/preferences.ui
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>KiConnect::DlgSettingsKiConnect</class>
|
||||||
|
<widget class="QWidget" name="KiConnect::DlgSettingsKiConnect">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1151</width>
|
||||||
|
<height>663</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>1151</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="defaults_group">
|
||||||
|
<property name="title">
|
||||||
|
<string>Defaults</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Default Board Thickness</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Gui::PrefUnitSpinBox" name="spin_thickness">
|
||||||
|
<property name="unit" stdset="0">
|
||||||
|
<string>mm</string>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.600000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>default_thickness</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>Mod/KiConnect</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Gui::PrefCheckBox" name="check_load_parts">
|
||||||
|
<property name="text">
|
||||||
|
<string>Load Parts</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>parts_load</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>Mod/KiConnect</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="debug_group">
|
||||||
|
<property name="title">
|
||||||
|
<string>Debug and Development</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="Gui::PrefCheckBox" name="check_debug_reload">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Reload</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>debug_reload</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>Mod/KiConnect</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Gui::PrefCheckBox" name="checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string> Preferences from toolbar</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>Mod/KiConnect</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>prefs_toolbar</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::QuantitySpinBox</class>
|
||||||
|
<extends>QAbstractSpinBox</extends>
|
||||||
|
<header>Gui/QuantitySpinBox.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::PrefCheckBox</class>
|
||||||
|
<extends>QCheckBox</extends>
|
||||||
|
<header>Gui/PrefWidgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Gui::PrefUnitSpinBox</class>
|
||||||
|
<extends>Gui::QuantitySpinBox</extends>
|
||||||
|
<header>Gui/PrefWidgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -1,5 +1,10 @@
|
||||||
import os
|
import os
|
||||||
|
import FreeCAD as App
|
||||||
|
|
||||||
BOARD_THICKNESS = 0.80
|
BOARD_THICKNESS = 0.80
|
||||||
ICONPATH = os.path.join(os.path.dirname(__file__), "resources", 'icons')
|
ICONPATH = os.path.join(os.path.dirname(__file__), "resources", 'icons')
|
||||||
|
UIPATH = os.path.join(os.path.dirname(__file__), "resources", 'ui')
|
||||||
KICAD9_3DMODEL_DIR = '/usr/share/kicad/3dmodels/'
|
KICAD9_3DMODEL_DIR = '/usr/share/kicad/3dmodels/'
|
||||||
|
PREF_PATH = 'User parameter:BaseApp/Preferences/Mod/KiConnect'
|
||||||
|
|
||||||
|
preferences = App.ParamGet(PREF_PATH)
|
||||||
|
|
Loading…
Add table
Reference in a new issue