From 4cbdf78836639701faa93f6b5057b1b4cf8c717a Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 8 Jun 2019 18:55:44 -0500 Subject: [PATCH 1/4] Path: lgtm Cleanup --- src/Mod/Path/PathCommands.py | 17 ++-- src/Mod/Path/PathScripts/PathArray.py | 2 +- src/Mod/Path/PathScripts/PathComment.py | 2 +- src/Mod/Path/PathScripts/PathDeburr.py | 30 ++++--- src/Mod/Path/PathScripts/PathJobGui.py | 111 ++++++++++++++---------- src/Mod/Path/PathScripts/PathSurface.py | 74 ++++++++-------- src/Mod/Path/PathScripts/PathUtils.py | 77 ++++++++-------- 7 files changed, 169 insertions(+), 144 deletions(-) diff --git a/src/Mod/Path/PathCommands.py b/src/Mod/Path/PathCommands.py index 63aae97ba9..d5d0e7efb0 100644 --- a/src/Mod/Path/PathCommands.py +++ b/src/Mod/Path/PathCommands.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - # *************************************************************************** # * * # * Copyright (c) 2016 sliptonic * @@ -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): diff --git a/src/Mod/Path/PathScripts/PathArray.py b/src/Mod/Path/PathScripts/PathArray.py index 4b4fc93351..d7fe6e8994 100644 --- a/src/Mod/Path/PathScripts/PathArray.py +++ b/src/Mod/Path/PathScripts/PathArray.py @@ -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): diff --git a/src/Mod/Path/PathScripts/PathComment.py b/src/Mod/Path/PathScripts/PathComment.py index 2747e3130e..06f756b2e9 100644 --- a/src/Mod/Path/PathScripts/PathComment.py +++ b/src/Mod/Path/PathScripts/PathComment.py @@ -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): diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index d1148f0216..bd26d7df06 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -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 - diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index 9eaa150de6..7fb3fb9add 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -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() - diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index b951c0e1b6..aca39dcbe6 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -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) diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index c4da1a461f..ac651b25ae 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -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 - - From 795442a85afbcdc2e451b56463ebce0a3e54a1e5 Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 8 Jun 2019 23:10:11 -0500 Subject: [PATCH 2/4] Path: remove obsolete code --- .../Path/PathScripts/Macros/create_tool.py | 42 ------------ src/Mod/Path/PathScripts/Macros/holefinder.py | 65 ------------------- .../Path/PathScripts/Macros/outer_profile.py | 45 ------------- 3 files changed, 152 deletions(-) delete mode 100644 src/Mod/Path/PathScripts/Macros/create_tool.py delete mode 100644 src/Mod/Path/PathScripts/Macros/holefinder.py delete mode 100644 src/Mod/Path/PathScripts/Macros/outer_profile.py diff --git a/src/Mod/Path/PathScripts/Macros/create_tool.py b/src/Mod/Path/PathScripts/Macros/create_tool.py deleted file mode 100644 index bec8f0a4a0..0000000000 --- a/src/Mod/Path/PathScripts/Macros/create_tool.py +++ /dev/null @@ -1,42 +0,0 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2014 Daniel Falck * -#* * -#* 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 * -#* * -#*************************************************************************** - -''' -This macro is used in conjunction with the toolpathparams script to create an object that represents a tool for use in a CNC program. Create a group and then select it- then run the macro. -You will have to edit the parameters inside the Data tab of the tool object. -''' - -import FreeCAD -import FreeCADGui -import PathScripts -import toolpathparams as tp - - -tl = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Tools") - -tp.ToolParams(tl) -tp.ViewProviderToolParams(tl.ViewObject) - -sel = FreeCADGui.Selection.getSelection() -g = sel[0] -g.addObject(tl) -App.activeDocument().recompute() diff --git a/src/Mod/Path/PathScripts/Macros/holefinder.py b/src/Mod/Path/PathScripts/Macros/holefinder.py deleted file mode 100644 index f8ff6f4ece..0000000000 --- a/src/Mod/Path/PathScripts/Macros/holefinder.py +++ /dev/null @@ -1,65 +0,0 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2014 Daniel Falck * -#* * -#* This program is free software; you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation; either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* This program is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY; without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Library General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with this program; if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#*************************************************************************** -import FreeCAD -from FreeCAD import Base -import Part -import Draft -from PySide import QtGui,QtCore -from math import pi -''' -This macro makes a list of holes for drilling from a solid -1. Select a solid object that has holes in it and run the macro -2. It only collects info on holes that are parallel to the Z axis- I don't have a 4 or 5 axis mill at the moment -3. It pulls the center of the hole bounding box and the XLength for it's diameter -4. It will place a list of the holes on the clipboard -5. Uncomment the line that starts with '#Draft.makeLine' and manipulate it, if you want to see lines down the center of each hole. -6. Manipulate the line that starts with 'holelist.append' to make the list fit your own needs- I've put the ZMax at the ZMax of the solid's bounding box -because I want to make sure that my drill tip doesn't collide with anything on the top of the part. YMMV. -''' -def findholes(obj): - facelist = [] - holelist =[] - vz = Base.Vector(0,0,1) - for f in obj.Faces: - if ( round(f.ParameterRange[0], 8)==0.0 ) and ( round(f.ParameterRange[1],8) == round(pi*2, 8) ) : #eliminate flat faces - facelist.append(f) - - for h in facelist: - for w in h.Wires: - for c in w.Edges: - if ( isinstance(c.Curve,Part.LineSegment)): - v0=Base.Vector(c.Vertexes[0].X, c.Vertexes[0].Y, c.Vertexes[0].Z); v1=Base.Vector(c.Vertexes[1].X,c.Vertexes[1].Y, c.Vertexes[1].Z) - if (v1.sub(v0).x == 0) and (v1.sub(v0).y == 0): - lsp = Base.Vector(h.BoundBox.Center.x,h.BoundBox.Center.y,h.BoundBox.ZMax) - lep = Base.Vector(h.BoundBox.Center.x,h.BoundBox.Center.y,h.BoundBox.ZMin) - if obj.isInside(lsp, 0,False) or obj.isInside(lep, 0,False): - pass - else: - Draft.makeLine((h.BoundBox.Center.x,h.BoundBox.Center.y,obj.BoundBox.ZMax ),(h.BoundBox.Center.x,h.BoundBox.Center.y,h.BoundBox.ZMin )) - x =h.BoundBox.Center.x;y=h.BoundBox.Center.y;zmax=obj.BoundBox.ZMax;zmin=h.BoundBox.ZMin;diameter=h.BoundBox.XLength - holelist.append((diameter, x,y,zmax,zmin)) - clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(holelist)) - -sel=Gui.Selection.getSelection() -obj = sel[0].Shape -findholes(obj) diff --git a/src/Mod/Path/PathScripts/Macros/outer_profile.py b/src/Mod/Path/PathScripts/Macros/outer_profile.py deleted file mode 100644 index 5ebf2b9403..0000000000 --- a/src/Mod/Path/PathScripts/Macros/outer_profile.py +++ /dev/null @@ -1,45 +0,0 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2014 Daniel Falck * -#* * -#* 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 * -#* * -#*************************************************************************** -''' -This macro finds the outside profile of a 3D shape. Right now it just creates wires that represent the shape,but it could be used for finding the outside profile of an object for a toolpath -''' -import FreeCADGui -import DraftGeomUtils -from FreeCAD import Vector -from PathScripts import find_outer_profile as fop - -sel = FreeCADGui.Selection.getSelection()[0] -obj = sel -el = fop.edgelist(obj) -hl = fop.horizontal(el) -connected = DraftGeomUtils.findWires(hl) -goodwires = fop.openFilter(connected) - -outerwires ,innerwires, same = fop.findOutsideWire(goodwires) -#get distance from outerwires Z to bottom of part -zdiff = obj.Shape.BoundBox.ZMin- outerwires.BoundBox.ZMax -outerwires.Placement.move(Vector(0,0,zdiff)) -Part.show(outerwires) - -zupperouter = outerwires -zupperouter.Placement.move(Vector(0,0,obj.Shape.BoundBox.ZMax)) -Part.show(zupperouter) From 6ccb0cf32c4bd9e4d0c2f5dadb76296ee2430dea Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 8 Jun 2019 23:10:47 -0500 Subject: [PATCH 3/4] Path: post processor cleanup --- src/Mod/Path/PathScripts/post/jtech_post.py | 14 +-- .../Path/PathScripts/post/linuxcnc_post.py | 2 +- src/Mod/Path/PathScripts/post/opensbp_post.py | 14 ++- src/Mod/Path/PathScripts/post/opensbp_pre.py | 115 +++++++++--------- .../Path/PathScripts/post/smoothie_post.py | 92 +++++++------- 5 files changed, 118 insertions(+), 119 deletions(-) diff --git a/src/Mod/Path/PathScripts/post/jtech_post.py b/src/Mod/Path/PathScripts/post/jtech_post.py index 4d54f74b95..29801abfeb 100644 --- a/src/Mod/Path/PathScripts/post/jtech_post.py +++ b/src/Mod/Path/PathScripts/post/jtech_post.py @@ -28,7 +28,6 @@ import argparse import datetime import shlex from PathScripts import PostUtils -from PathScripts import PathUtils TOOLTIP = ''' This is a postprocessor file for the Path workbench. It is used to @@ -54,7 +53,6 @@ parser.add_argument('--postamble', help='set commands to be issued after the las parser.add_argument('--inches', action='store_true', help='Convert output for US imperial mode (G20)') parser.add_argument('--modal', action='store_true', help='Output the Same G-command Name USE NonModal Mode') parser.add_argument('--axis-modal', action='store_true', help='Output the Same Axis Value Mode') -#parser.add_argument('--power-max', help='set the max value for laser power default=255') parser.add_argument('--power-on-delay', default='255', help='milliseconds - Add a delay after laser on before moving to pre-heat material. Default=0') @@ -104,7 +102,6 @@ POST_OPERATION = '''''' # Tool Change commands will be inserted before a tool change TOOL_CHANGE = '''''' -#POWER_MAX = 255 POWER_ON_DELAY = 0 # to distinguish python built-in open function from the one declared below @@ -152,9 +149,9 @@ def processArguments(argstring): MODAL = True if args.axis_modal: OUTPUT_DOUBLES = False - POWER_ON_DELAY = float(args.power_on_delay) / 1000 #milliseconds + POWER_ON_DELAY = float(args.power_on_delay) / 1000 # milliseconds - except: + except Exception: return False return True @@ -290,7 +287,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == '(' and not OUTPUT_COMMENTS: # command is a comment + if c.Name[0] == '(' and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order @@ -326,10 +323,6 @@ def parse(pathobj): # Check for Tool Change: if command == 'M6': continue - # if OUTPUT_COMMENTS: - # out += linenumber() + "(begin toolchange)\n" - for line in TOOL_CHANGE.splitlines(True): - out += linenumber() + line if command == "message": if OUTPUT_COMMENTS is False: @@ -349,4 +342,5 @@ def parse(pathobj): return out + print(__name__ + " gcode postprocessor loaded.") diff --git a/src/Mod/Path/PathScripts/post/linuxcnc_post.py b/src/Mod/Path/PathScripts/post/linuxcnc_post.py index a73750d65d..244902111c 100644 --- a/src/Mod/Path/PathScripts/post/linuxcnc_post.py +++ b/src/Mod/Path/PathScripts/post/linuxcnc_post.py @@ -142,7 +142,7 @@ def processArguments(argstring): print ('here') OUTPUT_DOUBLES = False - except: + except Exception: return False return True diff --git a/src/Mod/Path/PathScripts/post/opensbp_post.py b/src/Mod/Path/PathScripts/post/opensbp_post.py index 307f43c551..433370fb0f 100644 --- a/src/Mod/Path/PathScripts/post/opensbp_post.py +++ b/src/Mod/Path/PathScripts/post/opensbp_post.py @@ -26,7 +26,7 @@ from PathScripts import PostUtils # ***************************************************************************/ -TOOLTIP=''' +TOOLTIP = ''' This is an postprocessor file for the Path workbench. It will output path data in a format suitable for OpenSBP controllers like shopbot. This postprocessor, once placed in the appropriate PathScripts folder, can be used directly from @@ -50,7 +50,7 @@ ToDo ''' -TOOLTIP_ARGS=''' +TOOLTIP_ARGS = ''' Arguments for opensbp: --comments ... insert comments - mostly for debugging --inches ... convert output to inches @@ -80,16 +80,20 @@ POST_OPERATION = '''''' TOOL_CHANGE = '''''' # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open CurrentState = {} + def getMetricValue(val): return val + + def getImperialValue(val): return val / 25.4 + GetValue = getMetricValue @@ -110,7 +114,6 @@ def export(objectslist, filename, argstring): if arg == '--no-show-editor': SHOW_EDITOR = False - for obj in objectslist: if not hasattr(obj, "Path"): s = "the object " + obj.Name @@ -333,7 +336,6 @@ def parse(pathobj): global CurrentState output = "" - params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'K', 'F', 'S', 'T'] # Above list controls the order of parameters if hasattr(pathobj, "Group"): # We have a compound or project. @@ -356,7 +358,7 @@ def parse(pathobj): elif command[0] == '(': output += "' " + command + "\n" else: - print("I don't know what the hell the command: ",end='') + print("I don't know what the hell the command: ", end='') print(command + " means. Maybe I should support it.") return output diff --git a/src/Mod/Path/PathScripts/post/opensbp_pre.py b/src/Mod/Path/PathScripts/post/opensbp_pre.py index 61db9d9db4..615e804ca4 100644 --- a/src/Mod/Path/PathScripts/post/opensbp_pre.py +++ b/src/Mod/Path/PathScripts/post/opensbp_pre.py @@ -49,13 +49,14 @@ Many other OpenSBP commands not handled from __future__ import print_function import FreeCAD import PathScripts.PathUtil as PathUtil -import os, Path +import os +import Path -AXIS = 'X','Y','Z','A','B' #OpenSBP always puts multiaxis move parameters in this order -SPEEDS = 'XY','Z','A','B' +AXIS = 'X', 'Y', 'Z', 'A', 'B' # OpenSBP always puts multiaxis move parameters in this order +SPEEDS = 'XY', 'Z', 'A', 'B' # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open @@ -63,10 +64,10 @@ def open(filename): "called when freecad opens a file." docname = os.path.splitext(os.path.basename(filename))[0] doc = FreeCAD.newDocument(docname) - insert(filename,doc.Name) + insert(filename, doc.Name) -def insert(filename,docname): +def insert(filename, docname): "called when freecad imports a file" "This insert expects parse to return a list of strings" "each string will become a separate path" @@ -76,7 +77,7 @@ def insert(filename,docname): gcode = parse(gcode) doc = FreeCAD.getDocument(docname) for subpath in gcode: - obj = doc.addObject("Path::Feature","Path") + obj = doc.addObject("Path::Feature", "Path") path = Path.Path(subpath) obj.Path = path @@ -88,123 +89,121 @@ def parse(inputstring): lines = inputstring.split("\n") return_output = [] output = "" - last = {'X':None,'Y':None,'Z':None,'A':None,'B':None} - lastrapidspeed = {'XY':"50", 'Z':"50", 'A':"50", 'B':"50" } #set default rapid speeds - lastfeedspeed = {'XY':"50", 'Z':"50", 'A':"50", 'B':"50" } #set default feed speed + last = {'X': None, 'Y': None, 'Z': None, 'A': None, 'B': None} + lastrapidspeed = {'XY': "50", 'Z': "50", 'A': "50", 'B': "50"} # set default rapid speeds + lastfeedspeed = {'XY': "50", 'Z': "50", 'A': "50", 'B': "50"} # set default feed speed movecommand = ['G1', 'G0', 'G02', 'G03'] - for l in lines: + for line in lines: # remove any leftover trailing and preceding spaces - l = l.strip() - if not l: + line = line.strip() + if not line: # discard empty lines continue - if l[0] in ["'","&"]: + if line[0] in ["'", "&"]: # discard comment and other non strictly gcode lines - if l[0:9] == "'New Path": + if line[0:9] == "'New Path": # starting new path - if any (x in output for x in movecommand): #make sure the path has at least one move command. + if any(x in output for x in movecommand): # make sure the path has at least one move command. return_output.append(output) output = "" continue - words = [a.strip() for a in l.split(",")] + words = [a.strip() for a in line.split(",")] words[0] = words[0].upper() - if words[0] in ["J2","J3","J4","J5","M2","M3","M4","M5"]: #multi-axis jogs and moves - if words[0][0] == 'J': #jog move + if words[0] in ["J2", "J3", "J4", "J5", "M2", "M3", "M4", "M5"]: # multi-axis jogs and moves + if words[0][0] == 'J': # jog move s = "G0 " - else: #feed move + else: # feed move s = "G1 " speed = lastfeedspeed["XY"] - for i in range (1, len(words)): - if words [i] == '': - if last[AXIS[i-1]] == None: + for i in range(1, len(words)): + if words[i] == '': + if last[AXIS[i - 1]] is None: continue else: - s += AXIS[i-1] + last[AXIS[i-1]] + s += AXIS[i - 1] + last[AXIS[i - 1]] else: - s += AXIS[i-1] + words[i] - last[AXIS[i-1]] = words[i] - output += s +" F" + speed + '\n' + s += AXIS[i - 1] + words[i] + last[AXIS[i - 1]] = words[i] + output += s + " F" + speed + '\n' - if words[0] in ["JA","JB","JX","JY","JZ","MA","MB","MX","MY","MZ"]: #single axis jogs and moves - if words[0][0] == 'J': #jog move + if words[0] in ["JA", "JB", "JX", "JY", "JZ", "MA", "MB", "MX", "MY", "MZ"]: # single axis jogs and moves + if words[0][0] == 'J': # jog move s = "G0 " - if words[0][1] in ['X','Y']: + if words[0][1] in ['X', 'Y']: speed = lastrapidspeed["XY"] else: speed = lastrapidspeed[words[0][1]] - else: #feed move + else: # feed move s = "G1 " - if words[0][1] in ['X','Y']: + if words[0][1] in ['X', 'Y']: speed = lastfeedspeed["XY"] else: speed = lastfeedspeed[words[0][1]] - last[words[0][1]] = words[1] output += s for key, val in PathUtil.keyValueIter(last): if val is not None: output += key + str(val) + " F" + speed + "\n" - if words[0] in ["JS"]: #set jog speed - for i in range (1, len(words)): - if words [i] == '': + if words[0] in ["JS"]: # set jog speed + for i in range(1, len(words)): + if words[i] == '': continue else: - lastrapidspeed[SPEEDS[i-1]] = words[i] + lastrapidspeed[SPEEDS[i - 1]] = words[i] - if words[0] in ["MD"]: #move distance with distance and angle. - #unsupported at this time + if words[0] in ["MD"]: # move distance with distance and angle. + # unsupported at this time continue - if words[0] in ["MH"]: #move home - #unsupported at this time + if words[0] in ["MH"]: # move home + # unsupported at this time continue - if words[0] in ["MS"]: #set move speed - for i in range (1, len(words)): - if words [i] == '': + if words[0] in ["MS"]: # set move speed + for i in range(1, len(words)): + if words[i] == '': continue else: - lastfeedspeed[SPEEDS[i-1]] = words[i] - if words[0] in ["MO"]: #motors off - #unsupported at this time + lastfeedspeed[SPEEDS[i - 1]] = words[i] + if words[0] in ["MO"]: # motors off + # unsupported at this time continue - if words[0] in ["TR"]: #Setting spindle speed - if float(words[1]) < 0: + if words[0] in ["TR"]: # Setting spindle speed + if float(words[1]) < 0: s = "M4 S" else: s = "M3 S" s += str(abs(float(words[1]))) output += s + '\n' - if words[0] in ["CG"]: #Gcode circle/arc - if words[1] != "": # diameter mode + if words[0] in ["CG"]: # Gcode circle/arc + if words[1] != "": # diameter mode print("diameter mode not supported") continue else: - if words[7] == "1": #CW + if words[7] == "1": # CW s = "G2" - else: #CCW + else: # CCW s = "G3" - s += " X" + words[2] + " Y" + words[3] + " I" + words[4] + " J" + words[5] + " F" + str(lastfeedspeed["XY"]) - output += s + '\n' + output += s + '\n' last["X"] = words[2] last["Y"] = words[3] - #Make sure all appended paths have at least one move command. - if any (x in output for x in movecommand): + # Make sure all appended paths have at least one move command. + if any(x in output for x in movecommand): return_output.append(output) print("done preprocessing.") return return_output -print(__name__ + " gcode preprocessor loaded.") +print(__name__ + " gcode preprocessor loaded.") diff --git a/src/Mod/Path/PathScripts/post/smoothie_post.py b/src/Mod/Path/PathScripts/post/smoothie_post.py index 6929f1ba39..121dc4cdea 100644 --- a/src/Mod/Path/PathScripts/post/smoothie_post.py +++ b/src/Mod/Path/PathScripts/post/smoothie_post.py @@ -22,7 +22,14 @@ # ***************************************************************************/ from __future__ import print_function -TOOLTIP=''' +import argparse +import datetime +from PathScripts import PostUtils +import FreeCAD +from FreeCAD import Units +import shlex + +TOOLTIP = ''' This is a postprocessor file for the Path workbench. It is used to take a pseudo-gcode fragment outputted by a Path object, and output real GCode suitable for a smoothieboard. This postprocessor, once placed @@ -33,13 +40,6 @@ import smoothie_post smoothie_post.export(object,"/path/to/file.ncc","") ''' -import argparse -import datetime -from PathScripts import PostUtils -import FreeCAD -from FreeCAD import Units -import shlex - now = datetime.datetime.now() parser = argparse.ArgumentParser(prog='linuxcnc', add_help=False) @@ -58,7 +58,7 @@ parser.add_argument('--IP_ADDR', help='IP Address for machine target machine') parser.add_argument('--verbose', action='store_true', help='verbose output for debugging, default="False"') parser.add_argument('--inches', action='store_true', help='Convert output for US imperial mode (G20)') -TOOLTIP_ARGS=parser.format_help() +TOOLTIP_ARGS = parser.format_help() # These globals set common customization preferences OUTPUT_COMMENTS = True @@ -108,9 +108,10 @@ TOOL_CHANGE = '''''' # to distinguish python built-in open function from the one declared below -if open.__module__ in ['__builtin__','io']: +if open.__module__ in ['__builtin__', 'io']: pythonopen = open + def processArguments(argstring): global OUTPUT_HEADER global OUTPUT_COMMENTS @@ -125,7 +126,6 @@ def processArguments(argstring): global UNIT_SPEED_FORMAT global UNIT_FORMAT - try: args = parser.parse_args(shlex.split(argstring)) @@ -159,11 +159,12 @@ def processArguments(argstring): IP_ADDR = args.IP_ADDR VERBOSE = args.verbose - except: + except Exception: return False return True + def export(objectslist, filename, argstring): processArguments(argstring) global UNITS @@ -181,13 +182,13 @@ def export(objectslist, filename, argstring): # sure we're using the current values in the Machine Def. myMachine = None for pathobj in objectslist: - if hasattr(pathobj,"MachineName"): + if hasattr(pathobj, "MachineName"): myMachine = pathobj.MachineName if hasattr(pathobj, "MachineUnits"): if pathobj.MachineUnits == "Metric": - UNITS = "G21" + UNITS = "G21" else: - UNITS = "G20" + UNITS = "G20" if myMachine is None: FreeCAD.Console.PrintWarning("No machine found in this selection\n") @@ -258,68 +259,71 @@ def sendToSmoothie(IP_ADDR, GCODE, fname): global VERBOSE fname = os.path.basename(fname) - FreeCAD.Console.PrintMessage ('sending to smoothie: {}\n'.format(fname)) + FreeCAD.Console.PrintMessage('sending to smoothie: {}\n'.format(fname)) f = GCODE.rstrip() - filesize= len(f) + filesize = len(f) # make connection to sftp server - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(4.0) s.connect((IP_ADDR, 115)) - tn= s.makefile(mode='rw') + tn = s.makefile(mode='rw') # read startup prompt - ln= tn.readline() - if not ln.startswith("+") : + ln = tn.readline() + if not ln.startswith("+"): FreeCAD.Console.PrintMessage("Failed to connect with sftp: {}\n".format(ln)) - sys.exit(); + sys.exit() - if VERBOSE: print("RSP: " + ln.strip()) + if VERBOSE: + print("RSP: " + ln.strip()) # Issue initial store command tn.write("STOR OLD /sd/" + fname + "\n") tn.flush() - ln= tn.readline() - if not ln.startswith("+") : + ln = tn.readline() + if not ln.startswith("+"): FreeCAD.Console.PrintError("Failed to create file: {}\n".format(ln)) - sys.exit(); + sys.exit() - if VERBOSE: print("RSP: " + ln.strip()) + if VERBOSE: + print("RSP: " + ln.strip()) # send size of file tn.write("SIZE " + str(filesize) + "\n") tn.flush() - ln= tn.readline() - if not ln.startswith("+") : + ln = tn.readline() + if not ln.startswith("+"): FreeCAD.Console.PrintError("Failed: {}\n".format(ln)) - sys.exit(); + sys.exit() - if VERBOSE: print("RSP: " + ln.strip()) + if VERBOSE: + print("RSP: " + ln.strip()) - cnt= 0 + cnt = 0 # now send file for line in f.splitlines(1): tn.write(line) - if VERBOSE : + if VERBOSE: cnt += len(line) print("SND: " + line.strip()) print(str(cnt) + "/" + str(filesize) + "\r", end='') tn.flush() - ln= tn.readline() - if not ln.startswith("+") : + ln = tn.readline() + if not ln.startswith("+"): FreeCAD.Console.PrintError("Failed to save file: {}\n".format(ln)) - sys.exit(); + sys.exit() - if VERBOSE: print("RSP: " + ln.strip()) + if VERBOSE: + print("RSP: " + ln.strip()) # exit tn.write("DONE\n") tn.flush() - ln= tn.readline() tn.close() FreeCAD.Console.PrintMessage("Upload complete\n") @@ -332,12 +336,13 @@ def linenumber(): return "N" + str(LINENR) + " " return "" + def parse(pathobj): global PRECISION out = "" lastcommand = None global SPINDLE_SPEED - precision_string = '.' + str(PRECISION) +'f' + precision_string = '.' + str(PRECISION) + 'f' # params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control # the order of parameters @@ -373,10 +378,10 @@ def parse(pathobj): for param in params: if param in c.Parameters: if param == 'F': - if c.Name not in ["G0", "G00"]: #linuxcnc doesn't use rapid speeds + if c.Name not in ["G0", "G00"]: # linuxcnc doesn't use rapid speeds speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity) outstring.append( - param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string ) ) + param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string)) elif param == 'T': outstring.append(param + str(c.Parameters['T'])) elif param == 'S': @@ -385,8 +390,7 @@ def parse(pathobj): else: pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length) outstring.append( - param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string) ) - #param + format(c.Parameters[param], precision_string)) + param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string)) if command in ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']: outstring.append('S' + str(SPINDLE_SPEED)) @@ -413,7 +417,7 @@ def parse(pathobj): # append the line to the final output for w in outstring: - out += w + COMMAND_SPACE + out += w + COMMAND_SPACE out = out.strip() + "\n" return out From b564189f75f184a24ab437a24ebb7159ba0ae399 Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 8 Jun 2019 23:11:58 -0500 Subject: [PATCH 4/4] Path: remove unnecessary imports --- src/Mod/Path/PathCommands.py | 2 -- src/Mod/Path/PathScripts/PathCollision.py | 4 ---- src/Mod/Path/PathScripts/PathDeburr.py | 3 --- src/Mod/Path/PathScripts/PathJobGui.py | 2 -- 4 files changed, 11 deletions(-) diff --git a/src/Mod/Path/PathCommands.py b/src/Mod/Path/PathCommands.py index d5d0e7efb0..432ac4e1fc 100644 --- a/src/Mod/Path/PathCommands.py +++ b/src/Mod/Path/PathCommands.py @@ -35,7 +35,6 @@ from PathScripts.PathUtils import findParentJob if FreeCAD.GuiUp: import FreeCADGui from PySide import QtCore - # from DraftTools import translate else: def translate(ctxt, txt): return txt @@ -79,7 +78,6 @@ class _CommandSelectLoop: return False def Activated(self): - # from PathScripts.PathUtils import loopdetect from PathScripts.PathUtils import horizontalEdgeLoop from PathScripts.PathUtils import horizontalFaceLoop sel = FreeCADGui.Selection.getSelectionEx()[0] diff --git a/src/Mod/Path/PathScripts/PathCollision.py b/src/Mod/Path/PathScripts/PathCollision.py index 5e959d9903..d17ee572c2 100644 --- a/src/Mod/Path/PathScripts/PathCollision.py +++ b/src/Mod/Path/PathScripts/PathCollision.py @@ -32,10 +32,6 @@ PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE) PathLog.trackModule('PathCollision') FreeCAD.setLogLevel('Path.Area', 0) -if FreeCAD.GuiUp: - import FreeCADGui - # from PySide import QtGui - # Qt translation handling def translate(context, text, disambig=None): diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index bd26d7df06..71b80209a7 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -24,12 +24,10 @@ import FreeCAD import Part -# 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 math from PySide import QtCore @@ -54,7 +52,6 @@ def toolDepthAndOffset(width, extraDepth, tool): tan = math.tan(math.radians(angle / 2)) toolDepth = 0 if 0 == tan else width / tan - # extraDepth = extraDepth depth = toolDepth + extraDepth toolOffset = tool.FlatRadius extraOffset = tool.Diameter / 2 - width if 180 == angle else extraDepth / tan diff --git a/src/Mod/Path/PathScripts/PathJobGui.py b/src/Mod/Path/PathScripts/PathJobGui.py index 7fb3fb9add..98816b478e 100644 --- a/src/Mod/Path/PathScripts/PathJobGui.py +++ b/src/Mod/Path/PathScripts/PathJobGui.py @@ -30,7 +30,6 @@ 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.PathGuiInit as PathGuiInit import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences @@ -41,7 +40,6 @@ import PathScripts.PathToolLibraryManager as PathToolLibraryManager import PathScripts.PathUtil as PathUtil import PathScripts.PathUtils as PathUtils import math -# import sys import traceback from PySide import QtCore, QtGui