def test20(self): '''Start and end are equal or start lower than finish ''' clearance_height= 15 safe_height = 12 start_depth = 10 step_down = 2 z_finish_step = 0 final_depth = 10 user_depths = None expected =[10] d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected) start_depth = 10 final_depth = 15 expected =[] d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test20(self): '''Start and end are equal or start lower than finish ''' clearance_height = 15 rapid_safety_space = 12 start_depth = 10 step_down = 2 z_finish_step = 0 final_depth = 10 user_depths = None expected = [] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected) start_depth = 10 final_depth = 15 expected = [] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test20(self): """Start and end are equal or start lower than finish""" args = { "clearance_height": 15, "safe_height": 12, "start_depth": 10, "step_down": 2, "z_finish_step": 0, "final_depth": 10, "user_depths": None, } expected = [10] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected) args["start_depth"] = 10 args["final_depth"] = 15 expected = [] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test20(self): '''Start and end are equal or start lower than finish ''' clearance_height = 15 rapid_safety_space = 12 start_depth = 10 step_down = 2 z_finish_step = 0 final_depth = 10 user_depths = None expected = [10] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected) start_depth = 10 final_depth = 15 expected = [] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test20(self): '''Start and end are equal or start lower than finish ''' clearance_height= 15 safe_height = 12 start_depth = 10 step_down = 2 z_finish_step = 0 final_depth = 10 user_depths = None expected =[10] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected) start_depth = 10 final_depth = 15 expected =[] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test010(self): """stepping down with single stepdown roughly equal to total depth""" args = { "clearance_height": 20.0, "safe_height": 15.0, "start_depth": 10.000000001, "step_down": 10.0, "z_finish_step": 0.0, "final_depth": 0.0, "user_depths": None, } expected = [0] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual( r, expected, "Expected {}, but result of {}".format(expected, r)) args = { "clearance_height": 20.0, "safe_height": 15.0, "start_depth": 10.0, "step_down": 9.9999999, "z_finish_step": 0.0, "final_depth": 0.0, "user_depths": None, } d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual( r, expected, "Expected {}, but result of {}".format(expected, r))
def test80(self): """Test handling of negative step-down, negative finish step, and relative size of step/finish""" # negative steps should be converted to positive values args = { "clearance_height": 3, "safe_height": 3, "start_depth": 2, "step_down": -1, "z_finish_step": -1, "final_depth": 0, "user_depths": None, } expected = [1.0, 0] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected) # a step_down less than the finish step is an error args = { "clearance_height": 3, "safe_height": 3, "start_depth": 2, "step_down": 0.1, "z_finish_step": 1, "final_depth": 0, "user_depths": None, } self.assertRaises(ValueError, PathUtils.depth_params, **args)
def _customDepthParams(self, obj, strDep, finDep): finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0 cdp = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, user_depths=None) return cdp
def test70(self): '''stepping down with stepdown greater than total depth''' clearance_height= 10 rapid_safety_space = 5 start_depth = 10 step_down = 20 z_finish_step = 1 final_depth = 0 user_depths = None expected =[1.0, 0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths(equalstep=True) self.assertListEqual (r, expected) d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual (r, expected)
def opExecute(self, obj, getsim=False): '''opExecute(obj, getsim=False) ... implementation of Path.Area ops. determines the parameters for _buildPathArea(). Do not overwrite, implement areaOpAreaParams(obj, isHole) ... op specific area param dictionary areaOpPathParams(obj, isHole) ... op specific path param dictionary areaOpShapes(obj) ... the shape for path area to process areaOpUseProjection(obj) ... return true if operation can use projection instead.''' PathLog.track() self.endVector = None finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=obj.FinalDepth.Value, user_depths=None) if PathOp.FeatureStartPoint & self.opFeatures(obj) and obj.UseStartPoint: start = obj.StartPoint else: start = None shapes = self.areaOpShapes(obj) jobs = [{ 'x': s[0].BoundBox.XMax, 'y': s[0].BoundBox.YMax, 'shape': s } for s in shapes] jobs = PathUtils.sort_jobs(jobs, ['x', 'y']) shapes = [j['shape'] for j in jobs] sims = [] for (shape, isHole) in shapes: try: (pp, sim) = self._buildPathArea(obj, shape, isHole, start, getsim) self.commandlist.extend(pp.Commands) sims.append(sim) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Check project and tool config.") if self.areaOpRetractTool(obj): self.endVector = None return sims
def test70(self): '''stepping down with stepdown greater than total depth''' clearance_height = 10 rapid_safety_space = 5 start_depth = 10 step_down = 20 z_finish_step = 1 final_depth = 0 user_depths = None expected = [1.0, 0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths(equalstep=True) self.assertListEqual(r, expected) d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test30(self): '''User Parameters passed in''' clearance_height= 10 rapid_safety_space = 5 start_depth = 0 step_down = 2 z_finish_step = 0 final_depth = -10 user_depths = [2, 4, 8, 10, 11, 12] expected =[2, 4, 8, 10, 11, 12] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual (r, expected)
def test00(self): '''Stepping down to zero ''' clearance_height= 15 rapid_safety_space = 12 start_depth = 10 step_down = 2 z_finish_step = 1 final_depth = 0 user_depths = None expected =[8,6,4,2,1,0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual (r, expected)
def test60(self): '''stepping down with equalstep=True and a finish depth''' clearance_height= 10 rapid_safety_space = 5 start_depth = 10 step_down = 3 z_finish_step = 1 final_depth = 0 user_depths = None expected =[7.0, 4.0, 1.0, 0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths(equalstep=True) self.assertListEqual (r, expected)
def test40(self): '''Finish depth passed in.''' clearance_height= 10 rapid_safety_space = 5 start_depth = 0 step_down = 2 z_finish_step = 1 final_depth = -10 user_depths = None expected =[-2, -4, -6, -8, -9, -10] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual (r, expected)
def test50(self): '''stepping down with equalstep=True''' clearance_height= 10 safe_height = 5 start_depth = 10 step_down = 3 z_finish_step = 0 final_depth = 0 user_depths = None expected =[7.5, 5.0, 2.5, 0] d = PathUtils.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) r = [i for i in d] self.assertListEqual (r, expected)
def test40(self): '''z_finish_step passed in.''' clearance_height= 10 safe_height = 5 start_depth = 0 step_down = 2 z_finish_step = 1 final_depth = -10 user_depths = None expected =[-2, -4, -6, -8, -9, -10] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test00(self): '''Stepping down to zero ''' clearance_height= 15 safe_height = 12 start_depth = 10 step_down = 2 z_finish_step = 1 final_depth = 0 user_depths = None expected =[8,6,4,2,1,0] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test30(self): '''User Parameters passed in''' clearance_height= 10 safe_height = 5 start_depth = 0 step_down = 2 z_finish_step = 0 final_depth = -10 user_depths = [2, 4, 8, 10, 11, 12] expected =[2, 4, 8, 10, 11, 12] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test70(self): '''stepping down with stepdown greater than total depth''' clearance_height= 10 safe_height = 5 start_depth = 10 step_down = 20 z_finish_step = 1 final_depth = 0 user_depths = None expected =[1.0, 0] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test60(self): '''stepping down with equalstep=True and a finish depth''' clearance_height= 10 safe_height = 5 start_depth = 10 step_down = 3 z_finish_step = 1 final_depth = 0 user_depths = None expected =[7.0, 4.0, 1.0, 0] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) r = [i for i in d] self.assertListEqual (r, expected)
def test60(self): '''stepping down with equalstep=True and a finish depth''' clearance_height = 10 rapid_safety_space = 5 start_depth = 10 step_down = 3 z_finish_step = 1 final_depth = 0 user_depths = None expected = [7.0, 4.0, 1.0, 0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths(equalstep=True) self.assertListEqual(r, expected)
def test00(self): '''Stepping down to zero ''' clearance_height = 15 rapid_safety_space = 12 start_depth = 10 step_down = 2 z_finish_step = 1 final_depth = 0 user_depths = None expected = [8, 6, 4, 2, 1, 0] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test00(self): """Stepping down to zero""" args = { "clearance_height": 15, "safe_height": 12, "start_depth": 10, "step_down": 2, "z_finish_step": 1, "final_depth": 0, "user_depths": None, } expected = [8, 6, 4, 2, 1, 0] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test30(self): '''User Parameters passed in''' clearance_height = 10 rapid_safety_space = 5 start_depth = 0 step_down = 2 z_finish_step = 0 final_depth = -10 user_depths = [2, 4, 8, 10, 11, 12] expected = [2, 4, 8, 10, 11, 12] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test40(self): """z_finish_step passed in.""" args = { "clearance_height": 10, "safe_height": 5, "start_depth": 0, "step_down": 2, "z_finish_step": 1, "final_depth": -10, "user_depths": None, } expected = [-2, -4, -6, -8, -9, -10] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test60(self): """stepping down with equalstep=True and a finish depth""" args = { "clearance_height": 10, "safe_height": 5, "start_depth": 10, "step_down": 3, "z_finish_step": 1, "final_depth": 0, "user_depths": None, } expected = [7.0, 4.0, 1.0, 0] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test10(self): '''Stepping from zero to a negative depth ''' clearance_height= 10 safe_height = 5 start_depth = 0 step_down = 2 z_finish_step = 0 final_depth = -10 user_depths = None expected =[-2, -4, -6, -8, -10] d = PU.depth_params(clearance_height, safe_height, start_depth, step_down, z_finish_step, final_depth, user_depths) r = [i for i in d] self.assertListEqual (r, expected)
def test70(self): """stepping down with stepdown greater than total depth""" args = { "clearance_height": 10, "safe_height": 5, "start_depth": 10, "step_down": 20, "z_finish_step": 1, "final_depth": 0, "user_depths": None, } expected = [1.0, 0] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test40(self): '''z_finish_step passed in.''' clearance_height = 10 rapid_safety_space = 5 start_depth = 0 step_down = 2 z_finish_step = 1 final_depth = -10 user_depths = None expected = [-2, -4, -6, -8, -9, -10] d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths) r = d.get_depths() self.assertListEqual(r, expected)
def test30(self): """User Parameters passed in""" args = { "clearance_height": 10, "safe_height": 5, "start_depth": 0, "step_down": 2, "z_finish_step": 0, "final_depth": -10, "user_depths": [2, 4, 8, 10, 11, 12], } expected = [2, 4, 8, 10, 11, 12] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def test001(self): """Stepping from zero to a negative depth""" args = { "clearance_height": 10, "safe_height": 5, "start_depth": 0, "step_down": 2, "z_finish_step": 0, "final_depth": -10, "user_depths": None, } expected = [-2, -4, -6, -8, -10] d = PathUtils.depth_params(**args) r = [i for i in d] self.assertListEqual(r, expected)
def calculateAdaptivePocket(self, obj, base, subObjTups): '''calculateAdaptivePocket(obj, base, subObjTups) Orient multiple faces around common facial center of mass. Identify edges that are connections for adjacent faces. Attempt to separate unconnected edges into top and bottom loops of the pocket. Trim the top and bottom of the pocket if available and requested. return: tuple with pocket shape information''' low = [] high = [] removeList = [] Faces = [] allEdges = [] makeHighFace = 0 tryNonPlanar = False isHighFacePlanar = True isLowFacePlanar = True faceType = 0 for (sub, face) in subObjTups: Faces.append(face) # identify max and min face heights for top loop (zmin, zmax) = self.getMinMaxOfFaces(Faces) # Order faces around common center of mass subObjTups = self.orderFacesAroundCenterOfMass(subObjTups) # find connected edges and map to edge names of base (connectedEdges, touching) = self.findSharedEdges(subObjTups) (low, high) = self.identifyUnconnectedEdges(subObjTups, touching) if len(high) > 0 and obj.AdaptivePocketStart is True: # attempt planar face with top edges of pocket allEdges = [] makeHighFace = 0 tryNonPlanar = False for (sub, face, ei) in high: allEdges.append(face.Edges[ei]) (hzmin, hzmax) = self.getMinMaxOfFaces(allEdges) try: highFaceShape = Part.Face( Part.Wire(Part.__sortEdges__(allEdges))) except Exception as ee: PathLog.warning(ee) PathLog.error( translate( "Path", "A planar adaptive start is unavailable. The non-planar will be attempted." )) tryNonPlanar = True else: makeHighFace = 1 if tryNonPlanar is True: try: highFaceShape = Part.makeFilledFace( Part.__sortEdges__(allEdges)) # NON-planar face method except Exception as eee: PathLog.warning(eee) PathLog.error( translate( "Path", "The non-planar adaptive start is also unavailable." ) + "(1)") isHighFacePlanar = False else: makeHighFace = 2 if makeHighFace > 0: FreeCAD.ActiveDocument.addObject('Part::Feature', 'topEdgeFace') highFace = FreeCAD.ActiveDocument.ActiveObject highFace.Shape = highFaceShape removeList.append(highFace.Name) # verify non-planar face is within high edge loop Z-boundaries if makeHighFace == 2: mx = hzmax + obj.StepDown.Value mn = hzmin - obj.StepDown.Value if highFace.Shape.BoundBox.ZMax > mx or highFace.Shape.BoundBox.ZMin < mn: PathLog.warning("ZMaxDiff: {}; ZMinDiff: {}".format( highFace.Shape.BoundBox.ZMax - mx, highFace.Shape.BoundBox.ZMin - mn)) PathLog.error( translate( "Path", "The non-planar adaptive start is also unavailable." ) + "(2)") isHighFacePlanar = False makeHighFace = 0 else: isHighFacePlanar = False if len(low) > 0 and obj.AdaptivePocketFinish is True: # attempt planar face with bottom edges of pocket allEdges = [] for (sub, face, ei) in low: allEdges.append(face.Edges[ei]) # (lzmin, lzmax) = self.getMinMaxOfFaces(allEdges) try: lowFaceShape = Part.Face( Part.Wire(Part.__sortEdges__(allEdges))) # lowFaceShape = Part.makeFilledFace(Part.__sortEdges__(allEdges)) # NON-planar face method except Exception as ee: PathLog.error(ee) PathLog.error("An adaptive finish is unavailable.") isLowFacePlanar = False else: FreeCAD.ActiveDocument.addObject('Part::Feature', 'bottomEdgeFace') lowFace = FreeCAD.ActiveDocument.ActiveObject lowFace.Shape = lowFaceShape removeList.append(lowFace.Name) else: isLowFacePlanar = False # Start with a regular pocket envelope strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value cuts = [] starts = [] finals = [] starts.append(obj.StartDepth.Value) finals.append(zmin) if obj.AdaptivePocketStart is True or len(subObjTups) == 1: strDep = zmax + obj.StepDown.Value starts.append(zmax + obj.StepDown.Value) finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0 depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, user_depths=None) shape = Part.makeCompound(Faces) env = PathUtils.getEnvelope(base[0].Shape, subshape=shape, depthparams=depthparams) cuts.append(env.cut(base[0].Shape)) # Might need to change to .cut(job.Stock.Shape) if pocket has no bottom # job = PathUtils.findParentJob(obj) # envBody = env.cut(job.Stock.Shape) if isHighFacePlanar is True and len(subObjTups) > 1: starts.append(hzmax + obj.StepDown.Value) # make shape to trim top of reg pocket strDep1 = obj.StartDepth.Value + (hzmax - hzmin) if makeHighFace == 1: # Planar face finDep1 = highFace.Shape.BoundBox.ZMin + obj.StepDown.Value else: # Non-Planar face finDep1 = hzmin + obj.StepDown.Value depthparams1 = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep1, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep1, user_depths=None) envTop = PathUtils.getEnvelope(base[0].Shape, subshape=highFace.Shape, depthparams=depthparams1) cbi = len(cuts) - 1 cuts.append(cuts[cbi].cut(envTop)) if isLowFacePlanar is True and len(subObjTups) > 1: # make shape to trim top of pocket if makeHighFace == 1: # Planar face strDep2 = lowFace.Shape.BoundBox.ZMax else: # Non-Planar face strDep2 = hzmax finDep2 = obj.FinalDepth.Value depthparams2 = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep2, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep2, user_depths=None) envBottom = PathUtils.getEnvelope(base[0].Shape, subshape=lowFace.Shape, depthparams=depthparams2) cbi = len(cuts) - 1 cuts.append(cuts[cbi].cut(envBottom)) # package pocket details into tuple sdi = len(starts) - 1 fdi = len(finals) - 1 cbi = len(cuts) - 1 pocket = (cuts[cbi], False, '3DPocket', 0.0, 'X', starts[sdi], finals[fdi]) if FreeCAD.GuiUp: import FreeCADGui for rn in removeList: FreeCADGui.ActiveDocument.getObject(rn).Visibility = False for rn in removeList: FreeCAD.ActiveDocument.getObject(rn).purgeTouched() self.tempObjectNames.append(rn) return pocket
def GenerateGCode(op,obj,adaptiveResults, helixDiameter): # pylint: disable=unused-argument if len(adaptiveResults) == 0 or len(adaptiveResults[0]["AdaptivePaths"]) == 0: return # minLiftDistance = op.tool.Diameter helixRadius = 0 for region in adaptiveResults: p1 = region["HelixCenterPoint"] p2 = region["StartPoint"] r =math.sqrt((p1[0]-p2[0]) * (p1[0]-p2[0]) + (p1[1]-p2[1]) * (p1[1]-p2[1])) if r > helixRadius: helixRadius = r stepDown = obj.StepDown.Value passStartDepth=obj.StartDepth.Value if stepDown < 0.1 : stepDown = 0.1 length = 2*math.pi * helixRadius if float(obj.HelixAngle) < 1: obj.HelixAngle = 1 helixAngleRad = math.pi * float(obj.HelixAngle) / 180.0 depthPerOneCircle = length * math.tan(helixAngleRad) #print("Helix circle depth: {}".format(depthPerOneCircle)) stepUp = obj.LiftDistance.Value if stepUp < 0: stepUp = 0 finish_step = obj.FinishDepth.Value if hasattr(obj, "FinishDepth") else 0.0 if finish_step > stepDown: finish_step = stepDown depth_params = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=stepDown, z_finish_step=finish_step, final_depth=obj.FinalDepth.Value, user_depths=None) # ml: this is dangerous because it'll hide all unused variables hence forward # however, I don't know what lx and ly signify so I'll leave them for now # pylint: disable=unused-variable lx = adaptiveResults[0]["HelixCenterPoint"][0] ly = adaptiveResults[0]["HelixCenterPoint"][1] lz = passStartDepth step = 0 for passEndDepth in depth_params.data: step = step + 1 for region in adaptiveResults: startAngle = math.atan2(region["StartPoint"][1] - region["HelixCenterPoint"][1], region["StartPoint"][0] - region["HelixCenterPoint"][0]) lx = region["HelixCenterPoint"][0] ly = region["HelixCenterPoint"][1] passDepth = (passStartDepth - passEndDepth) p1 = region["HelixCenterPoint"] p2 = region["StartPoint"] helixRadius = math.sqrt((p1[0]-p2[0]) * (p1[0]-p2[0]) + (p1[1]-p2[1]) * (p1[1]-p2[1])) # helix ramp if helixRadius > 0.001: r = helixRadius - 0.01 maxfi = passDepth / depthPerOneCircle * 2 * math.pi fi = 0 offsetFi = -maxfi + startAngle-math.pi/16 helixStart = [region["HelixCenterPoint"][0] + r * math.cos(offsetFi), region["HelixCenterPoint"][1] + r * math.sin(offsetFi)] op.commandlist.append(Path.Command("(Helix to depth: %f)"%passEndDepth)) if obj.UseHelixArcs == False: # rapid move to start point op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value})) # rapid move to safe height op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value})) # move to start depth op.commandlist.append(Path.Command("G1", {"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed})) while fi < maxfi: x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi) y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi) z = passStartDepth - fi / maxfi * (passStartDepth - passEndDepth) op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":z, "F": op.vertFeed})) lx = x ly = y fi=fi+math.pi/16 # one more circle at target depth to make sure center is cleared maxfi = maxfi + 2*math.pi while fi < maxfi: x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi) y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi) z = passEndDepth op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":z, "F": op.horizFeed})) lx = x ly = y fi = fi + math.pi/16 else: helixStart = [region["HelixCenterPoint"][0] + r, region["HelixCenterPoint"][1]] # rapid move to start point op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value})) # rapid move to safe height op.commandlist.append(Path.Command("G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value})) # move to start depth op.commandlist.append(Path.Command("G1", {"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed})) x = region["HelixCenterPoint"][0] + r y = region["HelixCenterPoint"][1] curDep = passStartDepth while curDep > (passEndDepth + depthPerOneCircle): op.commandlist.append(Path.Command("G2", { "X": x - (2*r), "Y": y, "Z": curDep - (depthPerOneCircle/2), "I": -r, "F": op.horizFeed})) op.commandlist.append(Path.Command("G2", { "X": x, "Y": y, "Z": curDep - depthPerOneCircle, "I": r, "F": op.horizFeed})) curDep = curDep - depthPerOneCircle lastStep = curDep - passEndDepth if lastStep > (depthPerOneCircle/2): op.commandlist.append(Path.Command("G2", { "X": x - (2*r), "Y": y, "Z": curDep - (lastStep/2), "I": -r, "F": op.horizFeed})) op.commandlist.append(Path.Command("G2", { "X": x, "Y": y, "Z": passEndDepth, "I": r, "F": op.horizFeed})) else: op.commandlist.append(Path.Command("G2", { "X": x - (2*r), "Y": y, "Z": passEndDepth, "I": -r, "F": op.horizFeed})) op.commandlist.append(Path.Command("G1", {"X": x, "Y": y, "Z": passEndDepth, "F": op.vertFeed})) # one more circle at target depth to make sure center is cleared op.commandlist.append(Path.Command("G2", { "X": x - (2*r), "Y": y, "Z": passEndDepth, "I": -r, "F": op.horizFeed})) op.commandlist.append(Path.Command("G2", { "X": x, "Y": y, "Z": passEndDepth, "I": r, "F": op.horizFeed})) lx = x ly = y else: # no helix entry # rapid move to clearance height op.commandlist.append(Path.Command("G0", {"X": region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": obj.ClearanceHeight.Value})) # straight plunge to target depth op.commandlist.append(Path.Command("G1", {"X":region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": passEndDepth,"F": op.vertFeed})) lz = passEndDepth z = obj.ClearanceHeight.Value op.commandlist.append(Path.Command("(Adaptive - depth: %f)"%passEndDepth)) # add adaptive paths for pth in region["AdaptivePaths"]: motionType = pth[0] #[0] contains motion type for pt in pth[1]: #[1] contains list of points x = pt[0] y = pt[1] # dist = math.sqrt((x-lx)*(x-lx) + (y-ly)*(y-ly)) if motionType == area.AdaptiveMotionType.Cutting: z = passEndDepth if z != lz: op.commandlist.append(Path.Command("G1", { "Z":z,"F": op.vertFeed})) op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "F": op.horizFeed})) elif motionType == area.AdaptiveMotionType.LinkClear: z = passEndDepth + stepUp if z != lz: op.commandlist.append(Path.Command("G0", { "Z":z})) op.commandlist.append(Path.Command("G0", { "X": x, "Y":y})) elif motionType == area.AdaptiveMotionType.LinkNotClear: z = obj.ClearanceHeight.Value if z != lz: op.commandlist.append(Path.Command("G0", { "Z":z})) op.commandlist.append(Path.Command("G0", { "X": x, "Y":y})) # elif motionType == area.AdaptiveMotionType.LinkClearAtPrevPass: # if lx!=x or ly!=y: # op.commandlist.append(Path.Command("G0", { "X": lx, "Y":ly, "Z":passStartDepth+stepUp})) # op.commandlist.append(Path.Command("G0", { "X": x, "Y":y, "Z":passStartDepth+stepUp})) lx = x ly = y lz = z # return to safe height in this Z pass z = obj.ClearanceHeight.Value if z != lz: op.commandlist.append(Path.Command("G0", { "Z":z})) lz = z passStartDepth = passEndDepth # return to safe height in this Z pass z = obj.ClearanceHeight.Value if z != lz: op.commandlist.append(Path.Command("G0", { "Z":z})) lz = z z = obj.ClearanceHeight.Value if z != lz: op.commandlist.append(Path.Command("G0", { "Z":z})) lz = z
def _waterline(self, obj, s, bb): import time import ocl def drawLoops(loops): nloop = 0 pp = [] pp.append(Path.Command("(waterline begin)" )) for loop in loops: p = loop[0] pp.append(Path.Command("(loop begin)" )) pp.append(Path.Command('G0', {"Z": obj.SafeHeight.Value, 'F': self.vertRapid})) pp.append(Path.Command('G0', {'X': p.x, "Y": p.y, 'F': self.horizRapid})) pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed})) for p in loop[1:]: pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) # zheight = p.z p = loop[0] pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) pp.append(Path.Command("(loop end)" )) print(" loop ", nloop, " with ", len(loop), " points") nloop = nloop + 1 pp.append(Path.Command("(waterline end)" )) return pp depthparams = PathUtils.depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) t_before = time.time() zheights = [i for i in depthparams] wl = ocl.Waterline() wl.setSTL(s) cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] print ("zheights: {}".format(zheights)) for zh in zheights: print("calculating Waterline at z= ", zh) wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = [] for loops in all_loops: # at each z-height, we may get many loops print(" %d/%d:" % (n, len(all_loops))) output.extend(drawLoops(loops)) n = n + 1 print("(" + str(calctime) + ")") return output
def _waterline(self, obj, s, bb): import time import ocl def drawLoops(loops): nloop = 0 pp = [] pp.append(Path.Command("(waterline begin)")) for loop in loops: p = loop[0] pp.append(Path.Command("(loop begin)")) pp.append(Path.Command('G0', {"Z": obj.SafeHeight.Value, 'F': self.vertRapid})) pp.append(Path.Command('G0', {'X': p.x, "Y": p.y, 'F': self.horizRapid})) pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed})) prev = ocl.Point(float("inf"), float("inf"), float("inf")) next = ocl.Point(float("inf"), float("inf"), float("inf")) optimize = obj.Optimize for i in range(1, len(loop)): p = loop[i] if i < len(loop) - 1: next.x = loop[i + 1].x next.y = loop[i + 1].y next.z = loop[i + 1].z else: optimize = False if not optimize or not self.isPointOnLine(FreeCAD.Vector(prev.x, prev.y, prev.z), FreeCAD.Vector(next.x, next.y, next.z), FreeCAD.Vector(p.x, p.y, p.z)): pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) prev.x = p.x prev.y = p.y prev.z = p.z # zheight = p.z p = loop[0] pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) pp.append(Path.Command("(loop end)")) print(" loop ", nloop, " with ", len(loop), " points") nloop = nloop + 1 pp.append(Path.Command("(waterline end)")) return pp depthparams = PathUtils.depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value) t_before = time.time() zheights = [i for i in depthparams] wl = ocl.Waterline() wl.setSTL(s) if obj.ToolController.Tool.ToolType == 'BallEndMill': cutter = ocl.BallCutter(obj.ToolController.Tool.Diameter, 5) # TODO: 5 represents cutting edge height. Should be replaced with the data from toolcontroller? else: cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] print ("zheights: {}".format(zheights)) for zh in zheights: print("calculating Waterline at z= ", zh) wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = [] for loops in all_loops: # at each z-height, we may get many loops print(" %d/%d:" % (n, len(all_loops))) output.extend(drawLoops(loops)) n = n + 1 print("(" + str(calctime) + ")") return output
def _waterline(self, obj, s, bb): import time import ocl def drawLoops(loops): nloop = 0 pp = [] pp.append(Path.Command("(waterline begin)" )) for loop in loops: p = loop[0] pp.append(Path.Command("(loop begin)" )) pp.append(Path.Command('G0', {"Z": obj.SafeHeight.Value, 'F': self.vertRapid})) pp.append(Path.Command('G0', {'X': p.x, "Y": p.y, 'F': self.horizRapid})) pp.append(Path.Command('G1', {"Z": p.z, 'F': self.vertFeed})) for p in loop[1:]: pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) # zheight = p.z p = loop[0] pp.append(Path.Command('G1', {'X': p.x, "Y": p.y, "Z": p.z, 'F': self.horizFeed})) pp.append(Path.Command("(loop end)" )) print(" loop ", nloop, " with ", len(loop), " points") nloop = nloop + 1 pp.append(Path.Command("(waterline end)" )) return pp depthparams = PathUtils.depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) t_before = time.time() zheights = [i for i in depthparams] wl = ocl.Waterline() wl.setSTL(s) cutter = ocl.CylCutter(obj.ToolController.Tool.Diameter, 5) wl.setCutter(cutter) # this should be smaller than the smallest details in the STL file wl.setSampling(obj.SampleInterval) # AdaptiveWaterline() also has settings for minimum sampling interval # (see c++ code) all_loops = [] print ("zheights: {}".format(zheights)) for zh in zheights: print("calculating Waterline at z= ", zh) wl.reset() wl.setZ(zh) # height for this waterline wl.run() all_loops.append(wl.getLoops()) t_after = time.time() calctime = t_after - t_before n = 0 output = [] for loops in all_loops: # at each z-height, we may get many loops print(" %d/%d:" % (n, len(all_loops))) output.extend(drawLoops(loops)) n = n + 1 print("(" + str(calctime) + ")") return output
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... returns envelope for all base shapes or wires for Arch.Panels.''' PathLog.track() PathLog.debug("----- areaOpShapes() in PathProfileFaces.py") if obj.UseComp: self.commandlist.append( Path.Command("(Compensated Tool Path. Diameter: " + str(self.radius * 2) + ")")) else: self.commandlist.append(Path.Command("(Uncompensated Tool Path)")) shapes = [] self.profileshape = [] finalDepths = [] baseSubsTuples = [] subCount = 0 allTuples = [] if obj.Base: # The user has selected subobjects from the base. Process each. if obj.EnableRotation != 'Off': for p in range(0, len(obj.Base)): (base, subsList) = obj.Base[p] for sub in subsList: subCount += 1 shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): rtn = False (norm, surf) = self.getFaceNormAndSurf(shape) (rtn, angle, axis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: (clnBase, angle, clnStock, tag) = self.applyRotationalAnalysis( obj, base, angle, axis, subCount) # Verify faces are correctly oriented - InverseAngle might be necessary faceIA = getattr(clnBase.Shape, sub) (norm, surf) = self.getFaceNormAndSurf(faceIA) (rtn, praAngle, praAxis, praInfo) = self.faceRotationAnalysis( obj, norm, surf) if rtn is True: PathLog.error( translate( "Path", "Face appears misaligned after initial rotation." )) if obj.AttemptInverseAngle is True and obj.InverseAngle is False: (clnBase, clnStock, angle) = self.applyInverseAngle( obj, clnBase, clnStock, axis, angle) else: msg = translate( "Path", "Consider toggling the 'InverseAngle' property and recomputing." ) PathLog.error(msg) # title = translate("Path", 'Rotation Warning') # self.guiMessage(title, msg, False) else: PathLog.debug( "Face appears to be oriented correctly." ) tup = clnBase, sub, tag, angle, axis, clnStock else: if self.warnDisabledAxis(obj, axis) is False: PathLog.debug( str(sub) + ": No rotation used") axis = 'X' angle = 0.0 tag = base.Name + '_' + axis + str( angle).replace('.', '_') stock = PathUtils.findParentJob(obj).Stock tup = base, sub, tag, angle, axis, stock # Eif allTuples.append(tup) # Eif # Efor # Efor if subCount > 1: msg = translate('Path', "Multiple faces in Base Geometry.") + " " msg += translate( 'Path', "Depth settings will be applied to all faces.") PathLog.warning(msg) # title = translate("Path", "Depth Warning") # self.guiMessage(title, msg) (Tags, Grps) = self.sortTuplesByIndex( allTuples, 2) # return (TagList, GroupList) subList = [] for o in range(0, len(Tags)): subList = [] for (base, sub, tag, angle, axis, stock) in Grps[o]: subList.append(sub) pair = base, subList, angle, axis, stock baseSubsTuples.append(pair) # Efor else: PathLog.info( translate("Path", "EnableRotation property is 'Off'.")) stock = PathUtils.findParentJob(obj).Stock for (base, subList) in obj.Base: baseSubsTuples.append((base, subList, 0.0, 'X', stock)) # for base in obj.Base: for (base, subsList, angle, axis, stock) in baseSubsTuples: holes = [] faces = [] for sub in subsList: shape = getattr(base.Shape, sub) if isinstance(shape, Part.Face): faces.append(shape) if numpy.isclose(abs(shape.normalAt(0, 0).z), 1): # horizontal face for wire in shape.Wires[1:]: holes.append((base.Shape, wire)) else: ignoreSub = base.Name + '.' + sub msg = translate( 'Path', "Found a selected object which is not a face. Ignoring: {}" .format(ignoreSub)) PathLog.error(msg) FreeCAD.Console.PrintWarning(msg) # return for shape, wire in holes: f = Part.makeFace(wire, 'Part::FaceMakerSimple') drillable = PathUtils.isDrillable(shape, wire) if (drillable and obj.processCircles) or (not drillable and obj.processHoles): PathLog.track() # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) if len(faces) > 0: profileshape = Part.makeCompound(faces) self.profileshape.append(profileshape) if obj.processPerimeter: PathLog.track() if profileshape: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, profileshape, stock) finalDepths.append(finDep) PathLog.debug( "Adjusted face depths strDep: {}, and finDep: {}". format(self.strDep, self.finDep)) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) else: strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value try: env = PathUtils.getEnvelope( base.Shape, subshape=profileshape, depthparams=self.depthparams) except Exception: # PathUtils.getEnvelope() failed to return an object. PathLog.error( translate('Path', 'Unable to create path for face(s).')) else: # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) else: for shape in faces: # Recalculate depthparams (strDep, finDep) = self.calculateStartFinalDepths( obj, shape, stock) finalDepths.append(finDep) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=strDep, # obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=finDep, # obj.FinalDepth.Value, user_depths=None) env = PathUtils.getEnvelope( base.Shape, subshape=shape, depthparams=self.depthparams) tup = env, False, 'pathProfileFaces', angle, axis, strDep, finDep shapes.append(tup) # Eif # adjust FinalDepth as needed finalDepth = min(finalDepths) if obj.FinalDepth.Value < finalDepth: obj.FinalDepth.Value = finalDepth else: # Try to build targets from the job base if 1 == len(self.model) and hasattr(self.model[0], "Proxy"): if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet if obj.processCircles or obj.processHoles: for shape in self.model[0].Proxy.getHoles( self.model[0], transform=True): for wire in shape.Wires: drillable = PathUtils.isDrillable( self.model[0].Proxy, wire) if (drillable and obj.processCircles) or ( not drillable and obj.processHoles): f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, True)) tup = env, True, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) if obj.processPerimeter: for shape in self.model[0].Proxy.getOutlines( self.model[0], transform=True): for wire in shape.Wires: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( self.model[0].Shape, subshape=f, depthparams=self.depthparams) # shapes.append((env, False)) tup = env, False, 'pathProfileFaces', 0.0, 'X', obj.StartDepth.Value, obj.FinalDepth.Value shapes.append(tup) self.removalshapes = shapes PathLog.debug("%d shapes" % len(shapes)) return shapes
def areaOpShapes(self, obj): '''areaOpShapes(obj) ... return shapes representing the solids to be removed.''' PathLog.track() subObjTups = [] removalshapes = [] if obj.Base: PathLog.debug("base items exist. Processing... ") for base in obj.Base: PathLog.debug("obj.Base item: {}".format(base)) # Check if all subs are faces allSubsFaceType = True Faces = [] for sub in base[1]: if "Face" in sub: face = getattr(base[0].Shape, sub) Faces.append(face) subObjTups.append((sub, face)) else: allSubsFaceType = False break if len(Faces) == 0: allSubsFaceType = False if allSubsFaceType is True and obj.HandleMultipleFeatures == 'Collectively': if obj.OpFinalDepth == obj.FinalDepth: (fzmin, fzmax) = self.getMinMaxOfFaces(Faces) obj.FinalDepth.Value = fzmin finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=fzmin, user_depths=None) PathLog.info( "Updated obj.FinalDepth.Value and self.depthparams to zmin: {}" .format(fzmin)) if obj.AdaptivePocketStart is True or obj.AdaptivePocketFinish is True: pocketTup = self.calculateAdaptivePocket( obj, base, subObjTups) if pocketTup is not False: removalshapes.append( pocketTup ) # (shape, isHole, sub, angle, axis, strDep, finDep) else: strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value shape = Part.makeCompound(Faces) env = PathUtils.getEnvelope( base[0].Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(base[0].Shape) obj.removalshape.tessellate(0.1) # (shape, isHole, sub, angle, axis, strDep, finDep) removalshapes.append( (obj.removalshape, False, '3DPocket', 0.0, 'X', strDep, finDep)) else: for sub in base[1]: if "Face" in sub: shape = Part.makeCompound( [getattr(base[0].Shape, sub)]) else: edges = [ getattr(base[0].Shape, sub) for sub in base[1] ] shape = Part.makeFace(edges, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope( base[0].Shape, subshape=shape, depthparams=self.depthparams) obj.removalshape = env.cut(base[0].Shape) obj.removalshape.tessellate(0.1) removalshapes.append((obj.removalshape, False)) else: # process the job base object as a whole PathLog.debug("processing the whole job base object") strDep = obj.StartDepth.Value finDep = obj.FinalDepth.Value recomputeDepthparams = False for base in self.model: if obj.OpFinalDepth == obj.FinalDepth: if base.Shape.BoundBox.ZMin < obj.FinalDepth.Value: obj.FinalDepth.Value = base.Shape.BoundBox.ZMin finDep = base.Shape.BoundBox.ZMin recomputeDepthparams = True PathLog.info( "Updated obj.FinalDepth.Value to {}".format( finDep)) if obj.OpStartDepth == obj.StartDepth: if base.Shape.BoundBox.ZMax > obj.StartDepth.Value: obj.StartDepth.Value = base.Shape.BoundBox.ZMax finDep = base.Shape.BoundBox.ZMax recomputeDepthparams = True PathLog.info( "Updated obj.StartDepth.Value to {}".format( strDep)) if recomputeDepthparams is True: finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 self.depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=obj.FinalDepth.Value, user_depths=None) recomputeDepthparams = False if obj.ProcessStockArea is True: job = PathUtils.findParentJob(obj) finish_step = obj.FinishDepth.Value if hasattr( obj, "FinishDepth") else 0.0 depthparams = PathUtils.depth_params( clearance_height=obj.ClearanceHeight.Value, safe_height=obj.SafeHeight.Value, start_depth=obj.StartDepth.Value, step_down=obj.StepDown.Value, z_finish_step=finish_step, final_depth=base.Shape.BoundBox.ZMin, user_depths=None) stockEnvShape = PathUtils.getEnvelope( job.Stock.Shape, subshape=None, depthparams=depthparams) obj.removalshape = stockEnvShape.cut(base.Shape) obj.removalshape.tessellate(0.1) else: env = PathUtils.getEnvelope(base.Shape, subshape=None, depthparams=self.depthparams) obj.removalshape = env.cut(base.Shape) obj.removalshape.tessellate(0.1) removalshapes.append((obj.removalshape, False, '3DPocket', 0.0, 'X', strDep, finDep)) return removalshapes