Drilling refactoring and cleanup

This commit is contained in:
Pekka Roivainen
2017-05-01 23:01:35 +03:00
committed by wmayer
parent 0b8b5768cb
commit b4ae9b69b2
2 changed files with 174 additions and 160 deletions

View File

@@ -46,38 +46,26 @@
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="3">
<widget class="QListWidget" name="baseList">
<property name="toolTip">
<string>Drag to reorder, then update.</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<widget class="QTableWidget" name="baseList">
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addBase">
<widget class="QPushButton" name="uiEnableAll">
<property name="toolTip">
<string>Add item selected in window.</string>
<string>Enable all features in the list.</string>
</property>
<property name="text">
<string>add</string>
<string>Enable All</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteBase">
<widget class="QPushButton" name="uiDisableAll">
<property name="toolTip">
<string>Remove Item selected in list, then update.</string>
<string>Disable all features in the list</string>
</property>
<property name="text">
<string>Remove</string>
<string>Disable all</string>
</property>
</widget>
</item>
@@ -91,7 +79,27 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<item row="2" column="0">
<widget class="QPushButton" name="uiEnableSelected">
<property name="toolTip">
<string>Enable selected items in the list</string>
</property>
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="uiDisableSelected">
<property name="toolTip">
<string>Disable selected items in the list.</string>
</property>
<property name="text">
<string>Disable</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>All objects will be processed using the same operation properties.</string>

View File

@@ -58,10 +58,12 @@ except AttributeError:
class ObjectDrilling:
def __init__(self, obj):
# Base & location
obj.addProperty("App::PropertyLinkSubList", "Base","Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry of this toolpath"))
#obj.addProperty("App::PropertyVectorList", "Positions", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Locations of insterted holding tags"))
obj.addProperty("App::PropertyIntegerList", "Disabled", "Path", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Ids of disabled holding tags"))
#Properties of the holes
obj.addProperty("App::PropertyStringList", "Names", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Names of the holes"))
obj.addProperty("App::PropertyVectorList", "Positions", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Locations of insterted holes"))
obj.addProperty("App::PropertyIntegerList", "Enabled", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Enable/disable status of the holes"))
obj.addProperty("App::PropertyFloatList", "Diameters", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Diameters holes"))
# General Properties
obj.addProperty("App::PropertyBool", "Active", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property","Make False, to prevent operation from generating code"))
@@ -82,6 +84,7 @@ class ObjectDrilling:
# Tool Properties
obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path"))
obj.Proxy = self
self.vertFeed = 0.0
self.horizFeed = 0.0
@@ -94,6 +97,37 @@ class ObjectDrilling:
def __setstate__(self, state):
return None
def sort_locations(self, locations):
""" sort holes by the nearest neighbor method
originally written by m0n5t3r for PathHelix
"""
from Queue import PriorityQueue
def sqdist(a, b):
""" square Euclidean distance """
return (a['x'] - b['x'] ) ** 2 + (a['y'] - b['y']) ** 2
def find_closest(location_list, location, dist):
q = PriorityQueue()
for j in location_list:
q.put((dist(j, location) + location['x'], j))
prio, result = q.get()
return result
out = []
zero = {'x': 0,'y': 0}
out.append(find_closest(locations, zero, sqdist))
while locations:
closest = find_closest(locations, out[-1], sqdist)
out.append(closest)
locations.remove(closest)
return out
def onChanged(self, obj, prop):
pass
# if prop == "UserLabel":
@@ -121,51 +155,42 @@ class ObjectDrilling:
else:
self.radius = tool.Diameter/2
if not obj.Base:
if len(obj.Names) == 0:
parentJob = PathUtils.findParentJob(obj)
if parentJob is None:
return
baseobject = parentJob.Base
if baseobject is None:
return
holes = self.findHoles(obj, baseobject.Shape)
for hole in holes:
self.addDrillableLocation(obj, baseobject, hole[0])
names = []
positions = []
enabled = []
diameters = []
for h in holes:
names.append(h['featureName'])
positions.append(FreeCAD.Vector(h['x'], h['y'],0))
enabled.append(1)
diameters.append(h['d'])
obj.Names = names
obj.Positions = positions
obj.Enabled = enabled
obj.Diameters = diameters
locations = []
output = "(Begin Drilling)\n"
if obj.Base:
for loc in obj.Base:
#print loc
for sub in loc[1]:
#locations.append(self._findDrillingVector(loc))
if "Face" in sub or "Edge" in sub:
s = getattr(loc[0].Shape, sub)
else:
s = loc[0].Shape
if s.ShapeType in ['Wire', 'Edge']:
X = s.Edges[0].Curve.Center.x
Y = s.Edges[0].Curve.Center.y
Z = s.Edges[0].Curve.Center.z
elif s.ShapeType in ['Vertex']:
X = s.Point.x
Y = s.Point.y
Z = s.Point.z
elif s.ShapeType in ['Face']:
#if abs(s.normalAt(0, 0).z) == 1: # horizontal face
X = s.CenterOfMass.x
Y = s.CenterOfMass.y
Z = s.CenterOfMass.z
locations.append(FreeCAD.Vector(X, Y, Z))
if len(obj.Names) > 0:
for i in range(len(obj.Names)):
if(obj.Enabled[i]>0):
locations.append({'x':obj.Positions[i].x, 'y': obj.Positions[i].y})
locations = self.sort_locations(locations)
output += "G90 G98\n"
# rapid to clearance height
output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
# rapid to first hole location, with spindle still retracted:
p0 = locations[0]
output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
output += "G0 X" + fmt(p0['x']) + " Y" + fmt(p0['y']) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
# move tool to clearance plane
output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
pword = ""
@@ -180,8 +205,8 @@ class ObjectDrilling:
cmd = "G81"
for p in locations:
output += cmd + \
" X" + fmt(p.x) + \
" Y" + fmt(p.y) + \
" X" + fmt(p['x']) + \
" Y" + fmt(p['y']) + \
" Z" + fmt(obj.FinalDepth.Value) + qword + pword + \
" R" + str(obj.RetractHeight.Value) + \
" F" + str(self.vertFeed) + "\n" \
@@ -214,7 +239,7 @@ class ObjectDrilling:
x = e.Curve.Center.x
y = e.Curve.Center.y
diameter = e.BoundBox.XLength
holelist.append((candidateEdgeName, e, x, y, diameter))
holelist.append({'featureName':candidateEdgeName, 'feature':e, 'x':x, 'y':y, 'd':diameter, 'enabled': True})
else:
PathLog.debug("shape is not planar")
for i in range(len(shape.Faces)):
@@ -225,38 +250,11 @@ class ObjectDrilling:
x = f.Surface.Center.x
y = f.Surface.Center.y
diameter = f.BoundBox.XLength
holelist.append((candidateFaceName, f, x, y, diameter))
holelist.append({'featureName':candidateFaceName, 'feature':f, 'x':x, 'y':y, 'd':diameter, 'enabled': True})
PathLog.debug("holes found: {}".format(holelist))
return holelist
def addDrillableLocation(self, obj, ss, sub=""):
PathLog.track('ss: {} sub: {}'.format(ss.Label, sub))
baselist = obj.Base
item = (ss, sub)
if len(baselist) == 0: # When adding the first base object, guess at heights
try:
bb = ss.Shape.BoundBox # parent boundbox
subobj = ss.Shape.getElement(sub)
fbb = subobj.BoundBox # feature boundbox
obj.StartDepth = bb.ZMax
obj.ClearanceHeight = bb.ZMax + 5.0
obj.SafeHeight = bb.ZMax + 3.0
obj.RetractHeight = bb.ZMax + 1.0
if fbb.ZMax < bb.ZMax:
obj.FinalDepth = fbb.ZMax
else:
obj.FinalDepth = bb.ZMin
except:
obj.StartDepth = 5.0
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
obj.RetractHeight = 6.0
baselist.append(item)
obj.Base = baselist
#self.execute(obj)
class _ViewProviderDrill:
@@ -336,8 +334,6 @@ class TaskPanel:
self.form = FreeCADGui.PySideUic.loadUi(":/panels/DrillingEdit.ui")
def accept(self):
#self.getFields()
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
@@ -369,6 +365,31 @@ class TaskPanel:
self.obj.ToolController = tc
self.obj.Proxy.execute(self.obj)
def updateFeatureList(self):
self.form.baseList.itemChanged.disconnect(self.checkedChanged) #disconnect this slot while creating objects
self.form.baseList.clear()
self.form.baseList.setColumnCount(2)
self.form.baseList.setRowCount(0)
self.form.baseList.setHorizontalHeaderLabels(["Feature", "Diameter"])
self.form.baseList.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
for i in range(len(self.obj.Names)):
self.form.baseList.insertRow(self.form.baseList.rowCount())
item = QtGui.QTableWidgetItem(self.obj.Names[i])
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
if self.obj.Enabled[i] == True:
item.setCheckState(QtCore.Qt.Checked)
else:
item.setCheckState(QtCore.Qt.Unchecked)
self.form.baseList.setItem(self.form.baseList.rowCount()-1,0,item)
item = QtGui.QTableWidgetItem("{:.3f}".format(self.obj.Diameters[i]))
self.form.baseList.setItem(self.form.baseList.rowCount()-1,1,item)
self.form.baseList.itemChanged.connect(self.checkedChanged)
self.form.baseList.setSortingEnabled(True)
def setFields(self):
PathLog.track()
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
@@ -378,10 +399,7 @@ class TaskPanel:
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
self.form.retractHeight.setText(FreeCAD.Units.Quantity(self.obj.RetractHeight.Value, FreeCAD.Units.Length).UserString)
self.form.baseList.clear()
for i in self.obj.Base:
for sub in i[1]:
self.form.baseList.addItem(i[0].Name + "." + sub)
self.updateFeatureList()
controllers = PathUtils.getToolControllers(self.obj)
labels = [c.Label for c in controllers]
@@ -402,81 +420,68 @@ class TaskPanel:
self.s = SelObserver()
FreeCADGui.Selection.addObserver(self.s)
# def addBase(self):
# # check that the selection contains exactly what we want
# selection = FreeCADGui.Selection.getSelectionEx()
# if not len(selection) >= 1:
# FreeCAD.Console.PrintError(translate("PathProject", "Please select at least one Drillable Location\n"))
# return
# for s in selection:
# if s.HasSubObjects:
# for i in s.SubElementNames:
# self.obj.Proxy.addDrillableLocation(self.obj, s.Object, i)
# else:
# self.obj.Proxy.addDrillableLocation(self.obj, s.Object)
# self.setFields() # defaults may have changed. Reload.
# self.form.baseList.clear()
# for i in self.obj.Base:
# for sub in i[1]:
# self.form.baseList.addItem(i[0].Name + "." + sub)
def deleteBase(self):
dlist = self.form.baseList.selectedItems()
for d in dlist:
newlist = []
for i in self.obj.Base[0][1]:
if not i == d.text().partition(".")[2]:
newlist.append(i)
bodyObj = self.obj.Base[0][0]
self.obj.Base = []
newB = [(bodyObj, newlist)]
self.obj.Base = newB
self.form.baseList.takeItem(self.form.baseList.row(d))
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def itemActivated(self):
FreeCADGui.Selection.clearSelection()
slist = self.form.baseList.selectedItems()
for i in slist:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# sub = o.Shape.getElement(objstring[2])
if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj, objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
if i.column() == 0:
parentJob = PathUtils.findParentJob(self.obj)
obj = parentJob.Base
if i.text() != "":
FreeCADGui.Selection.addSelection(obj, i.text())
else:
FreeCADGui.Selection.addSelection(obj)
FreeCADGui.updateGui()
# def reorderBase(self):
# newlist = []
# for i in range(self.form.baseList.count()):
# s = self.form.baseList.item(i).text()
# objstring = s.partition(".")
def checkedChanged(self):
enabledlist = self.obj.Enabled
# obj = FreeCAD.ActiveDocument.getObject(objstring[0])
# item = (obj, str(objstring[2]))
# newlist.append(item)
# self.obj.Base = newlist
for i in xrange(0,self.form.baseList.rowCount()):
try:
ind = self.obj.Names.index(self.form.baseList.item(i,0).text())
if self.form.baseList.item(i,0).checkState() == QtCore.Qt.Checked:
enabledlist[ind] = 1
else:
enabledlist[ind] = 0
except:
PathLog.track("Not found:"+self.form.baseList.item(i,0).text()+ " in "+str(self.obj.Names))
# self.obj.Proxy.execute(self.obj)
# FreeCAD.ActiveDocument.recompute()
self.obj.Enabled = enabledlist
FreeCAD.ActiveDocument.recompute()
def enableAll(self):
for i in xrange(0,self.form.baseList.rowCount()):
self.form.baseList.item(i,0).setCheckState(QtCore.Qt.Checked)
def enableSelected(self):
slist = self.form.baseList.selectedItems()
for i in slist:
r = i.row()
self.form.baseList.item(r,0).setCheckState(QtCore.Qt.Checked)
def disableAll(self):
for i in xrange(0,self.form.baseList.rowCount()):
self.form.baseList.item(i,0).setCheckState(QtCore.Qt.Unchecked)
def disableSelected(self):
slist = self.form.baseList.selectedItems()
for i in slist:
r = i.row()
self.form.baseList.item(r,0).setCheckState(QtCore.Qt.Unchecked)
def findAll(self):
self.obj.Base = []
""" Reset the list of features by running the findHoles again """
self.obj.Names = []
self.obj.Diameters = []
self.obj.Enabled = []
self.obj.Positions = []
self.obj.Proxy.execute(self.obj)
self.form.baseList.clear()
for i in self.obj.Base:
for sub in i[1]:
self.form.baseList.addItem(i[0].Name + "." + sub)
self.updateFeatureList()
FreeCAD.ActiveDocument.recompute()
Freecad.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok)
@@ -490,17 +495,18 @@ class TaskPanel:
self.form.safeHeight.editingFinished.connect(self.getFields)
self.form.clearanceHeight.editingFinished.connect(self.getFields)
#self.form.addBase.clicked.connect(self.addBase)
self.form.deleteBase.clicked.connect(self.deleteBase)
#buttons
self.form.uiEnableAll.clicked.connect(self.enableAll)
self.form.uiEnableSelected.clicked.connect(self.enableSelected)
self.form.uiDisableAll.clicked.connect(self.disableAll)
self.form.uiDisableSelected.clicked.connect(self.disableSelected)
self.form.uiFindAllHoles.clicked.connect(self.findAll)
#self.form.reorderBase.clicked.connect(self.reorderBase)
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
self.form.uiToolController.currentIndexChanged.connect(self.getFields)
self.form.baseList.itemChanged.connect(self.checkedChanged)
# sel = FreeCADGui.Selection.getSelectionEx()
# if len(sel) != 0 and sel[0].HasSubObjects:
# self.addBase()
self.form.uiToolController.currentIndexChanged.connect(self.getFields)
self.setFields()