Drilling refactoring and cleanup
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user