Added location points for drilling to base framework.

This commit is contained in:
Markus Lampert
2017-08-13 00:16:42 -07:00
committed by Yorik van Havre
parent b92d396753
commit 2642e668c5
8 changed files with 416 additions and 27 deletions

View File

@@ -42,6 +42,7 @@ SET(PathScripts_SRCS
PathScripts/PathFaceProfile.py
PathScripts/PathFixture.py
PathScripts/PathGeom.py
PathScripts/PathGetPoint.py
PathScripts/PathHelix.py
PathScripts/PathHelixGui.py
PathScripts/PathHop.py

View File

@@ -60,6 +60,7 @@
<file>panels/JobEdit.ui</file>
<file>panels/PageBaseGeometryEdit.ui</file>
<file>panels/PageBaseHoleGeometryEdit.ui</file>
<file>panels/PageBaseLocationEdit.ui</file>
<file>panels/PageDepthsEdit.ui</file>
<file>panels/PageHeightsEdit.ui</file>
<file>panels/PageOpDrillingEdit.ui</file>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>415</width>
<height>573</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QTableWidget" name="baseList">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;List of locations to be processed.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>X</string>
</property>
</column>
<column>
<property name="text">
<string>Y</string>
</property>
</column>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="editLocation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Edit selected location.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>All locations will be processed using the same operation properties.</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="removeLocation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Remove selected location from the list. The operation is no longer applied to them.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addLocation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Opens a newe dialog that lets you add arbitrary locations.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>baseList</tabstop>
<tabstop>addLocation</tabstop>
<tabstop>removeLocation</tabstop>
<tabstop>editLocation</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -104,7 +104,7 @@ class ObjectOp(PathOp.ObjectOp):
def opExecute(self, obj):
PathLog.track()
if len(obj.Base) == 0:
if len(obj.Base) == 0 and len(obj.Locations) == 0:
# Arch PanelSheet
features = []
if self.baseIsArchPanel(obj, self.baseobject):
@@ -133,6 +133,8 @@ class ObjectOp(PathOp.ObjectOp):
if self.isHoleEnabled(obj, base, sub):
pos = self.holePosition(obj, base, sub)
holes.append({'x': pos.x, 'y': pos.y, 'r': self.holeDiameter(obj, base, sub)})
for location in obj.Locations:
holes.append({'x': location.x, 'y': location.y, 'r': 0})
if len(holes) > 0:
self.circularHoleExecute(obj, holes)
@@ -168,9 +170,9 @@ class ObjectOp(PathOp.ObjectOp):
def setDepths(self, obj, zmax, zmin, bb):
PathLog.track(obj.Label, zmax, zmin, bb)
if zmax is None:
zmax = 5
zmax = bb.ZMax
if zmin is None:
zmin = 0
zmin = bb.ZMin
if zmin > zmax:
zmax = zmin

View File

@@ -52,7 +52,7 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
def circularHoleFeatures(self, obj):
# drilling works on anything
return PathOp.FeatureBaseGeometry
return PathOp.FeatureBaseGeometry | PathOp.FeatureLocations
def initCircularHoleOperation(self, obj):
@@ -71,6 +71,9 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
self.commandlist.append(Path.Command("(Begin Drilling)"))
# rapid to clearance height
self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
tiplength = 0.0
if obj.AddTipLength:
tiplength = PathUtils.drillTipLength(self.tool)
@@ -78,14 +81,13 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
holes = PathUtils.sort_jobs(holes, ['x', 'y'])
self.commandlist.append(Path.Command('G90'))
self.commandlist.append(Path.Command(obj.ReturnLevel))
# rapid to clearance height
self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
# rapid to first hole location, with spindle still retracted:
p0 = holes[0]
self.commandlist.append(Path.Command('G0', {'X': p0['x'], 'Y': p0['y'], 'F': self.horizRapid}))
# move tool to clearance plane
self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
# ml: I'm not sure whey these were here, they seem redundant
## rapid to first hole location, with spindle still retracted:
#p0 = holes[0]
#self.commandlist.append(Path.Command('G0', {'X': p0['x'], 'Y': p0['y'], 'F': self.horizRapid}))
## move tool to clearance plane
#self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid}))
cmd = "G81"
cmdParams = {}
@@ -118,6 +120,14 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
def opSetDefaultValues(self, obj):
obj.RetractHeight = 10
def opOnChanged(self, obj, prop):
super(self.__class__, self).opOnChanged(obj, prop)
if prop == 'Locations' and not 'Restore' in obj.State and obj.Locations and not obj.Base:
if not hasattr(self, 'baseobject'):
job = PathUtils.findParentJob(obj)
if job and job.Base:
self.setupDepthsFrom(obj, [], job.Base)
def Create(name):
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
proxy = ObjectDrilling(obj)

View File

@@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com> *
# * *
# * 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 Draft
import FreeCAD
import FreeCADGui
from PySide import QtCore, QtGui
from pivy import coin
class TaskPanel:
def __init__(self, formOrig, formPoint):
self.formOrig = formOrig
self.formPoint = formPoint
self.setupUi()
self.buttonBox = None
def setupUi(self):
self.formPoint.buttonBox.accepted.connect(self.pointAccept)
self.formPoint.buttonBox.rejected.connect(self.pointReject)
self.formPoint.ifValueX.editingFinished.connect(self.updatePoint)
self.formPoint.ifValueY.editingFinished.connect(self.updatePoint)
self.formPoint.ifValueZ.editingFinished.connect(self.updatePoint)
def addEscapeShortcut(self):
# The only way I could get to intercept the escape key, or really any key was
# by creating an action with a shortcut .....
self.escape = QtGui.QAction(self.formPoint)
self.escape.setText('Done')
self.escape.setShortcut(QtGui.QKeySequence.fromString('Esc'))
QtCore.QObject.connect(self.escape, QtCore.SIGNAL('triggered()'), self.pointDone)
self.formPoint.addAction(self.escape)
def removeEscapeShortcut(self):
if self.escape:
self.formPoint.removeAction(self.escape)
self.escape = None
def getPoint(self, whenDone, start=None):
def displayPoint(p):
self.formPoint.ifValueX.setText(FreeCAD.Units.Quantity(p.x, FreeCAD.Units.Length).UserString)
self.formPoint.ifValueY.setText(FreeCAD.Units.Quantity(p.y, FreeCAD.Units.Length).UserString)
self.formPoint.ifValueZ.setText(FreeCAD.Units.Quantity(p.z, FreeCAD.Units.Length).UserString)
self.formPoint.ifValueX.setFocus()
self.formPoint.ifValueX.selectAll()
def mouseMove(cb):
event = cb.getEvent()
pos = event.getPosition()
cntrl = event.wasCtrlDown()
shift = event.wasShiftDown()
self.pt = FreeCADGui.Snapper.snap(pos, lastpoint=start, active=cntrl, constrain=shift)
plane = FreeCAD.DraftWorkingPlane
p = plane.getLocalCoords(self.pt)
displayPoint(p)
def click(cb):
event = cb.getEvent()
if event.getButton() == 1 and event.getState() == coin.SoMouseButtonEvent.DOWN:
accept()
def accept():
if start:
self.pointAccept()
else:
self.pointAcceptAndContinue()
def cancel():
self.pointCancel()
self.pointWhenDone = whenDone
self.formOrig.hide()
self.formPoint.show()
self.addEscapeShortcut()
if start:
displayPoint(start)
else:
displayPoint(FreeCAD.Vector(0, 0, 0))
self.view = Draft.get3DView()
self.pointCbClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), click)
self.pointCbMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), mouseMove)
if self.buttonBox:
self.buttonBox.setEnabled(False)
FreeCADGui.Snapper.forceGridOff=True
def pointFinish(self, ok, cleanup = True):
obj = FreeCADGui.Snapper.lastSnappedObject
if cleanup:
self.removeGlobalCallbacks()
FreeCADGui.Snapper.off()
if self.buttonBox:
self.buttonBox.setEnabled(True)
self.removeEscapeShortcut()
self.formPoint.hide()
self.formOrig.show()
self.formOrig.setFocus()
if ok:
self.pointWhenDone(self.pt, obj)
else:
self.pointWhenDone(None, None)
def pointDone(self):
self.pointFinish(False)
def pointReject(self):
self.pointFinish(False)
def pointAccept(self):
self.pointFinish(True)
def pointAcceptAndContinue(self):
self.pointFinish(True, False)
def removeGlobalCallbacks(self):
if hasattr(self, 'view') and self.view:
if self.pointCbClick:
self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.pointCbClick)
self.pointCbClick = None
if self.pointCbMove:
self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.pointCbMove)
self.pointCbMove = None
self.view = None
def updatePoint(self):
x = FreeCAD.Units.Quantity(self.formPoint.ifValueX.text()).Value
y = FreeCAD.Units.Quantity(self.formPoint.ifValueY.text()).Value
z = FreeCAD.Units.Quantity(self.formPoint.ifValueZ.text()).Value
self.pt = FreeCAD.Vector(x, y, z)

View File

@@ -50,10 +50,11 @@ FeatureHeights = 0x0004
FeatureStartPoint = 0x0008
FeatureFinishDepth = 0x0010
FeatureStepDown = 0x0020
FeatureBaseVertexes = 0x1000
FeatureBaseEdges = 0x2000
FeatureBaseFaces = 0x4000
FeatureBasePanels = 0x8000
FeatureBaseVertexes = 0x0100
FeatureBaseEdges = 0x0200
FeatureBaseFaces = 0x0400
FeatureBasePanels = 0x0800
FeatureLocations = 0x1000
FeatureBaseGeometry = FeatureBaseVertexes | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels
@@ -66,27 +67,32 @@ class ObjectOp(object):
obj.addProperty("App::PropertyString", "Comment", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "An optional comment for this Operation"))
obj.addProperty("App::PropertyString", "UserLabel", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "User Assigned Label"))
if FeatureBaseGeometry & self.opFeatures(obj):
features = self.opFeatures(obj)
if FeatureBaseGeometry & features:
obj.addProperty("App::PropertyLinkSubList", "Base", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The base geometry for this operation"))
if FeatureTool & self.opFeatures(obj):
if FeatureLocations & features:
obj.addProperty("App::PropertyVectorList", "Locations", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Base locations for this operation"))
if FeatureTool & features:
obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path"))
if FeatureDepths & self.opFeatures(obj):
if FeatureDepths & features:
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z"))
if FeatureStepDown & self.opFeatures(obj):
if FeatureStepDown & features:
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
if FeatureFinishDepth & self.opFeatures(obj):
if FeatureFinishDepth & features:
obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum material removed on final pass."))
if FeatureHeights & self.opFeatures(obj):
if FeatureHeights & features:
obj.addProperty("App::PropertyDistance", "ClearanceHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height needed to clear clamps and obstructions"))
obj.addProperty("App::PropertyDistance", "SafeHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Rapid Safety Height between locations."))
if FeatureStartPoint & self.opFeatures(obj):
if FeatureStartPoint & features:
obj.addProperty("App::PropertyVector", "StartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "The start point of this path"))
obj.addProperty("App::PropertyBool", "UseStartPoint", "Start Point", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if specifying a Start Point"))
@@ -116,21 +122,23 @@ class ObjectOp(object):
obj.Active = True
if FeatureTool & self.opFeatures(obj):
features = self.opFeatures(obj)
if FeatureTool & features:
obj.ToolController = PathUtils.findToolController(obj)
if FeatureDepths & self.opFeatures(obj):
if FeatureDepths & features:
obj.StartDepth = 1.0
obj.FinalDepth = 0.0
if FeatureStepDown & self.opFeatures(obj):
if FeatureStepDown & features:
obj.StepDown = 1.0
if FeatureHeights & self.opFeatures(obj):
if FeatureHeights & features:
obj.ClearanceHeight = 10.0
obj.SafeHeight = 8.0
if FeatureStartPoint & self.opFeatures(obj):
if FeatureStartPoint & features:
obj.UseStartPoint = False
self.opSetDefaultValues(obj)

View File

@@ -24,6 +24,7 @@
import FreeCAD
import FreeCADGui
import PathScripts.PathGetPoint as PathGetPoint
import PathScripts.PathLog as PathLog
import PathScripts.PathSelection as PathSelection
import PathScripts.PathOp as PathOp
@@ -157,6 +158,8 @@ class TaskPanelPage(object):
# subclass interface
def initPage(self, obj):
pass
def modifyStandardButtons(self, buttonBox):
pass
def getForm(self):
pass
def getFields(self, obj):
@@ -316,6 +319,108 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
self.setFields(obj)
class TaskPanelBaseLocationPage(TaskPanelPage):
DataLocation = QtCore.Qt.ItemDataRole.UserRole
def getForm(self):
self.formLoc = FreeCADGui.PySideUic.loadUi(":/panels/PageBaseLocationEdit.ui")
self.formPts = FreeCADGui.PySideUic.loadUi(":/panels/PointEdit.ui")
form = QtGui.QWidget()
self.layout = QtGui.QVBoxLayout(form)
form.setWindowTitle(self.formLoc.windowTitle())
form.setSizePolicy(self.formLoc.sizePolicy())
self.formLoc.setParent(form)
self.formPts.setParent(form)
self.layout.addWidget(self.formLoc)
self.layout.addWidget(self.formPts)
self.formPts.hide()
self.getPoint = PathGetPoint.TaskPanel(self.formLoc, self.formPts)
return form
def modifyStandardButtons(self, buttonBox):
self.getPoint.buttonBox = buttonBox
def getTitle(self, obj):
return translate("PathOp", "Base Location")
def getFields(self, obj):
pass
def setFields(self, obj):
self.formLoc.baseList.blockSignals(True)
self.formLoc.baseList.clearContents()
self.formLoc.baseList.setRowCount(0)
for location in self.obj.Locations:
self.formLoc.baseList.insertRow(self.formLoc.baseList.rowCount())
item = QtGui.QTableWidgetItem("%.2f" % location.x)
item.setData(self.DataLocation, location.x)
self.formLoc.baseList.setItem(self.formLoc.baseList.rowCount()-1, 0, item)
item = QtGui.QTableWidgetItem("%.2f" % location.y)
item.setData(self.DataLocation, location.y)
self.formLoc.baseList.setItem(self.formLoc.baseList.rowCount()-1, 1, item)
self.formLoc.baseList.resizeColumnToContents(0)
self.formLoc.baseList.blockSignals(False)
def removeLocation(self):
deletedRows = []
selected = self.formLoc.baseList.selectedItems()
for item in selected:
row = self.formLoc.baseList.row(item)
if not row in deletedRows:
deletedRows.append(row)
self.formLoc.baseList.removeRow(row)
self.updateLocations()
FreeCAD.ActiveDocument.recompute()
def updateLocations(self):
PathLog.track()
locations = []
for i in range(self.formLoc.baseList.rowCount()):
x = self.formLoc.baseList.item(i, 0).data(self.DataLocation)
y = self.formLoc.baseList.item(i, 1).data(self.DataLocation)
location = FreeCAD.Vector(x, y, 0)
locations.append(location)
self.obj.Locations = locations
def addLocation(self):
self.getPoint.getPoint(self.addLocationAt)
def addLocationAt(self, point, obj):
if point:
locations = self.obj.Locations
locations.append(point)
self.obj.Locations = locations
FreeCAD.ActiveDocument.recompute()
def editLocation(self):
selected = self.formLoc.baseList.selectedItems()
if selected:
row = self.formLoc.baseList.row(item)
self.editRow = row
x = self.formLoc.baseList.item(row, 0).data(self.DataLocation)
y = self.formLoc.baseList.item(row, 1).data(self.DataLocation)
start = FreeCAD.Vector(x, y, 0)
self.getPoint.getPoint(self.editLocationAt, start)
def editLocationAt(self, point, obj):
if point:
self.formLoc.baseList.item(self.editRow, 0).setData(self.DataLocation, point.x)
self.formLoc.baseList.item(self.editRow, 1).setData(self.DataLocation, point.y)
self.updateLocations()
FreeCAD.ActiveDocument.recompute()
def registerSignalHandlers(self, obj):
self.formLoc.addLocation.clicked.connect(self.addLocation)
self.formLoc.removeLocation.clicked.connect(self.removeLocation)
self.formLoc.editLocation.clicked.connect(self.editLocation)
def pageUpdateData(self, obj, prop):
if prop in ['Locations']:
self.setFields(obj)
class TaskPanelHeightsPage(TaskPanelPage):
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageHeightsEdit.ui")
@@ -400,6 +505,12 @@ class TaskPanel(object):
else:
self.featurePages.append(TaskPanelBaseGeometryPage(obj, features))
if PathOp.FeatureLocations & features:
if hasattr(opPage, 'taskPanelBaseLocationPage'):
self.featurePages.append(opPage.taskPanelBaseLocationPage(obj, features))
else:
self.featurePages.append(TaskPanelBaseLocationPage(obj, features))
if PathOp.FeatureDepths & features:
if hasattr(opPage, 'taskPanelDepthsPage'):
self.featurePages.append(opPage.taskPanelDepthsPage(obj, features))
@@ -483,6 +594,10 @@ class TaskPanel(object):
self.setClean()
FreeCAD.ActiveDocument.recompute()
def modifyStandardButtons(self, buttonBox):
for page in self.featurePages:
page.modifyStandardButtons(buttonBox)
def panelGetFields(self):
PathLog.track()
for page in self.featurePages: