From 26bef05db27ef764610bad687d9248bdf82ee6f5 Mon Sep 17 00:00:00 2001 From: sliptonic Date: Thu, 3 Mar 2016 10:42:59 -0600 Subject: [PATCH] integrating dbtayls helix and ramp entry integrating dbtayls helix and ramp entry and cleanup fixed a bug with depth calculation and another with proper entry rapid moves --- src/Mod/Path/InitGui.py | 4 + src/Mod/Path/PathScripts/PathAreaUtils.py | 51 +- src/Mod/Path/PathScripts/PathKurveUtils.py | 15 +- src/Mod/Path/PathScripts/PathPocket.py | 867 ++++++++++++--------- src/Mod/Path/PathScripts/PathProfile.py | 77 ++ src/Mod/Path/PathScripts/PathUtils.py | 27 +- src/Mod/Path/PathScripts/nc/iso.py | 2 +- 7 files changed, 595 insertions(+), 448 deletions(-) diff --git a/src/Mod/Path/InitGui.py b/src/Mod/Path/InitGui.py index d0b664874..6194298d4 100644 --- a/src/Mod/Path/InitGui.py +++ b/src/Mod/Path/InitGui.py @@ -107,6 +107,10 @@ class PathWorkbench ( Workbench ): if len(FreeCADGui.Selection.getSelection()) == 1: if FreeCADGui.Selection.getSelection()[0].isDerivedFrom("Path::Feature"): self.appendContextMenu("",["Path_Inspect"]) + if "Profile" in FreeCADGui.Selection.getSelection()[0].Name: + self.appendContextMenu("",["Add_Tag"]) + self.appendContextMenu("",["Set_StartPoint"]) + self.appendContextMenu("",["Set_EndPoint"]) Gui.addWorkbench(PathWorkbench()) diff --git a/src/Mod/Path/PathScripts/PathAreaUtils.py b/src/Mod/Path/PathScripts/PathAreaUtils.py index 5845422f0..aae5c5a36 100644 --- a/src/Mod/Path/PathScripts/PathAreaUtils.py +++ b/src/Mod/Path/PathScripts/PathAreaUtils.py @@ -11,7 +11,7 @@ tool_radius_for_pocket = None def cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, final_depth): prev_p = p first = True - + #comment("cut_curve:14 rss:" + str(rapid_safety_space) + " current start depth :" + str(current_start_depth) + " final depth :" + str(final_depth) + " need rapid: " + str(need_rapid)) for vertex in curve.getVertices(): if need_rapid and first: # rapid across @@ -99,29 +99,29 @@ def cut_curvelist1(curve_list, rapid_safety_space, current_start_depth, depth, c rapid(z = clearance_height) -def cut_curvelist2(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss,start_point): - p = area.Point(0, 0) - start_x,start_y=start_point - first = True - for curve in curve_list: - need_rapid = True - if first == True: - direction = "on";radius = 0.0;offset_extra = 0.0; roll_radius = 0.0;roll_on = 0.0; roll_off = 0.0; rapid_safety_space; step_down = math.fabs(depth);extend_at_start = 0.0;extend_at_end = 0.0 - kurve_funcs.make_smaller( curve, start = area.Point(start_x,start_y)) - kurve_funcs.profile(curve, direction, radius , offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space , clearance_height, current_start_depth, step_down , depth, extend_at_start, extend_at_end) - else: - s = curve.FirstVertex().p - if keep_tool_down_if_poss == True: +# def cut_curvelist2(curve_list, rapid_safety_space, current_start_depth, depth, clearance_height, keep_tool_down_if_poss,start_point): +# p = area.Point(0, 0) +# start_x,start_y=start_point +# first = True +# for curve in curve_list: +# need_rapid = True +# if first == True: +# direction = "on";radius = 0.0;offset_extra = 0.0; roll_radius = 0.0;roll_on = 0.0; roll_off = 0.0; rapid_safety_space; step_down = math.fabs(depth);extend_at_start = 0.0;extend_at_end = 0.0 +# kurve_funcs.make_smaller( curve, start = area.Point(start_x,start_y)) +# kurve_funcs.profile(curve, direction, radius , offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space , clearance_height, current_start_depth, step_down , depth, extend_at_start, extend_at_end) +# else: +# s = curve.FirstVertex().p +# if keep_tool_down_if_poss == True: - # see if we can feed across - if feed_possible(p, s): - need_rapid = False - elif s.x == p.x and s.y == p.y: - need_rapid = False +# # see if we can feed across +# if feed_possible(p, s): +# need_rapid = False +# elif s.x == p.x and s.y == p.y: +# need_rapid = False - cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth) - first = False #change to True if you want to rapid back to start side before zigging again with unidirectional set - rapid(z = clearance_height) +# cut_curve(curve, need_rapid, p, rapid_safety_space, current_start_depth, depth) +# first = False #change to True if you want to rapid back to start side before zigging again with unidirectional set +# rapid(z = clearance_height) def recur(arealist, a1, stepover, from_center): # this makes arealist by recursively offsetting a1 inwards @@ -428,8 +428,9 @@ def pocket(a,tool_radius, extra_offset, stepover, depthparams, from_center, keep current_start_depth = depth else: - for depth in depths: - cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point) - current_start_depth = depth + print "PathAreaUtils:438 I guess it IS used. Who knew?" + # for depth in depths: + # cut_curvelist2(curve_list, depthparams.rapid_safety_space, current_start_depth, depth, depthparams.clearance_height, keep_tool_down_if_poss, start_point) + # current_start_depth = depth diff --git a/src/Mod/Path/PathScripts/PathKurveUtils.py b/src/Mod/Path/PathScripts/PathKurveUtils.py index 455da6dd5..f65c4d6b5 100644 --- a/src/Mod/Path/PathScripts/PathKurveUtils.py +++ b/src/Mod/Path/PathScripts/PathKurveUtils.py @@ -37,11 +37,6 @@ from nc.nc import * import PathScripts.nc.iso - - - - - def makeAreaVertex(seg): if seg.ShapeType =='Edge': if isinstance(seg.Curve,Part.Circle): @@ -54,18 +49,22 @@ def makeAreaVertex(seg): vertex = area.Point(seg.valueAt(seg.LastParameter)[0],seg.valueAt(seg.LastParameter)[1]) else: pass + #print "returning vertex: area.Point(" + str(seg.valueAt(seg.LastParameter)[0]) +"," + str(seg.valueAt(seg.LastParameter)[1]) +")" return vertex def makeAreaCurve(edges,direction,startpt=None,endpt=None): curveobj = area.Curve() - cleanededges = PathUtils.cleanedges(edges, 0.01) + cleanededges = Part.__sortEdges__(PathUtils.cleanedges(edges, 0.01)) + + for e in cleanededges: + print str(e.valueAt(e.FirstParameter)) + "," + str(e.valueAt(e.LastParameter)) edgelist=[] if len(cleanededges) == 1: #user selected a single edge. edgelist = cleanededges else: - edgelist = [] #Multiple edges. Need to sequence the vetexes. + #edgelist = [] #Multiple edges. Need to sequence the vetexes. #First get the first segment oriented correctly. #We first compare the last parameter of the first segment to see if it matches either end of the second segment. If not, it must need flipping. @@ -84,7 +83,7 @@ def makeAreaCurve(edges,direction,startpt=None,endpt=None): else: nextedge = PathUtils.reverseEdge(edge) edgelist.append(nextedge) - #print (str(area.Point(edgelist[0].Vertexes[0].X) + ", " + str(edgelist[0].Vertexes[0].Y))) + #print "makeareacurve 87: " + "area.Point(" + str(edgelist[0].Vertexes[0].X) + ", " + str(edgelist[0].Vertexes[0].Y)+")" curveobj.append(area.Point(edgelist[0].Vertexes[0].X,edgelist[0].Vertexes[0].Y)) # seglist =[] # if direction=='CW': diff --git a/src/Mod/Path/PathScripts/PathPocket.py b/src/Mod/Path/PathScripts/PathPocket.py index f7bdf0677..f0c40f42f 100644 --- a/src/Mod/Path/PathScripts/PathPocket.py +++ b/src/Mod/Path/PathScripts/PathPocket.py @@ -42,69 +42,60 @@ except AttributeError: def translate(context, text, disambig=None): return QtGui.QApplication.translate(context, text, disambig) -def frange(start, stop, step, finish): - x = [] - curdepth = start - if step == 0: - return x - # do the base cuts until finishing round - while curdepth >= stop + step + finish: - curdepth = curdepth - step - if curdepth <= stop + finish: - curdepth = stop + finish - x.append(curdepth) - - # we might have to do a last pass or else finish round might be too far away - if curdepth - stop > finish: - x.append(stop + finish) - - # do the the finishing round - if curdepth >= stop: - curdepth = stop - x.append(curdepth) - - # Why this? -# if start >= stop: -# start = stop -# x.append (start) - - return x class ObjectPocket: def __init__(self,obj): - obj.addProperty("App::PropertyLinkSub","Base","Path","The base geometry of this object") - obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool","The tool number in use") + obj.addProperty("App::PropertyLinkSub","Base","Path",translate("PathProject","The base geometry of this object")) + obj.addProperty("App::PropertyBool","Active","Path",translate("PathProject","Make False, to prevent operation from generating code")) + obj.addProperty("App::PropertyString","Comment","Path",translate("PathProject","An optional comment for this profile")) + obj.addProperty("App::PropertyEnumeration", "Algorithm", "Algorithm",translate("PathProject", "The library to use to generate the path")) + obj.Algorithm = ['OCC Native','libarea'] + + #Tool Properties + obj.addProperty("App::PropertyIntegerConstraint","ToolNumber","Tool",translate("PathProfile","The tool number in use")) obj.ToolNumber = (0, 0, 1000, 0) + obj.setEditorMode('ToolNumber',1) #make this read only + #Depth Properties + obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Depth", translate("PathProject","The height needed to clear clamps and obstructions")) + obj.addProperty("App::PropertyFloat", "SafeHeight", "Depth", translate("PathProject","Rapid Safety Height between locations.")) + obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Depth", translate("PathProject","Incremental Step Down of Tool")) + obj.StepDown = (0.0, 0.01, 100.0, 0.5) + obj.addProperty("App::PropertyFloat", "StartDepth", "Depth", translate("PathProject","Starting Depth of Tool- first cut depth in Z")) + obj.addProperty("App::PropertyFloat", "FinalDepth", "Depth", translate("PathProject","Final Depth of Tool- lowest value in Z")) + obj.addProperty("App::PropertyFloat", "FinishDepth", "Depth", translate("PathProject","Maximum material removed on final pass.")) + #obj.addProperty("App::PropertyFloat", "RetractHeight", "Depth", translate("PathProject","The height desired to retract tool when path is finished")) - obj.addProperty("App::PropertyFloat", "ClearanceHeight", "Pocket","The height needed to clear clamps and obstructions") - obj.addProperty("App::PropertyFloatConstraint", "StepDown", "Pocket","Incremental Step Down of Tool") - obj.StepDown = (0.0, 0.0, 100.0, 1.0) - - obj.addProperty("App::PropertyFloat", "StartDepth", "Pocket", "Starting Depth of Tool- first cut depth in Z") - obj.addProperty("App::PropertyBool","UseStartDepth","Pocket","make True, if manually specifying a Start Start Depth") - obj.addProperty("App::PropertyFloat", "FinalDepth", "Pocket", "Final Depth of Tool- lowest value in Z") - obj.addProperty("App::PropertyFloat", "RetractHeight", "Pocket", "The height desired to retract tool when path is finished") - - obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket","The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW") - obj.CutMode = ['Climb','Conventional'] - obj.addProperty("App::PropertyFloat", "MaterialAllowance", "Pocket", "Amount of material to leave") - obj.addProperty("App::PropertyFloat", "FinishDepth", "Pocket", "Maximum material removed on final pass.") - - obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket","Start pocketing at center or boundary") - obj.StartAt = ['Center', 'Edge'] - - obj.addProperty("App::PropertyFloatConstraint", "VertFeed", "Feed","Feed rate for vertical moves in Z") + #Feed Properties + obj.addProperty("App::PropertyFloatConstraint", "VertFeed", "Feed",translate("Vert Feed","Feed rate for vertical moves in Z")) obj.VertFeed = (0.0, 0.0, 100000.0, 1.0) - - obj.addProperty("App::PropertyFloatConstraint", "HorizFeed", "Feed","Feed rate for horizontal moves") + obj.addProperty("App::PropertyFloatConstraint", "HorizFeed", "Feed",translate("Horiz Feed","Feed rate for horizontal moves")) obj.HorizFeed = (0.0, 0.0, 100000.0, 1.0) + #Pocket Properties + obj.addProperty("App::PropertyEnumeration", "CutMode", "Pocket",translate("PathProject", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW")) + obj.CutMode = ['Climb','Conventional'] + obj.addProperty("App::PropertyFloat", "MaterialAllowance", "Pocket", translate("PathProject","Amount of material to leave")) + obj.addProperty("App::PropertyEnumeration", "StartAt", "Pocket",translate("PathProject", "Start pocketing at center or boundary")) + obj.StartAt = ['Center', 'Edge'] + obj.addProperty("App::PropertyFloatConstraint","StepOver","Pocket",translate("PathProject","Amount to step over on each pass")) + obj.StepOver = (0.0, 0.01, 100.0, 0.5) + obj.addProperty("App::PropertyBool","KeepToolDown","Pocket",translate("PathProject","Attempts to avoid unnecessary retractions.")) + obj.addProperty("App::PropertyBool","ZigUnidirectional","Pocket",translate("PathProject","Lifts tool at the end of each pass to respect cut mode.")) + obj.addProperty("App::PropertyBool","UseZigZag","Pocket",translate("PathProject","Use Zig Zag pattern to clear area.")) + obj.addProperty("App::PropertyFloat","ZigZagAngle","Pocket",translate("PathProject","Angle of the zigzag pattern")) + + #Entry Properties + obj.addProperty("App::PropertyBool","UseEntry","Entry",translate("PathProject","Allow Cutter enter material with a straight plunge.")) + obj.addProperty("App::PropertyFloatConstraint", "RampSize", "Entry", translate("PathProject","The minimum fraction of tool diameter to use for ramp length")) + obj.RampSize = (0.0, 0.01, 100.0, 0.5) + obj.addProperty("App::PropertyFloatConstraint", "HelixSize", "Entry", translate("PathProject","The fraction of tool diameter to use for calculating helix size.")) + obj.HelixSize = (0.0, 0.01, 100.0, 0.5) + obj.addProperty("App::PropertyFloatConstraint", "RampAngle", "Entry", translate("PathProject","The Angle of the ramp entry.")) + obj.RampAngle = (0.0, 0.01, 100.0, 0.5) - obj.addProperty("App::PropertyBool","Active","Path","Make False, to prevent operation from generating code") - obj.addProperty("App::PropertyString","Comment","Path","An optional comment for this profile") obj.Proxy = self @@ -127,53 +118,221 @@ class ObjectPocket: return self.getStock(o) return None + def buildpathlibarea(self, obj, a): + import PathScripts.PathUtils as PathUtils + import PathScripts.PathAreaUtils as PathAreaUtils + from PathScripts.PathUtils import depth_params + import area + + FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with libarea offsets.\n")) + + depthparams = depth_params (obj.ClearanceHeight, obj.SafeHeight, obj.StartDepth, obj.StepDown, obj.FinishDepth, obj.FinalDepth) + + horizfeed = obj.HorizFeed + extraoffset = obj.MaterialAllowance + stepover = obj.StepOver + use_zig_zag = obj.UseZigZag + zig_angle = obj.ZigZagAngle + from_center = (obj.StartAt == "Center") + keep_tool_down = obj.KeepToolDown + zig_unidirectional = obj.ZigUnidirectional + start_point = None + cut_mode = obj.CutMode + + PathAreaUtils.output('mem') + + print "a," + str(self.radius) + "," + str(extraoffset) + "," + str(stepover) + ",depthparams, " + str(from_center) + "," + str(keep_tool_down) + "," + str(use_zig_zag) + "," + str(zig_angle) + "," + str(zig_unidirectional) + "," + str(start_point) + "," + str(cut_mode) + + PathAreaUtils.pocket(a,self.radius,extraoffset, stepover,depthparams,from_center,keep_tool_down,use_zig_zag,zig_angle,zig_unidirectional,start_point,cut_mode) + + return PathAreaUtils.retrieve_gcode() - #To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket) - def execute(self,obj): - if obj.Base: - tool = PathUtils.getLastTool(obj) - if tool: - radius = tool.Diameter/2 - if radius < 0:# safe guard - radius -= radius + + def buildpathocc(self, obj, shape): + import Part, DraftGeomUtils + FreeCAD.Console.PrintMessage(translate("PathPocket","Generating toolpath with OCC native offsets.\n")) + + def prnt(vlu): return str("%.4f" % round(vlu, 4)) + + def rapid(x=None, y=None, z=None): + #Returns gcode to perform a rapid move + retstr = "G00" + if (x != None) or (y != None) or (z != None): + if (x != None): + retstr += " X" + str("%.4f" % x) + if (y != None): + retstr += " Y" + str("%.4f" % y) + if (z != None): + retstr += " Z" + str("%.4f" % z) else: - # temporary value, to be taken from the properties later on - radius = 1 + return "" + return retstr + "\n" - import Part, DraftGeomUtils - if "Face" in obj.Base[1][0]: - shape = getattr(obj.Base[0].Shape,obj.Base[1][0]) + def feed(x=None, y=None, z=None): + #Returns gcode to perform a linear feed + global feedxy + retstr = "G01 F" + if(x == None) and (y == None): + retstr += str("%.4f" % obj.HorizFeed) else: - edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]] - shape = Part.Wire(edges) - print len(edges) - - # absolute coords, millimeters, cancel offsets - output = "G90\nG21\nG40\n" - # save tool - if obj.ToolNumber > 0 and tool.ToolNumber != obj.ToolNumber: - output += "M06 T" + str(tool.ToolNumber) + "\n" + retstr += str("%.4f" % obj.VertFeed) - # build offsets - offsets = [] - nextradius = radius + if (x != None) or (y != None) or (z != None): + if (x != None): + retstr += " X" + str("%.4f" % x) + if (y != None): + retstr += " Y" + str("%.4f" % y) + if (z != None): + retstr += " Z" + str("%.4f" % z) + else: + return "" + return retstr + "\n" + + def arc(cx, cy, sx, sy, ex, ey, ez=None, ccw=False): + #Returns gcode to perform an arc + #Assumes XY plane or helix around Z + #Don't worry about starting Z- assume that's dealt with elsewhere + #If start/end radii aren't within eps, abort + eps = 0.01 + if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps: + print "ERROR: Illegal arc: Stand and end radii not equal" + return "" + + #Set [C]CW and feed + retstr = "" + if ccw: + retstr += "G03 F" + else: + retstr += "G02 F" + retstr += str(obj.HorizFeed) + + #End location + retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey) + + #Helix if requested + if ez != None: + retstr += " Z" + str("%.4f" % ez) + + #Append center offsets + retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy)) + + return retstr + "\n" + + def helicalPlunge(plungePos, rampangle, destZ, startZ): + #Returns gcode to helically plunge + #destZ is the milling level + #startZ is the height we can safely feed down to before helix-ing + helixCmds = "(START HELICAL PLUNGE)\n" + if(plungePos == None): + raise Error("Helical plunging requires a position!") + return None + if(not tool): + raise Error("Helical plunging requires a tool!") + return None + + helixX = plungePos.x + tool.Diameter/2. * plungeR + helixY = plungePos.y; + + helixCirc = math.pi * tool.Diameter * plungeR + dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc + + #Go to the start of the helix position + helixCmds += rapid(helixX, helixY) + helixCmds += rapid(z=startZ) + + #Helix as required to get to the requested depth + lastZ = startZ + curZ = max(startZ-dzPerRev, destZ) + done = False + while not done: + done = (curZ == destZ) + #NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid + #helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True) + + #Use two half-helixes; FreeCAD renders that correctly, + #and it fits with the other code breaking up 360-degree arcs + helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - tool.Diameter * plungeR, helixY, ez = (curZ + lastZ)/2., ccw=True) + helixCmds += arc(plungePos.x, plungePos.y, helixX - tool.Diameter * plungeR, helixY, helixX, helixY, ez = curZ, ccw=True) + lastZ = curZ + curZ = max(curZ - dzPerRev, destZ) + + return helixCmds + + def rampPlunge(edge, rampangle, destZ, startZ): + #Returns commands to linearly ramp into a cut + #FIXME: This ramps along the first edge, assuming it's long + #enough, NOT just wiggling back and forth by ~0.75 * toolD. + #Not sure if that's any worse, but it's simpler + # I think this should be changed to be limited to a maximum ramp size. Otherwise machine time will get longer than it needs to be. + + + rampCmds = "(START RAMP PLUNGE)\n" + if(edge == None): + raise Error("Ramp plunging requires an edge!") + return None + if(not tool): + raise Error("Ramp plunging requires a tool!") + + + sPoint = edge.Vertexes[0].Point + ePoint = edge.Vertexes[1].Point + #Evidently edges can get flipped- pick the right one in this case + #FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below + if ePoint == sPoint: + #print "FLIP" + ePoint = edge.Vertexes[-1].Point + #print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ) + + rampDist = edge.Length + rampDZ = math.sin(rampangle/180. * math.pi) * rampDist + + rampCmds += rapid(sPoint.x, sPoint.y) + rampCmds += rapid(z=startZ) + + #Ramp down to the requested depth + #FIXME: This might be an arc, so handle that as well + lastZ = startZ + curZ = max(startZ-rampDZ, destZ) + done = False + while not done: + done = (curZ == destZ) + + #If it's an arc, handle it! + if isinstance(edge.Curve,Part.Circle): + raise Error("rampPlunge: Screw it, not handling an arc.") + #Straight feed! Easy! + else: + rampCmds += feed(ePoint.x, ePoint.y, curZ) + rampCmds += feed(sPoint.x, sPoint.y) + + lastZ = curZ + curZ = max(curZ - rampDZ, destZ) + + return rampCmds + + + + output = "" + offsets = [] + nextradius = self.radius + result = DraftGeomUtils.pocket2d(shape,nextradius) + + while result: + #print "Adding " + str(len(result)) + " wires" + offsets.extend(result) + nextradius += self.radius result = DraftGeomUtils.pocket2d(shape,nextradius) - while result: - #print "Adding " + str(len(result)) + " wires" - offsets.extend(result) - nextradius += radius - result = DraftGeomUtils.pocket2d(shape,nextradius) - - # first move will be rapid, subsequent will be at feed rate - first = True - startPoint = None - fastZPos = max(obj.StartDepth + 2, obj.RetractHeight) - - # revert the list so we start with the outer wires - if obj.StartAt != 'Edge': - offsets.reverse() + + # first move will be rapid, subsequent will be at feed rate + first = True + startPoint = None + fastZPos = max(obj.StartDepth + 2, obj.ClearanceHeight) + + # revert the list so we start with the outer wires + if obj.StartAt != 'Edge': + offsets.reverse() # print "startDepth: " + str(obj.StartDepth) # print "finalDepth: " + str(obj.FinalDepth) @@ -181,291 +340,201 @@ class ObjectPocket: # print "finishDepth" + str(obj.FinishDepth) # print "offsets:", len(offsets) - def prnt(vlu): return str("%.4f" % round(vlu, 4)) - - #Fraction of tool radius our plunge helix is to be - #FIXME: This should be configurable - plungeR = 0.75 - - #(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging - #FIXME: This should be configurable - #FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best - rampD = 0.75 - - - #Total offset from the desired pocket edge is tool radius plus the plunge helix radius - #Any point on these curves could be the center of a plunge - helixBounds = DraftGeomUtils.pocket2d(shape, tool.Diameter / 2. * (1 + plungeR)) - - - #Try to find a location to nicely plunge, starting with a helix, then ramp - #Can't do it without knowledge of a tool - plungePos = None - rampEdge = None - if not tool: - raise Error("Ramp plunge location-finding requires a tool") - return - else: - #Since we're going to start machining either the inner-most - #edge or the outer (depending on StartAt setting), try to - #plunge near that location - - if helixBounds: - #Edge is easy- pick a point on helixBounds and go with it - if obj.StartAt == 'Edge': - plungePos = helixBounds[0].Edges[0].Vertexes[0].Point - #Center is harder- use a point from the first offset, check if it works - else: - plungePos = offsets[0].Edges[0].Vertexes[0].Point - - #If it turns out this is invalid for some reason, nuke plungePos - [perp,idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges) - if not perp or perp.Length < tool.Diameter / 2. * (1 + plungeR): - plungePos = None - #FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds - #Or some math to prove that it has to be (doubt that's true) - #Maybe reverse helixBounds and pick off that? - - - #If we didn't find a place to helix, how about a ramp? - if not plungePos: - #Check first edge of our offsets - if (offsets[0].Edges[0].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)): - rampEdge = offsets[0].Edges[0] - #The last edge also connects with the starting location- try that - elif (offsets[0].Edges[-1].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)): - rampEdge = offsets[0].Edges[-1] - else: - print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1]) - #FIXME: There's got to be a smarter way to find a place to ramp - - - #Returns gcode to perform a rapid move - def rapid(x=None, y=None, z=None): - retstr = "G00" - if (x != None) or (y != None) or (z != None): - if (x != None): - retstr += " X" + str("%.4f" % x) - if (y != None): - retstr += " Y" + str("%.4f" % y) - if (z != None): - retstr += " Z" + str("%.4f" % z) - else: - return "" - return retstr + "\n" - - #Returns gcode to perform a linear feed - def feed(x=None, y=None, z=None): - global feedxy - retstr = "G01 F" - if(x == None) and (y == None): - retstr += str("%.4f" % obj.HorizFeed) - else: - retstr += str("%.4f" % obj.VertFeed) - - if (x != None) or (y != None) or (z != None): - if (x != None): - retstr += " X" + str("%.4f" % x) - if (y != None): - retstr += " Y" + str("%.4f" % y) - if (z != None): - retstr += " Z" + str("%.4f" % z) - else: - return "" - return retstr + "\n" - - #Returns gcode to perform an arc - #Assumes XY plane or helix around Z - #Don't worry about starting Z- assume that's dealt with elsewhere - def arc(cx, cy, sx, sy, ex, ey, ez=None, ccw=False): - #If start/end radii aren't within eps, abort - eps = 0.01 - if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps: - print "ERROR: Illegal arc: Stand and end radii not equal" - return "" - - #Set [C]CW and feed - retstr = "" - if ccw: - retstr += "G03 F" - else: - retstr += "G02 F" - retstr += str(obj.HorizFeed) - - #End location - retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey) - - #Helix if requested - if ez != None: - retstr += " Z" + str("%.4f" % ez) - - #Append center offsets - retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy)) - - return retstr + "\n" + #Fraction of tool radius our plunge helix is to be + plungeR = obj.HelixSize + + #(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging + #FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best + rampD = obj.RampSize - #Returns gcode to helically plunge - #destZ is the milling level - #startZ is the height we can safely feed down to before helix-ing - def helicalPlunge(plungePos, rampangle, destZ, startZ): - helixCmds = "(START HELICAL PLUNGE)\n" - if(plungePos == None): - raise Error("Helical plunging requires a position!") - return None - if(not tool): - raise Error("Helical plunging requires a tool!") - return None - - helixX = plungePos.x + tool.Diameter/2. * plungeR - helixY = plungePos.y; - - helixCirc = math.pi * tool.Diameter * plungeR - dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc - - #Go to the start of the helix position - helixCmds += rapid(helixX, helixY) - helixCmds += rapid(z=startZ) - - #Helix as required to get to the requested depth - lastZ = startZ - curZ = max(startZ-dzPerRev, destZ) - done = False - while not done: - done = (curZ == destZ) - #NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid - #helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True) + #Total offset from the desired pocket edge is tool radius plus the plunge helix radius + #Any point on these curves could be the center of a plunge + helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + plungeR)) + + + #Try to find a location to nicely plunge, starting with a helix, then ramp + #Can't do it without knowledge of a tool + plungePos = None + rampEdge = None + tool = PathUtils.getTool(obj,obj.ToolNumber) + if not tool: + raise Error("Ramp plunge location-finding requires a tool") + return + else: + #Since we're going to start machining either the inner-most + #edge or the outer (depending on StartAt setting), try to + #plunge near that location + + if helixBounds and obj.UseEntry: + #Edge is easy- pick a point on helixBounds and go with it + if obj.StartAt == 'Edge': + plungePos = helixBounds[0].Edges[0].Vertexes[0].Point + #Center is harder- use a point from the first offset, check if it works + else: + plungePos = offsets[0].Edges[0].Vertexes[0].Point - #Use two half-helixes; FreeCAD renders that correctly, - #and it fits with the other code breaking up 360-degree arcs - helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - tool.Diameter * plungeR, helixY, ez = (curZ + lastZ)/2., ccw=True) - helixCmds += arc(plungePos.x, plungePos.y, helixX - tool.Diameter * plungeR, helixY, helixX, helixY, ez = curZ, ccw=True) - lastZ = curZ - curZ = max(curZ - dzPerRev, destZ) - - return helixCmds - - - #Returns commands to linearly ramp into a cut - #FIXME: This ramps along the first edge, assuming it's long - #enough, NOT just wiggling back and forth by ~0.75 * toolD. - #Not sure if that's any worse, but it's simpler - #FIXME: This code is untested - def rampPlunge(edge, rampangle, destZ, startZ): - rampCmds = "(START RAMP PLUNGE)\n" - if(edge == None): - raise Error("Ramp plunging requires an edge!") - return None - if(not tool): - raise Error("Ramp plunging requires a tool!") - - - sPoint = edge.Vertexes[0].Point - ePoint = edge.Vertexes[1].Point - #Evidently edges can get flipped- pick the right one in this case - #FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below - if ePoint == sPoint: - #print "FLIP" - ePoint = edge.Vertexes[-1].Point - #print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ) - - rampDist = edge.Length - rampDZ = math.sin(rampangle/180. * math.pi) * rampDist - - rampCmds += rapid(sPoint.x, sPoint.y) - rampCmds += rapid(z=startZ) - - #Ramp down to the requested depth - #FIXME: This might be an arc, so handle that as well - lastZ = startZ - curZ = max(startZ-rampDZ, destZ) - done = False - while not done: - done = (curZ == destZ) - - #If it's an arc, handle it! - if isinstance(edge.Curve,Part.Circle): - raise Error("rampPlunge: Screw it, not handling an arc.") - #Straight feed! Easy! - else: - rampCmds += feed(ePoint.x, ePoint.y, curZ) - rampCmds += feed(sPoint.x, sPoint.y) + #If it turns out this is invalid for some reason, nuke plungePos + [perp,idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges) + if not perp or perp.Length < self.radius * (1 + plungeR): + plungePos = None + #FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds + #Or some math to prove that it has to be (doubt that's true) + #Maybe reverse helixBounds and pick off that? + + + #If we didn't find a place to helix, how about a ramp? + if not plungePos and obj.UseEntry: + #Check first edge of our offsets + if (offsets[0].Edges[0].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)): + rampEdge = offsets[0].Edges[0] + #The last edge also connects with the starting location- try that + elif (offsets[0].Edges[-1].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)): + rampEdge = offsets[0].Edges[-1] + else: + print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1]) + #FIXME: There's got to be a smarter way to find a place to ramp + - lastZ = curZ - curZ = max(curZ - rampDZ, destZ) - - return rampCmds - - - - - #For helix-ing/ramping, know where we were last time - #FIXME: Can probably get this from the "machine"? - lastZ = fastZPos + #For helix-ing/ramping, know where we were last time + #FIXME: Can probably get this from the "machine"? + lastZ = fastZPos - for vpos in frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth): -# print "vpos: " + str(vpos) - #Every for every depth we should helix down - first = True - # loop over successive wires - for currentWire in offsets: -# print "new line (offset)" - last = None - for edge in currentWire.Edges: -# print "new edge" - if not last: - # we set the base GO to our fast move to our starting pos - if first: - #If we can helix, do so - if plungePos: - output += helicalPlunge(plungePos, 3, vpos, lastZ) - #print output - lastZ = vpos - #Otherwise, see if we can ramp - #FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along) - elif rampEdge: - output += rampPlunge(rampEdge, 3, vpos, lastZ) - lastZ = vpos - #Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice. - #FIXME: At least not with the lazy ramp programming above... - else: - print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp" - startPoint = edge.Vertexes[0].Point - output += "G0 X" + prnt(startPoint.x) + " Y" + prnt(startPoint.y) +\ - " Z" + prnt(fastZPos) + "\n" - first = False - #then move slow down to our starting point for our profile - last = edge.Vertexes[0].Point - output += "G1 X" + prnt(last.x) + " Y" + prnt(last.y) + " Z" + prnt(vpos) + "\n" - #if isinstance(edge.Curve,Part.Circle): - if DraftGeomUtils.geomType(edge) == "Circle": - point = edge.Vertexes[-1].Point - if point == last: # edges can come flipped - point = edge.Vertexes[0].Point -# print "flipped" - center = edge.Curve.Center - relcenter = center.sub(last) - v1 = last.sub(center) - v2 = point.sub(center) - if v1.cross(v2).z < 0: - output += "G2" + for vpos in PathUtils.frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth): + #Every for every depth we should helix down + first = True + # loop over successive wires + for currentWire in offsets: + last = None + for edge in currentWire.Edges: + if not last: + # we set the base GO to our fast move to our starting pos + if first: + #If we can helix, do so + if plungePos: + output += helicalPlunge(plungePos, obj.RampAngle, vpos, lastZ) + #print output + lastZ = vpos + #Otherwise, see if we can ramp + #FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along) + elif rampEdge: + output += rampPlunge(rampEdge, obj.RampAngle, vpos, lastZ) + lastZ = vpos + #Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice. + #FIXME: At least not with the lazy ramp programming above... else: - output += "G3" - output += " X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) - output += " I" + prnt(relcenter.x) + " J" +prnt(relcenter.y) + " K" + prnt(relcenter.z) - output += "\n" - last = point + print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp" + startPoint = edge.Vertexes[0].Point + output += "G0 X" + prnt(startPoint.x) + " Y" + prnt(startPoint.y) +\ + " Z" + prnt(fastZPos) + "\n" + first = False + #then move slow down to our starting point for our profile + last = edge.Vertexes[0].Point + output += "G1 X" + prnt(last.x) + " Y" + prnt(last.y) + " Z" + prnt(vpos) + "\n" + #if isinstance(edge.Curve,Part.Circle): + if DraftGeomUtils.geomType(edge) == "Circle": + point = edge.Vertexes[-1].Point + if point == last: # edges can come flipped + point = edge.Vertexes[0].Point + center = edge.Curve.Center + relcenter = center.sub(last) + v1 = last.sub(center) + v2 = point.sub(center) + if v1.cross(v2).z < 0: + output += "G2" else: - point = edge.Vertexes[-1].Point - if point == last: # edges can come flipped - point = edge.Vertexes[0].Point - output += "G1 X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) + "\n" - last = point + output += "G3" + output += " X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) + output += " I" + prnt(relcenter.x) + " J" +prnt(relcenter.y) + " K" + prnt(relcenter.z) + output += "\n" + last = point + else: + point = edge.Vertexes[-1].Point + if point == last: # edges can come flipped + point = edge.Vertexes[0].Point + output += "G1 X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) + "\n" + last = point + + #move back up + output += "G1 Z" + prnt(fastZPos) + "\n" + return output + + + #To reload this from FreeCAD, use: import PathScripts.PathPocket; reload(PathScripts.PathPocket) + def execute(self,obj): + if obj.Base: + + import Part, PathScripts.PathKurveUtils, DraftGeomUtils + if "Face" in obj.Base[1][0]: + shape = getattr(obj.Base[0].Shape,obj.Base[1][0]) + wire = shape.OuterWire + edges = wire.Edges + else: + edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]] + print "myedges: " + str(edges) + wire = Part.Wire(edges) + shape = None + + # tie the toolnumber to the PathLoadTool object ToolNumber + if len(obj.InList)>0: #check to see if obj is in the Project group yet + project = obj.InList[0] + tl = int(PathUtils.changeTool(obj,project)) + obj.ToolNumber= tl + + tool = PathUtils.getTool(obj,obj.ToolNumber) + if tool: + self.radius = tool.Diameter/2 + else: + # temporary value,in case we don't have any tools defined already + self.radius = 0.25 + + output = "" + if obj.Algorithm == "OCC Native": + if shape == None: + shape = wire + output += self.buildpathocc(obj, shape) + else: + try: + import area + except: + FreeCAD.Console.PrintError(translate("PathKurve","libarea needs to be installed for this command to work.\n")) + return + + a = area.Area() + if shape == None: + c = PathScripts.PathKurveUtils.makeAreaCurve(wire.Edges, 'CW') + a.append(c) + else: + for w in shape.Wires: + c = PathScripts.PathKurveUtils.makeAreaCurve(w.Edges, 'CW') + # if w.isSame(shape.OuterWire): + # print "outerwire" + # if c.IsClockwise(): + # c.Reverse() + # print "reverse outterwire" + # else: + # print "inner wire" + # if not c.IsClockwise(): + # c.Reverse() + # print "reverse inner" + a.append(c) + + ######## + ##This puts out some interesting information from libarea + print a.text() + ######## + + + a.Reorder() + output += self.buildpathlibarea(obj, a) + if obj.UseEntry: + obj.setEditorMode('HelixSize',0) #make this visible + obj.setEditorMode('RampAngle',0) #make this visible + obj.setEditorMode('RampSize',0) #make this visible + else: + obj.setEditorMode('HelixSize',2) #make this hidden + obj.setEditorMode('RampAngle',2) #make this hidden + obj.setEditorMode('RampSize',2) #make this hidden - #move back up - output += "G0 Z" + prnt(fastZPos) + "\n" -# print output -# path = Path.Path(output) -# obj.Path = path if obj.Active: path = Path.Path(output) obj.Path = path @@ -500,62 +569,80 @@ class CommandPathPocket: def GetResources(self): return {'Pixmap' : 'Path-Pocket', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Pocket","Pocket"), + 'MenuText': QtCore.QT_TRANSLATE_NOOP("PathPocket","Pocket"), 'Accel': "P, O", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Pocket","Creates a Path Pocket object from a loop of edges or a face")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathPocket","Creates a Path Pocket object from a loop of edges or a face")} def IsActive(self): return not FreeCAD.ActiveDocument is None - + def Activated(self): # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelectionEx() if len(selection) != 1: - FreeCAD.Console.PrintError(translate("Path_Pocket","Please select an edges loop from one object, or a single face\n")) + FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n")) return if len(selection[0].SubObjects) == 0: - FreeCAD.Console.PrintError(translate("Path_Pocket","Please select an edges loop from one object, or a single face\n")) + FreeCAD.Console.PrintError(translate("PathPocket","Please select an edges loop from one object, or a single face\n")) return for s in selection[0].SubObjects: if s.ShapeType != "Edge": if (s.ShapeType != "Face") or (len(selection[0].SubObjects) != 1): - FreeCAD.Console.PrintError(translate("Path_Pocket","Please select only edges or a single face\n")) + FreeCAD.Console.PrintError(translate("PathPocket","Please select only edges or a single face\n")) return if selection[0].SubObjects[0].ShapeType == "Edge": try: import Part w = Part.Wire(selection[0].SubObjects) + if w.isClosed() == False: + FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n")) + return + except: - FreeCAD.Console.PrintError(translate("Path_Pocket","The selected edges don't form a loop\n")) + FreeCAD.Console.PrintError(translate("PathPocket","The selected edges don't form a loop\n")) return + + # Take a guess at some reasonable values for Finish depth. + bb = selection[0].Object.Shape.BoundBox #parent boundbox + fbb = selection[0].SubObjects[0].BoundBox #feature boundbox + if fbb.ZMax < bb.ZMax: + zbottom = fbb.ZMax + else: + zbottom = bb.ZMin # if everything is ok, execute and register the transaction in the undo/redo stack - FreeCAD.ActiveDocument.openTransaction(translate("Path_Pocket","Create Pocket")) + FreeCAD.ActiveDocument.openTransaction(translate("PathPocket","Create Pocket")) FreeCADGui.addModule("PathScripts.PathPocket") - FreeCADGui.doCommand('prjexists = False') - FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Pocket")') + + FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","Pocket")') FreeCADGui.doCommand('PathScripts.PathPocket.ObjectPocket(obj)') + + FreeCADGui.doCommand('obj.Active = True') + FreeCADGui.doCommand('PathScripts.PathPocket.ViewProviderPocket(obj.ViewObject)') subs = "[" for s in selection[0].SubElementNames: subs += '"' + s + '",' subs += "]" FreeCADGui.doCommand('obj.Base = (FreeCAD.ActiveDocument.' + selection[0].ObjectName + ',' + subs + ')') - FreeCADGui.doCommand('obj.Active = True') - snippet = ''' -from PathScripts import PathUtils -PathUtils.addToProject(obj) + + + FreeCADGui.doCommand('from PathScripts import PathUtils') -ZMax = obj.Base[0].Shape.BoundBox.ZMax -ZMin = obj.Base[0].Shape.BoundBox.ZMin -obj.StepDown = 1.0 -obj.StartDepth = ZMax -obj.FinalDepth = ZMin -obj.ClearanceHeight = ZMax + 5.0 + FreeCADGui.doCommand('obj.StepOver = 1.0') + FreeCADGui.doCommand('obj.ClearanceHeight = ' + str(bb.ZMax + 2.0)) + FreeCADGui.doCommand('obj.StepDown = 1.0') + FreeCADGui.doCommand('obj.StartDepth= ' + str(bb.ZMax)) + FreeCADGui.doCommand('obj.FinalDepth=' + str(zbottom)) + FreeCADGui.doCommand('obj.ZigZagAngle=45') + FreeCADGui.doCommand('obj.UseEntry=True') + FreeCADGui.doCommand('obj.RampAngle = 3.0') + FreeCADGui.doCommand('obj.RampSize = 0.75') + FreeCADGui.doCommand('obj.HelixSize = 0.75') + + FreeCADGui.doCommand('PathScripts.PathUtils.addToProject(obj)') -''' - FreeCADGui.doCommand(snippet) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() diff --git a/src/Mod/Path/PathScripts/PathProfile.py b/src/Mod/Path/PathScripts/PathProfile.py index fe0ccf9b1..d2a3f7914 100644 --- a/src/Mod/Path/PathScripts/PathProfile.py +++ b/src/Mod/Path/PathScripts/PathProfile.py @@ -226,6 +226,8 @@ class ObjectProfile: curve = PathKurveUtils.makeAreaCurve(edgelist,direction,startpoint, endpoint) '''The following line uses a profile function written for use with FreeCAD. It's clean but incomplete. It doesn't handle + print "x = " + str(point.x) + print "y - " + str(point.y) holding tags start location CRC @@ -288,6 +290,78 @@ class ObjectProfile: # return None +class _CommandAddTag: + def GetResources(self): + return {'Pixmap' : 'Path-Holding', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Add Holding Tag"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Add Holding Tag")} + + def IsActive(self): + return not FreeCAD.ActiveDocument is None + + def setpoint(self,point,o): + obj=FreeCADGui.Selection.getSelection()[0] + obj.StartPoint.x = point.x + obj.StartPoint.y = point.y + loc = obj.locs + h = obj.heights + l = obj.lengths + a = obj.angles + + x = point.x + y = point.y + z = float(0.0) + loc.append(Vector(x,y,z)) + h.append(4.0) + l.append(5.0) + a.append(45.0) + + obj.locs = loc + obj.heights = h + obj.lengths = l + obj.angles = a + + + + def Activated(self): + + FreeCADGui.Snapper.getPoint(callback=self.setpoint) + +class _CommandSetStartPoint: + def GetResources(self): + return {'Pixmap' : 'Path-Holding', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Pick Start Point"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Pick Start Point")} + + def IsActive(self): + return not FreeCAD.ActiveDocument is None + + def setpoint(self,point,o): + obj=FreeCADGui.Selection.getSelection()[0] + obj.StartPoint.x = point.x + obj.StartPoint.y = point.y + def Activated(self): + + FreeCADGui.Snapper.getPoint(callback=self.setpoint) + +class _CommandSetEndPoint: + def GetResources(self): + return {'Pixmap' : 'Path-Holding', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Pick End Point"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Profile","Pick End Point")} + + def IsActive(self): + return not FreeCAD.ActiveDocument is None + + def setpoint(self,point,o): + obj=FreeCADGui.Selection.getSelection()[0] + obj.EndPoint.x = point.x + obj.EndPoint.y = point.y + def Activated(self): + + FreeCADGui.Snapper.getPoint(callback=self.setpoint) + + class CommandPathProfile: def GetResources(self): return {'Pixmap' : 'Path-Profile', @@ -568,5 +642,8 @@ class _EditPanel: if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_Profile',CommandPathProfile()) + FreeCADGui.addCommand('Add_Tag',_CommandAddTag()) + FreeCADGui.addCommand('Set_StartPoint',_CommandSetStartPoint()) + FreeCADGui.addCommand('Set_EndPoint',_CommandSetEndPoint()) FreeCAD.Console.PrintLog("Loading PathProfile... done\n") diff --git a/src/Mod/Path/PathScripts/PathUtils.py b/src/Mod/Path/PathScripts/PathUtils.py index 1a7caf058..669cfbe29 100644 --- a/src/Mod/Path/PathScripts/PathUtils.py +++ b/src/Mod/Path/PathScripts/PathUtils.py @@ -405,15 +405,9 @@ def frange(start, stop, step, finish): curdepth = stop x.append(curdepth) - # Why this? -# if start >= stop: -# start = stop -# x.append (start) return x - - class depth_params: def __init__(self, clearance_height, rapid_safety_space, start_depth, step_down, z_finish_depth, final_depth, user_depths=None): self.clearance_height = clearance_height @@ -425,6 +419,7 @@ class depth_params: self.user_depths = user_depths def get_depths(self): + print "in function" depths = [] if self.user_depths != None: depths = self.user_depths @@ -440,23 +435,7 @@ class depth_params: for i in range(1, layer_count): depth += layer_depth depths.append(depth) + depths.reverse() return depths -# def get_depths(start_depth, final_depth, step_down, z_finish_depth): -# '''get_depths returns a list of z heights for pocket clearing. First value is Z depth of the first pass, etc. -# start_depth: starting depth of pocket -# step_down: max amount removed per pocket pass -# z_finish_depth: amount to remove on last (finishing) pass -# final_depth: bottom of pocket''' -# depths = [depth] -# depth += z_finish_depth -# if depth + 0.0000001 < start_depth: -# if z_finish_depth > 0.0000001: depths.insert(0, depth) -# layer_count = int((start_depth - depth) / step_down - 0.0000001) + 1 -# if layer_count > 0: -# layer_depth = (start_depth - depth)/layer_count -# for i in range(1, layer_count): -# depth += layer_depth -# depths.insert(0, depth) - -# return depths + diff --git a/src/Mod/Path/PathScripts/nc/iso.py b/src/Mod/Path/PathScripts/nc/iso.py index b5bce214f..dc34c2bac 100644 --- a/src/Mod/Path/PathScripts/nc/iso.py +++ b/src/Mod/Path/PathScripts/nc/iso.py @@ -548,7 +548,7 @@ class Creator(nc.Creator): ## Moves def rapid(self, x=None, y=None, z=None, a=None, b=None, c=None ): - if self.same_xyz(x, y, z, a, b, c): return + #if self.same_xyz(x, y, z, a, b, c): return self.on_move() if self.g0123_modal: