diff --git a/src/Mod/Path/PathScripts/PathContour.py b/src/Mod/Path/PathScripts/PathContour.py index 9f457441df..62bf2334a9 100644 --- a/src/Mod/Path/PathScripts/PathContour.py +++ b/src/Mod/Path/PathScripts/PathContour.py @@ -178,21 +178,11 @@ class ObjectContour: simobj = None if getsim: - #from PathScripts.PathUtils import CollisionTester - parentJob = PathUtils.findParentJob(obj) - if parentJob is None: - pass - base = parentJob.Base - if base is None: - pass - profileparams['Thicken'] = True #{'Fill':0, 'Coplanar':0, 'Project':True, 'SectionMode':2, 'Thicken':True} profileparams['ToolRadius']= self.radius - self.radius *.005 profile.setParams(**profileparams) - sec = profile.makeSections(heights=[0.0])[0].getShape() + sec = profile.makeSections(mode=0, project=False, heights=depthparams.get_depths())[-1].getShape() simobj = sec.extrude(FreeCAD.Vector(0,0,baseobject.BoundBox.ZMax)) - #c = CollisionTester() - #simobj = c.getCollisionSim(base.Shape, cutPath) return pp, simobj diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index 37253e71f0..c1db84b3cb 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -168,15 +168,18 @@ class ObjectPocket: return None @waiting_effects - def _buildPathArea(self, obj, envelopeshape): + def _buildPathArea(self, obj, envelopeshape, getsim=False): PathLog.track() pocket = Path.Area() pocket.setPlane(Part.makeCircle(10)) pocket.add(envelopeshape) + removalshape = FreeCAD.ActiveDocument.addObject("Part::Feature", "Envelope") + removalshape.Shape = envelopeshape + stepover = (self.radius * 2) * (float(obj.StepOver)/100) - pocketparams = {'Fill': 2, + pocketparams = {'Fill': 0, 'Coplanar': 0, 'PocketMode': 1, 'SectionCount': -1, @@ -214,11 +217,23 @@ class ObjectPocket: pp = Path.fromShapes(**params) PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) - return pp - def execute(self, obj): + simobj = None + if getsim: + pocketparams['Thicken'] = True + pocketparams['ToolRadius']= self.radius - self.radius *.005 + pocket.setParams(**pocketparams) + #pocket.makeSections(mode=0, project=False, heights=depthparams.get_depths()) + simobj = pocket.getShape().extrude(FreeCAD.Vector(0,0,obj.StepDown.Value)) + removalshape = FreeCAD.ActiveDocument.addObject("Part::Feature", "simshape") + removalshape.Shape = simobj + + return pp, simobj + + def execute(self, obj, getsim=False): PathLog.track() commandlist = [] + simlist = [] commandlist.append(Path.Command("(" + obj.Label + ")")) if not obj.Active: path = Path.Path("(inactive operation)") @@ -266,7 +281,10 @@ class ObjectPocket: removalshape.Shape = env.cut(baseobject.Shape) try: - commandlist.extend(self._buildPathArea(obj, env.cut(baseobject.Shape)).Commands) + (pp, sim) = self._buildPathArea(obj, env.cut(baseobject.Shape), getsim=getsim) + if sim is not None: + simlist.append(sim) + commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a pocket path. Check project and tool config.") @@ -275,7 +293,12 @@ class ObjectPocket: env = PathUtils.getEnvelope(baseobject.Shape, subshape=None, stockheight=obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, env.cut(baseobject.Shape)).Commands) + (pp, sim) = self._buildPathArea(obj, env.cut(baseobject.Shape), getsim=getsim) + commandlist.extend(pp.Commands) + if sim is not None: + simlist.append(sim) + + #commandlist.extend(self._buildPathArea(obj, env.cut(baseobject.Shape)).Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a pocket path. Check project and tool config.") @@ -286,6 +309,12 @@ class ObjectPocket: path = Path.Path(commandlist) obj.Path = path obj.ViewObject.Visibility = True + if len(simlist) == 0: + return None + if len(simlist) > 1: + return simlist[0].fuse(simlist[1:]) + else: + return simlist[0] class _CommandSetPocketStartPoint: diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py index 2fb46b306a..888ec8c6e1 100644 --- a/src/Mod/Path/PathScripts/PathProfile.py +++ b/src/Mod/Path/PathScripts/PathProfile.py @@ -146,7 +146,7 @@ class ObjectProfile: obj.Base = baselist self.execute(obj) - def _buildPathArea(self, obj, baseobject, isHole=False, start=None): + def _buildPathArea(self, obj, baseobject, isHole=False, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(Part.makeCircle(10)) @@ -213,9 +213,17 @@ class ObjectProfile: PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) - return pp + simobj = None + if getsim: + profileparams['Thicken'] = True #{'Fill':0, 'Coplanar':0, 'Project':True, 'SectionMode':2, 'Thicken':True} + profileparams['ToolRadius']= self.radius - self.radius *.005 + profile.setParams(**profileparams) + sec = profile.makeSections(mode=0, project=False, heights=depthparams.get_depths())[-1].getShape() + simobj = sec.extrude(FreeCAD.Vector(0,0,baseobject.BoundBox.ZMax)) - def execute(self, obj): + return pp, simobj + + def execute(self, obj, getsim=False): import Part if not obj.Active: @@ -275,7 +283,8 @@ class ObjectProfile: if (drillable and obj.processCircles) or (not drillable and obj.processHoles): env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, stockheight=obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=True, start=None).Commands) + (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) + commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") @@ -286,7 +295,8 @@ class ObjectProfile: if obj.processPerimeter: env = PathUtils.getEnvelope(baseobject.Shape, subshape=profileshape, stockheight=obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, baseobject=env, start=None).Commands) + (pp, sim) = self._buildPathArea(obj, baseobject=env, start=None, getsim=getsim) + commandlist.extend(pp.commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") @@ -301,7 +311,8 @@ class ObjectProfile: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, stockheight=obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=False, start=None).Commands) + (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=False, start=None, getsim=getsim) + commandlist.extend(pp.commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") @@ -314,7 +325,8 @@ class ObjectProfile: f = Part.makeFace(wire, 'Part::FaceMakerSimple') env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, stockheight=obj.StartDepth) try: - commandlist.extend(self._buildPathArea(obj, baseobject=env, isHole=True, start=None).Commands) + (pp, sim) = self._buildPathArea(obj, baseobject=env, isHole=True, start=None, getsim=getsim) + commandlist.extend(pp.commands) except Exception as e: FreeCAD.Console.PrintError(e) FreeCAD.Console.PrintError("Something unexpected happened. Unable to generate a contour path. Check project and tool config.") diff --git a/src/Mod/Path/PathScripts/PathProfileEdges.py b/src/Mod/Path/PathScripts/PathProfileEdges.py index 64d8a0e787..70efb1782d 100644 --- a/src/Mod/Path/PathScripts/PathProfileEdges.py +++ b/src/Mod/Path/PathScripts/PathProfileEdges.py @@ -35,7 +35,7 @@ from PathScripts.PathUtils import waiting_effects """Path Profile from Edges Object and Command""" LOG_MODULE = 'PathProfileEdges' -PathLog.setLevel(PathLog.Level.DEBUG, LOG_MODULE) +PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE) # PathLog.trackModule('PathProfileEdges') if FreeCAD.GuiUp: @@ -142,7 +142,7 @@ class ObjectProfile: @waiting_effects - def _buildPathArea(self, obj, baseobject, start=None): + def _buildPathArea(self, obj, baseobject, start=None, getsim=False): PathLog.track() profile = Path.Area() profile.setPlane(Part.makeCircle(10)) @@ -185,12 +185,6 @@ class ObjectProfile: 'resume_height': obj.StepDown.Value, 'retraction': obj.ClearanceHeight.Value} - # Reverse the direction for holes - # if isHole: - # direction = "CW" if obj.Direction == "CCW" else "CCW" - # else: - # direction = obj.Direction - if obj.Direction == 'CCW': params['orientation'] = 0 else: @@ -203,26 +197,18 @@ class ObjectProfile: PathLog.debug("Generating Path with params: {}".format(params)) PathLog.debug(pp) - # if True: - # from PathScripts.PathUtils import CollisionTester - # parentJob = PathUtils.findParentJob(obj) - # if parentJob is None: - # pass - # base = parentJob.Base - # if base is None: - # pass + simobj = None + if getsim: + profileparams['Thicken'] = True #{'Fill':0, 'Coplanar':0, 'Project':True, 'SectionMode':2, 'Thicken':True} + profileparams['ToolRadius']= self.radius - self.radius *.005 + profile.setParams(**profileparams) + sec = profile.makeSections(mode=0, project=False, heights=depthparams.get_depths())[-1].getShape() + simobj = sec.extrude(FreeCAD.Vector(0,0,baseobject.BoundBox.ZMax)) - # profileparams['Thicken'] = True #{'Fill':0, 'Coplanar':0, 'Project':True, 'SectionMode':2, 'Thicken':True} - # profileparams['ToolRadius']= self.radius - self.radius *.005 - # profile.setParams(**profileparams) - # sec = profile.makeSections(heights=[0.0])[0].getShape() - # cutPath = sec.extrude(FreeCAD.Vector(0,0,baseobject.BoundBox.ZMax)) - # c = CollisionTester() - # c.getCollisionSim(base.Shape, cutPath) - # return pp + return pp, simobj - def execute(self, obj): + def execute(self, obj, getsim=False): # import Part # math #DraftGeomUtils commandlist = [] @@ -281,8 +267,8 @@ class ObjectProfile: env = PathUtils.getEnvelope(baseobject.Shape, subshape=f, stockheight=obj.StartDepth) try: - # commandlist.extend(self._buildPathArea(obj, wire).Commands) - commandlist.extend(self._buildPathArea(obj, baseobject=env, start=None).Commands) + (pp, sim) = self._buildPathArea(obj, baseobject=env, start=obj.StartPoint, getsim=getsim) + commandlist.extend(pp.Commands) except Exception as e: FreeCAD.Console.PrintError(e) @@ -294,6 +280,7 @@ class ObjectProfile: path = Path.Path(commandlist) obj.Path = path obj.ViewObject.Visibility = True + return sim class _ViewProviderProfile: diff --git a/src/Mod/Path/PathScripts/PathSanity.py b/src/Mod/Path/PathScripts/PathSanity.py index 6da87c69ff..64728c0466 100644 --- a/src/Mod/Path/PathScripts/PathSanity.py +++ b/src/Mod/Path/PathScripts/PathSanity.py @@ -26,10 +26,10 @@ Path projects. Ideally, the user could execute these utilities from an icon to make sure tools are selected and configured and defaults have been revised''' from __future__ import print_function -from PySide import QtCore, QtGui +from PySide import QtCore import FreeCAD import FreeCADGui -import PathScripts.PathUtils as PU +#import PathScripts.PathUtils as PU import PathScripts import PathScripts.PathCollision as PC # Qt tanslation handling @@ -81,18 +81,32 @@ class CommandPathSanity: PC.getCollisionObject(self.baseobj, simobj) #r.original = self.baseobj - if isinstance(item.Proxy, PathScripts.PathProfile.ObjectProfile): if item.Active: operationcount +=1 + simobj = item.Proxy.execute(item, getsim=True) + if simobj is not None: + print ('collision detected') + PC.getCollisionObject(self.baseobj, simobj) + #r.original = self.baseobj if isinstance(item.Proxy, PathScripts.PathProfileEdges.ObjectProfile): if item.Active: operationcount +=1 + simobj = item.Proxy.execute(item, getsim=True) + if simobj is not None: + print ('collision detected') + PC.getCollisionObject(self.baseobj, simobj) + #r.original = self.baseobj if isinstance(item.Proxy, PathScripts.PathPocket.ObjectPocket): if item.Active: operationcount +=1 + simobj = item.Proxy.execute(item, getsim=True) + if simobj is not None: + print ('collision detected') + PC.getCollisionObject(self.baseobj, simobj) + #r.original = self.baseobj if isinstance(item.Proxy, PathScripts.PathDrilling.ObjectDrilling): if item.Active: diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index 0626af8c61..a67c523337 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -685,44 +685,87 @@ class depth_params: user_depths: List of specified depths ''' - def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths=None): + def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths=None, equalstep=False): '''self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, [user_depths=None]''' if z_finish_step > step_down: raise ValueError('z_finish_step must be less than step_down') - self.clearance_height = clearance_height - self.rapid_safety_space = math.fabs(rapid_safety_space) - self.start_depth = start_depth - self.step_down = math.fabs(step_down) - self.z_finish_step = math.fabs(z_finish_step) - self.final_depth = final_depth - self.user_depths = user_depths + self.__clearance_height = clearance_height + self.__rapid_safety_space = math.fabs(rapid_safety_space) + self.__start_depth = start_depth + self.__step_down = math.fabs(step_down) + self.__z_finish_step = math.fabs(z_finish_step) + self.__final_depth = final_depth + self.__user_depths = user_depths + self.data = self.__get_depths(equalstep=equalstep) + self.index = 0 - def get_depths(self, equalstep=False): + def __iter__(self): + return self + + def next(self): + if self.index == len(self.data): + raise StopIteration + self.index = self.index + 1 + return self.data[self.index - 1] + + @property + def clearance_height(self): + """ + Height of all vises, clamps, and other obstructions. Rapid moves at clearance height + are always assumed to be safe from collision. + """ + return self.__clearance_height + + @property + def rapid_safety_space(self): + return self.__rapid_safety_space + + @property + def start_depth(self): + return self.__start_depth + + @property + def step_down(self): + return self.__step_down + + @property + def z_finish_depth(self): + return self.__z_finish_depth + + @property + def final_depth(self): + return self.__final_depth + + @property + def user_depths(self): + return self.__user_depths + + def __get_depths(self, equalstep=False): '''returns a list of depths to be used in order from first to last. equalstep=True: all steps down before the finish pass will be equalized.''' if self.user_depths is not None: - return self.user_depths + return self.__user_depths - total_depth = self.start_depth - self.final_depth + total_depth = self.__start_depth - self.__final_depth if total_depth < 0: return [] - depths = [self.final_depth] + depths = [self.__final_depth] # apply finish step if necessary - if self.z_finish_step > 0: - if self.z_finish_step < total_depth: - depths.append(self.z_finish_step + self.final_depth) + if self.__z_finish_step > 0: + if self.__z_finish_step < total_depth: + depths.append(self.__z_finish_step + self.__final_depth) else: return depths if equalstep: - depths += self.__equal_steps(self.start_depth, depths[-1], self.step_down)[1:] + depths += self.__equal_steps(self.__start_depth, depths[-1], self.__step_down)[1:] else: - depths += self.__fixed_steps(self.start_depth, depths[-1], self.step_down)[1:] + depths += self.__fixed_steps(self.__start_depth, depths[-1], self.__step_down)[1:] depths.reverse() return depths diff --git a/src/Mod/Path/PathTests/TestPathDepthParams.py b/src/Mod/Path/PathTests/TestPathDepthParams.py index 57e51a5d02..c8f4ed3e88 100644 --- a/src/Mod/Path/PathTests/TestPathDepthParams.py +++ b/src/Mod/Path/PathTests/TestPathDepthParams.py @@ -41,7 +41,7 @@ class depthTestCases(unittest.TestCase): 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() + r = [i for i in d] self.assertListEqual (r, expected) def test10(self): @@ -59,7 +59,7 @@ class depthTestCases(unittest.TestCase): expected =[-2, -4, -6, -8, -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() + r = [i for i in d] self.assertListEqual (r, expected) def test20(self): @@ -76,7 +76,7 @@ class depthTestCases(unittest.TestCase): 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() + r = [i for i in d] self.assertListEqual (r, expected) start_depth = 10 @@ -85,12 +85,9 @@ class depthTestCases(unittest.TestCase): 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() + r = [i for i in d] self.assertListEqual (r, expected) - - - def test30(self): '''User Parameters passed in''' clearance_height= 10 @@ -105,7 +102,7 @@ class depthTestCases(unittest.TestCase): 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() + r = [i for i in d] self.assertListEqual (r, expected) def test40(self): @@ -122,7 +119,7 @@ class depthTestCases(unittest.TestCase): 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() + r = [i for i in d] self.assertListEqual (r, expected) @@ -139,8 +136,8 @@ class depthTestCases(unittest.TestCase): expected =[7.5, 5.0, 2.5, 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) + d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) + r = [i for i in d] self.assertListEqual (r, expected) @@ -157,8 +154,8 @@ class depthTestCases(unittest.TestCase): 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) + d = PU.depth_params(clearance_height, rapid_safety_space, start_depth, step_down, z_finish_step, final_depth, user_depths, equalstep=True) + r = [i for i in d] self.assertListEqual (r, expected) def test70(self): @@ -175,9 +172,7 @@ class depthTestCases(unittest.TestCase): 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) + r = [i for i in d] 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) +