Refactored pocket and facing to use the same base class; added min travel and keep tool down to the interface - latter one is hidden since it currently doesn't seem to work.

This commit is contained in:
Markus Lampert
2017-08-19 14:37:39 -07:00
committed by Yorik van Havre
parent e2824a777a
commit 5cf63ae2de
7 changed files with 215 additions and 190 deletions

View File

@@ -55,6 +55,7 @@ SET(PathScripts_SRCS
PathScripts/PathOpGui.py
PathScripts/PathPlane.py
PathScripts/PathPocket.py
PathScripts/PathPocketBase.py
PathScripts/PathPocketBaseGui.py
PathScripts/PathPocketGui.py
PathScripts/PathPost.py

File diff suppressed because one or more lines are too long

View File

@@ -26,26 +26,11 @@ from __future__ import print_function
import FreeCAD
import Part
import PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
import PathScripts.PathPocketBase as PathPocketBase
import PathScripts.PathUtils as PathUtils
from PySide import QtCore, QtGui
if True:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
if FreeCAD.GuiUp:
import FreeCADGui
# Qt tanslation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
from PySide import QtCore
__title__ = "Path Mill Face Operation"
__author__ = "sliptonic (Brad Collette)"
@@ -53,31 +38,27 @@ __url__ = "http://www.freecadweb.org"
__doc__ = "Class and implementation of Mill Facing operation."
class ObjectFace(PathAreaOp.ObjectOp):
if True:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# Qt tanslation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
class ObjectFace(PathPocketBase.ObjectPocket):
'''Proxy object for Mill Facing operation.'''
def areaOpFeatures(self, obj):
'''areaOpFeatures(obj) ... mill facing uses FinishDepth and is based on faces.'''
return PathOp.FeatureBaseFaces | PathOp.FeatureFinishDepth
def initAreaOp(self, obj):
'''initAreaOp(obj) ... create operation specific properties'''
# Face Properties
obj.addProperty("App::PropertyEnumeration", "CutMode", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.CutMode = ['Climb', 'Conventional']
obj.addProperty("App::PropertyDistance", "PassExtension", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "How far the cutter should extend past the boundary"))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Start Faceing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyPercent", "StepOver", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Percent of cutter diameter to step over on each pass"))
obj.addProperty("App::PropertyBool", "KeepToolDown", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Attempts to avoid unnecessary retractions."))
obj.addProperty("App::PropertyBool", "ZigUnidirectional", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Lifts tool at the end of each pass to respect cut mode."))
obj.addProperty("App::PropertyBool", "UseZigZag", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use Zig Zag pattern to clear area."))
obj.addProperty("App::PropertyFloat", "ZigZagAngle", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angle of the zigzag pattern"))
def initPocketOp(self, obj):
'''initPocketOp(obj) ... create facing specific properties'''
obj.addProperty("App::PropertyEnumeration", "BoundaryShape", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Shape to use for calculating Boundary"))
obj.BoundaryShape = ['Perimeter', 'Boundbox']
obj.addProperty("App::PropertyEnumeration", "OffsetPattern", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "clearing pattern to use"))
obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
def pocketInvertExtraOffset(self):
return True
def areaOpOnChanged(self, obj, prop):
'''areaOpOnChanged(obj, prop) ... facing specific depths calculation.'''
@@ -95,43 +76,6 @@ class ObjectFace(PathAreaOp.ObjectOp):
obj.StartDepth = d.safe_height
obj.FinalDepth = d.start_depth
def areaOpUseProjection(self, obj):
'''areaOpUseProjection(obj) ... return False'''
return False
def areaOpAreaParams(self, obj, isHole):
'''areaOpAreaPrams(obj, isHole) ... return dictionary with mill facing area parameters'''
params = {}
params['Fill'] = 0
params['Coplanar'] = 0
params['PocketMode'] = 1
params['SectionCount'] = -1
params['Angle'] = obj.ZigZagAngle
params['FromCenter'] = (obj.StartAt == "Center")
params['PocketStepover'] = (self.radius * 2) * (float(obj.StepOver)/100)
params['PocketExtraOffset'] = 0 - obj.PassExtension.Value
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
params['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
params['ToolRadius'] = self.radius
return params
def areaOpPathParams(self, obj, isHole):
'''areaOpPathPrams(obj, isHole) ... return dictionary with mill facing path parameters'''
params = {}
params['feedrate'] = self.horizFeed
params['feedrate_v'] = self.vertFeed
params['verbose'] = True
params['resume_height'] = obj.StepDown
params['retraction'] = obj.ClearanceHeight.Value
if obj.UseStartPoint and obj.StartPoint is not None:
params['start'] = obj.StartPoint
return params
def areaOpShapes(self, obj):
'''areaOpShapes(obj) ... return top face'''
# Facing is done either against base objects

View File

@@ -24,11 +24,10 @@
import FreeCAD
import Part
import PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
import PathScripts.PathPocketBase as PathPocketBase
import PathScripts.PathUtils as PathUtils
from PathScripts import PathUtils
from PySide import QtCore
__doc__ = "Class and implementation of the Pocket operation."
@@ -44,61 +43,16 @@ def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
class ObjectPocket(PathAreaOp.ObjectOp):
class ObjectPocket(PathPocketBase.ObjectPocket):
'''Proxy object for Pocket operation.'''
def areaOpFeatures(self, obj):
'''areaOpFeatures(obj) ... Pockets have a FinishDepth and work on Faces'''
return PathOp.FeatureBaseFaces | PathOp.FeatureFinishDepth
def initPocketOp(self, obj):
'''initPocketOp(obj) ... setup receiver'''
pass
def initAreaOp(self, obj):
'''initAreaOp(obj) ... create pocket specific properties.'''
PathLog.track()
# Pocket Properties
obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.CutMode = ['Climb', 'Conventional']
obj.addProperty("App::PropertyDistance", "MaterialAllowance", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Amount of material to leave"))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Start pocketing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyPercent", "StepOver", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Percent of cutter diameter to step over on each pass"))
obj.addProperty("App::PropertyFloat", "ZigZagAngle", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angle of the zigzag pattern"))
obj.addProperty("App::PropertyEnumeration", "OffsetPattern", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "clearing pattern to use"))
obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
obj.addProperty("App::PropertyBool", "MinTravel", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use 3D Sorting of Path"))
def areaOpUseProjection(self, obj):
'''areaOpUseProjection(obj) ... return False'''
def pocketInvertExtraOffset(self):
return False
def areaOpAreaParams(self, obj, isHole):
'''areaOpAreaParams(obj, isHole) ... return dictionary with pocket's area parameters'''
params = {}
params['Fill'] = 0
params['Coplanar'] = 0
params['PocketMode'] = 1
params['SectionCount'] = -1
params['Angle'] = obj.ZigZagAngle
params['FromCenter'] = (obj.StartAt == "Center")
params['PocketStepover'] = (self.radius * 2) * (float(obj.StepOver)/100)
params['PocketExtraOffset'] = obj.MaterialAllowance.Value
params['ToolRadius'] = self.radius
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
params['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
return params
def areaOpPathParams(self, obj, isHole):
'''areaOpAreaParams(obj, isHole) ... return dictionary with pocket's path parameters'''
params = {}
# if MinTravel is turned on, set path sorting to 3DSort
# 3DSort shouldn't be used without a valid start point. Can cause
# tool crash without it.
if obj.MinTravel and obj.UseStartPoint and obj.StartPoint is not None:
params['sort_mode'] = 2
return params
def areaOpShapes(self, obj):
'''areaOpShapes(obj) ... return shapes representing the solids to be removed.'''
PathLog.track()

View File

@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2017 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 PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
from PySide import QtCore
__title__ = "Base Path Pocket Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path pocket operations."
if True:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# Qt tanslation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
class ObjectPocket(PathAreaOp.ObjectOp):
'''Base class for proxy objects of all pocket operations.'''
def areaOpFeatures(self, obj):
'''areaOpFeatures(obj) ... Pockets have a FinishDepth and work on Faces'''
return PathOp.FeatureBaseFaces | PathOp.FeatureFinishDepth
def initAreaOp(self, obj):
'''initAreaOp(obj) ... create pocket specific properties.
Do not overwrite, implement initPocketOp(obj) instead.'''
PathLog.track()
# Pocket Properties
obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
obj.CutMode = ['Climb', 'Conventional']
obj.addProperty("App::PropertyDistance", "ExtraOffset", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra offset to apply to the operation. Direction is operation dependent."))
obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Start pocketing at center or boundary"))
obj.StartAt = ['Center', 'Edge']
obj.addProperty("App::PropertyPercent", "StepOver", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Percent of cutter diameter to step over on each pass"))
obj.addProperty("App::PropertyFloat", "ZigZagAngle", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Angle of the zigzag pattern"))
obj.addProperty("App::PropertyEnumeration", "OffsetPattern", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "clearing pattern to use"))
obj.OffsetPattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
obj.addProperty("App::PropertyBool", "MinTravel", "Pocket", QtCore.QT_TRANSLATE_NOOP("App::Property", "Use 3D Sorting of Path"))
obj.addProperty("App::PropertyBool", "KeepToolDown", "Face", QtCore.QT_TRANSLATE_NOOP("App::Property", "Attempts to avoid unnecessary retractions."))
self.initPocketOp(obj)
def areaOpRetractTool(self, obj):
PathLog.debug("retracting tool: %d" % (not obj.KeepToolDown))
return not obj.KeepToolDown
def areaOpUseProjection(self, obj):
'''areaOpUseProjection(obj) ... return False'''
return False
def areaOpAreaParams(self, obj, isHole):
'''areaOpAreaParams(obj, isHole) ... return dictionary with pocket's area parameters'''
params = {}
params['Fill'] = 0
params['Coplanar'] = 0
params['PocketMode'] = 1
params['SectionCount'] = -1
params['Angle'] = obj.ZigZagAngle
params['FromCenter'] = (obj.StartAt == "Center")
params['PocketStepover'] = (self.radius * 2) * (float(obj.StepOver)/100)
extraOffset = obj.ExtraOffset.Value
if self.pocketInvertExtraOffset():
extraOffset = 0 - extraOffset
params['PocketExtraOffset'] = extraOffset
params['ToolRadius'] = self.radius
Pattern = ['ZigZag', 'Offset', 'Spiral', 'ZigZagOffset', 'Line', 'Grid', 'Triangle']
params['PocketMode'] = Pattern.index(obj.OffsetPattern) + 1
return params
def areaOpPathParams(self, obj, isHole):
'''areaOpAreaParams(obj, isHole) ... return dictionary with pocket's path parameters'''
params = {}
# if MinTravel is turned on, set path sorting to 3DSort
# 3DSort shouldn't be used without a valid start point. Can cause
# tool crash without it.
if obj.MinTravel and obj.UseStartPoint and obj.StartPoint is not None:
params['sort_mode'] = 2
return params

View File

@@ -60,14 +60,37 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
'''getForm() ... returns UI, adapted to the resutls from pocketFeatures()'''
form = FreeCADGui.PySideUic.loadUi(":/panels/PageOpPocketFullEdit.ui")
if not FeaturePocket & self.pocketFeatures():
form.pocketWidget.hide()
if not FeatureFacing & self.pocketFeatures():
if FeatureFacing & self.pocketFeatures():
form.extraOffsetLabel.setText(translate("PathPocket", "Pass Extension"))
form.extraOffset.setToolTip(translate("PathPocket", "The distance the facing operation will extend beyond the boundary shape."))
else:
form.facingWidget.hide()
if True:
# currently doesn't have an effect
form.keepToolDown.hide()
return form
def updateMinTravel(self, obj, setModel=True):
if obj.UseStartPoint:
self.form.minTravel.setEnabled(True)
else:
self.form.minTravel.setChecked(False)
self.form.minTravel.setEnabled(False)
if setModel and obj.MinTravel != self.form.minTravel.isChecked():
obj.MinTravel = self.form.minTravel.isChecked()
def updateZigZagAngle(self, obj, setModel=True):
if obj.OffsetPattern in ['Offset', 'Spiral']:
self.form.zigZagAngle.setEnabled(False)
else:
self.form.zigZagAngle.setEnabled(True)
if setModel:
self.updateInputField(obj, 'ZigZagAngle', self.form.zigZagAngle)
def getFields(self, obj):
'''getFields(obj) ... transfers values from UI to obj's proprties'''
if obj.CutMode != str(self.form.cutMode.currentText()):
@@ -76,35 +99,40 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
obj.StepOver = self.form.stepOverPercent.value()
if obj.OffsetPattern != str(self.form.offsetPattern.currentText()):
obj.OffsetPattern = str(self.form.offsetPattern.currentText())
self.updateInputField(obj, 'ZigZagAngle', self.form.zigZagAngle)
self.updateInputField(obj, 'ExtraOffset', self.form.extraOffset)
self.updateToolController(obj, self.form.toolController)
self.updateZigZagAngle(obj)
if FeaturePocket & self.pocketFeatures():
self.updateInputField(obj, 'MaterialAllowance', self.form.extraOffset)
if obj.UseStartPoint != self.form.useStartPoint.isChecked():
obj.UseStartPoint = self.form.useStartPoint.isChecked()
if obj.UseStartPoint != self.form.useStartPoint.isChecked():
obj.UseStartPoint = self.form.useStartPoint.isChecked()
if obj.KeepToolDown != self.form.keepToolDown.isChecked():
obj.KeepToolDown = self.form.keepToolDown.isChecked()
self.updateMinTravel(obj)
if FeatureFacing & self.pocketFeatures():
self.updateInputField(obj, 'PassExtension', self.form.passExtension)
if obj.BoundaryShape != str(self.form.boundaryShape.currentText()):
obj.BoundaryShape = str(self.form.boundaryShape.currentText())
def setFields(self, obj):
'''setFields(obj) ... transfers obj's property values to UI'''
self.form.zigZagAngle.setText(FreeCAD.Units.Quantity(obj.ZigZagAngle, FreeCAD.Units.Angle).UserString)
self.form.stepOverPercent.setValue(obj.StepOver)
self.form.extraOffset.setText(FreeCAD.Units.Quantity(obj.ExtraOffset.Value, FreeCAD.Units.Length).UserString)
self.form.useStartPoint.setChecked(obj.UseStartPoint)
self.form.keepToolDown.setChecked(obj.KeepToolDown)
self.form.zigZagAngle.setText(FreeCAD.Units.Quantity(obj.ZigZagAngle, FreeCAD.Units.Angle).UserString)
self.updateZigZagAngle(obj, False)
self.form.minTravel.setChecked(obj.MinTravel)
self.updateMinTravel(obj, False)
self.selectInComboBox(obj.OffsetPattern, self.form.offsetPattern)
self.selectInComboBox(obj.CutMode, self.form.cutMode)
self.setupToolController(obj, self.form.toolController)
if FeaturePocket & self.pocketFeatures():
self.form.useStartPoint.setChecked(obj.UseStartPoint)
self.form.extraOffset.setText(FreeCAD.Units.Quantity(obj.MaterialAllowance.Value, FreeCAD.Units.Length).UserString)
if FeatureFacing & self.pocketFeatures():
self.form.passExtension.setText(FreeCAD.Units.Quantity(obj.PassExtension.Value, FreeCAD.Units.Length).UserString)
self.selectInComboBox(obj.BoundaryShape, self.form.boundaryShape)
def getSignalsForUpdate(self, obj):
@@ -116,13 +144,12 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
signals.append(self.form.stepOverPercent.editingFinished)
signals.append(self.form.zigZagAngle.editingFinished)
signals.append(self.form.toolController.currentIndexChanged)
if FeaturePocket & self.pocketFeatures():
signals.append(self.form.extraOffset.editingFinished)
signals.append(self.form.useStartPoint.clicked)
signals.append(self.form.extraOffset.editingFinished)
signals.append(self.form.useStartPoint.clicked)
signals.append(self.form.keepToolDown.clicked)
signals.append(self.form.minTravel.clicked)
if FeatureFacing & self.pocketFeatures():
signals.append(self.form.boundaryShape.currentIndexChanged)
signals.append(self.form.passExtension.editingFinished)
return signals

View File

@@ -29,7 +29,7 @@ import PathScripts.PathOp as PathOp
from PySide import QtCore
__title__ = "Path Contour Operation"
__title__ = "Base Path Profile Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path profile operations."
@@ -40,22 +40,10 @@ if False:
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtGui
# Qt tanslation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
__title__ = "Path Profile Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and properties for all profile operations."
"""Path Profile object and FreeCAD command for operating on sets of features"""
class ObjectProfile(PathAreaOp.ObjectOp):
'''Base class for proxy objects of all profile operations.'''