def drawLoops(loops): nloop = 0 waterlinestring = "" waterlinestring += "(waterline begin)" for loop in loops: p = loop[0] loopstring = "(loop begin)" + "\n" loopstring += "G0 Z" + str(obj.SafeHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" loopstring += "G0 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + "F " + PathUtils.fmt(self.horizRapid) + "\n" loopstring += "G1 Z" + str(fmt(p.z)) + "\n" for p in loop[1:]: loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ " Z" + str(fmt(p.z)) + "\n" zheight = p.z p = loop[0] loopstring += "G1 X" + \ str(fmt(p.x)) + " Y" + str(fmt(p.y)) + \ " Z" + str(fmt(zheight)) + "\n" loopstring += "(loop end)" + "\n" print " loop ", nloop, " with ", len(loop), " points" nloop = nloop + 1 waterlinestring += loopstring waterlinestring += "(waterline end)" + "\n" return waterlinestring
def _dropcutter(self, obj, s, bb): import ocl import time cutter = ocl.CylCutter(self.radius * 2, 5) pdc = ocl.PathDropCutter() # create a pdc pdc.setSTL(s) pdc.setCutter(cutter) pdc.minimumZ = 0.25 pdc.setSampling(obj.SampleInterval) # some parameters for this "zigzig" pattern xmin = bb.XMin - cutter.getDiameter() xmax = bb.XMax + cutter.getDiameter() ymin = bb.YMin - cutter.getDiameter() ymax = bb.YMax + cutter.getDiameter() # number of lines in the y-direction Ny = int(bb.YLength / cutter.getDiameter()) dy = float(ymax - ymin) / Ny # the y step-over path = ocl.Path() # create an empty path object # add Line objects to the path in this loop for n in xrange(0, Ny): y = ymin + n * dy p1 = ocl.Point(xmin, y, 0) # start-point of line p2 = ocl.Point(xmax, y, 0) # end-point of line if (n % 2 == 0): # even l = ocl.Line(p1, p2) # line-object else: # odd l = ocl.Line(p2, p1) # line-object path.append(l) # add the line to the path pdc.setPath(path) # run drop-cutter on the path t_before = time.time() pdc.run() t_after = time.time() print "calculation took ", t_after - t_before, " s" # retrieve the points clp = pdc.getCLPoints() print "points received: " + str(len(clp)) # generate the path commands output = "" output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" output += "G0 X" + str(clp[0].x) + " Y" + str(clp[0].y) + "F " + PathUtils.fmt(self.horizRapid) + "\n" output += "G1 Z" + str(clp[0].z) + " F" + str(self.vertFeed) + "\n" for c in clp: output += "G1 X" + str(c.x) + " Y" + \ str(c.y) + " Z" + str(c.z) + "\n" return output
def execute(self, obj): output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription if obj.Base: output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n" wires = [] for o in obj.Base: # we only consider the outer wire if this is a Face for w in o[0].Shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append (Part.Wire(tempedges)) if obj.Algorithm == "OCC Native": output += self.buildpathocc(obj, wires) output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value)+"\n" # print output if output == "": output += "(No commands processed)" if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def opExecute(self, obj): '''opExecute(obj) ... process engraving operation''' PathLog.track() zValues = [] if obj.StepDown.Value != 0: z = obj.StartDepth.Value - obj.StepDown.Value while z > obj.FinalDepth.Value: zValues.append(z) z -= obj.StepDown.Value zValues.append(obj.FinalDepth.Value) self.zValues = zValues output = '' try: if self.baseobject.isDerivedFrom('Sketcher::SketchObject') or \ self.baseobject.isDerivedFrom('Part::Part2DObject') or \ hasattr(self.baseobject, 'ArrayType'): output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid})) # we only consider the outer wire if this is a Face wires = [] for w in self.baseobject.Shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, wires, zValues) self.wires = wires elif isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet wires = [] for tag in self.baseobject.Proxy.getTags(self.baseobject, transform=True): output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid})) tagWires = [] for w in tag.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) tagWires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, tagWires, zValues) wires.extend(tagWires) self.wires = wires else: raise ValueError('Unknown baseobject type for engraving') output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid})) except Exception as e: #PathLog.error("Exception: %s" % e) PathLog.error(translate("Path", "The Job Base Object has no engraveable element. Engraving operation will produce no output."))
def _buildPathLibarea(self, obj, edgelist): import PathScripts.PathKurveUtils as PathKurveUtils import math import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) output = "" output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint) roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 if obj.UseComp is False: obj.Side = 'On' else: if obj.Direction == 'CW': obj.Side = 'Left' else: obj.Side = 'Right' PathKurveUtils.clear_tags() for i in range(len(obj.locs)): tag = obj.locs[i] h = obj.heights[i] l = obj.lengths[i] a = math.radians(obj.angles[i]) PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h) depthparams = depth_params( obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2( curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def _buildPathLibarea(self, obj, edgelist): import PathScripts.PathKurveUtils as PathKurveUtils # import math # import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) output = "" output += "G0 Z" + str( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" curve = PathKurveUtils.makeAreaCurve(edgelist, obj.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 or probably other features in heekscnc''' # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC) '''The following calls the original procedure from h toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile. This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16''' roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2(curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def _buildPathLibarea(self, obj, edgelist): import PathScripts.PathKurveUtils as PathKurveUtils # import math # import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) output = "" output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" curve = PathKurveUtils.makeAreaCurve(edgelist, obj.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 or probably other features in heekscnc''' # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC) '''The following calls the original procedure from h toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile. This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16''' roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 depthparams = depth_params( obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2( curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def _buildPathLibarea(self, obj, edgelist): import PathScripts.PathKurveUtils as PathKurveUtils # import math # import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) output = "" output += "G0 Z" + str( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" curve = PathKurveUtils.makeAreaCurve(edgelist, obj.Direction, startpoint, endpoint) roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 if obj.UseComp is False: obj.Side = 'On' else: if obj.Direction == 'CW': obj.Side = 'Left' else: obj.Side = 'Right' depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown.Value, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2(curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def profile(offset_curve, side_of_line, radius=1.0, vertfeed=0.0, horizfeed=0.0, offset_extra=0.0, rapid_safety_space=None, clearance=None, start_depth=None, stepdown=None, final_depth=None, use_CRC=False, roll_on=None, roll_off=None, roll_start=False, roll_end=True, roll_radius=None, roll_start_pt=None, roll_end_pt=None): output = "" output += "G0 Z" + str(clearance) + "\n" # print("in profile: 151") # offset_curve = area.Curve(curve) if offset_curve.getNumVertices() <= 1: raise Exception("Sketch has no elements!") if side_of_line == "On": use_CRC = False elif (side_of_line == "Left") or (side_of_line == "Right"): # get tool radius plus little bit of extra offset, if needed to clean # up profile a little more offset = radius + offset_extra if side_of_line == 'Left': offset_curve.Offset(offset) else: offset_curve.Offset(-offset) if offset_curve is False: raise Exception("couldn't offset kurve " + str(offset_curve)) else: raise Exception("Side must be 'Left','Right', or 'On'") # ========================================================================= # #roll_on roll_off section # roll_on_curve = area.Curve() # if offset_curve.getNumVertices() <= 1: return # first_span = offset_curve.GetFirstSpan() # if roll_on == None: # rollstart = first_span.p # elif roll_on == 'auto': # if roll_radius < 0.0000000001: # rollstart = first_span.p # v = first_span.GetVector(0.0) # if direction == 'right': # off_v = area.Point(v.y, -v.x) # else: # off_v = area.Point(-v.y, v.x) # rollstart = first_span.p + off_v * roll_radius # else: # rollstart = roll_on # # rvertex = area.Vertex(first_span.p) # # if first_span.p == rollstart: # rvertex.type = 0 # else: # v = first_span.GetVector(0.0) # get start direction # rvertex.c, rvertex.type = area.TangentialArc(first_span.p, rollstart, -v) # rvertex.type = -rvertex.type # because TangentialArc was used in reverse # # add a start roll on point # roll_on_curve.append(rollstart) # # # add the roll on arc # roll_on_curve.append(rvertex) # #end of roll_on roll_off section # ========================================================================= # do multiple depths layer_count = int((start_depth - final_depth) / stepdown) if layer_count * stepdown + 0.00001 < start_depth - final_depth: layer_count += 1 # current_start_depth = start_depth prev_depth = start_depth for i in range(1, layer_count + 1): if i == layer_count: depth = final_depth else: depth = start_depth - i * stepdown mat_depth = prev_depth start_z = mat_depth # first move output += "G0 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\ " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) +\ " Z" + str(PathUtils.fmt(mat_depth + rapid_safety_space)) + "\n" # feed down to depth mat_depth = depth if start_z > mat_depth: mat_depth = start_z # feed down in Z output += "G1 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\ " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) + " Z" + str(PathUtils.fmt(depth)) +\ " F" + str(PathUtils.fmt(vertfeed)) + "\n" if use_CRC: if side_of_line == 'left': output += "G41" + "\n" else: output += "G42" + "\n" # cut the main kurve current_perim = 0.0 lastx = offset_curve.GetFirstSpan().p.x lasty = offset_curve.GetFirstSpan().p.y for span in offset_curve.GetSpans(): current_perim += span.Length() if span.v.type == 0: # line # feed(span.v.p.x, span.v.p.y, ez) output += "G1 X" + str(PathUtils.fmt(span.v.p.x)) + " Y" + str(PathUtils.fmt(span.v.p.y)) +\ " Z" + str(PathUtils.fmt(depth)) + " F" + \ str(PathUtils.fmt(horizfeed)) + "\n" lastx = span.v.p.x lasty = span.v.p.y elif (span.v.type == 1) or (span.v.type == -1): if span.v.type == 1: # anti-clockwise arc command = 'G3' elif span.v.type == -1: # clockwise arc command = 'G2' arc_I = span.v.c.x - lastx arc_J = span.v.c.y - lasty output += command + "X" + str(PathUtils.fmt( span.v.p.x)) + " Y" + str(PathUtils.fmt( span.v.p.y)) # +" Z"+ str(PathUtils.fmt(depth)) output += " I" + str(PathUtils.fmt(arc_I)) + " J" + str( PathUtils.fmt(arc_J)) + " F" + str( PathUtils.fmt(horizfeed) ) + '\n' # " K"+str(PathUtils.fmt(depth)) +"\n" lastx = span.v.p.x lasty = span.v.p.y else: raise Exception("valid geometry identifier needed") if use_CRC: # end_CRC() output += "G40" + "\n" # rapid up to the clearance height output += "G0 Z" + str(PathUtils.fmt(clearance)) + "\n" del offset_curve return output
def profile(curve, side_of_line, radius=1.0, vertfeed=0.0, horizfeed=0.0, offset_extra=0.0, rapid_safety_space=None, clearance=None, start_depth=None, stepdown=None, final_depth=None, use_CRC=False, roll_on=None, roll_off=None, roll_start=False, roll_end=True, roll_radius=None, roll_start_pt=None, roll_end_pt=None): output = "" output += "G0 Z" + str(clearance) + "\n" print "in profile: 151" offset_curve = area.Curve(curve) if offset_curve.getNumVertices() <= 1: raise Exception, "Sketch has no elements!" if side_of_line == "On": use_CRC = False elif (side_of_line == "Left") or (side_of_line == "Right"): # get tool radius plus little bit of extra offset, if needed to clean # up profile a little more offset = radius + offset_extra if side_of_line == 'Left': offset_curve.Offset(offset) else: offset_curve.Offset(-offset) if offset_curve is False: raise Exception, "couldn't offset kurve " + str(offset_curve) else: raise Exception, "Side must be 'Left','Right', or 'On'" # ========================================================================= # #roll_on roll_off section # roll_on_curve = area.Curve() # if offset_curve.getNumVertices() <= 1: return # first_span = offset_curve.GetFirstSpan() # if roll_on == None: # rollstart = first_span.p # elif roll_on == 'auto': # if roll_radius < 0.0000000001: # rollstart = first_span.p # v = first_span.GetVector(0.0) # if direction == 'right': # off_v = area.Point(v.y, -v.x) # else: # off_v = area.Point(-v.y, v.x) # rollstart = first_span.p + off_v * roll_radius # else: # rollstart = roll_on # # rvertex = area.Vertex(first_span.p) # # if first_span.p == rollstart: # rvertex.type = 0 # else: # v = first_span.GetVector(0.0) # get start direction # rvertex.c, rvertex.type = area.TangentialArc(first_span.p, rollstart, -v) # rvertex.type = -rvertex.type # because TangentialArc was used in reverse # # add a start roll on point # roll_on_curve.append(rollstart) # # # add the roll on arc # roll_on_curve.append(rvertex) # #end of roll_on roll_off section # ========================================================================= # do multiple depths layer_count = int((start_depth - final_depth) / stepdown) if layer_count * stepdown + 0.00001 < start_depth - final_depth: layer_count += 1 current_start_depth = start_depth prev_depth = start_depth for i in range(1, layer_count + 1): if i == layer_count: depth = final_depth else: depth = start_depth - i * stepdown mat_depth = prev_depth start_z = mat_depth # first move output += "G0 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\ " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) +\ " Z" + str(PathUtils.fmt(mat_depth + rapid_safety_space)) + "\n" # feed down to depth mat_depth = depth if start_z > mat_depth: mat_depth = start_z # feed down in Z output += "G1 X" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.x)) +\ " Y" + str(PathUtils.fmt(offset_curve.GetFirstSpan().p.y)) + " Z" + str(PathUtils.fmt(depth)) +\ " F" + str(PathUtils.fmt(vertfeed)) + "\n" if use_CRC: if side_of_line == 'left': output += "G41" + "\n" else: output += "G42" + "\n" # cut the main kurve current_perim = 0.0 lastx = offset_curve.GetFirstSpan().p.x lasty = offset_curve.GetFirstSpan().p.y for span in offset_curve.GetSpans(): current_perim += span.Length() if span.v.type == 0: # line # feed(span.v.p.x, span.v.p.y, ez) output += "G1 X" + str(PathUtils.fmt(span.v.p.x)) + " Y" + str(PathUtils.fmt(span.v.p.y)) +\ " Z" + str(PathUtils.fmt(depth)) + " F" + \ str(PathUtils.fmt(horizfeed)) + "\n" lastx = span.v.p.x lasty = span.v.p.y elif (span.v.type == 1) or (span.v.type == -1): if span.v.type == 1: # anti-clockwise arc command = 'G3' elif span.v.type == -1: # clockwise arc command = 'G2' arc_I = span.v.c.x - lastx arc_J = span.v.c.y - lasty output += command + "X" + str(PathUtils.fmt(span.v.p.x)) + " Y" + str( PathUtils.fmt(span.v.p.y)) # +" Z"+ str(PathUtils.fmt(depth)) output += " I" + str(PathUtils.fmt(arc_I)) + " J" + str(PathUtils.fmt(arc_J)) + " F" + str( PathUtils.fmt(horizfeed)) + '\n' # " K"+str(PathUtils.fmt(depth)) +"\n" lastx = span.v.p.x lasty = span.v.p.y else: raise Exception, "valid geometry identifier needed" if use_CRC: # end_CRC() output += "G40" + "\n" # rapid up to the clearance height output += "G0 Z" + str(PathUtils.fmt(clearance)) + "\n" del offset_curve return output
def execute(self, obj): PathLog.track() output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 if not obj.Base: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return holes = self.findHoles(obj, baseobject.Shape) for hole in holes: self.addDrillableLocation(obj, baseobject, hole[0]) locations = [] output = "(Begin Drilling)\n" if obj.Base: for loc in obj.Base: #print loc for sub in loc[1]: #locations.append(self._findDrillingVector(loc)) if "Face" in sub or "Edge" in sub: s = getattr(loc[0].Shape, sub) else: s = loc[0].Shape if s.ShapeType in ['Wire', 'Edge']: X = s.Edges[0].Curve.Center.x Y = s.Edges[0].Curve.Center.y Z = s.Edges[0].Curve.Center.z elif s.ShapeType in ['Vertex']: X = s.Point.x Y = s.Point.y Z = s.Point.z elif s.ShapeType in ['Face']: #if abs(s.normalAt(0, 0).z) == 1: # horizontal face X = s.CenterOfMass.x Y = s.CenterOfMass.y Z = s.CenterOfMass.z locations.append(FreeCAD.Vector(X, Y, Z)) output += "G90 G98\n" # rapid to clearance height output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p.x) + \ " Y" + fmt(p.y) + \ " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def buildpathocc(self, obj, wires, zValues): '''buildpathocc(obj, wires, zValues) ... internal helper function to generate engraving commands.''' PathLog.track() output = "" for wire in wires: offset = wire # reorder the wire offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex) last = None for z in zValues: if last: self.commandlist.append(Path.Command('G1', {'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed})) for edge in offset.Edges: if not last: # we set the first move to our first point last = edge.Vertexes[0].Point output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) # Rapid to starting position self.commandlist.append(Path.Command('G0', {'X': last.x, 'Y': last.y, 'Z': obj.ClearanceHeight.Value, 'F': self.horizRapid})) output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) # Rapid to safe height self.commandlist.append(Path.Command('G0', {'X': last.x, 'Y': last.y, 'Z': obj.SafeHeight.Value, 'F': self.vertRapid})) output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(z) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth self.commandlist.append(Path.Command('G0', {'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed})) if isinstance(edge.Curve, Part.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: output += "G3" output += " X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(z) output += " I" + PathUtils.fmt(relcenter.x) + " J" + PathUtils.fmt(relcenter.y) + " K" + PathUtils.fmt(relcenter.z) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" cmd = 'G2' if v1.cross(v2).z < 0 else 'G3' args = {} args['X'] = point.x args['Y'] = point.y args['Z'] = z args['I'] = relcenter.x args['J'] = relcenter.y args['K'] = relcenter.z args['F'] = self.horizFeed self.commandlist.append(Path.Command(cmd, args)) last = point else: point = edge.Vertexes[-1].Point if point == last: # edges can come flipped point = edge.Vertexes[0].Point output += "G1 X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(z) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" self.commandlist.append(Path.Command('G1', {'X': point.x, 'Y': point.y, 'Z': z, 'F': self.horizFeed})) last = point output += "G0 Z " + PathUtils.fmt(obj.ClearanceHeight.Value) self.commandlist.append(Path.Command('G0', {'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid})) return output
def _buildPathLibarea(self, obj, edgelist, isHole): import PathScripts.PathKurveUtils as PathKurveUtils import math import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) # Reverse the direction for holes if isHole: direction = "CW" if obj.Direction == "CCW" else "CCW" else: direction = obj.Direction output = "" output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" 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 or probably other features in heekscnc''' # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC) '''The following calls the original procedure from h toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile. This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16''' roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 ''' Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils. I need to access the location vector, length, angle in radians and height. ''' PathKurveUtils.clear_tags() for i in range(len(obj.locs)): tag = obj.locs[i] h = obj.heights[i] l = obj.lengths[i] a = math.radians(obj.angles[i]) PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h) depthparams = depth_params( obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2( curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def execute(self, obj): PathLog.track() output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) # PathUtils.getTool(obj, toolLoad.ToolNumber) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 wires = [] parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return try: if baseobject.isDerivedFrom('Sketcher::SketchObject') or \ baseobject.isDerivedFrom('Part::Part2DObject'): output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" # we only consider the outer wire if this is a Face for w in baseobject.Shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) if obj.Algorithm == "OCC Native": output += self.buildpathocc(obj, wires) elif isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet shapes = baseobject.Proxy.getTags(baseobject, transform=True) for shape in shapes: output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" for w in shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) if obj.Algorithm == "OCC Native": output += self.buildpathocc(obj, wires) else: raise ValueError('Unknown baseobject type for engraving') output += "G0 Z" + PathUtils.fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" except: FreeCAD.Console.PrintError("The Job Base Object has no engraveable element. Engraving operation will produce no output.") # print output if output == "": output += "(No commands processed)" if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def _buildPathLibarea(self, obj, edgelist, isHole): import PathScripts.PathKurveUtils as PathKurveUtils import math import area output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' if obj.StartPoint and obj.UseStartPoint: startpoint = obj.StartPoint else: startpoint = None if obj.EndPoint and obj.UseEndPoint: endpoint = obj.EndPoint else: endpoint = None PathKurveUtils.output('mem') PathKurveUtils.feedrate_hv(self.horizFeed, self.vertFeed) # Reverse the direction for holes if isHole: direction = "CW" if obj.Direction == "CCW" else "CCW" else: direction = obj.Direction output = "" output += "G0 Z" + str( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" 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 or probably other features in heekscnc''' # output += PathKurveUtils.profile(curve, side, radius, vf, hf, offset_extra, rapid_safety_space, clearance, start_depth, step_down, final_depth, use_CRC) '''The following calls the original procedure from h toolLoad = obj.activeTCeekscnc profile function. This, in turn, calls many other procedures to modify the profile. This procedure is hacked together from heekscnc and has not been thoroughly reviewed or understood for FreeCAD. It can probably be thoroughly optimized and improved but it'll take a smarter mind than mine to do it. -sliptonic Feb16''' roll_radius = 2.0 extend_at_start = 0.0 extend_at_end = 0.0 lead_in_line_len = 0.0 lead_out_line_len = 0.0 ''' Right here, I need to know the Holding Tags group from the tree that refers to this profile operation and build up the tags for PathKurve Utils. I need to access the location vector, length, angle in radians and height. ''' PathKurveUtils.clear_tags() for i in range(len(obj.locs)): tag = obj.locs[i] h = obj.heights[i] l = obj.lengths[i] a = math.radians(obj.angles[i]) PathKurveUtils.add_tag(area.Point(tag.x, tag.y), l, a, h) depthparams = depth_params(obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, 0.0, obj.FinalDepth.Value, None) PathKurveUtils.profile2(curve, obj.Side, self.radius, self.vertFeed, self.horizFeed, self.vertRapid, self.horizRapid, obj.OffsetExtra.Value, roll_radius, None, None, depthparams, extend_at_start, extend_at_end, lead_in_line_len, lead_out_line_len) output += PathKurveUtils.retrieve_gcode() return output
def opExecute(self, obj): '''opExecute(obj) ... process engraving operation''' PathLog.track() zValues = [] if obj.StepDown.Value != 0: z = obj.StartDepth.Value - obj.StepDown.Value while z > obj.FinalDepth.Value: zValues.append(z) z -= obj.StepDown.Value zValues.append(obj.FinalDepth.Value) self.zValues = zValues output = '' try: if self.baseobject.isDerivedFrom('Sketcher::SketchObject') or \ self.baseobject.isDerivedFrom('Part::Part2DObject') or \ hasattr(self.baseobject, 'ArrayType'): output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" self.commandlist.append( Path.Command('G0', { 'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid })) # we only consider the outer wire if this is a Face wires = [] for w in self.baseobject.Shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, wires, zValues) self.wires = wires elif isinstance(self.baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet wires = [] for tag in self.baseobject.Proxy.getTags(self.baseobject, transform=True): output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" self.commandlist.append( Path.Command('G0', { 'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid })) tagWires = [] for w in tag.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) tagWires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, tagWires, zValues) wires.extend(tagWires) self.wires = wires elif obj.Base: wires = [] for base, subs in obj.Base: edges = [] for sub in subs: edges.extend(base.Shape.getElement(sub).Edges) shapeWires = adjustWirePlacement( obj, base, TechDraw.edgeWalker(edges)) wires.extend(shapeWires) output += self.buildpathocc(obj, wires, zValues) self.wires = wires elif not obj.BaseShapes: raise ValueError( translate('PathEngrave', "Unknown baseobject type for engraving (%s)") % (obj.Base)) if obj.BaseShapes: wires = [] for shape in obj.BaseShapes: shapeWires = adjustWirePlacement(obj, shape, shape.Shape.Wires) output += self.buildpathocc(obj, shapeWires, zValues) wires.extend(shapeWires) self.wires = wires output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" self.commandlist.append( Path.Command('G0', { 'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid })) except Exception as e: PathLog.error(e) traceback.print_exc() PathLog.error( translate( 'PathEngrave', 'The Job Base Object has no engraveable element. Engraving operation will produce no output.' ))
def execute(self, obj): PathLog.track() if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError( "No Tool Controller is selected. We need a tool to build a Path." ) return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool( toolLoad) # PathUtils.getTool(obj, toolLoad.ToolNumber) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError( "No Tool found or diameter is zero. We need a tool to build a Path." ) return else: self.radius = tool.Diameter / 2 wires = [] parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return try: if baseobject.isDerivedFrom('Sketcher::SketchObject') or \ baseobject.isDerivedFrom('Part::Part2DObject') or \ hasattr(baseobject, 'ArrayType'): output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" # we only consider the outer wire if this is a Face for w in baseobject.Shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, wires) elif isinstance(baseobject.Proxy, ArchPanel.PanelSheet): # process the sheet shapes = baseobject.Proxy.getTags(baseobject, transform=True) for shape in shapes: output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" for w in shape.Wires: tempedges = PathUtils.cleanedges(w.Edges, 0.5) wires.append(Part.Wire(tempedges)) output += self.buildpathocc(obj, wires) else: raise ValueError('Unknown baseobject type for engraving') output += "G0 Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" except: FreeCAD.Console.PrintError( "The Job Base Object has no engraveable element. Engraving operation will produce no output." ) # print output if output == "": output += "(No commands processed)" path = Path.Path(output) obj.Path = path
def execute(self, obj): PathLog.track() output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError("No Tool Controller is selected. We need a tool to build a Path.") return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError("No Tool found or diameter is zero. We need a tool to build a Path.") return else: self.radius = tool.Diameter/2 if len(obj.Names) == 0: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return # Arch PanelSheet if hasattr(baseobject, "Proxy"): holes = [] if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): baseobject.Proxy.execute(baseobject) i = 0 holeshapes = baseobject.Proxy.getHoles(baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool(obj.ToolController).Diameter for holeshape in holeshapes: PathLog.debug('Entering new HoleShape') for wire in holeshape.Wires: PathLog.debug('Entering new Wire') for edge in wire.Edges: if PathUtils.isDrillable(baseobject, edge, tooldiameter): PathLog.debug('Found drillable hole edges: {}'.format(edge)) x = edge.Curve.Center.x y = edge.Curve.Center.y diameter = edge.BoundBox.XLength holes.append({'x': x, 'y': y, 'featureName': baseobject.Name+'.'+'Drill'+str(i), 'd': diameter}) i = i + 1 else: holes = self.findHoles(obj, baseobject.Shape) for i in range(len(holes)): holes[i]['featureName'] = baseobject.Name + '.' + holes[i]['featureName'] names = [] positions = [] enabled = [] diameters = [] for h in holes: if len(names) == 0: self.findHeights(obj, baseobject, h) names.append(h['featureName']) positions.append(FreeCAD.Vector(h['x'], h['y'], 0)) enabled.append(1) diameters.append(h['d']) obj.Names = names obj.Positions = positions obj.Enabled = enabled obj.Diameters = diameters locations = [] output = "(Begin Drilling)\n" for i in range(len(obj.Names)): if obj.Enabled[i] > 0: locations.append({'x': obj.Positions[i].x, 'y': obj.Positions[i].y}) if len(locations) > 0: locations = PathUtils.sort_jobs(locations, ['x', 'y']) output += "G90 G98\n" # rapid to clearance height output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0['x']) + " Y" + fmt(p0['y']) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0 and obj.PeckEnabled: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0 and obj.DwellEnabled: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p['x']) + \ " Y" + fmt(p['y']) + \ " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def buildpathocc(self, obj, wires, zValues): '''buildpathocc(obj, wires, zValues) ... internal helper function to generate engraving commands.''' PathLog.track() output = "" for wire in wires: offset = wire # reorder the wire offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex) last = None for z in zValues: if last: self.commandlist.append( Path.Command('G1', { 'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed })) for edge in offset.Edges: if not last: # we set the first move to our first point last = edge.Vertexes[0].Point output += "G0" + " X" + PathUtils.fmt( last.x ) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.horizRapid) # Rapid to starting position self.commandlist.append( Path.Command( 'G0', { 'X': last.x, 'Y': last.y, 'Z': obj.ClearanceHeight.Value, 'F': self.horizRapid })) output += "G0" + " X" + PathUtils.fmt( last.x) + " Y" + PathUtils.fmt( last.y ) + " Z" + PathUtils.fmt( obj.SafeHeight.Value) + "F " + PathUtils.fmt( self.horizRapid) # Rapid to safe height self.commandlist.append( Path.Command( 'G0', { 'X': last.x, 'Y': last.y, 'Z': obj.SafeHeight.Value, 'F': self.vertRapid })) output += "G1" + " X" + PathUtils.fmt( last.x) + " Y" + PathUtils.fmt( last.y ) + " Z" + PathUtils.fmt(z) + "F " + PathUtils.fmt( self.vertFeed) + "\n" # Vertical feed to depth self.commandlist.append( Path.Command( 'G0', { 'X': last.x, 'Y': last.y, 'Z': z, 'F': self.vertFeed })) if isinstance(edge.Curve, Part.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: output += "G3" output += " X" + PathUtils.fmt( point.x) + " Y" + PathUtils.fmt( point.y) + " Z" + PathUtils.fmt(z) output += " I" + PathUtils.fmt( relcenter.x) + " J" + PathUtils.fmt( relcenter.y) + " K" + PathUtils.fmt( relcenter.z) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" cmd = 'G2' if v1.cross(v2).z < 0 else 'G3' args = {} args['X'] = point.x args['Y'] = point.y args['Z'] = z args['I'] = relcenter.x args['J'] = relcenter.y args['K'] = relcenter.z args['F'] = self.horizFeed self.commandlist.append(Path.Command(cmd, args)) last = point else: point = edge.Vertexes[-1].Point if point == last: # edges can come flipped point = edge.Vertexes[0].Point output += "G1 X" + PathUtils.fmt( point.x) + " Y" + PathUtils.fmt( point.y) + " Z" + PathUtils.fmt(z) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" self.commandlist.append( Path.Command( 'G1', { 'X': point.x, 'Y': point.y, 'Z': z, 'F': self.horizFeed })) last = point output += "G0 Z " + PathUtils.fmt(obj.ClearanceHeight.Value) self.commandlist.append( Path.Command('G0', { 'Z': obj.ClearanceHeight.Value, 'F': self.vertRapid })) return output
def execute(self, obj): output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' toolLoad = PathUtils.getLastToolLoad(obj) if toolLoad is None or toolLoad.ToolNumber == 0: self.vertFeed = 100 self.horizFeed = 100 self.vertRapid = 100 self.horizRapid = 100 self.radius = 0.25 obj.ToolNumber = 0 obj.ToolDescription = "UNDEFINED" else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = PathUtils.getTool(obj, toolLoad.ToolNumber) if tool.Diameter == 0: self.radius = 0.25 else: self.radius = tool.Diameter/2 obj.ToolNumber = toolLoad.ToolNumber obj.ToolDescription = toolLoad.Name if obj.UserLabel == "": obj.Label = obj.Name + " :" + obj.ToolDescription else: obj.Label = obj.UserLabel + " :" + obj.ToolDescription locations = [] output = "(Begin Drilling)\n" if obj.Base: for loc in obj.Base: #print loc for sub in loc[1]: #locations.append(self._findDrillingVector(loc)) if "Face" in sub or "Edge" in sub: s = getattr(loc[0].Shape, sub) else: s = loc[0].Shape if s.ShapeType in ['Wire', 'Edge']: X = s.Edges[0].Curve.Center.x Y = s.Edges[0].Curve.Center.y Z = s.Edges[0].Curve.Center.z elif s.ShapeType in ['Vertex']: X = s.Point.x Y = s.Point.y Z = s.Point.z elif s.ShapeType in ['Face']: #if abs(s.normalAt(0, 0).z) == 1: # horizontal face X = s.CenterOfMass.x Y = s.CenterOfMass.y Z = s.CenterOfMass.z locations.append(FreeCAD.Vector(X, Y, Z)) output += "G90 G98\n" # rapid to clearance height output += "G0 Z" + str(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0.x) + " Y" + fmt(p0.y) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p.x) + \ " Y" + fmt(p.y) + \ " Z" + fmt(obj.FinalDepth.Value) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" # path = Path.Path(output) # obj.Path = path if obj.Active: path = Path.Path(output) obj.Path = path obj.ViewObject.Visibility = True else: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False
def buildpathocc(self, obj, shape): """Build pocket Path using Native OCC algorithm.""" import Part import DraftGeomUtils from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge, depth_params FreeCAD.Console.PrintMessage(translate("PathPocket", "Generating toolpath with OCC native offsets.\n")) extraoffset = obj.MaterialAllowance.Value # Build up the offset loops output = "" if obj.Comment != "": output += '(' + str(obj.Comment)+')\n' output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" offsets = [] nextradius = self.radius + extraoffset result = DraftGeomUtils.pocket2d(shape, nextradius) while result: offsets.extend(result) nextradius += (self.radius * 2) * (float(obj.StepOver)/100) result = DraftGeomUtils.pocket2d(shape, nextradius) # revert the list so we start with the outer wires if obj.StartAt != 'Edge': offsets.reverse() plungePos = None rampEdge = None if obj.UseEntry: # Try to find an entry location toold = self.radius*2 helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + obj.HelixSize)) if helixBounds: rampD = obj.RampSize if obj.StartAt == 'Edge': plungePos = helixBounds[0].Edges[0].Vertexes[0].Point 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 < self.radius * (1 + obj.HelixSize): plungePos = None FreeCAD.Console.PrintError(translate("PathPocket", "Helical Entry location not found.\n")) # 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 plungePos is None: # If we didn't find a place to helix, how about a ramp? FreeCAD.Console.PrintMessage(translate("PathPocket", "Attempting ramp entry.\n")) if (offsets[0].Edges[0].Length >= toold * 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 >= toold * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)): rampEdge = offsets[0].Edges[-1] else: FreeCAD.Console.PrintError(translate("PathPocket", "Ramp Entry location not found.\n")) # 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 # For helix-ing/ramping, know where we were last time # FIXME: Can probably get this from the "machine"? lastZ = obj.ClearanceHeight.Value startPoint = None depthparams = depth_params( obj.ClearanceHeight.Value, obj.SafeHeight.Value, obj.StartDepth.Value, obj.StepDown, obj.FinishDepth.Value, obj.FinalDepth.Value) for vpos in depthparams.get_depths(): 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, self.radius*2, obj.HelixSize, self.horizFeed) 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: 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 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\ " Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n" first = False # then move slow down to our starting point for our profile last = edge.Vertexes[0].Point output += "G1 X" + fmt(last.x) + " Y" + fmt(last.y) + " Z" + fmt(vpos) + " F" + fmt(self.vertFeed) + "\n" 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: output += "G3" output += " X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos) output += " I" + fmt(relcenter.x) + " J" + fmt(relcenter.y) + " K" + fmt(relcenter.z) + " F" + fmt(self.horizFeed) 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" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos) + " F" + fmt(self.horizFeed) + "\n" last = point # move back up output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n" return output
def buildpathocc(self, obj, wires): import Part import DraftGeomUtils output = "" # absolute coords, millimeters, cancel offsets for wire in wires: offset = wire # reorder the wire offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex) # we create the path from the offset shape last = None for edge in offset.Edges: if not last: # we set the first move to our first point last = edge.Vertexes[0].Point output += "G0" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.SafeHeight.Value) # Rapid sto starting position output += "G1" + " X" + PathUtils.fmt(last.x) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) + "F " + PathUtils.fmt(self.vertFeed) + "\n" # Vertical feed to depth if isinstance(edge.Curve, Part.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: output += "G3" output += " X" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) output += " I" + PathUtils.fmt(relcenter.x) + " J" + PathUtils.fmt(relcenter.y) + " K" + PathUtils.fmt(relcenter.z) output += " F " + PathUtils.fmt(self.horizFeed) 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" + PathUtils.fmt(point.x) + " Y" + PathUtils.fmt(point.y) + " Z" + PathUtils.fmt(obj.FinalDepth.Value) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" last = point output += "G0 Z " + PathUtils.fmt(obj.SafeHeight.Value) return output
def execute(self, obj): PathLog.track() if not obj.Active: path = Path.Path("(inactive operation)") obj.Path = path obj.ViewObject.Visibility = False return output = "" if obj.Comment != "": output += '(' + str(obj.Comment) + ')\n' toolLoad = obj.ToolController if toolLoad is None or toolLoad.ToolNumber == 0: FreeCAD.Console.PrintError( "No Tool Controller is selected. We need a tool to build a Path." ) return else: self.vertFeed = toolLoad.VertFeed.Value self.horizFeed = toolLoad.HorizFeed.Value self.vertRapid = toolLoad.VertRapid.Value self.horizRapid = toolLoad.HorizRapid.Value tool = toolLoad.Proxy.getTool(toolLoad) if not tool or tool.Diameter == 0: FreeCAD.Console.PrintError( "No Tool found or diameter is zero. We need a tool to build a Path." ) return else: self.radius = tool.Diameter / 2 tiplength = 0.0 if obj.AddTipLength: tiplength = PathUtils.drillTipLength(tool) if len(obj.Names) == 0: parentJob = PathUtils.findParentJob(obj) if parentJob is None: return baseobject = parentJob.Base if baseobject is None: return # Arch PanelSheet if hasattr(baseobject, "Proxy"): holes = [] if isinstance(baseobject.Proxy, ArchPanel.PanelSheet): baseobject.Proxy.execute(baseobject) i = 0 holeshapes = baseobject.Proxy.getHoles(baseobject, transform=True) tooldiameter = obj.ToolController.Proxy.getTool( obj.ToolController).Diameter for holeshape in holeshapes: PathLog.debug('Entering new HoleShape') for wire in holeshape.Wires: PathLog.debug('Entering new Wire') for edge in wire.Edges: if PathUtils.isDrillable( baseobject, edge, tooldiameter): PathLog.debug( 'Found drillable hole edges: {}'. format(edge)) x = edge.Curve.Center.x y = edge.Curve.Center.y diameter = edge.BoundBox.XLength holes.append({ 'x': x, 'y': y, 'featureName': baseobject.Name + '.' + 'Drill' + str(i), 'd': diameter }) i = i + 1 else: holes = self.findHoles(obj, baseobject.Shape) for i in range(len(holes)): holes[i]['featureName'] = baseobject.Name + '.' + holes[i][ 'featureName'] names = [] positions = [] enabled = [] diameters = [] for h in holes: if len(names) == 0: self.setDepths(obj, baseobject, h) names.append(h['featureName']) positions.append(FreeCAD.Vector(h['x'], h['y'], 0)) enabled.append(1) diameters.append(h['d']) obj.Names = names obj.Positions = positions obj.Enabled = enabled obj.Diameters = diameters locations = [] output = "(Begin Drilling)\n" for i in range(len(obj.Names)): if obj.Enabled[i] > 0: locations.append({ 'x': obj.Positions[i].x, 'y': obj.Positions[i].y }) if len(locations) > 0: locations = PathUtils.sort_jobs(locations, ['x', 'y']) output += "G90 " + obj.ReturnLevel + "\n" # rapid to clearance height output += "G0 Z" + str( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" # rapid to first hole location, with spindle still retracted: p0 = locations[0] output += "G0 X" + fmt(p0['x']) + " Y" + fmt( p0['y']) + "F " + PathUtils.fmt(self.horizRapid) + "\n" # move tool to clearance plane output += "G0 Z" + fmt( obj.ClearanceHeight.Value) + "F " + PathUtils.fmt( self.vertRapid) + "\n" pword = "" qword = "" if obj.PeckDepth.Value > 0 and obj.PeckEnabled: cmd = "G83" qword = " Q" + fmt(obj.PeckDepth.Value) elif obj.DwellTime > 0 and obj.DwellEnabled: cmd = "G82" pword = " P" + fmt(obj.DwellTime) else: cmd = "G81" for p in locations: output += cmd + \ " X" + fmt(p['x']) + \ " Y" + fmt(p['y']) + \ " Z" + fmt(obj.FinalDepth.Value - tiplength) + qword + pword + \ " R" + str(obj.RetractHeight.Value) + \ " F" + str(self.vertFeed) + "\n" \ output += "G80\n" path = Path.Path(output) obj.Path = path
def buildpathocc(self, obj, wires): import Part import DraftGeomUtils output = "" # absolute coords, millimeters, cancel offsets for wire in wires: offset = wire # reorder the wire offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex) # we create the path from the offset shape last = None for edge in offset.Edges: if not last: # we set the first move to our first point last = edge.Vertexes[0].Point output += "G0" + " X" + PathUtils.fmt( last.x ) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt( obj.SafeHeight.Value) # Rapid sto starting position output += "G1" + " X" + PathUtils.fmt( last.x ) + " Y" + PathUtils.fmt(last.y) + " Z" + PathUtils.fmt( obj.FinalDepth.Value) + "F " + PathUtils.fmt( self.vertFeed) + "\n" # Vertical feed to depth if isinstance(edge.Curve, Part.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: output += "G3" output += " X" + PathUtils.fmt( point.x) + " Y" + PathUtils.fmt( point.y) + " Z" + PathUtils.fmt( obj.FinalDepth.Value) output += " I" + PathUtils.fmt( relcenter.x) + " J" + PathUtils.fmt( relcenter.y) + " K" + PathUtils.fmt(relcenter.z) output += " F " + PathUtils.fmt(self.horizFeed) 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" + PathUtils.fmt( point.x) + " Y" + PathUtils.fmt( point.y) + " Z" + PathUtils.fmt( obj.FinalDepth.Value) output += " F " + PathUtils.fmt(self.horizFeed) output += "\n" last = point output += "G0 Z " + PathUtils.fmt(obj.SafeHeight.Value) return output