Path: lgtm Cleanup

This commit is contained in:
brad
2019-06-08 18:55:44 -05:00
parent 58608df237
commit 4cbdf78836
7 changed files with 169 additions and 144 deletions

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
@@ -36,12 +35,12 @@ from PathScripts.PathUtils import findParentJob
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
from DraftTools import translate
# from DraftTools import translate
else:
def translate(ctxt, txt):
return txt
__title__="FreeCAD Path Commands"
__title__ = "FreeCAD Path Commands"
__author__ = "sliptonic"
__url__ = "http://www.freecadweb.org"
@@ -80,7 +79,7 @@ class _CommandSelectLoop:
return False
def Activated(self):
#from PathScripts.PathUtils import loopdetect
# from PathScripts.PathUtils import loopdetect
from PathScripts.PathUtils import horizontalEdgeLoop
from PathScripts.PathUtils import horizontalFaceLoop
sel = FreeCADGui.Selection.getSelectionEx()[0]
@@ -104,7 +103,7 @@ class _CommandSelectLoop:
for e in elist:
for i in loopwire.Edges:
if e.hashCode() == i.hashCode():
FreeCADGui.Selection.addSelection(obj, "Edge"+str(elist.index(e)+1))
FreeCADGui.Selection.addSelection(obj, "Edge" + str(elist.index(e) + 1))
def formsPartOfALoop(self, obj, sub, names):
if names[0][0:4] != 'Edge':
@@ -117,9 +116,11 @@ class _CommandSelectLoop:
return False
return True
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Path_SelectLoop', _CommandSelectLoop())
class _ToggleOperation:
"command definition to toggle Operation Active state"
def GetResources(self):
@@ -135,7 +136,7 @@ class _ToggleOperation:
try:
obj = FreeCADGui.Selection.getSelectionEx()[0].Object
return isinstance(obj.Proxy, PathScripts.PathOp.ObjectOp)
except:
except(IndexError, AttributeError):
return False
def Activated(self):
@@ -143,9 +144,11 @@ class _ToggleOperation:
obj.Active = not(obj.Active)
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Path_OpActiveToggle', _ToggleOperation())
class _CopyOperation:
"the Path Copy Operation command definition"
def GetResources(self):
@@ -160,7 +163,7 @@ class _CopyOperation:
try:
obj = FreeCADGui.Selection.getSelectionEx()[0].Object
return isinstance(obj.Proxy, PathScripts.PathOp.ObjectOp)
except:
except(IndexError, AttributeError):
return False
def Activated(self):

View File

@@ -246,7 +246,7 @@ class CommandPathArray:
try:
obj = FreeCADGui.Selection.getSelectionEx()[0].Object
return isinstance(obj.Proxy, PathScripts.PathOp.ObjectOp)
except:
except(IndexError, AttributeError):
return False
def Activated(self):

View File

@@ -26,7 +26,7 @@
import FreeCAD
import FreeCADGui
import Path
from PySide import QtCore, QtGui
from PySide import QtCore
# Qt translation handling
def translate(context, text, disambig=None):

View File

@@ -24,12 +24,12 @@
import FreeCAD
import Part
import Path
# import Path
import PathScripts.PathEngraveBase as PathEngraveBase
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp
import PathScripts.PathOpTools as PathOpTools
import PathScripts.PathUtil as PathUtil
# import PathScripts.PathUtil as PathUtil
import math
from PySide import QtCore
@@ -40,25 +40,28 @@ if False:
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
def toolDepthAndOffset(width, extraDepth, tool):
'''toolDepthAndOffset(width, extraDepth, tool) ... return tuple for given parameters.'''
angle = tool.CuttingEdgeAngle
if 0 == angle:
angle = 180
tan = math.tan(math.radians(angle/2))
tan = math.tan(math.radians(angle / 2))
toolDepth = 0 if 0 == tan else width / tan
extraDepth = extraDepth
# extraDepth = extraDepth
depth = toolDepth + extraDepth
toolOffset = tool.FlatRadius
extraOffset = tool.Diameter/2 - width if 180 == angle else extraDepth / tan
extraOffset = tool.Diameter / 2 - width if 180 == angle else extraDepth / tan
offset = toolOffset + extraOffset
return (depth, offset)
class ObjectDeburr(PathEngraveBase.ObjectOp):
'''Proxy class for Deburr operation.'''
@@ -67,14 +70,14 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
def initOperation(self, obj):
PathLog.track(obj.Label)
obj.addProperty('App::PropertyDistance', 'Width', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'The desired width of the chamfer'))
obj.addProperty('App::PropertyDistance', 'ExtraDepth', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'The additional depth of the tool path'))
obj.addProperty('App::PropertyEnumeration', 'Join', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'How to join chamfer segments'))
obj.addProperty('App::PropertyDistance', 'Width', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'The desired width of the chamfer'))
obj.addProperty('App::PropertyDistance', 'ExtraDepth', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'The additional depth of the tool path'))
obj.addProperty('App::PropertyEnumeration', 'Join', 'Deburr', QtCore.QT_TRANSLATE_NOOP('PathDeburr', 'How to join chamfer segments'))
obj.Join = ['Round', 'Miter']
obj.setEditorMode('Join', 2) # hide for now
obj.setEditorMode('Join', 2) # hide for now
def opOnDocumentRestored(self, obj):
obj.setEditorMode('Join', 2) # hide for now
obj.setEditorMode('Join', 2) # hide for now
def opExecute(self, obj):
PathLog.track(obj.Label)
@@ -125,7 +128,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
def opRejectAddBase(self, obj, base, sub):
'''The chamfer op can only deal with features of the base model, all others are rejected.'''
return not base in self.model
return base not in self.model
def opSetDefaultValues(self, obj, job):
PathLog.track(obj.Label, job.Label)
@@ -135,16 +138,17 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
obj.setExpression('StepDown', '0 mm')
obj.StepDown = '0 mm'
def SetupProperties():
setup = []
setup.append('Width')
setup.append('ExtraDepth')
return setup
def Create(name, obj = None):
def Create(name, obj=None):
'''Create(name) ... Creates and returns a Deburr operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
proxy = ObjectDeburr(obj, name)
return obj

View File

@@ -30,7 +30,7 @@ import PathScripts.PathJob as PathJob
import PathScripts.PathJobCmd as PathJobCmd
import PathScripts.PathJobDlg as PathJobDlg
import PathScripts.PathGeom as PathGeom
import PathScripts.PathGui as PathGui
# import PathScripts.PathGui as PathGui
import PathScripts.PathGuiInit as PathGuiInit
import PathScripts.PathLog as PathLog
import PathScripts.PathPreferences as PathPreferences
@@ -41,7 +41,7 @@ import PathScripts.PathToolLibraryManager as PathToolLibraryManager
import PathScripts.PathUtil as PathUtil
import PathScripts.PathUtils as PathUtils
import math
import sys
# import sys
import traceback
from PySide import QtCore, QtGui
@@ -49,16 +49,19 @@ from collections import Counter
from contextlib import contextmanager
from pivy import coin
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
def _OpenCloseResourceEditor(obj, vobj, edit):
job = PathUtils.findParentJob(obj)
if job and job.ViewObject and job.ViewObject.Proxy:
@@ -74,6 +77,7 @@ def _OpenCloseResourceEditor(obj, vobj, edit):
missing = 'Proxy'
PathLog.warning("Cannot edit %s - no %s" % (obj.Label, missing))
@contextmanager
def selectionEx():
sel = FreeCADGui.Selection.getSelectionEx()
@@ -173,7 +177,7 @@ class ViewProvider:
PathLog.info("Expected a specific object to edit - %s not recognized" % obj.Label)
return self.openTaskPanel()
def uneditObject(self, obj = None):
def uneditObject(self, obj=None):
self.unsetEdit(None, None)
def getIcon(self):
@@ -247,6 +251,7 @@ class ViewProvider:
action.triggered.connect(self.setEdit)
menu.addAction(action)
class StockEdit(object):
Index = -1
StockType = PathStock.StockType.Unknown
@@ -262,8 +267,9 @@ class StockEdit(object):
def IsStock(cls, obj):
return PathStock.StockType.FromStock(obj.Stock) == cls.StockType
def activate(self, obj, select = False):
def activate(self, obj, select=False):
PathLog.track(obj.Label, select)
def showHide(widget, activeWidget):
if widget == activeWidget:
widget.show()
@@ -294,11 +300,14 @@ class StockEdit(object):
# the following members must be overwritten by subclasses
def editorFrame(self):
return None
def setFields(self, obj):
pass
def setupUi(self, obj):
pass
class StockFromBaseBoundBoxEdit(StockEdit):
Index = 2
StockType = PathStock.StockType.FromBase
@@ -307,7 +316,7 @@ class StockFromBaseBoundBoxEdit(StockEdit):
PathLog.track()
return self.form.stockFromBase
def getFieldsStock(self, stock, fields = ['xneg', 'xpos', 'yneg', 'ypos', 'zneg', 'zpos']):
def getFieldsStock(self, stock, fields=['xneg', 'xpos', 'yneg', 'ypos', 'zneg', 'zpos']):
try:
if 'xneg' in fields:
stock.ExtXneg = FreeCAD.Units.Quantity(self.form.stockExtXneg.text())
@@ -324,7 +333,7 @@ class StockFromBaseBoundBoxEdit(StockEdit):
except:
pass
def getFields(self, obj, fields = ['xneg', 'xpos', 'yneg', 'ypos', 'zneg', 'zpos']):
def getFields(self, obj, fields=['xneg', 'xpos', 'yneg', 'ypos', 'zneg', 'zpos']):
PathLog.track(obj.Label, fields)
if self.IsStock(obj):
self.getFieldsStock(obj.Stock, fields)
@@ -363,9 +372,11 @@ class StockFromBaseBoundBoxEdit(StockEdit):
def checkXpos(self):
self.trackXpos = self.form.stockExtXneg.text() == self.form.stockExtXpos.text()
self.getFields(self.obj, ['xpos'])
def checkYpos(self):
self.trackYpos = self.form.stockExtYneg.text() == self.form.stockExtYpos.text()
self.getFields(self.obj, ['ypos'])
def checkZpos(self):
self.trackZpos = self.form.stockExtZneg.text() == self.form.stockExtZpos.text()
self.getFields(self.obj, ['zpos'])
@@ -376,12 +387,14 @@ class StockFromBaseBoundBoxEdit(StockEdit):
self.form.stockExtXpos.setText(self.form.stockExtXneg.text())
fields.append('xpos')
self.getFields(self.obj, fields)
def updateYpos(self):
fields = ['yneg']
if self.trackYpos:
self.form.stockExtYpos.setText(self.form.stockExtYneg.text())
fields.append('ypos')
self.getFields(self.obj, fields)
def updateZpos(self):
fields = ['zneg']
if self.trackZpos:
@@ -389,6 +402,7 @@ class StockFromBaseBoundBoxEdit(StockEdit):
fields.append('zpos')
self.getFields(self.obj, fields)
class StockCreateBoxEdit(StockEdit):
Index = 0
StockType = PathStock.StockType.CreateBox
@@ -396,13 +410,13 @@ class StockCreateBoxEdit(StockEdit):
def editorFrame(self):
return self.form.stockCreateBox
def getFields(self, obj, fields = ['length', 'widht', 'height']):
def getFields(self, obj, fields=['length', 'widht', 'height']):
try:
if self.IsStock(obj):
if 'length' in fields:
obj.Stock.Length = FreeCAD.Units.Quantity(self.form.stockBoxLength.text())
if 'width' in fields:
obj.Stock.Width = FreeCAD.Units.Quantity(self.form.stockBoxWidth.text())
obj.Stock.Width = FreeCAD.Units.Quantity(self.form.stockBoxWidth.text())
if 'height' in fields:
obj.Stock.Height = FreeCAD.Units.Quantity(self.form.stockBoxHeight.text())
else:
@@ -415,15 +429,16 @@ class StockCreateBoxEdit(StockEdit):
self.setStock(obj, PathStock.CreateBox(obj))
self.force = False
self.setLengthField(self.form.stockBoxLength, obj.Stock.Length)
self.setLengthField(self.form.stockBoxWidth, obj.Stock.Width)
self.setLengthField(self.form.stockBoxWidth, obj.Stock.Width)
self.setLengthField(self.form.stockBoxHeight, obj.Stock.Height)
def setupUi(self, obj):
self.setFields(obj)
self.form.stockBoxLength.textChanged.connect(lambda: self.getFields(obj, ['length']))
self.form.stockBoxWidth.textChanged.connect(lambda: self.getFields(obj, ['width']))
self.form.stockBoxWidth.textChanged.connect(lambda: self.getFields(obj, ['width']))
self.form.stockBoxHeight.textChanged.connect(lambda: self.getFields(obj, ['height']))
class StockCreateCylinderEdit(StockEdit):
Index = 1
StockType = PathStock.StockType.CreateCylinder
@@ -431,7 +446,7 @@ class StockCreateCylinderEdit(StockEdit):
def editorFrame(self):
return self.form.stockCreateCylinder
def getFields(self, obj, fields = ['radius', 'height']):
def getFields(self, obj, fields=['radius', 'height']):
try:
if self.IsStock(obj):
if 'radius' in fields:
@@ -455,6 +470,7 @@ class StockCreateCylinderEdit(StockEdit):
self.form.stockCylinderRadius.textChanged.connect(lambda: self.getFields(obj, ['radius']))
self.form.stockCylinderHeight.textChanged.connect(lambda: self.getFields(obj, ['height']))
class StockFromExistingEdit(StockEdit):
Index = 3
StockType = PathStock.StockType.Unknown
@@ -464,7 +480,7 @@ class StockFromExistingEdit(StockEdit):
def getFields(self, obj):
stock = self.form.stockExisting.itemData(self.form.stockExisting.currentIndex())
if not (hasattr(obj.Stock, 'Objects') and len(obj.Stock.Objects) == 1 and obj.Stock.Objects[0] == stock):
if not (hasattr(obj.Stock, 'Objects') and len(obj.Stock.Objects) == 1 and obj.Stock.Objects[0] == stock):
if stock:
stock = PathJob.createResourceClone(obj, stock, 'Stock', 'Stock')
stock.ViewObject.Visibility = True
@@ -499,6 +515,7 @@ class StockFromExistingEdit(StockEdit):
self.setFields(obj)
self.form.stockExisting.currentIndexChanged.connect(lambda: self.getFields(obj))
class TaskPanel:
DataObject = QtCore.Qt.ItemDataRole.UserRole
DataProperty = QtCore.Qt.ItemDataRole.UserRole + 1
@@ -609,7 +626,7 @@ class TaskPanel:
flist.append(self.form.wcslist.item(i).text())
self.obj.Fixtures = flist
except:
FreeCAD.Console.PrintWarning("The Job was created without fixture support. Please delete and recreate the job\r\n")
FreeCAD.Console.PrintWarning("The Job was created without fixture support. Please delete and recreate the job\r\n")
self.updateTooltips()
self.stockEdit.getFields(self.obj)
@@ -641,7 +658,7 @@ class TaskPanel:
vUnit = FreeCAD.Units.Quantity(1, FreeCAD.Units.Velocity).getUserPreferred()[2]
for row,tc in enumerate(sorted(self.obj.ToolController, key=lambda tc: tc.Label)):
for row, tc in enumerate(sorted(self.obj.ToolController, key=lambda tc: tc.Label)):
self.form.activeToolController.addItem(tc.Label, tc)
if tc == select:
index = row
@@ -701,11 +718,10 @@ class TaskPanel:
item = self.form.wcslist.findItems(f, QtCore.Qt.MatchExactly)[0]
item.setCheckState(QtCore.Qt.Checked)
self.form.postProcessorOutputFile.setText(self.obj.PostProcessorOutputFile)
self.selectComboBoxText(self.form.postProcessor, self.obj.PostProcessor)
self.form.postProcessorArguments.setText(self.obj.PostProcessorArgs)
#self.obj.Proxy.onChanged(self.obj, "PostProcessor")
# self.obj.Proxy.onChanged(self.obj, "PostProcessor")
self.updateTooltips()
self.form.operationsList.clear()
@@ -758,16 +774,16 @@ class TaskPanel:
row = self.form.operationsList.currentRow()
if row > 0:
item = self.form.operationsList.takeItem(row)
self.form.operationsList.insertItem(row-1, item)
self.form.operationsList.setCurrentRow(row-1)
self.form.operationsList.insertItem(row - 1, item)
self.form.operationsList.setCurrentRow(row - 1)
self.getFields()
def operationMoveDown(self):
row = self.form.operationsList.currentRow()
if row < self.form.operationsList.count() - 1:
item = self.form.operationsList.takeItem(row)
self.form.operationsList.insertItem(row+1, item)
self.form.operationsList.setCurrentRow(row+1)
self.form.operationsList.insertItem(row + 1, item)
self.form.operationsList.setCurrentRow(row + 1)
self.getFields()
def toolControllerSelect(self):
@@ -837,7 +853,7 @@ class TaskPanel:
if FreeCAD.Units.Velocity == val.Unit:
setattr(tc, prop, val)
elif FreeCAD.Units.Unit() == val.Unit:
val = FreeCAD.Units.Quantity(item.text()+vUnit);
val = FreeCAD.Units.Quantity(item.text() + vUnit)
setattr(tc, prop, val)
except:
pass
@@ -857,13 +873,13 @@ class TaskPanel:
PathLog.debug("flip")
p = sel.Object.Placement
loc = sel.Object.Placement.Base
rot = FreeCAD.Rotation(FreeCAD.Vector(1-axis.x, 1-axis.y, 1-axis.z), 180)
rot = FreeCAD.Rotation(FreeCAD.Vector(1 - axis.x, 1 - axis.y, 1 - axis.z), 180)
sel.Object.Placement = FreeCAD.Placement(loc, p.Rotation.multiply(rot))
def rotateSel(sel, n):
p = sel.Object.Placement
loc = sel.Object.Placement.Base
r = axis.cross(n) # rotation axis
# p = sel.Object.Placement
# loc = sel.Object.Placement.Base
r = axis.cross(n) # rotation axis
a = DraftVecUtils.angle(n, axis, r) * 180 / math.pi
PathLog.debug("oh boy: (%.2f, %.2f, %.2f) -> %.2f" % (r.x, r.y, r.z, a))
Draft.rotate(sel.Object, a, axis=r)
@@ -969,22 +985,26 @@ class TaskPanel:
FreeCADGui.Selection.addSelection(selObject, selFeature)
return (selObject, p)
def updateStockEditor(self, index, force = False):
def updateStockEditor(self, index, force=False):
def setupFromBaseEdit():
PathLog.track(index, force)
if force or not self.stockFromBase:
self.stockFromBase = StockFromBaseBoundBoxEdit(self.obj, self.form, force)
self.stockEdit = self.stockFromBase
def setupCreateBoxEdit():
PathLog.track(index, force)
if force or not self.stockCreateBox:
self.stockCreateBox = StockCreateBoxEdit(self.obj, self.form, force)
self.stockEdit = self.stockCreateBox
def setupCreateCylinderEdit():
PathLog.track(index, force)
if force or not self.stockCreateCylinder:
self.stockCreateCylinder = StockCreateCylinderEdit(self.obj, self.form, force)
self.stockEdit = self.stockCreateCylinder
def setupFromExisting():
PathLog.track(index, force)
if force or not self.stockFromExisting:
@@ -1098,7 +1118,7 @@ class TaskPanel:
want = Counter(models)
have = Counter([proxy.baseObject(obj, o) for o in obj.Model.Group])
obsolete = have - want
obsolete = have - want
additions = want - have
# first remove all obsolete base models
@@ -1123,7 +1143,6 @@ class TaskPanel:
else:
PathLog.track('no changes to model')
def tabPageChanged(self, index):
if index == 0:
# update the template with potential changes
@@ -1156,8 +1175,8 @@ class TaskPanel:
self.form.operationUp.clicked.connect(self.operationMoveUp)
self.form.operationDown.clicked.connect(self.operationMoveDown)
self.form.operationEdit.hide() # not supported yet
self.form.activeToolGroup.hide() # not supported yet
self.form.operationEdit.hide() # not supported yet
self.form.activeToolGroup.hide() # not supported yet
# Tool controller
self.form.toolControllerList.itemSelectionChanged.connect(self.toolControllerSelect)
@@ -1179,26 +1198,26 @@ class TaskPanel:
self.form.modelSetXAxis.clicked.connect(lambda: self.modelSetAxis(FreeCAD.Vector(1, 0, 0)))
self.form.modelSetYAxis.clicked.connect(lambda: self.modelSetAxis(FreeCAD.Vector(0, 1, 0)))
self.form.modelSetZAxis.clicked.connect(lambda: self.modelSetAxis(FreeCAD.Vector(0, 0, 1)))
self.form.modelSetX0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector(-1, 0, 0)))
self.form.modelSetY0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector( 0, -1, 0)))
self.form.modelSetZ0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector( 0, 0, -1)))
self.form.modelSetX0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector(-1, 0, 0)))
self.form.modelSetY0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector(0, -1, 0)))
self.form.modelSetZ0.clicked.connect(lambda: self.modelSet0(FreeCAD.Vector(0, 0, -1)))
self.form.setOrigin.clicked.connect(self.alignSetOrigin)
self.form.moveToOrigin.clicked.connect(self.alignMoveToOrigin)
self.form.modelMoveLeftUp.clicked.connect( lambda: self.modelMove(FreeCAD.Vector(-1, 1, 0)))
self.form.modelMoveLeft.clicked.connect( lambda: self.modelMove(FreeCAD.Vector(-1, 0, 0)))
self.form.modelMoveLeftDown.clicked.connect( lambda: self.modelMove(FreeCAD.Vector(-1, -1, 0)))
self.form.modelMoveLeftUp.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(-1, 1, 0)))
self.form.modelMoveLeft.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(-1, 0, 0)))
self.form.modelMoveLeftDown.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(-1, -1, 0)))
self.form.modelMoveUp.clicked.connect( lambda: self.modelMove(FreeCAD.Vector( 0, 1, 0)))
self.form.modelMoveDown.clicked.connect( lambda: self.modelMove(FreeCAD.Vector( 0, -1, 0)))
self.form.modelMoveUp.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(0, 1, 0)))
self.form.modelMoveDown.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(0, -1, 0)))
self.form.modelMoveRightUp.clicked.connect( lambda: self.modelMove(FreeCAD.Vector( 1, 1, 0)))
self.form.modelMoveRight.clicked.connect( lambda: self.modelMove(FreeCAD.Vector( 1, 0, 0)))
self.form.modelMoveRightDown.clicked.connect( lambda: self.modelMove(FreeCAD.Vector( 1, -1, 0)))
self.form.modelMoveRightUp.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(1, 1, 0)))
self.form.modelMoveRight.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(1, 0, 0)))
self.form.modelMoveRightDown.clicked.connect(lambda: self.modelMove(FreeCAD.Vector(1, -1, 0)))
self.form.modelRotateLeft.clicked.connect( lambda: self.modelRotate(FreeCAD.Vector(0, 0, 1)))
self.form.modelRotateRight.clicked.connect( lambda: self.modelRotate(FreeCAD.Vector(0, 0, -1)))
self.form.modelRotateLeft.clicked.connect(lambda: self.modelRotate(FreeCAD.Vector(0, 0, 1)))
self.form.modelRotateRight.clicked.connect(lambda: self.modelRotate(FreeCAD.Vector(0, 0, -1)))
self.updateSelection()
@@ -1227,13 +1246,17 @@ class TaskPanel:
# SelectionObserver interface
def addSelection(self, doc, obj, sub, pnt):
self.updateSelection()
def removeSelection(self, doc, obj, sub):
self.updateSelection()
def setSelection(self, doc):
self.updateSelection()
def clearSelection(self, doc):
self.updateSelection()
def Create(base, template=None):
'''Create(base, template) ... creates a job instance for the given base object
using template to configure it.'''
@@ -1251,6 +1274,6 @@ def Create(base, template=None):
traceback.print_exc(exc)
FreeCAD.ActiveDocument.abortTransaction()
# make sure the UI has been initialized
PathGuiInit.Startup()

View File

@@ -58,10 +58,8 @@ from __future__ import print_function
import FreeCAD
import MeshPart
# import Part
import Path
import PathScripts.PathLog as PathLog
# import PathScripts.PathPocketBase as PathPocketBase
import PathScripts.PathUtils as PathUtils
import PathScripts.PathOp as PathOp
@@ -94,7 +92,7 @@ def translate(context, text, disambig=None):
# OCL must be installed
try:
import ocl
except:
except ImportError:
FreeCAD.Console.PrintError(
translate("Path_Surface", "This operation requires OpenCamLib to be installed.") + "\n")
import sys
@@ -113,7 +111,7 @@ class ObjectSurface(PathOp.ObjectOp):
def baseObject(self):
'''baseObject() ... returns super of receiver
Used to call base implementation in overwritten functions.'''
return super(__class__, self)
return super(self.__class__, self)
def opFeatures(self, obj):
'''opFeatures(obj) ... return all standard features and edges based geomtries'''
@@ -184,13 +182,13 @@ class ObjectSurface(PathOp.ObjectOp):
initIdx = 0.0
# Instantiate additional class operation variables
rtn = self.resetOpVariables()
self.resetOpVariables()
# mark beginning of operation
self.startTime = time.time()
# Set cutter for OCL based on tool controller properties
rtn = self.setOclCutter(obj)
self.setOclCutter(obj)
self.reportThis("\n-----\n-----\nBegin 3D surface operation")
self.reportThis("Script version: " + __scriptVersion__ + " Lm: " + __lastModified__)
@@ -297,7 +295,7 @@ class ObjectSurface(PathOp.ObjectOp):
t = ocl.Triangle(ocl.Point(p[0], p[1], p[2] + obj.DepthOffset.Value),
ocl.Point(q[0], q[1], q[2] + obj.DepthOffset.Value),
ocl.Point(r[0], r[1], r[2] + obj.DepthOffset.Value))
aT = stl.addTriangle(t)
stl.addTriangle(t)
final = self._waterlineOp(obj, stl, bb)
elif obj.Algorithm == 'OCL Dropcutter':
# Create stl object via OCL
@@ -309,7 +307,7 @@ class ObjectSurface(PathOp.ObjectOp):
t = ocl.Triangle(ocl.Point(p[0], p[1], p[2]),
ocl.Point(q[0], q[1], q[2]),
ocl.Point(r[0], r[1], r[2]))
aT = stl.addTriangle(t)
stl.addTriangle(t)
# Rotate model back to original index
if obj.ScanType == 'Rotational':
@@ -479,8 +477,8 @@ class ObjectSurface(PathOp.ObjectOp):
if ignoreWasteFlag is True:
topoMap = createTopoMap(scanCLP, obj.IgnoreWasteDepth)
self.topoMap = listToMultiDimensional(topoMap, numLines, pntsPerLine)
rtnA = self._bufferTopoMap(numLines, pntsPerLine)
rtnB = self._highlightWaterline(4, 1)
self._bufferTopoMap(numLines, pntsPerLine)
self._highlightWaterline(4, 1)
self.topoMap = debufferMultiDimenList(self.topoMap)
ignoreMap = multiDimensionalToList(self.topoMap)
@@ -568,7 +566,7 @@ class ObjectSurface(PathOp.ObjectOp):
holdCount = 0
holdLine = 0
onLine = False
lineOfTravel = "X"
# lineOfTravel = "X"
pointsOnLine = 0
zMin = prvDep
zMax = prvDep
@@ -603,7 +601,7 @@ class ObjectSurface(PathOp.ObjectOp):
travVect = ocl.Point(float("inf"), float("inf"), float("inf"))
# Determine if releasing model from ignore waste areas
if obj.ReleaseFromWaste == True:
if obj.ReleaseFromWaste is True:
minIgnVal = 0
# Set values for first gcode point in layer
@@ -630,7 +628,7 @@ class ObjectSurface(PathOp.ObjectOp):
pntCount += 1
if pntCount == 1:
# PathLog.debug("--Start row: " + str(rowCount))
nn = 1
pass # nn = 1
elif pntCount == pntsPerLine:
# PathLog.debug("--End row: " + str(rowCount))
pntCount = 0
@@ -769,8 +767,8 @@ class ObjectSurface(PathOp.ObjectOp):
if self.onHold is False:
if not optimize or not self.isPointOnLine(FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)):
output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
elif i == lastCLP:
output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
# elif i == lastCLP:
# output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
# Rotate point data
prev.x = pnt.x
@@ -831,7 +829,6 @@ class ObjectSurface(PathOp.ObjectOp):
hscType = self.holdStopTypes.pop(0)
if hscType == "End":
N = None
# Create gcode commands to connect p1 and p2
hpCmds = self.holdStopEndCmds(obj, p2, "Hold Stop: End point")
elif hscType == "Mid":
@@ -867,7 +864,6 @@ class ObjectSurface(PathOp.ObjectOp):
return commands
def _rotationalDropCutterOp(self, obj, stl, bb):
eT = time.time()
self.resetTolerance = 0.0000001 # degrees
self.layerEndzMax = 0.0
commands = []
@@ -878,12 +874,12 @@ class ObjectSurface(PathOp.ObjectOp):
rings = []
lCnt = 0
rNum = 0
stepDeg = 1.1
layCircum = 1.1
begIdx = 0.0
endIdx = 0.0
arc = 0.0
sumAdv = 0.0
# stepDeg = 1.1
# layCircum = 1.1
# begIdx = 0.0
# endIdx = 0.0
# arc = 0.0
# sumAdv = 0.0
bbRad = self.bbRadius
def invertAdvances(advances):
@@ -905,7 +901,7 @@ class ObjectSurface(PathOp.ObjectOp):
rngs.append([1.1]) # Initiate new ring
for line in scanLines: # extract circular set(ring) of points from scan lines
rngs[num].append(line[num])
nn = rngs[num].pop(0)
rngs[num].pop(0)
return rngs
def indexAdvances(arc, stepDeg):
@@ -1027,8 +1023,8 @@ class ObjectSurface(PathOp.ObjectOp):
else:
if obj.CutMode == 'Conventional':
advances = invertAdvances(advances)
rt = advances.reverse()
rtn = scanLines.reverse()
advances.reverse()
scanLines.reverse()
# Invert advances if RotationAxis == Y
if obj.RotationAxis == 'Y':
@@ -1062,8 +1058,8 @@ class ObjectSurface(PathOp.ObjectOp):
def _indexedDropCutScan(self, obj, stl, advances, xmin, ymin, xmax, ymax, layDep, sample):
cutterOfst = 0.0
radsRot = 0.0
reset = 0.0
# radsRot = 0.0
# reset = 0.0
iCnt = 0
Lines = []
result = None
@@ -1085,9 +1081,9 @@ class ObjectSurface(PathOp.ObjectOp):
# Rotate STL object using OCL method
radsRot = math.radians(adv)
if obj.RotationAxis == 'X':
rStl = stl.rotate(radsRot, 0.0, 0.0)
stl.rotate(radsRot, 0.0, 0.0)
else:
rStl = stl.rotate(0.0, radsRot, 0.0)
stl.rotate(0.0, radsRot, 0.0)
# Set STL after rotation is made
pdc.setSTL(stl)
@@ -1127,9 +1123,9 @@ class ObjectSurface(PathOp.ObjectOp):
# Rotate STL object back to original position using OCL method
reset = -1 * math.radians(sumAdv - self.resetTolerance)
if obj.RotationAxis == 'X':
rStl = stl.rotate(reset, 0.0, 0.0)
stl.rotate(reset, 0.0, 0.0)
else:
rStl = stl.rotate(0.0, reset, 0.0)
stl.rotate(0.0, reset, 0.0)
self.resetTolerance = 0.0
return Lines
@@ -1217,8 +1213,8 @@ class ObjectSurface(PathOp.ObjectOp):
if self.onHold is False:
if not optimize or not self.isPointOnLine(FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(nxt.x, nxt.y, nxt.z), FreeCAD.Vector(pnt.x, pnt.y, pnt.z)):
output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
elif i == lastCLP:
output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
# elif i == lastCLP:
# output.append(Path.Command('G1', {'X': pnt.x, 'Y': pnt.y, 'Z': pnt.z, 'F': self.horizFeed}))
# Rotate point data
prev.x = pnt.x
@@ -1242,7 +1238,7 @@ class ObjectSurface(PathOp.ObjectOp):
output = []
nxtAng = 0
zMax = 0.0
prev = ocl.Point(float("inf"), float("inf"), float("inf"))
# prev = ocl.Point(float("inf"), float("inf"), float("inf"))
nxt = ocl.Point(float("inf"), float("inf"), float("inf"))
pnt = ocl.Point(float("inf"), float("inf"), float("inf"))
@@ -1390,8 +1386,8 @@ class ObjectSurface(PathOp.ObjectOp):
yVal = ymin + (nSL * smplInt)
p1 = ocl.Point(xmin, yVal, fd) # start-point of line
p2 = ocl.Point(xmax, yVal, fd) # end-point of line
l = ocl.Line(p1, p2) # line-object
path.append(l) # add the line to the path
path.append(ocl.Line(p1, p2))
# path.append(l) # add the line to the path
pdc.setPath(path)
pdc.run() # run drop-cutter on the path
@@ -1406,9 +1402,9 @@ class ObjectSurface(PathOp.ObjectOp):
# Create topo map from scanLines (highs and lows)
self.topoMap = self._createTopoMap(scanLines, layDep, lenSL, pntsPerLine)
# Add buffer lines and columns to topo map
rtn = self._bufferTopoMap(lenSL, pntsPerLine)
self._bufferTopoMap(lenSL, pntsPerLine)
# Identify layer waterline from OCL scan
rtn = self._highlightWaterline(4, 9)
self._highlightWaterline(4, 9)
# Extract waterline and convert to gcode
loopList = self._extractWaterlines(obj, scanLines, lyr, layDep)
time.sleep(0.1)

View File

@@ -30,7 +30,6 @@ import PathScripts.PathGeom as PathGeom
import TechDraw
import math
import numpy
import sys
from DraftGeomUtils import geomType
from FreeCAD import Vector
@@ -44,13 +43,15 @@ if False:
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
#FreeCAD.setLogLevel('Path.Area', 0)
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
UserInput = None
def waiting_effects(function):
def new_function(*args, **kwargs):
if not FreeCAD.GuiUp:
@@ -60,7 +61,7 @@ def waiting_effects(function):
try:
res = function(*args, **kwargs)
# don't catch exceptions - want to know where they are coming from ....
#except Exception as e:
# except Exception as e:
# raise e
# print("Error {}".format(e.args[0]))
finally:
@@ -148,7 +149,7 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
PathLog.debug("candidate is a circle")
v0 = edge.Vertexes[0].Point
v1 = edge.Vertexes[1].Point
#check if the cylinder seam is vertically aligned. Eliminate tilted holes
# check if the cylinder seam is vertically aligned. Eliminate tilted holes
if (numpy.isclose(v1.sub(v0).x, 0, rtol=1e-05, atol=1e-06)) and \
(numpy.isclose(v1.sub(v0).y, 0, rtol=1e-05, atol=1e-06)):
drillable = True
@@ -160,7 +161,7 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
# object. This eliminates extruded circles but allows
# actual holes.
if obj.isInside(lsp, 1e-6, False) or obj.isInside(lep, 1e-6, False):
PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp,lep))
PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp, lep))
drillable = False
# eliminate elliptical holes
elif not hasattr(face.Surface, "Radius"):
@@ -168,15 +169,15 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
drillable = False
else:
if tooldiameter is not None:
drillable = face.Surface.Radius >= tooldiameter/2
drillable = face.Surface.Radius >= tooldiameter / 2
else:
drillable = True
elif type(face.Surface) == Part.Plane and PathGeom.pointsCoincide(face.Surface.Axis, FreeCAD.Vector(0,0,1)):
elif type(face.Surface) == Part.Plane and PathGeom.pointsCoincide(face.Surface.Axis, FreeCAD.Vector(0, 0, 1)):
if len(face.Edges) == 1 and type(face.Edges[0].Curve) == Part.Circle:
center = face.Edges[0].Curve.Center
if obj.isInside(center, 1e-6, False):
if tooldiameter is not None:
drillable = face.Edges[0].Curve.Radius >= tooldiameter/2
drillable = face.Edges[0].Curve.Radius >= tooldiameter / 2
else:
drillable = True
else:
@@ -189,12 +190,12 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
else:
PathLog.debug("Has Radius, Circle")
if tooldiameter is not None:
drillable = edge.Curve.Radius >= tooldiameter/2
drillable = edge.Curve.Radius >= tooldiameter / 2
if not drillable:
FreeCAD.Console.PrintMessage(
"Found a drillable hole with diameter: {}: "
"too small for the current tool with "
"diameter: {}".format(edge.Curve.Radius*2, tooldiameter))
"Found a drillable hole with diameter: {}: "
"too small for the current tool with "
"diameter: {}".format(edge.Curve.Radius * 2, tooldiameter))
else:
drillable = True
PathLog.debug("candidate is drillable: {}".format(drillable))
@@ -204,7 +205,8 @@ def isDrillable(obj, candidate, tooldiameter=None, includePartials=False):
# fixme set at 4 decimal places for testing
def fmt(val): return format(val, '.4f')
def fmt(val):
return format(val, '.4f')
def segments(poly):
@@ -235,6 +237,7 @@ def loopdetect(obj, edge1, edge2):
loopwire = next(x for x in loop)[1]
return loopwire
def horizontalEdgeLoop(obj, edge):
'''horizontalEdgeLoop(obj, edge) ... returns a wire in the horizontal plane, if that is the only horizontal wire the given edge is a part of.'''
h = edge.hashCode()
@@ -244,6 +247,7 @@ def horizontalEdgeLoop(obj, edge):
return loops[0]
return None
def horizontalFaceLoop(obj, face, faceList=None):
'''horizontalFaceLoop(obj, face, faceList=None) ... returns a list of face names which form the walls of a vertical hole face is a part of.
All face names listed in faceList must be part of the hole for the solution to be returned.'''
@@ -256,8 +260,8 @@ def horizontalFaceLoop(obj, face, faceList=None):
for wire in wires:
hashes = [e.hashCode() for e in wire.Edges]
#find all faces that share a an edge with the wire and are vertical
faces = ["Face%d"%(i+1) for i,f in enumerate(obj.Shape.Faces) if any(e.hashCode() in hashes for e in f.Edges) and PathGeom.isVertical(f)]
# find all faces that share a an edge with the wire and are vertical
faces = ["Face%d" % (i + 1) for i, f in enumerate(obj.Shape.Faces) if any(e.hashCode() in hashes for e in f.Edges) and PathGeom.isVertical(f)]
if faceList and not all(f in faces for f in faceList):
continue
@@ -265,7 +269,7 @@ def horizontalFaceLoop(obj, face, faceList=None):
# verify they form a valid hole by getting the outline and comparing
# the resulting XY footprint with that of the faces
comp = Part.makeCompound([obj.Shape.getElement(f) for f in faces])
outline = TechDraw.findShapeOutline(comp, 1, FreeCAD.Vector(0,0,1))
outline = TechDraw.findShapeOutline(comp, 1, FreeCAD.Vector(0, 0, 1))
# findShapeOutline always returns closed wires, by removing the
# trace-backs single edge spikes don't contriubte to the bound box
@@ -284,6 +288,7 @@ def horizontalFaceLoop(obj, face, faceList=None):
return faces
return None
def filterArcs(arcEdge):
'''filterArcs(Edge) -used to split arcs that over 180 degrees. Returns list '''
PathLog.track()
@@ -302,10 +307,8 @@ def filterArcs(arcEdge):
arcstpt = s.valueAt(s.FirstParameter)
arcmid = s.valueAt(
(s.LastParameter - s.FirstParameter) * 0.5 + s.FirstParameter)
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter) *
0.25 + s.FirstParameter) # future midpt for arc1
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter) *
0.75 + s.FirstParameter) # future midpt for arc2
arcquad1 = s.valueAt((s.LastParameter - s.FirstParameter) * 0.25 + s.FirstParameter) # future midpt for arc1
arcquad2 = s.valueAt((s.LastParameter - s.FirstParameter) * 0.75 + s.FirstParameter) # future midpt for arc2
arcendpt = s.valueAt(s.LastParameter)
# reconstruct with 2 arcs
arcseg1 = Part.ArcOfCircle(arcstpt, arcquad1, arcmid)
@@ -345,10 +348,6 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
'''
PathLog.track(partshape, subshape, depthparams)
# if partshape.Volume == 0.0: #Not a 3D object
# return None
zShift = 0
if subshape is not None:
if isinstance(subshape, Part.Face):
@@ -360,7 +359,6 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
PathLog.debug("About to section with params: {}".format(area.getParams()))
sec = area.makeSections(heights=[0.0], project=True)[0].getShape()
# zShift = partshape.BoundBox.ZMin - subshape.BoundBox.ZMin
PathLog.debug('partshapeZmin: {}, subshapeZMin: {}, zShift: {}'.format(partshape.BoundBox.ZMin, subshape.BoundBox.ZMin, zShift))
else:
@@ -371,9 +369,7 @@ def getEnvelope(partshape, subshape=None, depthparams=None):
# If depthparams are passed, use it to calculate bottom and height of
# envelope
if depthparams is not None:
# eLength = float(stockheight)-partshape.BoundBox.ZMin
eLength = depthparams.safe_height - depthparams.final_depth
#envelopeshape = sec.extrude(FreeCAD.Vector(0, 0, eLength))
zShift = depthparams.final_depth - sec.BoundBox.ZMin
PathLog.debug('boundbox zMIN: {} elength: {} zShift {}'.format(partshape.BoundBox.ZMin, eLength, zShift))
else:
@@ -467,6 +463,7 @@ def GetJobs(jobname=None):
return [job for job in PathJob.Instances() if job.Name == jobname]
return PathJob.Instances()
def addToJob(obj, jobname=None):
'''adds a path object to a job
obj = obj
@@ -492,6 +489,7 @@ def addToJob(obj, jobname=None):
job.Proxy.addOperation(obj)
return job
def rapid(x=None, y=None, z=None):
""" Returns gcode string to perform a rapid move."""
retstr = "G00"
@@ -583,11 +581,11 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
raise Exception("Helical plunging requires a position!")
return None
helixX = plungePos.x + toold/2 * plungeR
helixX = plungePos.x + toold / 2 * plungeR
helixY = plungePos.y
helixCirc = math.pi * toold * plungeR
dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc
dzPerRev = math.sin(rampangle / 180. * math.pi) * helixCirc
# Go to the start of the helix position
helixCmds += rapid(helixX, helixY)
@@ -595,7 +593,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
# Helix as required to get to the requested depth
lastZ = startZ
curZ = max(startZ-dzPerRev, destZ)
curZ = max(startZ - dzPerRev, destZ)
done = False
while not done:
done = (curZ == destZ)
@@ -604,7 +602,7 @@ def helicalPlunge(plungePos, rampangle, destZ, startZ, toold, plungeR, horizFeed
# Use two half-helixes; FreeCAD renders that correctly,
# and it fits with the other code breaking up 360-degree arcs
helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - toold * plungeR, helixY, horizFeed, ez=(curZ + lastZ)/2., ccw=True)
helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - toold * plungeR, helixY, horizFeed, ez=(curZ + lastZ) / 2., ccw=True)
helixCmds += arc(plungePos.x, plungePos.y, helixX - toold * plungeR, helixY, helixX, helixY, horizFeed, ez=curZ, ccw=True)
lastZ = curZ
curZ = max(curZ - dzPerRev, destZ)
@@ -641,7 +639,7 @@ def rampPlunge(edge, rampangle, destZ, startZ):
ePoint = edge.Vertexes[-1].Point
rampDist = edge.Length
rampDZ = math.sin(rampangle/180. * math.pi) * rampDist
rampDZ = math.sin(rampangle / 180. * math.pi) * rampDist
rampCmds += rapid(sPoint.x, sPoint.y)
rampCmds += rapid(z=startZ)
@@ -649,7 +647,7 @@ def rampPlunge(edge, rampangle, destZ, startZ):
# Ramp down to the requested depth
# FIXME: This might be an arc, so handle that as well
curZ = max(startZ-rampDZ, destZ)
curZ = max(startZ - rampDZ, destZ)
done = False
while not done:
done = (curZ == destZ)
@@ -699,7 +697,7 @@ def sort_jobs(locations, keys, attractors=[]):
def find_closest(location_list, location, dist):
q = PriorityQueue()
for i,j in enumerate(location_list):
for i, j in enumerate(location_list):
# prevent dictionary comparison by inserting the index
q.put((dist(j, location) + weight(j), i, j))
@@ -720,6 +718,7 @@ def sort_jobs(locations, keys, attractors=[]):
return out
def guessDepths(objshape, subs=None):
"""
takes an object shape and optional list of subobjects and returns a depth_params
@@ -751,6 +750,7 @@ def guessDepths(objshape, subs=None):
return depth_params(clearance, safe, start, 1.0, 0.0, final, user_depths=None, equalstep=False)
def drillTipLength(tool):
"""returns the length of the drillbit tip."""
if tool.CuttingEdgeAngle == 180 or tool.CuttingEdgeAngle == 0.0 or tool.Diameter == 0.0:
@@ -760,13 +760,14 @@ def drillTipLength(tool):
PathLog.error(translate("Path", "Invalid Cutting Edge Angle %.2f, must be >0° and <=180°") % tool.CuttingEdgeAngle)
return 0.0
theta = math.radians(tool.CuttingEdgeAngle)
length = (tool.Diameter/2) / math.tan(theta/2)
length = (tool.Diameter / 2) / math.tan(theta / 2)
if length < 0:
PathLog.error(translate("Path", "Cutting Edge Angle (%.2f) results in negative tool tip length") % tool.CuttingEdgeAngle)
return 0.0
return length
class depth_params:
class depth_params(object):
'''calculates the intermediate depth values for various operations given the starting, ending, and stepdown parameters
(self, clearance_height, safe_height, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None], equalstep=False)
@@ -821,7 +822,7 @@ class depth_params:
@property
def safe_height(self):
"""
Height of top of raw stock material. Rapid moves above safe height are
Height of top of raw stock material. Rapid moves above safe height are
assumed to be safe within an operation. May not be safe between
operations or tool changes.
All moves below safe height except retraction should be at feed rate.
@@ -922,5 +923,3 @@ class depth_params:
return depths
else:
return [stop] + depths