| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | import FreeCAD |
| | import Part |
| | import Path |
| | import Path.Base.FeedRate as PathFeedRate |
| | import Path.Base.Generator.tapping as tapping |
| | import Path.Base.MachineState as PathMachineState |
| | import Path.Op.Base as PathOp |
| | import Path.Op.CircularHoleBase as PathCircularHoleBase |
| | import PathScripts.PathUtils as PathUtils |
| | from PySide.QtCore import QT_TRANSLATE_NOOP |
| |
|
| | __title__ = "Path Tapping Operation" |
| | __author__ = "sliptonic (Brad Collette)" |
| | __url__ = "https://www.freecad.org" |
| | __doc__ = "Path Tapping operation." |
| | __contributors__ = "luvtofish (Dan Henderson)" |
| |
|
| | if False: |
| | Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule()) |
| | Path.Log.trackModule(Path.Log.thisModule()) |
| | else: |
| | Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) |
| |
|
| | translate = FreeCAD.Qt.translate |
| |
|
| |
|
| | class ObjectTapping(PathCircularHoleBase.ObjectOp): |
| | """Proxy object for Tapping operation.""" |
| |
|
| | @classmethod |
| | def propertyEnumerations(self, dataType="data"): |
| | """helixOpPropertyEnumerations(dataType="data")... return property enumeration lists of specified dataType. |
| | Args: |
| | dataType = 'data', 'raw', 'translated' |
| | Notes: |
| | 'data' is list of internal string literals used in code |
| | 'raw' is list of (translated_text, data_string) tuples |
| | 'translated' is list of translated string literals |
| | """ |
| |
|
| | |
| | enums = { |
| | "ReturnLevel": [ |
| | (translate("CAM_Tapping", "G98"), "G98"), |
| | (translate("CAM_Tapping", "G99"), "G99"), |
| | ], |
| | "ExtraOffset": [ |
| | (translate("CAM_Tapping", "None"), "None"), |
| | (translate("CAM_Tapping", "Drill Tip"), "Drill Tip"), |
| | (translate("CAM_Tapping", "2x Drill Tip"), "2x Drill Tip"), |
| | ], |
| | } |
| |
|
| | if dataType == "raw": |
| | return enums |
| |
|
| | data = list() |
| | idx = 0 if dataType == "translated" else 1 |
| |
|
| | Path.Log.debug(enums) |
| |
|
| | for k, v in enumerate(enums): |
| | data.append((v, [tup[idx] for tup in enums[v]])) |
| | Path.Log.debug(data) |
| |
|
| | return data |
| |
|
| | def circularHoleFeatures(self, obj): |
| | """circularHoleFeatures(obj) ... tapping works on anything, turn on all Base geometries and Locations.""" |
| | return PathOp.FeatureBaseGeometry | PathOp.FeatureLocations | PathOp.FeatureCoolant |
| |
|
| | def initCircularHoleOperation(self, obj): |
| | """initCircularHoleOperation(obj) ... add tapping specific properties to obj.""" |
| | obj.addProperty( |
| | "App::PropertyFloat", |
| | "DwellTime", |
| | "Tap", |
| | QT_TRANSLATE_NOOP("App::Property", "The time to dwell at bottom of tapping cycle"), |
| | ) |
| | obj.addProperty( |
| | "App::PropertyBool", |
| | "DwellEnabled", |
| | "Tap", |
| | QT_TRANSLATE_NOOP("App::Property", "Enable dwell"), |
| | ) |
| | obj.addProperty( |
| | "App::PropertyBool", |
| | "AddTipLength", |
| | "Tap", |
| | QT_TRANSLATE_NOOP( |
| | "App::Property", |
| | "Calculate the tip length and subtract from final depth", |
| | ), |
| | ) |
| | obj.addProperty( |
| | "App::PropertyEnumeration", |
| | "ReturnLevel", |
| | "Tap", |
| | QT_TRANSLATE_NOOP("App::Property", "Controls how tool retracts Default=G98"), |
| | ) |
| | obj.addProperty( |
| | "App::PropertyDistance", |
| | "RetractHeight", |
| | "Tap", |
| | QT_TRANSLATE_NOOP( |
| | "App::Property", |
| | "The height where feed starts and height during retract tool when path is finished while in a peck operation", |
| | ), |
| | ) |
| | obj.addProperty( |
| | "App::PropertyEnumeration", |
| | "ExtraOffset", |
| | "Tap", |
| | QT_TRANSLATE_NOOP("App::Property", "How far the tap depth is extended"), |
| | ) |
| |
|
| | for n in self.propertyEnumerations(): |
| | setattr(obj, n[0], n[1]) |
| |
|
| | def circularHoleExecute(self, obj, holes): |
| | """circularHoleExecute(obj, holes) ... generate tapping operation for each hole in holes.""" |
| | Path.Log.track() |
| | machine = PathMachineState.MachineState() |
| |
|
| | if not hasattr(obj.ToolController.Tool, "Pitch"): |
| | Path.Log.error( |
| | translate( |
| | "Path_Tapping", |
| | "Tapping Operation requires a Tap tool with Pitch", |
| | ) |
| | ) |
| | return |
| |
|
| | self.commandlist.append(Path.Command("(Begin Tapping)")) |
| |
|
| | |
| | command = Path.Command("G0", {"Z": obj.ClearanceHeight.Value}) |
| | machine.addCommand(command) |
| | self.commandlist.append(command) |
| |
|
| | self.commandlist.append(Path.Command("G90")) |
| |
|
| | |
| | endoffset = 0.0 |
| | if obj.ExtraOffset == "Drill Tip": |
| | endoffset = PathUtils.drillTipLength(self.tool) |
| | elif obj.ExtraOffset == "2x Drill Tip": |
| | endoffset = PathUtils.drillTipLength(self.tool) * 2 |
| |
|
| | |
| | self.commandlist.append( |
| | Path.Command(obj.ReturnLevel).addAnnotations({"operation": "tapping"}) |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | startHeight = obj.StartDepth.Value + self.job.SetupSheet.SafeHeightOffset.Value |
| |
|
| | edgelist = [] |
| | for hole in holes: |
| | v1 = FreeCAD.Vector(hole["x"], hole["y"], obj.StartDepth.Value) |
| | v2 = FreeCAD.Vector(hole["x"], hole["y"], obj.FinalDepth.Value - endoffset) |
| | edgelist.append(Part.makeLine(v1, v2)) |
| |
|
| | |
| | for edge in edgelist: |
| | Path.Log.debug(edge) |
| |
|
| | |
| |
|
| | startPoint = edge.Vertexes[0].Point |
| |
|
| | command = Path.Command( |
| | "G0", {"X": startPoint.x, "Y": startPoint.y, "Z": startHeight} |
| | ) |
| | self.commandlist.append(command) |
| | machine.addCommand(command) |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | dwelltime = obj.DwellTime if obj.DwellEnabled else 0.0 |
| | repeat = 1 |
| |
|
| | |
| | isRightHand = ( |
| | getattr(obj.ToolController.Tool, "SpindleDirection", "Forward") == "Forward" |
| | ) |
| |
|
| | |
| | pitch = getattr(obj.ToolController.Tool, "Pitch", None) |
| | if pitch is None or pitch == 0: |
| | Path.Log.error( |
| | translate( |
| | "Path_Tapping", |
| | "Tapping Operation requires a Tap tool with non-zero Pitch", |
| | ) |
| | ) |
| | continue |
| |
|
| | spindle_speed = getattr(obj.ToolController, "SpindleSpeed", None) |
| | if spindle_speed is None or spindle_speed == 0: |
| | Path.Log.error( |
| | translate( |
| | "Path_Tapping", |
| | "Tapping Operation requires a ToolController with non-zero SpindleSpeed", |
| | ) |
| | ) |
| | continue |
| |
|
| | try: |
| | tappingcommands = tapping.generate( |
| | edge, |
| | dwelltime, |
| | repeat, |
| | obj.RetractHeight.Value, |
| | isRightHand, |
| | pitch, |
| | spindle_speed, |
| | ) |
| |
|
| | except ValueError as e: |
| | Path.Log.info(e) |
| | continue |
| |
|
| | for command in tappingcommands: |
| | self.commandlist.append(command) |
| | machine.addCommand(command) |
| |
|
| | |
| | self.commandlist.append(Path.Command("G80").addAnnotations({"operation": "tapping"})) |
| | |
| | |
| | |
| |
|
| | |
| | PathFeedRate.setFeedRate(self.commandlist, obj.ToolController) |
| |
|
| | def opSetDefaultValues(self, obj, job): |
| | """opSetDefaultValues(obj, job) ... set default value for RetractHeight""" |
| | obj.ExtraOffset = "None" |
| |
|
| | if hasattr(job.SetupSheet, "RetractHeight"): |
| | obj.RetractHeight = job.SetupSheet.RetractHeight |
| | elif self.applyExpression(obj, "RetractHeight", "StartDepth+SetupSheet.SafeHeightOffset"): |
| | if not job: |
| | obj.RetractHeight = 10 |
| | else: |
| | obj.RetractHeight.Value = obj.StartDepth.Value + 1.0 |
| |
|
| | if hasattr(job.SetupSheet, "DwellTime"): |
| | obj.DwellTime = job.SetupSheet.DwellTime |
| | else: |
| | obj.DwellTime = 1 |
| |
|
| |
|
| | def SetupProperties(): |
| | setup = [] |
| | setup.append("DwellTime") |
| | setup.append("DwellEnabled") |
| | setup.append("AddTipLength") |
| | setup.append("ReturnLevel") |
| | setup.append("ExtraOffset") |
| | setup.append("RetractHeight") |
| | return setup |
| |
|
| |
|
| | def Create(name, obj=None, parentJob=None): |
| | """Create(name) ... Creates and returns a Tapping operation.""" |
| | if obj is None: |
| | obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) |
| |
|
| | obj.Proxy = ObjectTapping(obj, name, parentJob) |
| | if obj.Proxy: |
| | obj.Proxy.findAllHoles(obj) |
| |
|
| | return obj |
| |
|