diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index 5bebe54954..47c529145a 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -20,6 +20,7 @@ SET(PathScripts_SRCS PathCommands.py PathScripts/PathAreaOp.py PathScripts/PathArray.py + PathScripts/PathCircularHoleBase.py PathScripts/PathComment.py PathScripts/PathCompoundExtended.py PathScripts/PathCopy.py diff --git a/src/Mod/Path/PathScripts/PathDrilling.py b/src/Mod/Path/PathScripts/PathDrilling.py index 5a7d21b6c5..4369648303 100644 --- a/src/Mod/Path/PathScripts/PathDrilling.py +++ b/src/Mod/Path/PathScripts/PathDrilling.py @@ -27,19 +27,14 @@ from __future__ import print_function import ArchPanel import FreeCAD import Path +import PathScripts.PathCircularHoleBase as PathCircularHoleBase import PathScripts.PathLog as PathLog import PathScripts.PathOp as PathOp import PathScripts.PathUtils as PathUtils -import string -import sys from PathScripts.PathUtils import fmt, waiting_effects from PySide import QtCore -# xrange is not available in python3 -if sys.version_info.major >= 3: - xrange = range - if False: PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) @@ -53,10 +48,11 @@ def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) -class ObjectDrilling(PathOp.ObjectOp): +class ObjectDrilling(PathCircularHoleBase.ObjectOp): - def opFeatures(self, obj): - return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureHeights | PathOp.FeatureBaseGeometry + def circularHoleFeatures(self, obj): + # drilling works on anything + return PathOp.FeatureBaseGeometry def initOperation(self, obj): @@ -71,197 +67,47 @@ class ObjectDrilling(PathOp.ObjectOp): obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished")) - self.vertFeed = 0.0 - self.horizFeed = 0.0 - self.vertRapid = 0.0 - self.horizRapid = 0.0 - - def baseIsArchPanel(self, obj, base): - return hasattr(base, "Proxy") and isinstance(base.Proxy, ArchPanel.PanelSheet) - - def getArchPanelEdge(self, obj, base, sub): - ids = string.split(sub, '.') - holeId = int(ids[0]) - wireId = int(ids[1]) - edgeId = int(ids[2]) - - for holeNr, hole in enumerate(base.Proxy.getHoles(base, transform=True)): - if holeNr == holeId: - for wireNr, wire in enumerate(hole.Wires): - if wireNr == wireId: - for edgeNr, edge in enumerate(wire.Edges): - if edgeNr == edgeId: - return edge - - def holeDiameter(self, obj, base, sub): - if self.baseIsArchPanel(obj, base): - edge = self.getArchPanelEdge(obj, base, sub) - return edge.BoundBox.XLength - - shape = base.Shape.getElement(sub) - if shape.ShapeType == 'Vertex': - return 0 - - # for all other shapes the diameter is just the dimension in X - return shape.BoundBox.XLength - - def holePosition(self, obj, base, sub): - if self.baseIsArchPanel(obj, base): - edge = self.getArchPanelEdge(obj, base, sub) - center = edge.Curve.Center - return FreeCAD.Vector(center.x, center.y, 0) - - shape = base.Shape.getElement(sub) - if shape.ShapeType == 'Vertex': - return FreeCAD.Vector(shape.X, shape.Y, 0) - - if shape.ShapeType == 'Edge': - return FreeCAD.Vector(shape.Curve.Center.x, shape.Curve.Center.y, 0) - - if shape.ShapeType == 'Face': - return FreeCAD.Vector(shape.Surface.Center.x, shape.Surface.Center.y, 0) - - PathLog.error('This is bad') - - def isHoleEnabled(self, obj, base, sub): - name = "%s.%s" % (base.Name, sub) - return not name in obj.Disabled - - def opExecute(self, obj): + def circularHoleExecute(self, obj, holes): PathLog.track() + self.commandlist.append(Path.Command("(Begin Drilling)")) + tiplength = 0.0 if obj.AddTipLength: tiplength = PathUtils.drillTipLength(tool) - if len(obj.Base) == 0: - job = PathUtils.findParentJob(obj) - if not job or not job.Base: - return - baseobject = job.Base + 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: - # Arch PanelSheet - features = [] - fbb = None - if self.baseIsArchPanel(obj, baseobject): - holeshapes = baseobject.Proxy.getHoles(baseobject, transform=True) - tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter - for holeNr, hole in enumerate(holeshapes): - PathLog.debug('Entering new HoleShape') - for wireNr, wire in enumerate(hole.Wires): - PathLog.debug('Entering new Wire') - for edgeNr, edge in enumerate(wire.Edges): - if PathUtils.isDrillable(baseobject, edge, tooldiameter): - PathLog.debug('Found drillable hole edges: {}'.format(edge)) - features.append((baseobject, "%d.%d.%d" % (holeNr, wireNr, edgeNr))) + 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})) - else: - features = self.findHoles(obj, baseobject) - for base,sub in features: - shape = base.Shape.getElement(sub) - fbb = fbb.united(shape.BoundBox) if fbb else shape.BoundBox - obj.Base = features - self.setDepths(obj, obj.Base[0][0].Shape.BoundBox, fbb) - obj.Disabled = [] + cmd = "G81" + cmdParams = {} + cmdParams['Z'] = obj.FinalDepth.Value - tiplength + cmdParams['F'] = self.vertFeed + cmdParams['R'] = obj.RetractHeight.Value + if obj.PeckEnabled and obj.PeckDepth.Value > 0: + cmd = "G83" + cmdParams['Q'] = obj.PeckDepth.Value + elif obj.DwellEnabled and obj.DwellTime > 0: + cmd = "G82" + cmdParams['P'] = obj.DwellTime - locations = [] - self.commandlist.append(Path.Command("(Begin Drilling)")) + for p in holes: + params = {} + params['X'] = p['x'] + params['Y'] = p['y'] + params.update(cmdParams) + self.commandlist.append(Path.Command(cmd, params)) - for base, subs in obj.Base: - for sub in subs: - if self.isHoleEnabled(obj, base, sub): - pos = self.holePosition(obj, base, sub) - locations.append({'x': pos.x, 'y': pos.y}) - - if len(locations) > 0: - locations = PathUtils.sort_jobs(locations, ['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 = locations[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 = {} - cmdParams['Z'] = obj.FinalDepth.Value - tiplength - cmdParams['F'] = self.vertFeed - cmdParams['R'] = obj.RetractHeight.Value - if obj.PeckEnabled and obj.PeckDepth.Value > 0: - cmd = "G83" - cmdParams['Q'] = obj.PeckDepth.Value - elif obj.DwellEnabled and obj.DwellTime > 0: - cmd = "G82" - cmdParams['P'] = obj.DwellTime - - for p in locations: - params = {} - params['X'] = p['x'] - params['Y'] = p['y'] - params.update(cmdParams) - self.commandlist.append(Path.Command(cmd, params)) - - self.commandlist.append(Path.Command('G80')) - - def setDepths(self, obj, bb, fbb): - if bb and fbb: - 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 - else: - obj.StartDepth = 5.0 - obj.ClearanceHeight = 10.0 - obj.SafeHeight = 8.0 - obj.RetractHeight = 6.0 - - def findHoles(self, obj, baseobject): - import DraftGeomUtils as dgu - shape = baseobject.Shape - PathLog.track('obj: {} shape: {}'.format(obj, shape)) - holelist = [] - features = [] - # tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter - tooldiameter = None - PathLog.debug('search for holes larger than tooldiameter: {}: '.format(tooldiameter)) - if dgu.isPlanar(shape): - PathLog.debug("shape is planar") - for i in range(len(shape.Edges)): - candidateEdgeName = "Edge" + str(i + 1) - e = shape.getElement(candidateEdgeName) - if PathUtils.isDrillable(shape, e, tooldiameter): - PathLog.debug('edge candidate: {} (hash {})is drillable '.format(e, e.hashCode())) - x = e.Curve.Center.x - y = e.Curve.Center.y - diameter = e.BoundBox.XLength - holelist.append({'featureName': candidateEdgeName, 'feature': e, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) - features.append((baseobject, candidateEdgeName)) - PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateEdgeName)) - else: - PathLog.debug("shape is not planar") - for i in range(len(shape.Faces)): - candidateFaceName = "Face" + str(i + 1) - f = shape.getElement(candidateFaceName) - if PathUtils.isDrillable(shape, f, tooldiameter): - PathLog.debug('face candidate: {} is drillable '.format(f)) - x = f.Surface.Center.x - y = f.Surface.Center.y - diameter = f.BoundBox.XLength - holelist.append({'featureName': candidateFaceName, 'feature': f, 'x': x, 'y': y, 'd': diameter, 'enabled': True}) - features.append((baseobject, candidateFaceName)) - PathLog.debug("Found hole feature %s.%s" % (baseobject.Label, candidateFaceName)) - - PathLog.debug("holes found: {}".format(holelist)) - return features + self.commandlist.append(Path.Command('G80')) def opSetDefaultValues(self, obj): obj.RetractHeight = 10