Merge pull request #3938 from sliptonic/feature/dragknifepanel
[PATH] Task panel for dragknife and axismap dressups. fixes #2840
This commit is contained in:
@@ -83,6 +83,7 @@
|
||||
<file>icons/edge-join-round-not.svg</file>
|
||||
<file>icons/edge-join-round.svg</file>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>panels/AxisMapEdit.ui</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
<file>panels/DlgJobCreate.ui</file>
|
||||
<file>panels/DlgJobModelSelect.ui</file>
|
||||
@@ -94,6 +95,7 @@
|
||||
<file>panels/DlgToolEdit.ui</file>
|
||||
<file>panels/DogboneEdit.ui</file>
|
||||
<file>panels/DressupPathBoundary.ui</file>
|
||||
<file>panels/DragKnifeEdit.ui</file>
|
||||
<file>panels/HoldingTagsEdit.ui</file>
|
||||
<file>panels/PageBaseGeometryEdit.ui</file>
|
||||
<file>panels/PageBaseHoleGeometryEdit.ui</file>
|
||||
|
||||
105
src/Mod/Path/Gui/Resources/panels/AxisMapEdit.ui
Normal file
105
src/Mod/Path/Gui/Resources/panels/AxisMapEdit.ui
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskPanel</class>
|
||||
<widget class="QWidget" name="TaskPanel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>376</width>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>AxisMap Dressup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>275</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblRadius">
|
||||
<property name="text">
|
||||
<string>Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<widget class="Gui::QuantitySpinBox" name="radius">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The radius of the wrapped axis</p></body></html></string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblAxisMapInput">
|
||||
<property name="text">
|
||||
<string>Axis Mapping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="2">
|
||||
<widget class="QComboBox" name="axisMapInput">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The input mapping axis. Coordinates of the first axis will be mapped to the second.</p></body></html></string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>X->A</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Y->A</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>X->B</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Y->B</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>X->C</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Y->C</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
110
src/Mod/Path/Gui/Resources/panels/DragKnifeEdit.ui
Normal file
110
src/Mod/Path/Gui/Resources/panels/DragKnifeEdit.ui
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskPanel</class>
|
||||
<widget class="QWidget" name="TaskPanel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>376</width>
|
||||
<height>387</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dragknife Dressup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>275</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblFilterAngle">
|
||||
<property name="text">
|
||||
<string>Filter Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblPivotHeight">
|
||||
<property name="text">
|
||||
<string>Pivot Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="2">
|
||||
<widget class="Gui::QuantitySpinBox" name="offsetDistance">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Distance the point trails behind the spindle</p></body></html></string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblOffSetDistance">
|
||||
<property name="text">
|
||||
<string>Offset Distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="Gui::QuantitySpinBox" name="pivotHeight">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Height to raise during corner action</p></body></html></string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<widget class="Gui::QuantitySpinBox" name="filterAngle">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Angles less than filter angle will not receive corner actions</p></body></html></string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">deg</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -26,6 +26,7 @@ import Path
|
||||
import math
|
||||
import PathScripts.PathGeom as PathGeom
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import PathScripts.PathGui as PathGui
|
||||
|
||||
from PySide import QtCore
|
||||
|
||||
@@ -35,21 +36,24 @@ if FreeCAD.GuiUp:
|
||||
__doc__ = """Axis remapping Dressup object and FreeCAD command. This dressup remaps one axis of motion to another.
|
||||
For example, you can re-map the Y axis to A to control a 4th axis rotary."""
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
movecommands = ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']
|
||||
rapidcommands = ['G0', 'G00']
|
||||
arccommands = ['G2', 'G3', 'G02', 'G03']
|
||||
|
||||
|
||||
class ObjectDressup:
|
||||
|
||||
def __init__(self, obj):
|
||||
maplist = ["X->A", "Y->A", "X->B", "Y->B", "X->C", "Y->C"]
|
||||
obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The base path to modify"))
|
||||
obj.addProperty("App::PropertyEnumeration", "AxisMap", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The input mapping axis"))
|
||||
obj.addProperty("App::PropertyDistance", "Radius", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The radius of the wrapped axis"))
|
||||
obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The base path to modify"))
|
||||
obj.addProperty("App::PropertyEnumeration", "AxisMap", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The input mapping axis"))
|
||||
obj.addProperty("App::PropertyDistance", "Radius", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupAxisMap", "The radius of the wrapped axis"))
|
||||
obj.AxisMap = maplist
|
||||
obj.AxisMap = "Y->A"
|
||||
obj.Proxy = self
|
||||
@@ -68,15 +72,15 @@ class ObjectDressup:
|
||||
def _stripArcs(self, path, d):
|
||||
'''converts all G2/G3 commands into G1 commands'''
|
||||
newcommandlist = []
|
||||
currLocation = {'X':0,'Y':0,'Z':0, 'F': 0}
|
||||
currLocation = {'X': 0, 'Y': 0, 'Z': 0, 'F': 0}
|
||||
|
||||
for p in path:
|
||||
if p.Name in arccommands:
|
||||
curVec = FreeCAD.Vector(currLocation['X'], currLocation['Y'], currLocation['Z'])
|
||||
arcwire = PathGeom.edgeForCmd(p, curVec)
|
||||
pointlist = arcwire.discretize(Deflection=d)
|
||||
pointlist = arcwire.discretize(Deflection=d)
|
||||
for point in pointlist:
|
||||
newcommand = Path.Command("G1", {'X':point.x, 'Y':point.y, 'Z':point.z})
|
||||
newcommand = Path.Command("G1", {'X': point.x, 'Y': point.y, 'Z': point.z})
|
||||
newcommandlist.append(newcommand)
|
||||
currLocation.update(newcommand.Parameters)
|
||||
else:
|
||||
@@ -85,7 +89,6 @@ class ObjectDressup:
|
||||
|
||||
return newcommandlist
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
inAxis = obj.AxisMap[0]
|
||||
@@ -103,20 +106,20 @@ class ObjectDressup:
|
||||
pathlist = self._stripArcs(pp, d)
|
||||
|
||||
newcommandlist = []
|
||||
currLocation = {'X':0,'Y':0,'Z':0, 'F': 0}
|
||||
currLocation = {'X': 0, 'Y': 0, 'Z': 0, 'F': 0}
|
||||
|
||||
for c in pathlist: #obj.Base.Path.Commands:
|
||||
for c in pathlist:
|
||||
newparams = dict(c.Parameters)
|
||||
remapvar = newparams.pop(inAxis, None)
|
||||
if remapvar is not None:
|
||||
newparams[outAxis] = self._linear2angular(obj.Radius, remapvar)
|
||||
locdiff = dict(set(newparams.items()) - set(currLocation.items()))
|
||||
if len(locdiff) == 1 and outAxis in locdiff: #pure rotation. Calculate rotational feed rate
|
||||
if len(locdiff) == 1 and outAxis in locdiff: # pure rotation. Calculate rotational feed rate
|
||||
if 'F' in c.Parameters:
|
||||
feed = c.Parameters['F']
|
||||
else:
|
||||
feed = currLocation['F']
|
||||
newparams.update({"F":self._linear2angular(obj.Radius, feed)})
|
||||
newparams.update({"F": self._linear2angular(obj.Radius, feed)})
|
||||
newcommand = Path.Command(c.Name, newparams)
|
||||
newcommandlist.append(newcommand)
|
||||
currLocation.update(newparams)
|
||||
@@ -129,15 +132,61 @@ class ObjectDressup:
|
||||
obj.Path = path
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if not 'Restore' in obj.State and prop == "Radius":
|
||||
if 'Restore' not in obj.State and prop == "Radius":
|
||||
job = PathUtils.findParentJob(obj)
|
||||
if job:
|
||||
job.Proxy.setCenterOfRotation(self.center(obj))
|
||||
|
||||
|
||||
def center(self, obj):
|
||||
return FreeCAD.Vector(0, 0, 0 - obj.Radius.Value)
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/AxisMapEdit.ui")
|
||||
self.radius = PathGui.QuantitySpinBox(self.form.radius, obj, 'Radius')
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupDragKnife", "Edit Dragknife Dress-up"))
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getFields(self):
|
||||
self.radius.updateProperty()
|
||||
self.obj.AxisMap = self.form.axisMapInput.currentText()
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def updateUI(self):
|
||||
self.radius.updateSpinBox()
|
||||
self.form.axisMapInput.setCurrentText(self.obj.AxisMap)
|
||||
self.updateModel()
|
||||
|
||||
def updateModel(self):
|
||||
self.getFields()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def setFields(self):
|
||||
self.updateUI()
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
|
||||
def setupUi(self):
|
||||
self.setFields()
|
||||
self.form.radius.valueChanged.connect(self.updateModel)
|
||||
self.form.axisMapInput.currentIndexChanged.connect(self.updateModel)
|
||||
|
||||
|
||||
class ViewProviderDressup:
|
||||
|
||||
def __init__(self, vobj):
|
||||
@@ -156,6 +205,18 @@ class ViewProviderDressup:
|
||||
# FreeCADGui.ActiveDocument.getObject(obj.Base.Name).Visibility = False
|
||||
return
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
# pylint: disable=unused-argument
|
||||
return False
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
# pylint: disable=unused-argument
|
||||
FreeCADGui.Control.closeDialog()
|
||||
panel = TaskPanel(vobj.Object)
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
panel.setupUi()
|
||||
return True
|
||||
|
||||
def claimChildren(self):
|
||||
return [self.obj.Base]
|
||||
|
||||
@@ -176,6 +237,7 @@ class ViewProviderDressup:
|
||||
arg1.Object.Base = None
|
||||
return True
|
||||
|
||||
|
||||
class CommandPathDressup:
|
||||
# pylint: disable=no-init
|
||||
|
||||
@@ -219,6 +281,7 @@ class CommandPathDressup:
|
||||
FreeCADGui.doCommand('job.Proxy.addOperation(obj, base)')
|
||||
FreeCADGui.doCommand('obj.ViewObject.Proxy = PathScripts.PathDressupAxisMap.ViewProviderDressup(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('Gui.ActiveDocument.getObject(base.Name).Visibility = False')
|
||||
FreeCADGui.doCommand('obj.ViewObject.Document.setEdit(obj.ViewObject, 0)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import Path
|
||||
from PySide import QtCore
|
||||
import math
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import PathScripts.PathGui as PathGui
|
||||
|
||||
# lazily loaded modules
|
||||
from lazy_loader.lazy_loader import LazyLoader
|
||||
@@ -38,10 +39,12 @@ __doc__ = """Dragknife Dressup object and FreeCAD command"""
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
# Qt translation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
movecommands = ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']
|
||||
rapidcommands = ['G0', 'G00']
|
||||
arccommands = ['G2', 'G3', 'G02', 'G03']
|
||||
@@ -52,8 +55,8 @@ currLocation = {}
|
||||
class ObjectDressup:
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base path to modify"))
|
||||
obj.addProperty("App::PropertyAngle", "filterangle", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angles less than filter angle will not receive corner actions"))
|
||||
obj.addProperty("App::PropertyLink", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base path to modify"))
|
||||
obj.addProperty("App::PropertyAngle", "filterAngle", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angles less than filter angle will not receive corner actions"))
|
||||
obj.addProperty("App::PropertyFloat", "offset", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Distance the point trails behind the spindle"))
|
||||
obj.addProperty("App::PropertyFloat", "pivotheight", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Height to raise during corner action"))
|
||||
|
||||
@@ -66,7 +69,8 @@ class ObjectDressup:
|
||||
return None
|
||||
|
||||
def shortcut(self, queue):
|
||||
'''Determines whether its shorter to twist CW or CCW to align with the next move'''
|
||||
'''Determines whether its shorter to twist CW or CCW to align with
|
||||
the next move'''
|
||||
# get the vector of the last move
|
||||
|
||||
if queue[1].Name in arccommands:
|
||||
@@ -127,7 +131,7 @@ class ObjectDressup:
|
||||
|
||||
def arcExtension(self, obj, queue):
|
||||
'''returns gcode for arc extension'''
|
||||
global currLocation # pylint: disable=global-statement
|
||||
global currLocation # pylint: disable=global-statement
|
||||
results = []
|
||||
|
||||
offset = obj.offset
|
||||
@@ -166,7 +170,7 @@ class ObjectDressup:
|
||||
'''returns gcode to do an arc move toward an arc to perform
|
||||
a corner action twist. Includes lifting and plungeing the knife'''
|
||||
|
||||
global currLocation # pylint: disable=global-statement
|
||||
global currLocation # pylint: disable=global-statement
|
||||
pivotheight = obj.pivotheight
|
||||
offset = obj.offset
|
||||
results = []
|
||||
@@ -233,7 +237,7 @@ class ObjectDressup:
|
||||
|
||||
def lineExtension(self, obj, queue):
|
||||
'''returns gcode for line extension'''
|
||||
global currLocation # pylint: disable=global-statement
|
||||
global currLocation # pylint: disable=global-statement
|
||||
|
||||
offset = float(obj.offset)
|
||||
results = []
|
||||
@@ -259,7 +263,7 @@ class ObjectDressup:
|
||||
def lineTwist(self, obj, queue, lastXY, twistCW=False):
|
||||
'''returns gcode to do an arc move toward a line to perform
|
||||
a corner action twist. Includes lifting and plungeing the knife'''
|
||||
global currLocation # pylint: disable=global-statement
|
||||
global currLocation # pylint: disable=global-statement
|
||||
pivotheight = obj.pivotheight
|
||||
offset = obj.offset
|
||||
|
||||
@@ -310,7 +314,7 @@ class ObjectDressup:
|
||||
|
||||
def execute(self, obj):
|
||||
newpath = []
|
||||
global currLocation # pylint: disable=global-statement
|
||||
global currLocation # pylint: disable=global-statement
|
||||
|
||||
if not obj.Base:
|
||||
return
|
||||
@@ -384,7 +388,7 @@ class ObjectDressup:
|
||||
# check if the inciden angle incident exceeds the filter
|
||||
incident_angle = self.getIncidentAngle(queue)
|
||||
|
||||
if abs(incident_angle) >= obj.filterangle:
|
||||
if abs(incident_angle) >= obj.filterAngle:
|
||||
if self.shortcut(queue) == "CW":
|
||||
# if incident_angle >= 0:
|
||||
twistCW = True
|
||||
@@ -430,6 +434,56 @@ class ObjectDressup:
|
||||
obj.Path = path
|
||||
|
||||
|
||||
class TaskPanel:
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/DragKnifeEdit.ui")
|
||||
self.filterAngle = PathGui.QuantitySpinBox(self.form.filterAngle, obj, 'filterAngle')
|
||||
self.offsetDistance = PathGui.QuantitySpinBox(self.form.offsetDistance, obj, 'offset')
|
||||
self.pivotHeight = PathGui.QuantitySpinBox(self.form.pivotHeight, obj, 'pivotheight')
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_DressupDragKnife", "Edit Dragknife Dress-up"))
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def getFields(self):
|
||||
self.filterAngle.updateProperty()
|
||||
self.offsetDistance.updateProperty()
|
||||
self.pivotHeight.updateProperty()
|
||||
self.updateUI()
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def updateUI(self):
|
||||
self.filterAngle.updateSpinBox()
|
||||
self.offsetDistance.updateSpinBox()
|
||||
self.pivotHeight.updateSpinBox()
|
||||
|
||||
def updateModel(self):
|
||||
self.getFields()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def setFields(self):
|
||||
self.updateUI()
|
||||
|
||||
def open(self):
|
||||
pass
|
||||
|
||||
def setupUi(self):
|
||||
self.setFields()
|
||||
|
||||
|
||||
class ViewProviderDressup:
|
||||
|
||||
def __init__(self, vobj):
|
||||
@@ -454,6 +508,10 @@ class ViewProviderDressup:
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
# pylint: disable=unused-argument
|
||||
FreeCADGui.Control.closeDialog()
|
||||
panel = TaskPanel(vobj.Object)
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
panel.setupUi()
|
||||
return True
|
||||
|
||||
def claimChildren(self):
|
||||
@@ -521,9 +579,10 @@ class CommandDressupDragknife:
|
||||
FreeCADGui.doCommand('job.Proxy.addOperation(obj, base)')
|
||||
FreeCADGui.doCommand('obj.ViewObject.Proxy = PathScripts.PathDressupDragknife.ViewProviderDressup(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('Gui.ActiveDocument.getObject(base.Name).Visibility = False')
|
||||
FreeCADGui.doCommand('obj.filterangle = 20')
|
||||
FreeCADGui.doCommand('obj.filterAngle = 20')
|
||||
FreeCADGui.doCommand('obj.offset = 2')
|
||||
FreeCADGui.doCommand('obj.pivotheight = 4')
|
||||
FreeCADGui.doCommand('obj.ViewObject.Document.setEdit(obj.ViewObject, 0)')
|
||||
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
@@ -41,11 +41,13 @@ Part = LazyLoader('Part', globals(), 'Part')
|
||||
"""Z Depth Correction Dressup. This dressup takes a probe file as input and does bilinear interpolation of the Zdepths to correct for a surface which is not parallel to the milling table/bed. The probe file should conform to the format specified by the linuxcnc G38 probe logging: 9-number coordinate consisting of XYZABCUVW http://linuxcnc.org/docs/html/gcode/g-code.html#gcode:g38
|
||||
"""
|
||||
|
||||
LOGLEVEL = False
|
||||
|
||||
LOG_MODULE = PathLog.thisModule()
|
||||
|
||||
if False:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
if LOGLEVEL:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE)
|
||||
PathLog.trackModule(PathLog.thisModule())
|
||||
else:
|
||||
PathLog.setLevel(PathLog.Level.NOTICE, LOG_MODULE)
|
||||
|
||||
@@ -67,7 +69,6 @@ class ObjectDressup:
|
||||
obj.addProperty("App::PropertyFile", "probefile", "ProbeData", QtCore.QT_TRANSLATE_NOOP("Path_DressupZCorrect", "The point file from the surface probing."))
|
||||
obj.Proxy = self
|
||||
obj.addProperty("Part::PropertyPartShape", "interpSurface", "Path")
|
||||
#obj.setEditorMode('interpSurface', 2) # hide
|
||||
obj.addProperty("App::PropertyDistance", "ArcInterpolate", "Interpolate", QtCore.QT_TRANSLATE_NOOP("Path_DressupZCorrect", "Deflection distance for arc interpolation"))
|
||||
obj.addProperty("App::PropertyDistance", "SegInterpolate", "Interpolate", QtCore.QT_TRANSLATE_NOOP("Path_DressupZCorrectp", "break segments into smaller segments of this length."))
|
||||
obj.ArcInterpolate = 0.1
|
||||
@@ -335,6 +336,7 @@ class CommandPathDressup:
|
||||
FreeCADGui.doCommand('PathScripts.PathDressupZCorrect.ViewProviderDressup(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
FreeCADGui.doCommand('Gui.ActiveDocument.getObject(obj.Base.Name).Visibility = False')
|
||||
FreeCADGui.doCommand('obj.ViewObject.Document.setEdit(obj.ViewObject, 0)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
("App::PropertyDistance", "InternalFeaturesAdjustment", "Selected Geometry Settings",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Positive values push the cutter toward, or into, the feature. Negative values retract the cutter away from the feature.")),
|
||||
("App::PropertyBool", "InternalFeaturesCut", "Selected Geometry Settings",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Ignore internal feature areas within a larger selected face.")),
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Cut internal feature areas within a larger selected face.")),
|
||||
|
||||
("App::PropertyEnumeration", "BoundBox", "Clearing Options",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Select the overall boundary for the operation.")),
|
||||
@@ -249,8 +249,8 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
'AvoidLastX_Faces': 0,
|
||||
'PatternCenterCustom': FreeCAD.Vector(0.0, 0.0, 0.0),
|
||||
'GapThreshold': 0.005,
|
||||
'AngularDeflection': 0.25, # AngularDeflection is unused
|
||||
# Reasonable compromise between speed & precision
|
||||
'AngularDeflection': 0.25, # AngularDeflection is unused
|
||||
# Reasonable compromise between speed & precision
|
||||
'LinearDeflection': 0.001,
|
||||
# For debugging
|
||||
'ShowTempObjects': False
|
||||
@@ -341,7 +341,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
if isinstance(val, int) or isinstance(val, float):
|
||||
setVal = True
|
||||
if setVal:
|
||||
propVal = getattr(prop, 'Value')
|
||||
setattr(prop, 'Value', val)
|
||||
else:
|
||||
setattr(obj, n, val)
|
||||
@@ -625,7 +624,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
self.commandlist.extend(CMDS)
|
||||
else:
|
||||
PathLog.error('Failed to pre-process model and/or selected face(s).')
|
||||
|
||||
|
||||
# ###### CLOSING COMMANDS FOR OPERATION ######
|
||||
|
||||
@@ -973,7 +971,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
return SCANS
|
||||
|
||||
def _planarDropCutScan(self, pdc, A, B):
|
||||
#PNTS = list()
|
||||
(x1, y1) = A
|
||||
(x2, y2) = B
|
||||
path = ocl.Path() # create an empty path object
|
||||
@@ -988,7 +985,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
return PNTS # pdc.getCLPoints()
|
||||
|
||||
def _planarCircularDropCutScan(self, pdc, Arc, cMode):
|
||||
PNTS = list()
|
||||
path = ocl.Path() # create an empty path object
|
||||
(sp, ep, cp) = Arc
|
||||
|
||||
@@ -1038,7 +1034,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
PRTS = SCANDATA[so]
|
||||
lenPRTS = len(PRTS)
|
||||
first = PRTS[0][0] # first point of arc/line stepover group
|
||||
start = PRTS[0][0] # will change with each line/arc segment
|
||||
last = None
|
||||
cmds.append(Path.Command('N (Begin step {}.)'.format(so), {}))
|
||||
|
||||
@@ -1068,7 +1063,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
tolrnc))
|
||||
else:
|
||||
cmds.append(Path.Command('N (part {}.)'.format(i + 1), {}))
|
||||
start = prt[0]
|
||||
last = prt[lenPrt - 1]
|
||||
if so == peIdx or peIdx == -1:
|
||||
cmds.extend(self._planarSinglepassProcess(obj, prt))
|
||||
@@ -1129,18 +1123,15 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
peIdx = lenSCANDATA - 1
|
||||
|
||||
# Process each layer in depthparams
|
||||
prvLyrFirst = None
|
||||
prvLyrLast = None
|
||||
lastPrvStpLast = None
|
||||
for lyr in range(0, lenDP):
|
||||
odd = True # ZigZag directional switch
|
||||
lyrHasCmds = False
|
||||
actvSteps = 0
|
||||
LYR = list()
|
||||
prvStpFirst = None
|
||||
if lyr > 0:
|
||||
if prvStpLast is not None:
|
||||
lastPrvStpLast = prvStpLast
|
||||
# if lyr > 0:
|
||||
# if prvStpLast is not None:
|
||||
# lastPrvStpLast = prvStpLast
|
||||
prvStpLast = None
|
||||
lyrDep = depthparams[lyr]
|
||||
PathLog.debug('Multi-pass lyrDep: {}'.format(round(lyrDep, 4)))
|
||||
@@ -1244,7 +1235,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
if prtsHasCmds is True:
|
||||
stepHasCmds = True
|
||||
actvSteps += 1
|
||||
prvStpFirst = first
|
||||
stpOvrCmds.extend(transCmds)
|
||||
stpOvrCmds.append(Path.Command('N (Begin step {}.)'.format(so), {}))
|
||||
stpOvrCmds.append(Path.Command('G0', {'X': first.x, 'Y': first.y, 'F': self.horizRapid}))
|
||||
@@ -1253,7 +1243,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
|
||||
# Layer transition at first active step over in current layer
|
||||
if actvSteps == 1:
|
||||
prvLyrFirst = first
|
||||
LYR.append(Path.Command('N (Layer {} begins)'.format(lyr), {}))
|
||||
if lyr > 0:
|
||||
LYR.append(Path.Command('N (Layer transition)', {}))
|
||||
@@ -1267,7 +1256,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
|
||||
# Close layer, saving commands, if any
|
||||
if lyrHasCmds is True:
|
||||
prvLyrLast = last
|
||||
GCODE.extend(LYR) # save line commands
|
||||
GCODE.append(Path.Command('N (End of layer {})'.format(lyr), {}))
|
||||
|
||||
@@ -1366,13 +1354,13 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
prcs = False
|
||||
if onHold is False:
|
||||
onHold = True
|
||||
output.append( Path.Command('N (Start hold)', {}) )
|
||||
output.append( Path.Command('G0', {'Z': clrScnLn, 'F': self.vertRapid}) )
|
||||
output.append(Path.Command('N (Start hold)', {}))
|
||||
output.append(Path.Command('G0', {'Z': clrScnLn, 'F': self.vertRapid}))
|
||||
else:
|
||||
if onHold is True:
|
||||
onHold = False
|
||||
output.append( Path.Command('N (End hold)', {}) )
|
||||
output.append( Path.Command('G0', {'X': pnt.x, 'Y': pnt.y, 'F': self.horizRapid}) )
|
||||
output.append(Path.Command('N (End hold)', {}))
|
||||
output.append(Path.Command('G0', {'X': pnt.x, 'Y': pnt.y, 'F': self.horizRapid}))
|
||||
|
||||
# Process point
|
||||
if prcs is True:
|
||||
@@ -1541,7 +1529,6 @@ class ObjectSurface(PathOp.ObjectOp):
|
||||
pdc.setSampling(SampleInterval) # set sampling size
|
||||
return pdc
|
||||
|
||||
|
||||
# Main rotational scan functions
|
||||
def _processRotationalOp(self, JOB, obj, mdlIdx, compoundFaces=None):
|
||||
PathLog.debug('_processRotationalOp(self, JOB, obj, mdlIdx, compoundFaces=None)')
|
||||
|
||||
@@ -139,7 +139,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
("App::PropertyDistance", "InternalFeaturesAdjustment", "Selected Geometry Settings",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Positive values push the cutter toward, or into, the feature. Negative values retract the cutter away from the feature.")),
|
||||
("App::PropertyBool", "InternalFeaturesCut", "Selected Geometry Settings",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Ignore internal feature areas within a larger selected face.")),
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Cut internal feature areas within a larger selected face.")),
|
||||
|
||||
("App::PropertyEnumeration", "Algorithm", "Clearing Options",
|
||||
QtCore.QT_TRANSLATE_NOOP("App::Property", "Select the algorithm to use: OCL Dropcutter*, or Experimental (Not OCL based).")),
|
||||
@@ -341,7 +341,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
if isinstance(val, int) or isinstance(val, float):
|
||||
setVal = True
|
||||
if setVal:
|
||||
propVal = getattr(prop, 'Value')
|
||||
setattr(prop, 'Value', val)
|
||||
else:
|
||||
setattr(obj, n, val)
|
||||
@@ -790,8 +789,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
if scan is False:
|
||||
erFlg = True
|
||||
else:
|
||||
##if aTyp == 'L':
|
||||
## stpOvr.append(FreeCAD.Vector(scan[0][0].x, scan[0][0].y, scan[0][0].z))
|
||||
stpOvr.append(scan)
|
||||
if erFlg is False:
|
||||
SCANS.append(stpOvr)
|
||||
@@ -819,7 +816,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
horizGC = 'G1'
|
||||
height = first.z
|
||||
elif (minSTH + (2.0 * tolrnc)) >= max(first.z, lstPnt.z):
|
||||
height = False # allow end of Zig to cut to beginning of Zag
|
||||
height = False # allow end of Zig to cut to beginning of Zag
|
||||
|
||||
# Create raise, shift, and optional lower commands
|
||||
if height is not False:
|
||||
@@ -881,7 +878,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
self.layerEndPnt = FreeCAD.Vector(0.0, 0.0, 0.0)
|
||||
|
||||
# Set extra offset to diameter of cutter to allow cutter to move around perimeter of model
|
||||
toolDiam = self.cutter.getDiameter()
|
||||
|
||||
if subShp is None:
|
||||
# Get correct boundbox
|
||||
@@ -1012,9 +1008,9 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
for p in range(0, pntsPerLine):
|
||||
pre.append(0)
|
||||
post.append(0)
|
||||
for l in range(0, lenSL):
|
||||
self.topoMap[l].insert(0, 0)
|
||||
self.topoMap[l].append(0)
|
||||
for i in range(0, lenSL):
|
||||
self.topoMap[i].insert(0, 0)
|
||||
self.topoMap[i].append(0)
|
||||
self.topoMap.insert(0, pre)
|
||||
self.topoMap.append(post)
|
||||
return True
|
||||
@@ -1195,7 +1191,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
# generate the path commands
|
||||
output = []
|
||||
|
||||
prev = FreeCAD.Vector(2135984513.165, -58351896873.17455, 13838638431.861)
|
||||
# prev = FreeCAD.Vector(2135984513.165, -58351896873.17455, 13838638431.861)
|
||||
nxt = FreeCAD.Vector(0.0, 0.0, 0.0)
|
||||
|
||||
# Create first point
|
||||
@@ -1218,7 +1214,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'F': self.horizFeed}))
|
||||
|
||||
# Rotate point data
|
||||
prev = pnt
|
||||
pnt = nxt
|
||||
|
||||
# Save layer end point for use in transitioning to next layer
|
||||
@@ -1233,7 +1228,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
PathLog.debug('_experimentalWaterlineOp()')
|
||||
|
||||
commands = []
|
||||
t_begin = time.time()
|
||||
base = JOB.Model.Group[mdlIdx]
|
||||
# safeSTL = self.safeSTLs[mdlIdx]
|
||||
self.endVector = None
|
||||
@@ -1287,7 +1281,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
caCnt += 1
|
||||
if area.Area > 0.0:
|
||||
cont = True
|
||||
caWireCnt = len(area.Wires) - 1 # first wire is boundFace wire
|
||||
self.showDebugObject(area, 'CutArea_{}'.format(caCnt))
|
||||
else:
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
@@ -1297,7 +1290,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
if cont:
|
||||
area.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - area.BoundBox.ZMin))
|
||||
activeArea = area.cut(trimFace)
|
||||
activeAreaWireCnt = len(activeArea.Wires) # first wire is boundFace wire
|
||||
self.showDebugObject(activeArea, 'ActiveArea_{}'.format(caCnt))
|
||||
ofstArea = PathUtils.getOffsetArea(activeArea,
|
||||
ofst,
|
||||
@@ -1370,9 +1362,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
|
||||
# Get slice at depth of shape
|
||||
csFaces = self._getModelCrossSection(shape, csHght) # returned at Z=0.0
|
||||
if not csFaces:
|
||||
data = FreeCAD.Units.Quantity(csHght, FreeCAD.Units.Length).UserString
|
||||
else:
|
||||
if csFaces:
|
||||
if len(csFaces) > 0:
|
||||
useFaces = self._getSolidAreasFromPlanarFaces(csFaces)
|
||||
else:
|
||||
@@ -1497,8 +1487,8 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
GCODE = [Path.Command('N (Beginning of Single-pass layer.)', {})]
|
||||
tolrnc = JOB.GeometryTolerance.Value
|
||||
lenstpOVRS = len(stpOVRS)
|
||||
lstSO = lenstpOVRS - 1
|
||||
lstStpOvr = False
|
||||
# lstSO = lenstpOVRS - 1
|
||||
# lstStpOvr = False
|
||||
gDIR = ['G3', 'G2']
|
||||
|
||||
if self.CutClimb is True:
|
||||
@@ -1518,8 +1508,6 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
first = PRTS[0][0] # first point of arc/line stepover group
|
||||
last = None
|
||||
cmds.append(Path.Command('N (Begin step {}.)'.format(so), {}))
|
||||
if so == lstSO:
|
||||
lstStpOvr = True
|
||||
|
||||
if so > 0:
|
||||
if cutPattern == 'CircularZigZag':
|
||||
@@ -1689,7 +1677,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
PathLog.track()
|
||||
|
||||
paths = []
|
||||
pathParams = {} # pylint: disable=assignment-from-no-return
|
||||
pathParams = {} # pylint: disable=assignment-from-no-return
|
||||
|
||||
pathParams['shapes'] = [wire]
|
||||
pathParams['feedrate'] = self.horizFeed
|
||||
@@ -1705,7 +1693,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
(pp, end_vector) = Path.fromShapes(**pathParams)
|
||||
paths.extend(pp.Commands)
|
||||
|
||||
self.endVector = end_vector # pylint: disable=attribute-defined-outside-init
|
||||
self.endVector = end_vector # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
return (paths, end_vector)
|
||||
|
||||
@@ -1739,8 +1727,8 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
xyz = endPnt
|
||||
cmds.append(Path.Command('G1', {'X': strtPnt.x, 'Y': strtPnt.y, 'Z': strtPnt.z, 'F': self.horizFeed}))
|
||||
cmds.append(Path.Command(gCmd, {'X': xyz.x, 'Y': xyz.y, 'Z': xyz.z,
|
||||
'I': ijk.x, 'J': ijk.y, 'K': ijk.z, # leave same xyz.z height
|
||||
'F': self.horizFeed}))
|
||||
'I': ijk.x, 'J': ijk.y, 'K': ijk.z, # leave same xyz.z height
|
||||
'F': self.horizFeed}))
|
||||
cmds.append(Path.Command('G1', {'X': endPnt.x, 'Y': endPnt.y, 'Z': endPnt.z, 'F': self.horizFeed}))
|
||||
|
||||
return cmds
|
||||
@@ -1819,7 +1807,7 @@ class ObjectWaterline(PathOp.ObjectOp):
|
||||
do.Shape = objShape
|
||||
do.purgeTouched()
|
||||
self.tempGroup.addObject(do)
|
||||
# Eclass
|
||||
|
||||
|
||||
def SetupProperties():
|
||||
''' SetupProperties() ... Return list of properties required for operation.'''
|
||||
|
||||
Reference in New Issue
Block a user