Consolidated path tool editor and added customized support for endmill, drill and v-bit.
This commit is contained in:
288
src/Mod/Path/PathScripts/PathToolEdit.py
Normal file
288
src/Mod/Path/PathScripts/PathToolEdit.py
Normal file
@@ -0,0 +1,288 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2018 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import PathScripts.PathGui as PathGui
|
||||
import PathScripts.PathLog as PathLog
|
||||
import math
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
class ToolEditorDefault:
|
||||
'''Generic Tool parameter editor for all Tools that don't have a customized edit function.
|
||||
Let's the user enter the raw internal data. Not the best approach but this is the starting point.'''
|
||||
def __init__(self, editor):
|
||||
self.editor = editor
|
||||
self.form = editor.form
|
||||
|
||||
def setupUI(self):
|
||||
self.form.paramImage.hide()
|
||||
self.form.paramGeneric.show()
|
||||
|
||||
def updateUI(self):
|
||||
self.form.toolDiameter.setText(FreeCAD.Units.Quantity(self.editor.tool.Diameter, FreeCAD.Units.Length).UserString)
|
||||
self.form.toolFlatRadius.setText(FreeCAD.Units.Quantity(self.editor.tool.FlatRadius, FreeCAD.Units.Length).UserString)
|
||||
self.form.toolCornerRadius.setText(FreeCAD.Units.Quantity(self.editor.tool.CornerRadius, FreeCAD.Units.Length).UserString)
|
||||
self.form.toolCuttingEdgeHeight.setText(FreeCAD.Units.Quantity(self.editor.tool.CuttingEdgeHeight, FreeCAD.Units.Length).UserString)
|
||||
self.form.toolCuttingEdgeAngle.setText(FreeCAD.Units.Quantity(self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle).UserString)
|
||||
|
||||
def updateTool(self):
|
||||
self.editor.tool.Diameter = FreeCAD.Units.parseQuantity(self.form.toolDiameter.text())
|
||||
self.editor.tool.FlatRadius = FreeCAD.Units.parseQuantity(self.form.toolFlatRadius.text())
|
||||
self.editor.tool.CornerRadius = FreeCAD.Units.parseQuantity(self.form.toolCornerRadius.text())
|
||||
self.editor.tool.CuttingEdgeAngle = FreeCAD.Units.Quantity(self.form.toolCuttingEdgeAngle.text())
|
||||
self.editor.tool.CuttingEdgeHeight = FreeCAD.Units.parseQuantity(self.form.toolCuttingEdgeHeight.text())
|
||||
|
||||
class ToolEditorImage(object):
|
||||
'''Base implementation for all customized Tool parameter editors.
|
||||
While not required it is simplest to subclass specific editors.'''
|
||||
def __init__(self, editor, imageFile, hide='', disable=''):
|
||||
self.editor = editor
|
||||
self.form = editor.form
|
||||
self.imagePath = "{}Mod/Path/Images/Tools/{}".format(FreeCAD.getHomePath(), imageFile)
|
||||
self.image = QtGui.QPixmap(self.imagePath)
|
||||
self.hide = hide
|
||||
self.disable = disable
|
||||
|
||||
form = editor.form
|
||||
self.widgets = {
|
||||
'D' : (form.label_D, form.value_D),
|
||||
'd' : (form.label_d, form.value_d),
|
||||
'H' : (form.label_H, form.value_H),
|
||||
'a' : (form.label_a, form.value_a),
|
||||
'S' : (form.label_S, form.value_S)
|
||||
}
|
||||
|
||||
def setupUI(self):
|
||||
PathLog.track()
|
||||
self.form.paramGeneric.hide()
|
||||
self.form.paramImage.show()
|
||||
|
||||
for key, widgets in self.widgets.items():
|
||||
hide = key in self.hide
|
||||
disable = key in self.disable
|
||||
for w in widgets:
|
||||
w.setHidden(hide)
|
||||
w.setDisabled(disable)
|
||||
if not hide and not disable:
|
||||
widgets[1].editingFinished.connect(self.editor.refresh)
|
||||
|
||||
self.form.image.setPixmap(self.image)
|
||||
|
||||
def updateUI(self):
|
||||
PathLog.track()
|
||||
self.form.value_D.setText(self.quantityDiameter(True).UserString)
|
||||
self.form.value_d.setText(self.quantityFlatRadius(True).UserString)
|
||||
self.form.value_a.setText(self.quantityCuttingEdgeAngle(True).UserString)
|
||||
self.form.value_H.setText(self.quantityCuttingEdgeHeight(True).UserString)
|
||||
|
||||
def updateTool(self):
|
||||
PathLog.track()
|
||||
toolDefault = Path.Tool()
|
||||
if 'D' in self.hide:
|
||||
self.editor.tool.Diameter = toolDefault.Diameter
|
||||
else:
|
||||
self.editor.tool.Diameter = self.quantityDiameter(False)
|
||||
|
||||
if 'd' in self.hide:
|
||||
self.editor.tool.FlatRadius = toolDefault.FlatRadius
|
||||
else:
|
||||
self.editor.tool.FlatRadius = self.quantityFlatRadius(False)
|
||||
|
||||
if 'a' in self.hide:
|
||||
self.editor.tool.CuttingEdgeAngle = toolDefault.CuttingEdgeAngle
|
||||
else:
|
||||
self.editor.tool.CuttingEdgeAngle = self.quantityCuttingEdgeAngle(False)
|
||||
|
||||
if 'H' in self.hide:
|
||||
self.editor.tool.CuttingEdgeHeight = toolDefault.CuttingEdgeHeight
|
||||
else:
|
||||
self.editor.tool.CuttingEdgeHeight = self.quantityCuttingEdgeHeight(False)
|
||||
|
||||
self.editor.tool.CornerRadius = toolDefault.CornerRadius
|
||||
|
||||
def quantityDiameter(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(self.editor.tool.Diameter, FreeCAD.Units.Length)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_D.text())
|
||||
|
||||
def quantityFlatRadius(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(self.editor.tool.FlatRadius, FreeCAD.Units.Length) * 2
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_d.text()) / 2
|
||||
|
||||
def quantityCuttingEdgeAngle(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle) / 2
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_a.text()) * 2
|
||||
|
||||
def quantityCuttingEdgeHeight(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(self.editor.tool.CuttingEdgeHeight, FreeCAD.Units.Length)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_H.text())
|
||||
|
||||
class ToolEditorEndmill(ToolEditorImage):
|
||||
'''Tool parameter editor for endmills.'''
|
||||
def __init__(self, editor):
|
||||
super(self.__class__, self).__init__(editor, 'endmill.svg', 'da', 'S')
|
||||
|
||||
class ToolEditorDrill(ToolEditorImage):
|
||||
'''Tool parameter editor for drills.'''
|
||||
def __init__(self, editor):
|
||||
super(self.__class__, self).__init__(editor, 'drill.svg', 'dS', '')
|
||||
|
||||
def quantityCuttingEdgeAngle(self, propertyToDisplay):
|
||||
if propertyToDisplay:
|
||||
return FreeCAD.Units.Quantity(self.editor.tool.CuttingEdgeAngle, FreeCAD.Units.Angle)
|
||||
return FreeCAD.Units.parseQuantity(self.form.value_a.text())
|
||||
|
||||
class ToolEditorEngrave(ToolEditorImage):
|
||||
'''Tool parameter editor for v-bits.'''
|
||||
def __init__(self, editor):
|
||||
super(self.__class__, self).__init__(editor, 'v-bit.svg', '', 'HS')
|
||||
|
||||
def quantityCuttingEdgeHeight(self, propertyToDisplay):
|
||||
PathLog.track()
|
||||
dr = (self.quantityDiameter(False) - self.quantityFlatRadius(False)) / 2
|
||||
da = self.quantityCuttingEdgeAngle(False).Value
|
||||
return dr / math.tan(math.radians(da) / 2)
|
||||
|
||||
class ToolEditor:
|
||||
'''UI and controller for editing a Tool.
|
||||
The controller embeds the UI to the parentWidget which has to have a layout attached to it.
|
||||
The editor maintains two Tools, self.tool and self.Tool. The former is the one being edited
|
||||
and always reflects the current state. self.Tool on the other hand is the "official" Tool
|
||||
which should be used externally. The state is transferred between the two with accept and
|
||||
reject.
|
||||
|
||||
The editor uses instances of ToolEditorDefault and ToolEditorImage to deal with the changes
|
||||
of the actual parameters. For any ToolType not mapped in ToolTypeImage the editor uses
|
||||
an instance of ToolEditorDefault.
|
||||
'''
|
||||
|
||||
ToolTypeImage = {
|
||||
'EndMill': ToolEditorEndmill,
|
||||
'Drill': ToolEditorDrill,
|
||||
'Engraver': ToolEditorEngrave }
|
||||
|
||||
def __init__(self, tool, parentWidget, parent=None):
|
||||
self.Parent = parent
|
||||
self.Tool = tool
|
||||
self.tool = tool.copy()
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/ToolEditor.ui")
|
||||
|
||||
self.form.setParent(parentWidget)
|
||||
parentWidget.layout().addWidget(self.form)
|
||||
|
||||
for tooltype in Path.Tool.getToolTypes(tool):
|
||||
self.form.toolType.addItem(tooltype)
|
||||
for material in Path.Tool.getToolMaterials(tool):
|
||||
self.form.toolMaterial.addItem(material)
|
||||
|
||||
self.setupToolType(self.tool.ToolType)
|
||||
|
||||
def accept(self):
|
||||
self.Tool = self.tool
|
||||
|
||||
def reject(self):
|
||||
self.tool = self.Tool
|
||||
|
||||
def getType(self, tooltype):
|
||||
"gets a combobox index number for a given type or viceversa"
|
||||
toolslist = Path.Tool.getToolTypes(Path.Tool())
|
||||
if isinstance(tooltype, str):
|
||||
if tooltype in toolslist:
|
||||
return toolslist.index(tooltype)
|
||||
else:
|
||||
return 0
|
||||
return toolslist[tooltype]
|
||||
|
||||
def getMaterial(self, material):
|
||||
"gets a combobox index number for a given material or viceversa"
|
||||
matslist = Path.Tool.getToolMaterials(Path.Tool())
|
||||
if isinstance(material, str):
|
||||
if material in matslist:
|
||||
return matslist.index(material)
|
||||
else:
|
||||
return 0
|
||||
return matslist[material]
|
||||
|
||||
def updateUI(self):
|
||||
PathLog.track()
|
||||
self.form.toolName.setText(self.tool.Name)
|
||||
self.form.toolType.setCurrentIndex(self.getType(self.tool.ToolType))
|
||||
self.form.toolMaterial.setCurrentIndex(self.getMaterial(self.tool.Material))
|
||||
self.form.toolLengthOffset.setText(FreeCAD.Units.Quantity(self.tool.LengthOffset, FreeCAD.Units.Length).UserString)
|
||||
|
||||
self.editor.updateUI()
|
||||
|
||||
def updateToolName(self):
|
||||
self.tool.Name = str(self.form.toolName.text())
|
||||
|
||||
def updateToolType(self):
|
||||
PathLog.track()
|
||||
self.form.blockSignals(True)
|
||||
self.tool.ToolType = self.getType(self.form.toolType.currentIndex())
|
||||
self.setupToolType(self.tool.ToolType)
|
||||
self.updateUI()
|
||||
self.form.blockSignals(False)
|
||||
|
||||
def setupToolType(self, tt):
|
||||
PathLog.track()
|
||||
if 'Undefined' == tt:
|
||||
tt = Path.Tool.getToolTypes(Path.Tool())[0]
|
||||
if tt in self.ToolTypeImage:
|
||||
self.editor = self.ToolTypeImage[tt](self)
|
||||
else:
|
||||
PathLog.debug("weak supported ToolType = %s" % (tt))
|
||||
self.editor = ToolEditorDefault(self)
|
||||
self.editor.setupUI()
|
||||
|
||||
def updateTool(self):
|
||||
PathLog.track()
|
||||
self.tool.Material = self.getMaterial(self.form.toolMaterial.currentIndex())
|
||||
self.tool.LengthOffset = FreeCAD.Units.parseQuantity(self.form.toolLengthOffset.text())
|
||||
self.editor.updateTool()
|
||||
|
||||
def refresh(self):
|
||||
PathLog.track()
|
||||
self.form.blockSignals(True)
|
||||
self.updateTool()
|
||||
self.updateUI()
|
||||
self.form.blockSignals(False)
|
||||
|
||||
def setupUI(self):
|
||||
PathLog.track()
|
||||
self.updateUI()
|
||||
|
||||
self.form.toolName.editingFinished.connect(self.updateToolName)
|
||||
self.form.toolType.currentIndexChanged.connect(self.updateToolType)
|
||||
self.form.toolMaterial.currentIndexChanged.connect(self.refresh)
|
||||
self.form.toolLengthOffset.valueChanged.connect(self.refresh)
|
||||
|
||||
Reference in New Issue
Block a user