def getLeadStart(self, obj, queue, action): '''returns Lead In G-code.''' global currLocation results = [] # zdepth = currLocation["Z"] op = PathDressup.baseOp(obj.Base) tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value toolnummer = tc.ToolNumber # set the correct twist command if self.getDirectionOfPath(obj) == 'left': arcdir = "G3" else: arcdir = "G2" R = obj.Length.Value # Radius of roll or length if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.notice(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z)) else: p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base # PathLog.notice(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y)) v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) else: off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) offsetvector = FreeCAD.Vector(v.x*R, v.y*R, 0) # IJ if obj.RadiusCenter == 'Radius': leadstart = (p0.add(off_v)).sub(offsetvector) # Rmode else: leadstart = p0.add(off_v) # Dmode if action == 'start': extendcommand = Path.Command('G0', {"X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": op.ClearanceHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y, "Z": op.SafeHeight.Value}) results.append(extendcommand) if action == 'layer': if not obj.KeepToolDown: extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', {"X": leadstart.x, "Y": leadstart.y}) results.append(extendcommand) extendcommand = Path.Command('G1', {"X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed}) results.append(extendcommand) if obj.UseMashineCRC: if self.getDirectionOfPath(obj) == 'right': results.append(Path.Command('G42', {'D': toolnummer})) else: results.append(Path.Command('G41', {'D': toolnummer})) if obj.StyleOn == 'Arc': arcmove = Path.Command(arcdir, {"X": p0.x, "Y": p0.y, "I": offsetvector.x, "J": offsetvector.y, "F": horizFeed}) # add G2/G3 move results.append(arcmove) elif obj.StyleOn == 'Tangent': extendcommand = Path.Command('G1', {"X": p0.x, "Y": p0.y, "F": horizFeed}) results.append(extendcommand) else: PathLog.notice(" CURRENT_IN Perp") return results
def setup(self, obj, initial): PathLog.info("Here we go ... ") if initial: if hasattr(obj.Base, "BoneBlacklist"): # dressing up a bone dressup obj.Side = obj.Base.Side else: # otherwise dogbones are opposite of the base path's side side = Side.Right if hasattr(obj.Base, 'Side') and obj.Base.Side == 'Inside': side = Side.Left if hasattr(obj.Base, 'Directin') and obj.Base.Direction == 'CCW': side = Side.oppositeOf(side) obj.Side = side self.toolRadius = 5 tc = PathDressup.toolController(obj.Base) if tc is None or tc.ToolNumber == 0: self.toolRadius = 5 else: tool = tc.Proxy.getTool( tc) # PathUtils.getTool(obj, tc.ToolNumber) if not tool or tool.Diameter == 0: self.toolRadius = 5 else: self.toolRadius = tool.Diameter / 2 self.shapes = {} self.dbg = []
def SetupOperation(self, itool): self.operation = self.activeOps[itool] try: self.tool = PathDressup.toolController(self.operation).Tool except Exception: self.tool = None if (self.tool is not None): if isinstance(self.tool, Path.Tool): # handle legacy tools toolProf = self.CreateToolProfile( self.tool, Vector(0, 1, 0), Vector(0, 0, 0), float(self.tool.Diameter) / 2.0) self.cutTool.Shape = Part.makeSolid( toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1))) else: # handle tool bits self.cutTool.Shape = self.tool.Shape if not self.cutTool.Shape.isValid() or self.cutTool.Shape.isNull(): self.EndSimulation() raise RuntimeError( "Path Simulation: Error in tool geometry - {}".format( self.tool.Name)) self.cutTool.ViewObject.show() self.voxSim.SetToolShape(self.cutTool.Shape, 0.05 * self.accuracy) self.icmd = 0 self.curpos = FreeCAD.Placement(self.initialPos, self.stdrot) self.cutTool.Placement = self.curpos self.opCommands = self.operation.Path.Commands
def setup(self, obj, generate=False): PathLog.debug("setup") self.obj = obj try: pathData = PathData(obj) except ValueError: PathLog.error( translate( "Path_DressupTag", "Cannot insert holding tags for this path - please select a Profile path" ) + "\n") #if sys.version_info.major < 3: # traceback.print_exc(e) #else: # traceback.print_exc() return None self.toolRadius = PathDressup.toolController( obj.Base).Tool.Diameter / 2 self.pathData = pathData if generate: obj.Height = self.pathData.defaultTagHeight() obj.Width = self.pathData.defaultTagWidth() obj.Angle = self.pathData.defaultTagAngle() obj.Radius = self.pathData.defaultTagRadius() count = HoldingTagPreferences.defaultCount() self.generateTags(obj, count) return self.pathData
def setup(self, obj, initial): PathLog.info("Here we go ... ") if initial: if hasattr(obj.Base, "BoneBlacklist"): # dressing up a bone dressup obj.Side = obj.Base.Side else: # otherwise dogbones are opposite of the base path's side side = Side.Right if hasattr(obj.Base, 'Side') and obj.Base.Side == 'Inside': side = Side.Left if hasattr(obj.Base, 'Directin') and obj.Base.Direction == 'CCW': side = Side.oppositeOf(side) obj.Side = side self.toolRadius = 5 tc = PathDressup.toolController(obj.Base) if tc is None or tc.ToolNumber == 0: self.toolRadius = 5 else: tool = tc.Proxy.getTool(tc) # PathUtils.getTool(obj, tc.ToolNumber) if not tool or tool.Diameter == 0: self.toolRadius = 5 else: self.toolRadius = tool.Diameter / 2 self.shapes = {} self.dbg = []
def getLeadEnd(self, obj, queue, action): '''returns the Gcode of LeadOut.''' global currLocation results = [] horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value R = obj.Length.Value # Radius of roll or length # set the correct twist command if self.getDirectionOfPath(obj) == 'right': arcdir = "G2" else: arcdir = "G3" if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) else: # dealing with a circle p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) offsetvector = FreeCAD.Vector(v.x * R, v.y * R, 0.0) if obj.RadiusCenter == 'Radius': leadend = (p1.add(off_v)).add(offsetvector) # Rmode else: leadend = p1.add(off_v) # Dmode IJ = off_v # .negative() results.append(queue[1]) if obj.StyleOff == 'Arc': arcmove = Path.Command( arcdir, { "X": leadend.x, "Y": leadend.y, "I": IJ.x, "J": IJ.y, "F": horizFeed }) # add G2/G3 move results.append(arcmove) elif obj.StyleOff == 'Tangent': extendcommand = Path.Command( 'G1', { "X": leadend.x, "Y": leadend.y, "Z": currLocation["Z"], "F": horizFeed }) results.append(extendcommand) else: PathLog.notice(" CURRENT_IN Perp") if obj.UseMashineCRC: # crc off results.append(Path.Command('G40', {})) return results
def SetupOperation(self, itool): self.operation = self.activeOps[itool] try: self.tool = PathDressup.toolController(self.operation).Tool except: self.tool = None # if hasattr(self.operation, "ToolController"): # self.tool = self.operation.ToolController.Tool if (self.tool is not None): toolProf = self.CreateToolProfile(self.tool, Vector(0, 1, 0), Vector(0, 0, 0), self.tool.Diameter / 2.0) self.cutTool.Shape = Part.makeSolid(toolProf.revolve(Vector(0, 0, 0), Vector(0, 0, 1))) self.cutTool.ViewObject.show() self.voxSim.SetCurrentTool(self.tool) self.icmd = 0 self.curpos = FreeCAD.Placement(self.initialPos, self.stdrot) # self.cutTool.Placement = FreeCAD.Placement(self.curpos, self.stdrot) self.cutTool.Placement = self.curpos
def setup(self, obj, generate=False): PathLog.debug("setup") self.obj = obj try: pathData = PathData(obj) except ValueError: PathLog.error(translate("Path_DressupTag", "Cannot insert holding tags for this path - please select a Profile path")+"\n") return None self.toolRadius = PathDressup.toolController(obj.Base).Tool.Diameter / 2 self.pathData = pathData if generate: obj.Height = self.pathData.defaultTagHeight() obj.Width = self.pathData.defaultTagWidth() obj.Angle = self.pathData.defaultTagAngle() obj.Radius = self.pathData.defaultTagRadius() count = HoldingTagPreferences.defaultCount() self.generateTags(obj, count) return self.pathData
def getLeadEnd(self, obj, queue, action): '''returns the Gcode of LeadOut.''' global currLocation results = [] horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value R = obj.Length.Value # Radius of roll or length # set the correct twist command if self.getDirectionOfPath(obj) == 'right': arcdir = "G2" else: arcdir = "G3" if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) else: # dealing with a circle p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y*R, -v.x*R, 0.0) else: off_v = FreeCAD.Vector(-v.y*R, v.x*R, 0.0) offsetvector = FreeCAD.Vector(v.x*R, v.y*R, 0.0) if obj.RadiusCenter == 'Radius': leadend = (p1.add(off_v)).add(offsetvector) # Rmode else: leadend = p1.add(off_v) # Dmode IJ = off_v # .negative() #results.append(queue[1]) if obj.StyleOff == 'Arc': arcmove = Path.Command(arcdir, {"X": leadend.x, "Y": leadend.y, "I": IJ.x, "J": IJ.y, "F": horizFeed}) # add G2/G3 move results.append(arcmove) elif obj.StyleOff == 'Tangent': extendcommand = Path.Command('G1', {"X": leadend.x, "Y": leadend.y, "F": horizFeed}) results.append(extendcommand) else: PathLog.notice(" CURRENT_IN Perp") if obj.UseMashineCRC: # crc off results.append(Path.Command('G40', {})) return results
def getLeadEnd(self, obj, queue, action): '''returns the Gcode of LeadOut.''' # pylint: disable=unused-argument results = [] horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value R = obj.Length.Value # Radius of roll or length arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == 'right': arcdir = "G2" else: arcdir = "G3" if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) else: # dealing with a circle p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) # Check if we leave at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadOut) #PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move pij = copy.deepcopy(p0) pij.x += queue[1].Parameters['I'] pij.y += queue[1].Parameters['J'] ve = pij.sub(p1) if arcdir == queue[1].Name: arcs_identical = True if arcdir == "G2": vec_rot = self.rotate(ve, -90) else: vec_rot = self.rotate(ve, 90) vec_n = self.normalize(vec_rot) v = vec_n if arcdir == "G3": off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) else: off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) vec_inv = self.invert(vec_rot) vec_off = self.multiply(vec_inv, obj.ExtendLeadOut) offsetvector = FreeCAD.Vector(v.x * R - vec_off.x, v.y * R - vec_off.y, 0.0) if obj.RadiusCenter == 'Radius': leadend = (p1.add(off_v)).add(offsetvector) # Rmode if arcs_identical: t = p1.sub(leadend) t = p1.add(t) leadend = t off_v = self.multiply(off_v, -1) else: leadend = p1.add(off_v) # Dmode IJ = off_v # .negative() #results.append(queue[1]) if obj.StyleOff == 'Arc': if obj.ExtendLeadOut != 0: extendcommand = Path.Command('G1', { "X": p1.x - vec_off.x, "Y": p1.y - vec_off.y, "F": horizFeed }) results.append(extendcommand) arcmove = Path.Command( arcdir, { "X": leadend.x, "Y": leadend.y, "I": IJ.x, "J": IJ.y, "F": horizFeed }) # add G2/G3 move results.append(arcmove) elif obj.StyleOff == 'Tangent': extendcommand = Path.Command('G1', { "X": leadend.x, "Y": leadend.y, "F": horizFeed }) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") if obj.UseMachineCRC: # crc off results.append(Path.Command('G40', {})) return results
def createCommands(self, obj, edges): commands = [] for edge in edges: israpid = False for redge in self.rapids: if PathGeom.edgesMatch(edge, redge): israpid = True if israpid: v = edge.valueAt(edge.LastParameter) commands.append(Path.Command('G0', {'X': v.x, 'Y': v.y, 'Z': v.z})) else: commands.extend(PathGeom.cmdsForEdge(edge)) lastCmd = Path.Command('G0', {'X': 0.0, 'Y': 0.0, 'Z': 0.0}) outCommands = [] tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value if obj.RampFeedRate == "Horizontal Feed Rate": rampFeed = tc.HorizFeed.Value elif obj.RampFeedRate == "Vertical Feed Rate": rampFeed = tc.VertFeed.Value else: rampFeed = obj.CustomFeedRate.Value horizRapid = tc.HorizRapid.Value vertRapid = tc.VertRapid.Value for cmd in commands: params = cmd.Parameters zVal = params.get('Z', None) zVal2 = lastCmd.Parameters.get('Z', None) xVal = params.get('X', None) xVal2 = lastCmd.Parameters.get('X', None) yVal2 = lastCmd.Parameters.get('Y', None) yVal = params.get('Y', None) zVal = zVal and round(zVal, 8) zVal2 = zVal2 and round(zVal2, 8) if cmd.Name in ['G1', 'G2', 'G3', 'G01', 'G02', 'G03']: if zVal is not None and zVal2 != zVal: if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly(yVal, yVal2): # this is a straight plunge params['F'] = vertFeed else: # this is a ramp params['F'] = rampFeed else: params['F'] = horizFeed lastCmd = cmd elif cmd.Name in ['G0', 'G00']: if zVal is not None and zVal2 != zVal: params['F'] = vertRapid else: params['F'] = horizRapid lastCmd = cmd outCommands.append(Path.Command(cmd.Name, params)) return Path.Path(outCommands)
def createPath(self, obj, pathData, tags): PathLog.track() commands = [] lastEdge = 0 lastTag = 0 # sameTag = None t = 0 # inters = None edge = None segm = 50 if hasattr(obj, 'SegmentationFactor'): segm = obj.SegmentationFactor if segm <= 0: segm = 50 obj.SegmentationFactor = 50 self.mappers = [] mapper = None while edge or lastEdge < len(pathData.edges): PathLog.debug("------- lastEdge = %d/%d.%d/%d" % (lastEdge, lastTag, t, len(tags))) if not edge: edge = pathData.edges[lastEdge] debugEdge( edge, "======= new edge: %d/%d" % (lastEdge, len(pathData.edges))) lastEdge += 1 # sameTag = None if mapper: mapper.add(edge) if mapper.mappingComplete(): commands.extend(mapper.commands) edge = mapper.tail mapper = None else: edge = None if edge: tIndex = (t + lastTag) % len(tags) t += 1 i = tags[tIndex].intersects(edge, edge.FirstParameter) if i and self.isValidTagStartIntersection(edge, i): mapper = MapWireToTag(edge, tags[tIndex], i, segm, pathData.maxZ) self.mappers.append(mapper) edge = mapper.tail if not mapper and t >= len(tags): # gone through all tags, consume edge and move on if edge: debugEdge(edge, '++++++++') if pathData.rapid.isRapid(edge): v = edge.Vertexes[1] if not commands and PathGeom.isRoughly( 0, v.X) and PathGeom.isRoughly( 0, v.Y) and not PathGeom.isRoughly(0, v.Z): # The very first move is just to move to ClearanceHeight commands.append(Path.Command('G0', {'Z': v.Z})) else: commands.append( Path.Command('G0', { 'X': v.X, 'Y': v.Y, 'Z': v.Z })) else: commands.extend(PathGeom.cmdsForEdge(edge, segm=segm)) edge = None t = 0 lastCmd = Path.Command('G0', {'X': 0.0, 'Y': 0.0, 'Z': 0.0}) outCommands = [] tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value horizRapid = tc.HorizRapid.Value vertRapid = tc.VertRapid.Value for cmd in commands: params = cmd.Parameters zVal = params.get('Z', None) zVal2 = lastCmd.Parameters.get('Z', None) zVal = zVal and round(zVal, 8) zVal2 = zVal2 and round(zVal2, 8) if cmd.Name in ['G1', 'G2', 'G3', 'G01', 'G02', 'G03']: if False and zVal is not None and zVal2 != zVal: params['F'] = vertFeed else: params['F'] = horizFeed lastCmd = cmd elif cmd.Name in ['G0', 'G00']: if zVal is not None and zVal2 != zVal: params['F'] = vertRapid else: params['F'] = horizRapid lastCmd = cmd outCommands.append(Path.Command(cmd.Name, params)) return Path.Path(outCommands)
def toolRadius(self): return float(PathDressup.toolController( self.obj.Base).Tool.Diameter) / 2.0
def toolRadius(self): return PathDressup.toolController(self.obj.Base).Tool.Diameter / 2.0
def getLeadStart(self, obj, queue, action): """returns Lead In G-code.""" # Modified March 2022 by lcorley to support leadin extension results = [] op = PathDressup.baseOp(obj.Base) tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value toolnummer = tc.ToolNumber arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == "left": arcdir = "G3" else: arcdir = "G2" R = obj.Length.Value # Radius of roll or length if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) PathLog.debug(" CURRENT_IN Line : P0 Z:{} p1 Z:{}".format( p0.z, p1.z)) else: p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) PathLog.debug( " CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format( p0.x, p0.y, p1.x, p1.y)) # Calculate offset vector (will be overwritten for arcs) if self.getDirectionOfPath(obj) == "right": off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) # Check if we enter at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadIn) PathLog.debug( "LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}". format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move # Calculate coordinates for middle of circle pij = copy.deepcopy(p0) pij.x += queue[1].Parameters["I"] pij.y += queue[1].Parameters["J"] # Check if lead in and operation go in same direction (usually for inner circles) if arcdir == queue[1].Name: arcs_identical = True # Calculate vector circle start -> circle middle vec_circ = pij.sub(p0) # Rotate vector to get direction for lead in if arcdir == "G2": vec_rot = self.rotate(vec_circ, 90) else: vec_rot = self.rotate(vec_circ, -90) # Normalize and invert vector vec_n = self.normalize(vec_rot) v = self.invert(vec_n) # Calculate offset of lead in if arcdir == "G3": off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) else: off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) offsetvector = FreeCAD.Vector(v.x * R, v.y * R, 0) # IJ if obj.RadiusCenter == "Radius": leadstart = (p0.add(off_v)).sub(offsetvector) # Rmode if arcs_identical: t = p0.sub(leadstart) t = p0.add(t) leadstart = t offsetvector = self.multiply(offsetvector, -1) else: leadstart = p0.add(off_v) # Dmode # At this point leadstart is the beginning of the leadin arc # and offsetvector points from leadstart to the center of the leadin arc # so the offsetvector is a radius of the leadin arc at its start # The extend line should be tangent to the leadin arc at this point, or perpendicular to the radius if arcdir == "G2": tangentvec = self.rotate(offsetvector, -90) else: tangentvec = self.rotate(offsetvector, 90) # Normalize the tangent vector tangentvecNorm = self.normalize(tangentvec) # Multiply tangentvecNorm by LeadIn length leadlinevec = self.multiply(tangentvecNorm, obj.ExtendLeadIn) # leadlinevec provides the offset from the beginning of the lead arc to the beginning of the extend line extendstart = leadstart.add(leadlinevec) if action == "start": if obj.ExtendLeadIn != 0: # Rapid move to beginning of extend line extendcommand = Path.Command( "G0", { "X": extendstart.x, "Y": extendstart.y, "Z": op.ClearanceHeight.Value, }, ) else: # Rapid move to beginning of leadin arc extendcommand = Path.Command( "G0", { "X": extendstart.x, "Y": extendstart.y, "Z": op.ClearanceHeight.Value, }, ) results.append(extendcommand) extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value}) results.append(extendcommand) if action == "layer": if not obj.KeepToolDown: extendcommand = Path.Command("G0", {"Z": op.SafeHeight.Value}) results.append(extendcommand) extendcommand = Path.Command("G0", { "X": extendstart.x, "Y": extendstart.y }) results.append(extendcommand) if obj.RapidPlunge: extendcommand = Path.Command("G0", {"Z": p1.z}) else: extendcommand = Path.Command("G1", {"Z": p1.z, "F": vertFeed}) results.append(extendcommand) if obj.UseMachineCRC: if self.getDirectionOfPath(obj) == "right": results.append(Path.Command("G42", {"D": toolnummer})) else: results.append(Path.Command("G41", {"D": toolnummer})) if obj.StyleOn == "Arc": if obj.ExtendLeadIn != 0: # Insert move to beginning of leadin arc extendcommand = Path.Command("G1", { "X": leadstart.x, "Y": leadstart.y, "F": horizFeed }) results.append(extendcommand) arcmove = Path.Command( arcdir, { "X": p0.x, "Y": p0.y, "Z": p0.z, "I": offsetvector.x, "J": offsetvector.y, "K": offsetvector.z, "F": horizFeed, }, ) # add G2/G3 move results.append(arcmove) elif obj.StyleOn == "Tangent": extendcommand = Path.Command("G1", { "X": p0.x, "Y": p0.y, "F": horizFeed }) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") currLocation.update(results[-1].Parameters) currLocation["Z"] = p1.z return results
def execute(self): if ( not self.baseOp or not self.baseOp.isDerivedFrom("Path::Feature") or not self.baseOp.Path ): return None if len(self.baseOp.Path.Commands) == 0: PathLog.warning("No Path Commands for %s" % self.baseOp.Label) return [] tc = PathDressup.toolController(self.baseOp) self.safeHeight = float(PathUtil.opProperty(self.baseOp, "SafeHeight")) self.clearanceHeight = float( PathUtil.opProperty(self.baseOp, "ClearanceHeight") ) self.strG0ZsafeHeight = Path.Command( # was a Feed rate with G1 "G0", {"Z": self.safeHeight, "F": tc.VertRapid.Value} ) self.strG0ZclearanceHeight = Path.Command("G0", {"Z": self.clearanceHeight}) cmd = self.baseOp.Path.Commands[0] pos = cmd.Placement.Base # bogus m/c position to create first edge bogusX = True bogusY = True commands = [cmd] lastExit = None for cmd in self.baseOp.Path.Commands[1:]: if cmd.Name in PathGeom.CmdMoveAll: if bogusX: bogusX = "X" not in cmd.Parameters if bogusY: bogusY = "Y" not in cmd.Parameters edge = PathGeom.edgeForCmd(cmd, pos) if edge: inside = edge.common(self.boundary).Edges outside = edge.cut(self.boundary).Edges if not self.inside: # UI "inside boundary" param tmp = inside inside = outside outside = tmp # it's really a shame that one cannot trust the sequence and/or # orientation of edges if 1 == len(inside) and 0 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), " + ", cmd) # cmd fully included by boundary if lastExit: if not ( bogusX or bogusY ): # don't insert false paths based on bogus m/c position commands.extend( self.boundaryCommands( lastExit, pos, tc.VertFeed.Value ) ) lastExit = None commands.append(cmd) pos = PathGeom.commandEndPoint(cmd, pos) elif 0 == len(inside) and 1 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), " - ", cmd) # cmd fully excluded by boundary if not lastExit: lastExit = pos pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track( _vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd ) # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(ie) if ie: e = ie[0] LastPt = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, LastPt) newPos = e.valueAt(e.FirstParameter) if flip else LastPt # inside edges are taken at this point (see swap of inside/outside # above - so we can just connect the dots ... if lastExit: if not (bogusX or bogusY): commands.extend( self.boundaryCommands( lastExit, pos, tc.VertFeed.Value ) ) lastExit = None PathLog.track(e, flip) if not ( bogusX or bogusY ): # don't insert false paths based on bogus m/c position commands.extend( PathGeom.cmdsForEdge( e, flip, False, 50, tc.HorizFeed.Value, tc.VertFeed.Value, ) ) inside.remove(e) pos = newPos lastExit = newPos else: oe = [ e for e in outside if PathGeom.edgeConnectsTo(e, pos) ] PathLog.track(oe) if oe: e = oe[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = ( e.valueAt(e.FirstParameter) if flip else ptL ) # outside edges are never taken at this point (see swap of # inside/outside above) - so just move along ... outside.remove(e) pos = newPos else: PathLog.error("huh?") import Part Part.show(Part.Vertex(pos), "pos") for e in inside: Part.show(e, "ei") for e in outside: Part.show(e, "eo") raise Exception("This is not supposed to happen") # Eif # Eif # Ewhile # Eif # pos = PathGeom.commandEndPoint(cmd, pos) # Eif else: PathLog.track("no-move", cmd) commands.append(cmd) if lastExit: commands.extend(self.boundaryCommands(lastExit, None, tc.VertFeed.Value)) lastExit = None PathLog.track(commands) return Path.Path(commands)
def getLeadEnd(self, obj, queue, action): """returns the Gcode of LeadOut.""" results = [] horizFeed = PathDressup.toolController(obj.Base).HorizFeed.Value R = obj.Length.Value # Radius of roll or length arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == "right": arcdir = "G2" else: arcdir = "G3" if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) else: # dealing with a circle p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == "right": off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) # Check if we leave at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadOut) PathLog.debug( "LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}". format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move pij = copy.deepcopy(p0) pij.x += queue[1].Parameters["I"] pij.y += queue[1].Parameters["J"] ve = pij.sub(p1) if arcdir == queue[1].Name: arcs_identical = True if arcdir == "G2": vec_rot = self.rotate(ve, -90) else: vec_rot = self.rotate(ve, 90) vec_n = self.normalize(vec_rot) v = vec_n if arcdir == "G3": off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) else: off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) vec_inv = self.invert(vec_rot) offsetvector = FreeCAD.Vector(v.x * R, v.y * R, 0.0) if obj.RadiusCenter == "Radius": leadend = (p1.add(off_v)).add(offsetvector) # Rmode if arcs_identical: t = p1.sub(leadend) t = p1.add(t) leadend = t off_v = self.multiply(off_v, -1) else: leadend = p1.add(off_v) # Dmode IJ = off_v # At this point leadend is the location of the end of the leadout arc # IJ is an offset from the beginning of the leadout arc to its center. # It is parallel to a tangent line at the end of the leadout arc # Create the normalized tangent vector tangentvecNorm = self.normalize(IJ) leadlinevec = self.multiply(tangentvecNorm, obj.ExtendLeadOut) extendleadoutend = leadend.add(leadlinevec) if obj.StyleOff == "Arc": arcmove = Path.Command( arcdir, { "X": leadend.x, "Y": leadend.y, "Z": leadend.z, "I": IJ.x, "J": IJ.y, "K": IJ.z, "F": horizFeed, }, ) # add G2/G3 move results.append(arcmove) if obj.ExtendLeadOut != 0: extendcommand = Path.Command( "G1", { "X": extendleadoutend.x, "Y": extendleadoutend.y, "F": horizFeed }, ) results.append(extendcommand) elif obj.StyleOff == "Tangent": extendcommand = Path.Command("G1", { "X": leadend.x, "Y": leadend.y, "F": horizFeed }) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") if obj.UseMachineCRC: # crc off results.append(Path.Command("G40", {})) return results
def createPath(self, obj, pathData, tags): PathLog.track() commands = [] lastEdge = 0 lastTag = 0 # sameTag = None t = 0 # inters = None edge = None segm = 50 if hasattr(obj, 'SegmentationFactor'): segm = obj.SegmentationFactor if segm <= 0: segm = 50 obj.SegmentationFactor = 50 self.mappers = [] mapper = None tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value horizRapid = tc.HorizRapid.Value vertRapid = tc.VertRapid.Value while edge or lastEdge < len(pathData.edges): PathLog.debug("------- lastEdge = %d/%d.%d/%d" % (lastEdge, lastTag, t, len(tags))) if not edge: edge = pathData.edges[lastEdge] debugEdge(edge, "======= new edge: %d/%d" % (lastEdge, len(pathData.edges))) lastEdge += 1 # sameTag = None if mapper: mapper.add(edge) if mapper.mappingComplete(): commands.extend(mapper.commands) edge = mapper.tail mapper = None else: edge = None if edge: tIndex = (t + lastTag) % len(tags) t += 1 i = tags[tIndex].intersects(edge, edge.FirstParameter) if i and self.isValidTagStartIntersection(edge, i): mapper = MapWireToTag(edge, tags[tIndex], i, segm, pathData.maxZ, hSpeed = horizFeed, vSpeed = vertFeed) self.mappers.append(mapper) edge = mapper.tail if not mapper and t >= len(tags): # gone through all tags, consume edge and move on if edge: debugEdge(edge, '++++++++') if pathData.rapid.isRapid(edge): v = edge.Vertexes[1] if not commands and PathGeom.isRoughly(0, v.X) and PathGeom.isRoughly(0, v.Y) and not PathGeom.isRoughly(0, v.Z): # The very first move is just to move to ClearanceHeight commands.append(Path.Command('G0', {'Z': v.Z, 'F': horizRapid})) else: commands.append(Path.Command('G0', {'X': v.X, 'Y': v.Y, 'Z': v.Z, 'F': vertRapid})) else: commands.extend(PathGeom.cmdsForEdge(edge, segm=segm, hSpeed = horizFeed, vSpeed = vertFeed)) edge = None t = 0 return Path.Path(commands)
def getLeadStart(self, obj, queue, action): '''returns Lead In G-code.''' results = [] op = PathDressup.baseOp(obj.Base) tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value toolnummer = tc.ToolNumber arcs_identical = False # Set the correct twist command if self.getDirectionOfPath(obj) == 'left': arcdir = "G3" else: arcdir = "G2" R = obj.Length.Value # Radius of roll or length if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.debug(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z)) else: p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.debug(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y)) # Calculate offset vector (will be overwritten for arcs) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) # Check if we enter at line or arc command if queue[1].Name in movecommands and queue[1].Name not in arccommands: # We have a line move vec = p1.sub(p0) vec_n = self.normalize(vec) vec_inv = self.invert(vec_n) vec_off = self.multiply(vec_inv, obj.ExtendLeadIn) #PathLog.debug("LineCMD: {}, Vxinv: {}, Vyinv: {}, Vxoff: {}, Vyoff: {}".format(queue[0].Name, vec_inv.x, vec_inv.y, vec_off.x, vec_off.y)) else: # We have an arc move # Calculate coordinates for middle of circle pij = copy.deepcopy(p0) pij.x += queue[1].Parameters['I'] pij.y += queue[1].Parameters['J'] # Check if lead in and operation go in same direction (usually for inner circles) if arcdir == queue[1].Name: arcs_identical = True # Calculate vector circle start -> circle middle vec_circ = pij.sub(p0) # Rotate vector to get direction for lead in if arcdir == "G2": vec_rot = self.rotate(vec_circ, 90) else: vec_rot = self.rotate(vec_circ, -90) # Normalize and invert vector vec_n = self.normalize(vec_rot) v = self.invert(vec_n) # Calculate offset of lead in if arcdir == "G3": off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) else: off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) # Multiply offset by LeadIn length vec_off = self.multiply(vec_n, obj.ExtendLeadIn) offsetvector = FreeCAD.Vector(v.x * R - vec_off.x, v.y * R - vec_off.y, 0) # IJ if obj.RadiusCenter == 'Radius': leadstart = (p0.add(off_v)).sub(offsetvector) # Rmode if arcs_identical: t = p0.sub(leadstart) t = p0.add(t) leadstart = t offsetvector = self.multiply(offsetvector, -1) else: leadstart = p0.add(off_v) # Dmode if action == 'start': #extendcommand = Path.Command('G0', {"X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value}) #results.append(extendcommand) extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y, "Z": op.ClearanceHeight.Value }) results.append(extendcommand) extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) if action == 'layer': if not obj.KeepToolDown: extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y }) results.append(extendcommand) if not obj.RapidPlunge: extendcommand = Path.Command('G1', { "X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed }) else: extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y, "Z": p1.z, }) results.append(extendcommand) if obj.UseMachineCRC: if self.getDirectionOfPath(obj) == 'right': results.append(Path.Command('G42', {'D': toolnummer})) else: results.append(Path.Command('G41', {'D': toolnummer})) if obj.StyleOn == 'Arc': arcmove = Path.Command( arcdir, { "X": p0.x + vec_off.x, "Y": p0.y + vec_off.y, "I": offsetvector.x + vec_off.x, "J": offsetvector.y + vec_off.y, "F": horizFeed }) # add G2/G3 move results.append(arcmove) if obj.ExtendLeadIn != 0: extendcommand = Path.Command('G1', { "X": p0.x, "Y": p0.y, "F": horizFeed }) results.append(extendcommand) elif obj.StyleOn == 'Tangent': extendcommand = Path.Command('G1', { "X": p0.x, "Y": p0.y, "F": horizFeed }) results.append(extendcommand) else: PathLog.debug(" CURRENT_IN Perp") currLocation.update(results[-1].Parameters) currLocation['Z'] = p1.z return results
def createCommands(self, obj, edges): commands = [] for edge in edges: israpid = False for redge in self.rapids: if PathGeom.edgesMatch(edge, redge): israpid = True if israpid: v = edge.valueAt(edge.LastParameter) commands.append( Path.Command("G0", { "X": v.x, "Y": v.y, "Z": v.z })) else: commands.extend(PathGeom.cmdsForEdge(edge)) lastCmd = Path.Command("G0", {"X": 0.0, "Y": 0.0, "Z": 0.0}) outCommands = [] tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value if obj.RampFeedRate == "Horizontal Feed Rate": rampFeed = tc.HorizFeed.Value elif obj.RampFeedRate == "Vertical Feed Rate": rampFeed = tc.VertFeed.Value elif obj.RampFeedRate == "Ramp Feed Rate": rampFeed = math.sqrt( pow(tc.VertFeed.Value, 2) + pow(tc.HorizFeed.Value, 2)) else: rampFeed = obj.CustomFeedRate.Value horizRapid = tc.HorizRapid.Value vertRapid = tc.VertRapid.Value for cmd in commands: params = cmd.Parameters zVal = params.get("Z", None) zVal2 = lastCmd.Parameters.get("Z", None) xVal = params.get("X", None) xVal2 = lastCmd.Parameters.get("X", None) yVal2 = lastCmd.Parameters.get("Y", None) yVal = params.get("Y", None) zVal = zVal and round(zVal, 8) zVal2 = zVal2 and round(zVal2, 8) if cmd.Name in ["G1", "G2", "G3", "G01", "G02", "G03"]: if zVal is not None and zVal2 != zVal: if PathGeom.isRoughly(xVal, xVal2) and PathGeom.isRoughly( yVal, yVal2): # this is a straight plunge params["F"] = vertFeed else: # this is a ramp params["F"] = rampFeed else: params["F"] = horizFeed lastCmd = cmd elif cmd.Name in ["G0", "G00"]: if zVal is not None and zVal2 != zVal: params["F"] = vertRapid else: params["F"] = horizRapid lastCmd = cmd outCommands.append(Path.Command(cmd.Name, params)) return Path.Path(outCommands)
def createPath(self, obj, pathData, tags): PathLog.track() commands = [] lastEdge = 0 lastTag = 0 # sameTag = None t = 0 # inters = None edge = None segm = 50 if hasattr(obj, 'SegmentationFactor'): segm = obj.SegmentationFactor if segm <= 0: segm = 50 obj.SegmentationFactor = 50 self.mappers = [] mapper = None while edge or lastEdge < len(pathData.edges): PathLog.debug("------- lastEdge = %d/%d.%d/%d" % (lastEdge, lastTag, t, len(tags))) if not edge: edge = pathData.edges[lastEdge] debugEdge(edge, "======= new edge: %d/%d" % (lastEdge, len(pathData.edges))) lastEdge += 1 # sameTag = None if mapper: mapper.add(edge) if mapper.mappingComplete(): commands.extend(mapper.commands) edge = mapper.tail mapper = None else: edge = None if edge: tIndex = (t + lastTag) % len(tags) t += 1 i = tags[tIndex].intersects(edge, edge.FirstParameter) if i and self.isValidTagStartIntersection(edge, i): mapper = MapWireToTag(edge, tags[tIndex], i, segm, pathData.maxZ) self.mappers.append(mapper) edge = mapper.tail if not mapper and t >= len(tags): # gone through all tags, consume edge and move on if edge: debugEdge(edge, '++++++++') if pathData.rapid.isRapid(edge): v = edge.Vertexes[1] if not commands and PathGeom.isRoughly(0, v.X) and PathGeom.isRoughly(0, v.Y) and not PathGeom.isRoughly(0, v.Z): # The very first move is just to move to ClearanceHeight commands.append(Path.Command('G0', {'Z': v.Z})) else: commands.append(Path.Command('G0', {'X': v.X, 'Y': v.Y, 'Z': v.Z})) else: commands.extend(PathGeom.cmdsForEdge(edge, segm=segm)) edge = None t = 0 lastCmd = Path.Command('G0', {'X': 0.0, 'Y': 0.0, 'Z': 0.0}) outCommands = [] tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value horizRapid = tc.HorizRapid.Value vertRapid = tc.VertRapid.Value for cmd in commands: params = cmd.Parameters zVal = params.get('Z', None) zVal2 = lastCmd.Parameters.get('Z', None) zVal = zVal and round(zVal, 8) zVal2 = zVal2 and round(zVal2, 8) if cmd.Name in ['G1', 'G2', 'G3', 'G01', 'G02', 'G03']: if False and zVal is not None and zVal2 != zVal: params['F'] = vertFeed else: params['F'] = horizFeed lastCmd = cmd elif cmd.Name in ['G0', 'G00']: if zVal is not None and zVal2 != zVal: params['F'] = vertRapid else: params['F'] = horizRapid lastCmd = cmd outCommands.append(Path.Command(cmd.Name, params)) return Path.Path(outCommands)
def getLeadStart(self, obj, queue, action): '''returns Lead In G-code.''' global currLocation results = [] # zdepth = currLocation["Z"] op = PathDressup.baseOp(obj.Base) tc = PathDressup.toolController(obj.Base) horizFeed = tc.HorizFeed.Value vertFeed = tc.VertFeed.Value toolnummer = tc.ToolNumber # set the correct twist command if self.getDirectionOfPath(obj) == 'left': arcdir = "G3" else: arcdir = "G2" R = obj.Length.Value # Radius of roll or length if queue[1].Name == "G1": # line p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base v = self.normalize(p1.sub(p0)) # PathLog.notice(" CURRENT_IN : P0 Z:{} p1 Z:{}".format(p0.z,p1.z)) else: p0 = queue[0].Placement.Base p1 = queue[1].Placement.Base # PathLog.notice(" CURRENT_IN ARC : P0 X:{} Y:{} P1 X:{} Y:{} ".format(p0.x,p0.y,p1.x,p1.y)) v = self.normalize(p1.sub(p0)) if self.getDirectionOfPath(obj) == 'right': off_v = FreeCAD.Vector(v.y * R, -v.x * R, 0.0) else: off_v = FreeCAD.Vector(-v.y * R, v.x * R, 0.0) offsetvector = FreeCAD.Vector(v.x * R, v.y * R, 0) # IJ if obj.RadiusCenter == 'Radius': leadstart = (p0.add(off_v)).sub(offsetvector) # Rmode else: leadstart = p0.add(off_v) # Dmode if action == 'start': extendcommand = Path.Command('G0', { "X": 0.0, "Y": 0.0, "Z": op.ClearanceHeight.Value }) results.append(extendcommand) extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y, "Z": op.ClearanceHeight.Value }) results.append(extendcommand) extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y, "Z": op.SafeHeight.Value }) results.append(extendcommand) if action == 'layer': if not obj.KeepToolDown: extendcommand = Path.Command('G0', {"Z": op.SafeHeight.Value}) results.append(extendcommand) extendcommand = Path.Command('G0', { "X": leadstart.x, "Y": leadstart.y }) results.append(extendcommand) extendcommand = Path.Command('G1', { "X": leadstart.x, "Y": leadstart.y, "Z": p1.z, "F": vertFeed }) results.append(extendcommand) if obj.UseMashineCRC: if self.getDirectionOfPath(obj) == 'right': results.append(Path.Command('G42', {'D': toolnummer})) else: results.append(Path.Command('G41', {'D': toolnummer})) if obj.StyleOn == 'Arc': arcmove = Path.Command( arcdir, { "X": p0.x, "Y": p0.y, "I": offsetvector.x, "J": offsetvector.y, "F": horizFeed }) # add G2/G3 move results.append(arcmove) elif obj.StyleOn == 'Tangent': extendcommand = Path.Command('G1', { "X": p0.x, "Y": p0.y, "F": horizFeed }) results.append(extendcommand) else: PathLog.notice(" CURRENT_IN Perp") return results
def execute(self, obj): if not obj.Base or not obj.Base.isDerivedFrom('Path::Feature') or not obj.Base.Path: return tc = PathDressup.toolController(obj.Base) if len(obj.Base.Path.Commands) > 0: self.safeHeight = float(PathUtil.opProperty(obj.Base, 'SafeHeight')) self.clearanceHeight = float(PathUtil.opProperty(obj.Base, 'ClearanceHeight')) boundary = obj.Stock.Shape cmd = obj.Base.Path.Commands[0] pos = cmd.Placement.Base commands = [cmd] lastExit = None for cmd in obj.Base.Path.Commands[1:]: if cmd.Name in PathGeom.CmdMoveAll: edge = PathGeom.edgeForCmd(cmd, pos) inside = edge.common(boundary).Edges outside = edge.cut(boundary).Edges if not obj.Inside: t = inside inside = outside outside = t # it's really a shame that one cannot trust the sequence and/or # orientation of edges if 1 == len(inside) and 0 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), ' + ', cmd) # cmd fully included by boundary if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value)) lastExit = None commands.append(cmd) pos = PathGeom.commandEndPoint(cmd, pos) elif 0 == len(inside) and 1 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), ' - ', cmd) # cmd fully excluded by boundary if not lastExit: lastExit = pos pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd) # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(ie) if ie: e = ie[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = e.valueAt(e.FirstParameter) if flip else ptL # inside edges are taken at this point (see swap of inside/outside # above - so we can just connect the dots ... if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value)) lastExit = None PathLog.track(e, flip) commands.extend(PathGeom.cmdsForEdge(e, flip, False)) inside.remove(e) pos = newPos lastExit = newPos else: oe = [e for e in outside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(oe) if oe: e = oe[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = e.valueAt(e.FirstParameter) if flip else ptL # outside edges are never taken at this point (see swap of # inside/oustide above) - so just move along ... outside.remove(e) pos = newPos else: PathLog.error('huh?') import Part Part.show(Part.Vertex(pos), 'pos') for e in inside: Part.show(e, 'ei') for e in outside: Part.show(e, 'eo') raise Exception('This is not supposed to happen') #pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track('no-move', cmd) commands.append(cmd) if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, None, tc.VertFeed.Value)) lastExit = None else: PathLog.warning("No Path Commands for %s" % obj.Base.Label) commands = [] PathLog.track(commands) obj.Path = Path.Path(commands)