diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index 5e05ee625288..cfd552ca7b64 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -494,14 +494,29 @@ def opExecute(self, obj): else: self.CutClimb = True + # Instantiate additional class operation variables + self.resetOpVariables() + + # Setup cutter for OCL and cutout value for operation - based on tool controller properties + oclTool = PathSurfaceSupport.OCL_Tool(ocl, obj) + self.cutter = oclTool.getOclTool() + if not self.cutter: + PathLog.error(translate('PathSurface', "Canceling 3D Surface operation. Error creating OCL cutter.")) + return + self.toolDiam = self.cutter.getDiameter() # oclTool.diameter + self.radius = self.toolDiam / 2.0 + self.useTiltCutter = oclTool.useTiltCutter() + self.cutOut = (self.toolDiam * (float(obj.StepOver) / 100.0)) + self.gaps = [self.toolDiam, self.toolDiam, self.toolDiam] + # Begin GCode for operation with basic information # ... and move cutter to clearance height and startpoint output = '' if obj.Comment != '': self.commandlist.append(Path.Command('N ({})'.format(str(obj.Comment)), {})) self.commandlist.append(Path.Command('N ({})'.format(obj.Label), {})) - self.commandlist.append(Path.Command('N (Tool type: {})'.format(str(obj.ToolController.Tool.ToolType)), {})) - self.commandlist.append(Path.Command('N (Compensated Tool Path. Diameter: {})'.format(str(obj.ToolController.Tool.Diameter)), {})) + self.commandlist.append(Path.Command('N (Tool type: {})'.format(oclTool.toolType), {})) + self.commandlist.append(Path.Command('N (Compensated Tool Path. Diameter: {})'.format(oclTool.diameter), {})) self.commandlist.append(Path.Command('N (Sample interval: {})'.format(str(obj.SampleInterval.Value)), {})) self.commandlist.append(Path.Command('N (Step over %: {})'.format(str(obj.StepOver)), {})) self.commandlist.append(Path.Command('N ({})'.format(output), {})) @@ -509,9 +524,6 @@ def opExecute(self, obj): if obj.UseStartPoint is True: self.commandlist.append(Path.Command('G0', {'X': obj.StartPoint.x, 'Y': obj.StartPoint.y, 'F': self.horizRapid})) - # Instantiate additional class operation variables - self.resetOpVariables() - # Impose property limits self.opApplyPropertyLimits(obj) @@ -532,16 +544,6 @@ def opExecute(self, obj): # Add temp object to temp group folder with following code: # ... self.tempGroup.addObject(OBJ) - # Setup cutter for OCL and cutout value for operation - based on tool controller properties - self.cutter = self.setOclCutter(obj) - if self.cutter is False: - PathLog.error(translate('PathSurface', "Canceling 3D Surface operation. Error creating OCL cutter.")) - return - self.toolDiam = self.cutter.getDiameter() - self.radius = self.toolDiam / 2.0 - self.cutOut = (self.toolDiam * (float(obj.StepOver) / 100.0)) - self.gaps = [self.toolDiam, self.toolDiam, self.toolDiam] - # Get height offset values for later use self.SafeHeightOffset = JOB.SetupSheet.SafeHeightOffset.Value self.ClearHeightOffset = JOB.SetupSheet.ClearanceHeightOffset.Value @@ -610,6 +612,9 @@ def opExecute(self, obj): # Save gcode produced self.commandlist.extend(CMDS) + else: + PathLog.error('Failed to pre-process model and/or selected face(s).') + # ###### CLOSING COMMANDS FOR OPERATION ###### @@ -2006,7 +2011,6 @@ def resetOpVariables(self, all=True): self.stl = None self.fullSTL = None self.cutOut = 0.0 - self.radius = 0.0 self.useTiltCutter = False return True @@ -2123,20 +2127,12 @@ def showDebugObject(self, objShape, objName): do.Shape = objShape do.purgeTouched() self.tempGroup.addObject(do) +# Eclass def SetupProperties(): ''' SetupProperties() ... Return list of properties required for operation.''' - setup = ['AvoidLastX_Faces', 'AvoidLastX_InternalFeatures', 'BoundBox'] - setup.extend(['BoundaryAdjustment', 'PatternCenterAt', 'PatternCenterCustom']) - setup.extend(['CircularUseG2G3', 'InternalFeaturesCut', 'InternalFeaturesAdjustment']) - setup.extend(['CutMode', 'CutPattern', 'CutPatternAngle', 'CutPatternReversed']) - setup.extend(['CutterTilt', 'DepthOffset', 'DropCutterDir', 'GapSizes', 'GapThreshold']) - setup.extend(['HandleMultipleFeatures', 'LayerMode', 'OptimizeStepOverTransitions']) - setup.extend(['ProfileEdges', 'BoundaryEnforcement', 'RotationAxis', 'SampleInterval']) - setup.extend(['ScanType', 'StartIndex', 'StartPoint', 'StepOver', 'StopIndex']) - setup.extend(['UseStartPoint', 'AngularDeflection', 'LinearDeflection', 'ShowTempObjects']) - return setup + return [tup[1] for tup in ObjectSurface.opPropertyDefinitions(False)] def Create(name, obj=None): diff --git a/src/Mod/Path/PathScripts/PathSurfaceSupport.py b/src/Mod/Path/PathScripts/PathSurfaceSupport.py index c88c3261a54e..b10b95d664bb 100644 --- a/src/Mod/Path/PathScripts/PathSurfaceSupport.py +++ b/src/Mod/Path/PathScripts/PathSurfaceSupport.py @@ -584,17 +584,21 @@ def preProcessModel(self, module): def _isReady(self, module): '''_isReady(module)... Internal method. Checks if required attributes are available for processing obj.Base (the Base Geometry).''' + PathLog.debug('ProcessSelectedFaces _isReady({})'.format(module)) if hasattr(self, module): self.module = module modMethod = getattr(self, module) # gets the attribute only modMethod() # executes as method else: + PathLog.error('PSF._isReady() no "{}" method.'.format(module)) return False if not self.radius: + PathLog.error('PSF._isReady() no cutter radius available.') return False if not self.depthParams: + PathLog.error('PSF._isReady() no depth params available.') return False return True @@ -932,7 +936,6 @@ def _calculateOffsetValue(self, isHole, isVoid=False): offset += self.radius + tolrnc return offset - # Eclass @@ -2304,6 +2307,333 @@ def getInternalFeatures(self): return False # Eclass +class OCL_Tool(): + """The OCL_Tool class is designed to translate a FreeCAD standard ToolBit shape, + or Legacy tool type, in the active Tool Controller, into an OCL tool type.""" + + def __init__(self, ocl, obj, safe=False): + self.ocl = ocl + self.obj = obj + self.tool = None + self.tiltCutter = False + self.safe = safe + self.oclTool = None + self.toolType = None + self.toolMode = None + self.toolMethod = None + + self.diameter = -1.0 + self.cornerRadius = -1.0 + self.flatRadius = -1.0 + self.cutEdgeHeight = -1.0 + self.cutEdgeAngle = -1.0 + # Default to zero. ToolBit likely is without. + self.lengthOffset = 0.0 + + if hasattr(obj, 'ToolController'): + if hasattr(obj.ToolController, 'Tool'): + self.tool = obj.ToolController.Tool + if hasattr(self.tool, 'ShapeName'): + self.toolType = self.tool.ShapeName # Indicates ToolBit tool + self.toolMode = 'ToolBit' + elif hasattr(self.tool, 'ToolType'): + self.toolType = self.tool.ToolType # Indicates Legacy tool + self.toolMode = 'Legacy' + if self.toolType: + PathLog.debug('OCL_Tool tool mode, type: {}, {}'.format(self.toolMode, self.toolType)) + + ''' + #### FreeCAD Legacy tool shape properties per tool type + shape = EndMill + Diameter + CuttingEdgeHeight + LengthOffset + + shape = Drill + Diameter + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = CenterDrill + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = CounterSink + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = CounterBore + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = FlyCutter + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = Reamer + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = Tap + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = SlotCutter + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = BallEndMill + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = ChamferMill + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = CornerRound + Diameter + FlatRadius + CornerRadius + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + shape = Engraver + Diameter + CuttingEdgeAngle # TipAngle from above, center shaft. 180 = flat tip (endmill) + CuttingEdgeHeight + LengthOffset + + + #### FreeCAD packaged ToolBit named constaints per shape files + shape = endmill + Diameter; Endmill diameter + Length; Overall length of the endmill + ShankDiameter; diameter of the shank + CuttingEdgeHeight + + shape = ballend + Diameter; Endmill diameter + Length; Overall length of the endmill + ShankDiameter; diameter of the shank + CuttingEdgeHeight + + shape = bullnose + Diameter; Endmill diameter + Length; Overall length of the endmill + ShankDiameter; diameter of the shank + FlatRadius;Radius of the bottom flat part. + CuttingEdgeHeight + + shape = drill + TipAngle; Full angle of the drill tip + Diameter; Drill bit diameter + Length; Overall length of the drillbit + + shape = v-bit + Diameter; Overall diameter of the V-bit + CuttingEdgeAngle;Full angle of the v-bit + Length; Overall bit length + ShankDiameter + FlatHeight;Height of the flat extension of the v-bit + FlatRadius; Diameter of the flat end of the tip + ''' + + # Private methods + def _setDimensions(self): + '''_setDimensions() ... Set values for possible dimensions.''' + if hasattr(self.tool, 'Diameter'): + self.diameter = float(self.tool.Diameter) + else: + msg = translate('PathSurfaceSupport', + 'Diameter dimension missing from ToolBit shape.') + FreeCAD.Console.PrintError(msg + '\n') + return False + if hasattr(self.tool, 'LengthOffset'): + self.lengthOffset = float(self.tool.LengthOffset) + if hasattr(self.tool, 'FlatRadius'): + self.flatRadius = float(self.tool.FlatRadius) + if hasattr(self.tool, 'CuttingEdgeHeight'): + self.cutEdgeHeight = float(self.tool.CuttingEdgeHeight) + if hasattr(self.tool, 'CuttingEdgeAngle'): + self.cutEdgeAngle = float(self.tool.CuttingEdgeAngle) + return True + + def _makeSafeCutter(self): + # Make safeCutter with 25% buffer around physical cutter + if self.safe: + self.diameter = self.diameter * 1.25 + if self.flatRadius == 0.0: + self.flatRadius = self.diameter * 0.25 + elif self.flatRadius > 0.0: + self.flatRadius = self.flatRadius * 1.25 + + def _oclCylCutter(self): + # Standard End Mill, Slot cutter, or Fly cutter + # OCL -> CylCutter::CylCutter(diameter, length) + if (self.diameter == -1.0 or self.cutEdgeHeight == -1.0): + return + self.oclTool = self.ocl.CylCutter( + self.diameter, + self.cutEdgeHeight + self.lengthOffset + ) + + def _oclBallCutter(self): + # Standard Ball End Mill + # OCL -> BallCutter::BallCutter(diameter, length) + if (self.diameter == -1.0 or self.cutEdgeHeight == -1.0): + return + self.tiltCutter = True + self.oclTool = self.ocl.BallCutter( + self.diameter, + self.cutEdgeHeight + self.lengthOffset + ) + + def _oclBullCutter(self): + # Standard Bull Nose cutter + # Reference: https://www.fine-tools.com/halbstabfraeser.html + # OCL -> BullCutter::BullCutter(diameter, minor radius, length) + if (self.diameter == -1.0 or + self.flatRadius == -1.0 or + self.cutEdgeHeight == -1.0): + return + self.oclTool = self.ocl.BullCutter( + self.diameter, + self.diameter - self.flatRadius, + self.cutEdgeHeight + self.lengthOffset + ) + + def _oclConeCutter(self): + # Engraver or V-bit cutter + # OCL -> ConeCutter::ConeCutter(diameter, angle, length) + if (self.diameter == -1.0 or + self.cuttingEdgeAngle == -1.0 or self.cutEdgeHeight == -1.0): + return + self.oclTool = self.ocl.ConeCutter( + self.diameter, + self.cuttingEdgeAngle, + self.cutEdgeHeight + self.lengthOffset + ) + + def _setToolMethod(self): + toolMap = dict() + + if self.toolMode == 'Legacy': + # Set cutter details + # https://www.freecadweb.org/api/dd/dfe/classPath_1_1Tool.html#details + toolMap = { + 'EndMill': 'CylCutter', + 'BallEndMill': 'BallCutter', + 'SlotCutter': 'CylCutter', + 'Engraver': 'ConeCutter', + 'Drill': 'ConeCutter', + 'CounterSink': 'ConeCutter', + 'FlyCutter': 'CylCutter', + 'CenterDrill': 'None', + 'CounterBore': 'None', + 'Reamer': 'None', + 'Tap': 'None', + 'ChamferMill': 'None', + 'CornerRound': 'None' + } + elif self.toolMode == 'ToolBit': + toolMap = { + 'endmill': 'CylCutter', + 'ballend': 'BallCutter', + 'bullnose': 'BullCutter', + 'drill': 'ConeCutter', + 'engraver': 'ConeCutter', + 'v-bit': 'ConeCutter', + 'chamfer': 'None' + } + self.toolMethod = 'None' + if self.toolType in toolMap: + self.toolMethod = toolMap[self.toolType] + + # Public methods + def getOclTool(self): + """getOclTool()... Call this method after class instantiation + to return OCL tool object.""" + # Check for tool controller and tool object + if not self.tool or not self.toolMode: + msg = translate('PathSurface', + 'Failed to identify tool for operation.') + FreeCAD.Console.PrintError(msg + '\n') + return False + + if not self._setDimensions(): + return False + + self._setToolMethod() + + if self.toolMethod == 'None': + err = translate('PathSurface', + 'Failed to map selected tool to an OCL tool type.') + FreeCAD.Console.PrintError(err + '\n') + return False + else: + PathLog.debug('OCL_Tool tool method: {}'.format(self.toolMethod)) + oclToolMethod = getattr(self, '_ocl' + self.toolMethod) + oclToolMethod() + + if self.oclTool: + return self.oclTool + + # Set error messages + err = translate('PathSurface', + 'Failed to translate active tool to OCL tool type.') + FreeCAD.Console.PrintError(err + '\n') + return False + + def useTiltCutter(self): + """useTiltCutter()... Call this method after getOclTool() method + to return status of cutter tilt availability - generally this + is for a ball end mill.""" + if not self.tool or not self.oclTool: + err = translate('PathSurface', + 'OCL tool not available. Cannot determine is cutter has tilt available.') + FreeCAD.Console.PrintError(err + '\n') + return False + return self.tiltCutter +# Eclass + # Support functions def makeExtendedBoundBox(wBB, bbBfr, zDep): PathLog.debug('makeExtendedBoundBox()') diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py index fa1b1fcffb23..78a564658bf7 100644 --- a/src/Mod/Path/PathScripts/PathToolBit.py +++ b/src/Mod/Path/PathScripts/PathToolBit.py @@ -151,6 +151,7 @@ def __init__(self, obj, shapeFile): obj.addProperty('App::PropertyFile', 'BitShape', 'Base', translate('PathToolBit', 'Shape for bit shape')) obj.addProperty('App::PropertyLink', 'BitBody', 'Base', translate('PathToolBit', 'The parametrized body representing the tool bit')) obj.addProperty('App::PropertyFile', 'File', 'Base', translate('PathToolBit', 'The file of the tool')) + obj.addProperty('App::PropertyString', 'ShapeName', 'Base', translate('PathToolBit', 'The name of the shape file')) if shapeFile is None: obj.BitShape = 'endmill.fcstd' self._setupBitShape(obj) @@ -230,6 +231,7 @@ def _loadBitBody(self, obj, path=None): if not path and p != obj.BitShape: obj.BitShape = p doc = FreeCAD.open(p) + obj.ShapeName = doc.Name docOpened = True return (doc, docOpened) diff --git a/src/Mod/Path/PathScripts/PathToolEdit.py b/src/Mod/Path/PathScripts/PathToolEdit.py index 10a32b54affb..c5186a8afbce 100644 --- a/src/Mod/Path/PathScripts/PathToolEdit.py +++ b/src/Mod/Path/PathScripts/PathToolEdit.py @@ -164,7 +164,7 @@ def quantityCuttingEdgeAngle(self, propertyToDisplay): class ToolEditorEngrave(ToolEditorImage): '''Tool parameter editor for v-bits.''' def __init__(self, editor): - super(ToolEditorEngrave, self).__init__(editor, 'v-bit.svg', '', 'HS') + super(ToolEditorEngrave, self).__init__(editor, 'v-bit.svg', '', 'dS') def quantityCuttingEdgeHeight(self, propertyToDisplay): PathLog.track() diff --git a/src/Mod/Path/PathScripts/PathWaterline.py b/src/Mod/Path/PathScripts/PathWaterline.py index 98465b01713f..2b48eb888781 100644 --- a/src/Mod/Path/PathScripts/PathWaterline.py +++ b/src/Mod/Path/PathScripts/PathWaterline.py @@ -466,14 +466,28 @@ def opExecute(self, obj): else: self.CutClimb = True + # Instantiate additional class operation variables + self.resetOpVariables() + + # Setup cutter for OCL and cutout value for operation - based on tool controller properties + oclTool = PathSurfaceSupport.OCL_Tool(ocl, obj) + self.cutter = oclTool.getOclTool() + if not self.cutter: + PathLog.error(translate('PathWaterline', "Canceling Waterline operation. Error creating OCL cutter.")) + return + self.toolDiam = self.cutter.getDiameter() + self.radius = self.toolDiam / 2.0 + self.cutOut = (self.toolDiam * (float(obj.StepOver) / 100.0)) + self.gaps = [self.toolDiam, self.toolDiam, self.toolDiam] + # Begin GCode for operation with basic information # ... and move cutter to clearance height and startpoint output = '' if obj.Comment != '': self.commandlist.append(Path.Command('N ({})'.format(str(obj.Comment)), {})) self.commandlist.append(Path.Command('N ({})'.format(obj.Label), {})) - self.commandlist.append(Path.Command('N (Tool type: {})'.format(str(obj.ToolController.Tool.ToolType)), {})) - self.commandlist.append(Path.Command('N (Compensated Tool Path. Diameter: {})'.format(str(obj.ToolController.Tool.Diameter)), {})) + self.commandlist.append(Path.Command('N (Tool type: {})'.format(oclTool.toolType), {})) + self.commandlist.append(Path.Command('N (Compensated Tool Path. Diameter: {})'.format(oclTool.diameter), {})) self.commandlist.append(Path.Command('N (Sample interval: {})'.format(str(obj.SampleInterval.Value)), {})) self.commandlist.append(Path.Command('N (Step over %: {})'.format(str(obj.StepOver)), {})) self.commandlist.append(Path.Command('N ({})'.format(output), {})) @@ -481,9 +495,6 @@ def opExecute(self, obj): if obj.UseStartPoint: self.commandlist.append(Path.Command('G0', {'X': obj.StartPoint.x, 'Y': obj.StartPoint.y, 'F': self.horizRapid})) - # Instantiate additional class operation variables - self.resetOpVariables() - # Impose property limits self.opApplyPropertyLimits(obj) @@ -504,16 +515,6 @@ def opExecute(self, obj): # Add temp object to temp group folder with following code: # ... self.tempGroup.addObject(OBJ) - # Setup cutter for OCL and cutout value for operation - based on tool controller properties - self.cutter = self.setOclCutter(obj) - if self.cutter is False: - PathLog.error(translate('PathWaterline', "Canceling Waterline operation. Error creating OCL cutter.")) - return - self.toolDiam = self.cutter.getDiameter() - self.radius = self.toolDiam / 2.0 - self.cutOut = (self.toolDiam * (float(obj.StepOver) / 100.0)) - self.gaps = [self.toolDiam, self.toolDiam, self.toolDiam] - # Get height offset values for later use self.SafeHeightOffset = JOB.SetupSheet.SafeHeightOffset.Value self.ClearHeightOffset = JOB.SetupSheet.ClearanceHeightOffset.Value @@ -1752,7 +1753,6 @@ def resetOpVariables(self, all=True): self.stl = None self.fullSTL = None self.cutOut = 0.0 - self.radius = 0.0 self.useTiltCutter = False return True @@ -1782,74 +1782,17 @@ def deleteOpVariables(self, all=True): del self.useTiltCutter return True - def setOclCutter(self, obj, safe=False): - ''' setOclCutter(obj) ... Translation function to convert FreeCAD tool definition to OCL formatted tool. ''' - # Set cutter details - # https://www.freecadweb.org/api/dd/dfe/classPath_1_1Tool.html#details - diam_1 = float(obj.ToolController.Tool.Diameter) - lenOfst = obj.ToolController.Tool.LengthOffset if hasattr(obj.ToolController.Tool, 'LengthOffset') else 0 - FR = obj.ToolController.Tool.FlatRadius if hasattr(obj.ToolController.Tool, 'FlatRadius') else 0 - CEH = obj.ToolController.Tool.CuttingEdgeHeight if hasattr(obj.ToolController.Tool, 'CuttingEdgeHeight') else 0 - CEA = obj.ToolController.Tool.CuttingEdgeAngle if hasattr(obj.ToolController.Tool, 'CuttingEdgeAngle') else 0 - - # Make safeCutter with 2 mm buffer around physical cutter - if safe is True: - diam_1 += 4.0 - if FR != 0.0: - FR += 2.0 - - PathLog.debug('ToolType: {}'.format(obj.ToolController.Tool.ToolType)) - if obj.ToolController.Tool.ToolType == 'EndMill': - # Standard End Mill - return ocl.CylCutter(diam_1, (CEH + lenOfst)) - - elif obj.ToolController.Tool.ToolType == 'BallEndMill' and FR == 0.0: - # Standard Ball End Mill - # OCL -> BallCutter::BallCutter(diameter, length) - self.useTiltCutter = True - return ocl.BallCutter(diam_1, (diam_1 / 2 + lenOfst)) - - elif obj.ToolController.Tool.ToolType == 'BallEndMill' and FR > 0.0: - # Bull Nose or Corner Radius cutter - # Reference: https://www.fine-tools.com/halbstabfraeser.html - # OCL -> BallCutter::BallCutter(diameter, length) - return ocl.BullCutter(diam_1, FR, (CEH + lenOfst)) - - elif obj.ToolController.Tool.ToolType == 'Engraver' and FR > 0.0: - # Bull Nose or Corner Radius cutter - # Reference: https://www.fine-tools.com/halbstabfraeser.html - # OCL -> ConeCutter::ConeCutter(diameter, angle, lengthOffset) - return ocl.ConeCutter(diam_1, (CEA / 2), lenOfst) - - elif obj.ToolController.Tool.ToolType == 'ChamferMill': - # Bull Nose or Corner Radius cutter - # Reference: https://www.fine-tools.com/halbstabfraeser.html - # OCL -> ConeCutter::ConeCutter(diameter, angle, lengthOffset) - return ocl.ConeCutter(diam_1, (CEA / 2), lenOfst) - else: - # Default to standard end mill - PathLog.warning("Defaulting cutter to standard end mill.") - return ocl.CylCutter(diam_1, (CEH + lenOfst)) - def showDebugObject(self, objShape, objName): if self.showDebugObjects: do = FreeCAD.ActiveDocument.addObject('Part::Feature', 'tmp_' + objName) do.Shape = objShape do.purgeTouched() self.tempGroup.addObject(do) - +# Eclass def SetupProperties(): ''' SetupProperties() ... Return list of properties required for operation.''' - setup = ['Algorithm', 'AvoidLastX_Faces', 'AvoidLastX_InternalFeatures', 'BoundBox'] - setup.extend(['BoundaryAdjustment', 'PatternCenterAt', 'PatternCenterCustom']) - setup.extend(['ClearLastLayer', 'InternalFeaturesCut', 'InternalFeaturesAdjustment']) - setup.extend(['CutMode', 'CutPattern', 'CutPatternAngle', 'CutPatternReversed']) - setup.extend(['DepthOffset', 'GapSizes', 'GapThreshold', 'StepOver']) - setup.extend(['HandleMultipleFeatures', 'LayerMode', 'OptimizeStepOverTransitions']) - setup.extend(['BoundaryEnforcement', 'SampleInterval', 'StartPoint', 'IgnoreOuterAbove']) - setup.extend(['UseStartPoint', 'AngularDeflection', 'LinearDeflection', 'ShowTempObjects']) - return setup + return [tup[1] for tup in ObjectWaterline.opPropertyDefinitions(False)] def Create(name, obj=None):