Path: lgtm Cleanup
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user