def execute(self, app): rdoc = self["rdoc"] radius = self["dia"] / 2 cw = self["cw"] #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): #print(blocks[bid]) path = app.gcode.toPath(bid)[0] #print(path) block = Block("trochoid") for segment in path: #print(segment.A) #block.append("g0 x0 y0") #block.append("g1 x10 y10") #block.append("g1 x20 y10") #block.append("g0 x0 y0") block.extend(self.trochoid(segment, rdoc, radius, cw)) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks( active, blocks, "Trochoidal created" ) #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Trochoidal")) #<<< feed back result
def calc(self,x,y,depth,peck,dwell,drillFeed,safeZforG0): self.safeZforG0 =float(abs(safeZforG0)) peck=abs(float(peck)) currentz=0.0 self.blocks = [] self.block = Block(self.name) self.block.append(CNC.grapid(x=x,y=y)) self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.accelerateIfNeeded(0.0,drillFeed) self.block.append("(entered)") while(currentz>depth): currentz-=peck if currentz < depth: currentz = depth kwargs={"f":float(drillFeed)} self.block.append(CNC.gline(None,None,float(currentz),**kwargs)) if self.safeZforG0 >0: self.block.append(CNC.grapid(z=0.0+self.safeZforG0)) else : self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.block.append("g4 %s"%(CNC.fmt("p",float(dwell)))) if currentz > depth: self.accelerateIfNeeded(currentz,drillFeed) self.block.append("(exiting)") self.block.append(CNC.grapid(z=CNC.vars["safe"])) self.blocks.append(self.block) return self.blocks
def slice(self, verts, faces, z, zout=None): block = Block("slice %f" % (float(z))) #FIXME: slice along different axes plane_orig = (0, 0, z) #z height to slice plane_norm = (0, 0, 1) #Crosscut contours = meshcut.cross_section(verts, faces, plane_orig, plane_norm) #Flatten contours if zout is not None: for contour in contours: for segment in contour: segment[2] = zout #Contours to G-code for contour in contours: #print(contour) first = contour[0] block.append("g0 x%f y%f z%f" % (first[0], first[1], first[2])) for segment in contour: block.append("g1 x%f y%f z%f" % (segment[0], segment[1], segment[2])) block.append("g1 x%f y%f z%f" % (first[0], first[1], segment[2])) block.append("( ---------- cut-here ---------- )") if block: del block[-1] if not block: block = None return block
def insertBlock(self, event=None): active = self.index(ACTIVE) if self._items: bid, lid = self._items[active] bid += 1 else: bid = 0 block = Block() block.expand = True block.append("g0 x0 y0") block.append("g1 z0") block.append(CNC.zsafe()) self.gcode.addUndo(self.gcode.addBlockUndo(bid,block)) self.selection_clear(0,END) self.fill() # find location of new block while active < self.size(): if self._items[active][0] == bid: break active += 1 self.selection_set(active) self.see(active) self.activate(active) self.edit() self.winfo_toplevel().event_generate("<<Modified>>")
def execute(self, app): #print("go!") blocks = [] paths_base = [] paths_isl = [] for bid in app.editor.getSelectedBlocks(): if app.gcode[bid].operationTest('island'): paths_isl.extend(app.gcode.toPath(bid)) else: paths_base.extend(app.gcode.toPath(bid)) for island in paths_isl: paths_newbase = [] while len(paths_base) > 0: base = paths_base.pop() base.intersectPath(island) island.intersectPath(base) newbase = Path("diff") #Add segments from outside of islands: for i, seg in enumerate(base): if not island.isInside(seg.midPoint()): newbase.append(seg) #Add segments from islands to base for i, seg in enumerate(island): if base.isInside(seg.midPoint( )): #and base.isInside(seg.A) and base.isInside(seg.B): newbase.append(seg) #Eulerize paths_newbase.extend(newbase.eulerize()) #paths_newbase.extend(newbase.split2contours()) paths_base = paths_newbase for base in paths_base: print(base) #base = base.eulerize(True) block = Block("diff") block.extend(app.gcode.fromPath(base)) blocks.append(block) #active = app.activeBlock() app.gcode.insBlocks( -1, blocks, "Diff") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Diff")) #<<< feed back result
def insertBlock(self, event=None): active = self.index(ACTIVE) if self._items: bid, lid = self._items[active] bid += 1 else: bid = 0 block = Block() block.expand = True block.append("G0 X0 Y0") block.append("G1 Z0") block.append(CNC.zsafe()) self.gcode.addUndo(self.gcode.addBlockUndo(bid,block)) self.selection_clear(0,END) self.fill() # find location of new block while active < self.size(): if self._items[active][0] == bid: break active += 1 self.selection_set(active) self.see(active) self.activate(active) self.edit() self.app.event_generate("<<Modified>>")
def execute(self, app): #print("go!") blocks = [] paths_base = [] paths_isl = [] for bid in app.editor.getSelectedBlocks(): if app.gcode[bid].operationTest('island'): paths_isl.extend(app.gcode.toPath(bid)) else: paths_base.extend(app.gcode.toPath(bid)) for island in paths_isl: paths_newbase = [] while len(paths_base) > 0: base = paths_base.pop() base.intersectPath(island) island.intersectPath(base) newbase = Path("diff") #Add segments from outside of islands: for i,seg in enumerate(base): if not island.isInside(seg.midPoint()): newbase.append(seg) #Add segments from islands to base for i,seg in enumerate(island): if base.isInside(seg.midPoint()): #and base.isInside(seg.A) and base.isInside(seg.B): newbase.append(seg) #Eulerize paths_newbase.extend(newbase.eulerize()) #paths_newbase.extend(newbase.split2contours()) paths_base = paths_newbase for base in paths_base: print(base) #base = base.eulerize(True) block = Block("diff") block.extend(app.gcode.fromPath(base)) blocks.append(block) #active = app.activeBlock() app.gcode.insBlocks(-1, blocks, "Diff") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Diff")) #<<< feed back result
def joinBlocks(self, event=None): if not self._items: return all_items = self._items sel_items = list(map(int,self.curselection())) change = True bl = Block(self.gcode[sel_items[0]].name()) for bid in sel_items: for line in self.gcode[bid]: bl.append(line) bl.append("( ---------- cut-here ---------- )") del bl[-1] self.gcode.addUndo(self.gcode.addBlockUndo(bid+1,bl)) if change: self.fill() self.deleteBlock() self.winfo_toplevel().event_generate("<<Modified>>")
def execute(self, app): preci = self.fromMm("preci") linpreci = self.fromMm("linpreci") numseg = self["numseg"] #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue #nblock = Block("flat "+app.gcode[bid].name()) #for i in app.gcode[bid]: # nblock.append(re.sub(r"\s?z-?[0-9\.]+","",i)) #blocks.append(nblock) eblock = Block("fit " + app.gcode[bid].name()) npath = app.gcode.toPath(bid)[0] npath = npath.mergeLines(linpreci) npath = npath.arcFit(preci, numseg) if npath.length() <= 0: #FIXME: not sure how this could happen print("Warning: ignoring zero length path!") continue eblock = app.gcode.fromPath(npath, eblock) blocks.append(eblock) #active = app.activeBlock() #if active == 0: active+=1 active = -1 #add to end app.gcode.insBlocks( active, blocks, "Arc fit") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Arc fit")) #<<< feed back result
def execute(self, app): maxseg = self.fromMm("maxseg") splitlines = self["splitlines"] #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue #nblock = Block("flat "+app.gcode[bid].name()) #for i in app.gcode[bid]: # nblock.append(re.sub(r"\s?z-?[0-9\.]+","",i)) #blocks.append(nblock) eblock = Block("lin "+app.gcode[bid].name()) opath = app.gcode.toPath(bid)[0] npath = opath.linearize(maxseg, splitlines) eblock = app.gcode.fromPath(npath,eblock) blocks.append(eblock) #active = app.activeBlock() #if active == 0: active+=1 active=-1 #add to end app.gcode.insBlocks(active, blocks, "Linearized") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Linearize")) #<<< feed back result
def make(self): d = self.thick # Convert to external dimensions if self.dx<0: dx = -self.dx - d*2 # external to internal else: dx = self.dx if self.dy<0: dy = -self.dy - d*2 # external to internal else: dy = self.dy if self.dz<0: dz = -self.dz - d*2 # external to internal else: dz = self.dz blocks = [] block = Block("%s-Bottom"%(self.name)) block.append("(Box: %g x %g x %g)"%(self.dx,self.dy,self.dz)) block.append("(Fingers: %d x %d x %d)"%(self.nx,self.ny,self.nz)) self._rectangle(block, 0.,-d, dx,dy, self.nx,-self.ny, 0,d) blocks.append(block) block = Block("%s-Left"%(self.name)) self._rectangle(block, -(dz+5*d),-d, dz,dy, self.nz,self.ny, d,d) blocks.append(block) block = Block("%s-Right"%(self.name)) self._rectangle(block, dx+3*d,-d, dz,dy, self.nz,self.ny, d,d) blocks.append(block) block = Block("%s-Front"%(self.name)) self._rectangle(block, 0,-(dz+4*d), dx,dz, -self.nx,-self.nz, 0,0) blocks.append(block) block = Block("%s-Back"%(self.name)) self._rectangle(block, 0,dy+4*d, dx,dz, -self.nx,-self.nz, 0,0) blocks.append(block) block = Block("%s-Top"%(self.name)) self._rectangle(block, dx+dz+8*d,-d, dx,dy, self.nx,-self.ny, 0,d) blocks.append(block) return blocks
def splitBlocks(self, event=None): if not self._items: return all_items = self._items sel_items = list(map(int,self.curselection())) change = True newblocks = [] for bid in sel_items: bl = Block(self.gcode[bid].name()) for line in self.gcode[bid]: if line == "( ---------- cut-here ---------- )": #newblocks.append(bl) #self.insertBlock(bl) self.gcode.addUndo(self.gcode.addBlockUndo(bid+1,bl)) bl = Block(self.gcode[bid].name()) else: bl.append(line) self.gcode.addUndo(self.gcode.addBlockUndo(bid+1,bl)) #newblocks.append(bl) #self.gcode.extend(newblocks) if change: self.fill() self.deleteBlock() self.winfo_toplevel().event_generate("<<Modified>>")
def slice(self, verts, faces, z, zout=None, axis='z'): tags = '[slice]' if axis == 'z': tags = '[slice,minz:%f]' % (float(z)) block = Block("slice %s%f %s" % (axis, float(z), tags)) #FIXME: slice along different axes if axis == 'x': plane_orig = (z, 0, 0) plane_norm = (1, 0, 0) elif axis == 'y': plane_orig = (0, z, 0) plane_norm = (0, 1, 0) else: plane_orig = (0, 0, z) #z height to slice plane_norm = (0, 0, 1) #Crosscut contours = meshcut.cross_section(verts, faces, plane_orig, plane_norm) #Flatten contours if zout is not None: for contour in contours: for segment in contour: segment[2] = zout #Contours to G-code for contour in contours: #print(contour) first = contour[0] block.append("g0 x%f y%f z%f" % (first[0], first[1], first[2])) for segment in contour: block.append("g1 x%f y%f z%f" % (segment[0], segment[1], segment[2])) block.append("g1 x%f y%f z%f" % (first[0], first[1], segment[2])) block.append("( ---------- cut-here ---------- )") if block: del block[-1] if not block: block = None return block
def execute(self, app): #print("go!") blocks = [] bid = app.editor.getSelectedBlocks()[0] xbasepath = app.gcode.toPath(bid)[0] bid = app.editor.getSelectedBlocks()[1] xislandpath = app.gcode.toPath(bid)[0] xbasepath.intersectPath(xislandpath) xislandpath.intersectPath(xbasepath) #xnewisland = self.pathBoolIntersection(xbasepath, xislandpath) xnewisland = self.pathBoolIntersection(xislandpath, xbasepath) #pth = Path("temp") #basepath.invert() #pth.extend(basepath) #pth.extend(basepath) ##pth.invert() block = Block("intersect") block.extend(app.gcode.fromPath(xnewisland)) blocks.append(block) #block = Block("diff") #block.extend(app.gcode.fromPath(pth)) #blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Intersect") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Intersect")) #<<< feed back result
def execute(self, app): #print("go!") blocks = [] bid = app.editor.getSelectedBlocks()[0] xbasepath = app.gcode.toPath(bid)[0] bid = app.editor.getSelectedBlocks()[1] xislandpath = app.gcode.toPath(bid)[0] xbasepath.intersectPath(xislandpath) xislandpath.intersectPath(xbasepath) #xnewisland = self.pathBoolIntersection(xbasepath, xislandpath) xnewisland = self.pathBoolIntersection(xislandpath, xbasepath) #pth = Path("temp") #basepath.invert() #pth.extend(basepath) #pth.extend(basepath) ##pth.invert() block = Block("diff") block.extend(app.gcode.fromPath(xnewisland)) blocks.append(block) #block = Block("diff") #block.extend(app.gcode.fromPath(pth)) #blocks.append(block) active = app.activeBlock() app.gcode.insBlocks( active, blocks, "Diff") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Diff")) #<<< feed back result
def execute(self, app): blocks = [] for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue eblock = Block("closed " + app.gcode[bid].name()) for path in app.gcode.toPath(bid): if not path.isClosed(): path.append(Segment(Segment.LINE, path[-1].B, path[0].A)) eblock = app.gcode.fromPath(path, eblock) #blocks.append(eblock) app.gcode[bid] = eblock #active=-1 #add to end #app.gcode.insBlocks(active, blocks, "Path closed") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Closepath")) #<<< feed back result
def addLines(lines): for line in lines.splitlines(): # Create a new block if self.__lid is None: self.__bid += 1 self.__lid = MAXINT block = Block() undoinfo.append(self.gcode.addBlockUndo(self.__bid,block)) selitems.append((self.__bid, None)) else: block = self.gcode.blocks[self.__bid] if self.__lid == MAXINT: selitems.append((self.__bid, len(block))) else: self.__lid += 1 selitems.append((self.__bid, self.__lid)) undoinfo.append(self.gcode.insLineUndo(self.__bid, self.__lid, line))
def execute(self, app): #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue path = app.gcode.toPath(bid)[0] x,y = path.center() eblock = Block("center of "+app.gcode[bid].name()) eblock.append("G0 x"+str(x)+" y"+str(y)) eblock.append("G1 Z0 F200") eblock.append("G0 Z10") blocks.append(eblock) #active = app.activeBlock() #if active == 0: active+=1 active=-1 #add to end app.gcode.insBlocks(active, blocks, "Center created") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Center")) #<<< feed back result
def execute(self, app): name = self["name"] if not name or name == "default": name = "Drillmark" marksize = self["Mark size"] x0 = self.fromMm("PosX") y0 = self.fromMm("PosY") marktype = self["Mark type"] block = Block(name + " %s diameter %s" % (marktype, CNC.fmt("", marksize))) self.appendBurn(app, block) self.appendMark(app, block) active = app.activeBlock() if active == 0: active = 1 blocks = [block] app.gcode.insBlocks(active, blocks, _("Manual drill mark")) app.refresh() # <<< refresh editor app.setStatus(_("Generated: MyPlugin Result"))
def execute(self, app): #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue #nblock = Block("flat "+app.gcode[bid].name()) #for i in app.gcode[bid]: # nblock.append(re.sub(r"\s?z-?[0-9\.]+","",i)) #blocks.append(nblock) eblock = Block("flat " + app.gcode[bid].name()) eblock = app.gcode.fromPath(app.gcode.toPath(bid), eblock) blocks.append(eblock) #active = app.activeBlock() #if active == 0: active+=1 active = -1 #add to end app.gcode.insBlocks( active, blocks, "Shape flattened" ) #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Flat")) #<<< feed back result
def slice(self, verts, faces, z, zout=None, axis='z'): tags = '[slice]' if axis=='z': tags = '[slice,minz:%f]'%(float(z)) block = Block("slice %s%f %s"%(axis,float(z),tags)) #FIXME: slice along different axes if axis == 'x': plane_orig = (z, 0, 0) plane_norm = (1, 0, 0) elif axis == 'y': plane_orig = (0, z, 0) plane_norm = (0, 1, 0) else: plane_orig = (0, 0, z) #z height to slice plane_norm = (0, 0, 1) #Crosscut contours = meshcut.cross_section(verts, faces, plane_orig, plane_norm) #Flatten contours if zout is not None: for contour in contours: for segment in contour: segment[2] = zout #Contours to G-code for contour in contours: #print(contour) gtype = 0 for segment in contour: block.append("g%s x%f y%f z%f"%(gtype, segment[0],segment[1],segment[2])) gtype = 1 block.append("g1 x%f y%f z%f"%(contour[0][0],contour[0][1],contour[0][2])) #Close shape block.append("( ---------- cut-here ---------- )") if block: del block[-1] if not block: block = None return block
def execute(self, app): try: import midiparser as midiparser except: app.setStatus(_("Error: This plugin requires midiparser.py")) return n = self["name"] if not n or n=="default": n="Midi2CNC" fileName = self["File"] x=0.0 y=0.0 z=0.0 x_dir=1.0; y_dir=1.0; z_dir=1.0; # List of MIDI channels (instruments) to import. # Channel 10 is percussion, so better to omit it channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] axes = self["AxisUsed"] active_axes = len(axes) transpose = (0,0,0) ppu = [ 200, 200, 200 ] ppu[0] = self["ppu_X"] ppu[1] = self["ppu_X"] ppu[2] = self["ppu_X"] safemin = [ 0, 0, 0 ] safemax = [ 100, 100, 50 ] safemax[0] = self["max_X"] safemax[1] = self["max_Y"] safemax[2] = self["max_Z"] try: midi = midiparser.File(fileName) except: app.setStatus(_("Error: Sorry can't parse the Midi file.")) return noteEventList=[] all_channels=set() for track in midi.tracks: #channels=set() for event in track.events: if event.type == midiparser.meta.SetTempo: tempo=event.detail.tempo # filter undesired instruments if ((event.type == midiparser.voice.NoteOn) and (event.channel in channels)): if event.channel not in channels: channels.add(event.channel) # NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off. if event.detail.velocity > 0: noteEventList.append([event.absolute, 1, event.detail.note_no, event.detail.velocity]) else: noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity]) if (event.type == midiparser.voice.NoteOff) and (event.channel in channels): if event.channel not in channels: channels.add(event.channel) noteEventList.append([event.absolute, 0, event.detail.note_no, event.detail.velocity]) # Finished with this track if len(channels) > 0: msg=', ' . join(['%2d' % ch for ch in sorted(channels)]) #print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg) all_channels = all_channels.union(channels) # List all channels encountered if len(all_channels) > 0: msg=', ' . join(['%2d' % ch for ch in sorted(all_channels)]) #print 'The file as a whole contains channels numbered: [%s ]' % msg # We now have entire file's notes with abs time from all channels # We don't care which channel/voice is which, but we do care about having all the notes in order # so sort event list by abstime to dechannelify noteEventList.sort() # print noteEventList # print len(noteEventList) last_time=-0 active_notes={} # make this a dict so we can add and remove notes by name # Start the output #Init blocks blocks = [] block = Block(self.name) block.append("(Midi2CNC)") block.append("(Midi:%s)" % fileName) block.append(CNC.zsafe()) block.append(CNC.grapid(0,0)) block.append(CNC.zenter(0)) for note in noteEventList: # note[timestamp, note off/note on, note_no, velocity] if last_time < note[0]: freq_xyz=[0,0,0] feed_xyz=[0,0,0] distance_xyz=[0,0,0] duration=0 # "i" ranges from 0 to "the number of active notes *or* the number of active axes, # whichever is LOWER". Note that the range operator stops # short of the maximum, so this means 0 to 2 at most for a 3-axis machine. # E.g. only look for the first few active notes to play despite what # is going on in the actual score. for i in range(0, min(len(active_notes.values()), active_axes)): # Which axis are should we be writing to? # j = self.axes_dict.get(axes)[i] # Debug # print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j) # Sound higher pitched notes first by sorting by pitch then indexing by axis # nownote=sorted(active_notes.values(), reverse=True)[i] # MIDI note 69 = A4(440Hz) # 2 to the power (69-69) / 12 * 440 = A4 440Hz # 2 to the power (64-69) / 12 * 440 = E4 329.627Hz # freq_xyz[j] = pow(2.0, (nownote-69 + transpose[j])/12.0)*440.0 # Here is where we need smart per-axis feed conversions # to enable use of X/Y *and* Z on a Makerbot # # feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z; # # Feed rate is expressed in mm / minutes so 60 times # scaling factor is required. feed_xyz[j] = ( freq_xyz[j] * 60.0 ) / ppu[j] # Get the duration in seconds from the MIDI values in divisions, at the given tempo duration = ( ( ( note[0] - last_time ) + 0.0 ) / ( midi.division + 0.0 ) * ( tempo / 1000000.0 ) ) # Get the actual relative distance travelled per axis in mm distance_xyz[j] = ( feed_xyz[j] * duration ) / 60.0 # Now that axes can be addressed in any order, need to make sure # that all of them are silent before declaring a rest is due. if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0: # At least one axis is playing, so process the note into # movements combined_feedrate = math.sqrt(feed_xyz[0]**2 + feed_xyz[1]**2 + feed_xyz[2]**2) # Turn around BEFORE crossing the limits of the # safe working envelope if self.reached_limit( x, distance_xyz[0], x_dir, safemin[0], safemax[0] ): x_dir = x_dir * -1 x = (x + (distance_xyz[0] * x_dir)) if self.reached_limit( y, distance_xyz[1], y_dir, safemin[1], safemax[1] ): y_dir = y_dir * -1 y = (y + (distance_xyz[1] * y_dir)) if self.reached_limit( z, distance_xyz[2], z_dir, safemin[2], safemax[2] ): z_dir = z_dir * -1 z = (z + (distance_xyz[2] * z_dir)) v = (x,y,z) block.append(CNC.glinev(1,v,combined_feedrate)) else: # Handle 'rests' in addition to notes. duration = (((note[0]-last_time)+0.0)/(midi.division+0.0)) * (tempo/1000000.0) block.append(CNC.gcode(4, [("P",duration)])) # finally, set this absolute time as the new starting time last_time = note[0] if note[1]==1: # Note on if active_notes.has_key(note[2]): pass else: # key and value are the same, but we don't really care. active_notes[note[2]]=note[2] elif note[1]==0: # Note off if(active_notes.has_key(note[2])): active_notes.pop(note[2]) blocks.append(block) active = app.activeBlock() if active==0: active=1 app.gcode.insBlocks(active, blocks, "Midi2CNC") app.refresh() app.setStatus(_("Generated Midi2CNC, ready to play?"))
def create_block(self, holes, name): targetDepth = self.fromMm("TargetDepth") peck = self.fromMm("Peck") dwell = self["Dwell"] block = Block(name) holesCount = 0 for bid in holes: for xH,yH,zH in bid: holesCount += 1 block.append(CNC.zsafe()) block.append(CNC.grapid(xH,yH)) if (peck != 0) : z = 0 while z > targetDepth: z = max(z-peck, targetDepth) block.append(CNC.zenter(zH + z)) block.append(CNC.zsafe()) block.append(CNC.zenter(zH + targetDepth)) #dwell time only on last pass if dwell != 0: block.append(CNC.gcode(4, [("P",dwell)])) #Gcode Zsafe on finish block.append(CNC.zsafe()) return (block,holesCount)
def execute(self, app): #Get inputs holesDistance = self.fromMm("HolesDistance") targetDepth = self.fromMm("TargetDepth") peck = self.fromMm("Peck") dwell = self["Dwell"] zSafe = CNC.vars["safe"] #Check inputs if holesDistance <= 0: app.setStatus(_("Driller abort: Distance must be > 0")) return if peck < 0: app.setStatus(_("Driller abort: Peck must be >= 0")) return if dwell < 0: app.setStatus( _("Driller abort: Dwell time >= 0, here time runs only forward!" )) return # Get selected blocks from editor selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Driller abort: Please select some path")) return #Get all segments from gcode allSegments = self.extractAllSegments(app, selBlocks) #Create holes locations allHoles = [] for bidSegment in allSegments: if len(bidSegment) == 0: continue #Summ all path length fullPathLength = 0.0 for s in bidSegment: fullPathLength += s[3] #Calc rest holes = fullPathLength // holesDistance rest = fullPathLength - (holesDistance * (holes)) #Travel along the path elapsedLength = rest / 2.0 #equaly distribute rest, as option??? bidHoles = [] while elapsedLength <= fullPathLength: #Search best segment to apply line interpolation bestSegment = bidSegment[0] segmentsSum = 0.0 perc = 0.0 for s in bidSegment: bestSegment = s segmentLength = bestSegment[3] perc = (elapsedLength - segmentsSum) / segmentLength segmentsSum += segmentLength if segmentsSum > elapsedLength: break #Fist point x1 = bestSegment[0][0] y1 = bestSegment[0][1] z1 = bestSegment[0][2] #Last point x2 = bestSegment[1][0] y2 = bestSegment[1][1] z2 = bestSegment[1][2] #Check if segment is not excluded if not bestSegment[2]: newHolePoint = (x1 + perc * (x2 - x1), y1 + perc * (y2 - y1), z1 + perc * (z2 - z1)) bidHoles.append(newHolePoint) #Go to next hole elapsedLength += holesDistance #Add bidHoles to allHoles allHoles.append(bidHoles) #Write gcommands from allSegments to the drill block n = self["name"] if not n or n == "default": n = "Driller" blocks = [] block = Block(self.name) holesCount = 0 for bid in allHoles: for xH, yH, zH in bid: holesCount += 1 block.append(CNC.grapid(None, None, zH + zSafe)) block.append(CNC.grapid(xH, yH)) if (peck != 0): z = 0 while z > targetDepth: z = max(z - peck, targetDepth) block.append(CNC.zenter(zH + z)) block.append(CNC.grapid(None, None, zH + zSafe)) block.append(CNC.zenter(zH + targetDepth)) #dwell time only on last pass if dwell != 0: block.append(CNC.gcode(4, [("P", dwell)])) #Gcode Zsafe on finish block.append(CNC.zsafe()) blocks.append(block) #Insert created block active = app.activeBlock() if active == 0: active = 1 app.gcode.insBlocks(active, blocks, "Driller") app.refresh() app.setStatus(_("Generated Driller: %d holes") % holesCount)
def execute(self, app): try: import midiparser as midiparser except: app.setStatus(_("Error: This plugin requires midiparser.py")) return n = self["name"] if not n or n == "default": n = "Midi2CNC" fileName = self["File"] x = 0.0 y = 0.0 z = 0.0 x_dir = 1.0 y_dir = 1.0 z_dir = 1.0 # List of MIDI channels (instruments) to import. # Channel 10 is percussion, so better to omit it channels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] axes = self["AxisUsed"] active_axes = len(axes) transpose = (0, 0, 0) ppu = [200, 200, 200] ppu[0] = self["ppu_X"] ppu[1] = self["ppu_X"] ppu[2] = self["ppu_X"] safemin = [0, 0, 0] safemax = [100, 100, 50] safemax[0] = self["max_X"] safemax[1] = self["max_Y"] safemax[2] = self["max_Z"] try: midi = midiparser.File(fileName) except: app.setStatus(_("Error: Sorry can't parse the Midi file.")) return noteEventList = [] all_channels = set() for track in midi.tracks: #channels=set() for event in track.events: if event.type == midiparser.meta.SetTempo: tempo = event.detail.tempo # filter undesired instruments if ((event.type == midiparser.voice.NoteOn) and (event.channel in channels)): if event.channel not in channels: channels.add(event.channel) # NB: looks like some use "note on (vel 0)" as equivalent to note off, so check for vel=0 here and treat it as a note-off. if event.detail.velocity > 0: noteEventList.append([ event.absolute, 1, event.detail.note_no, event.detail.velocity ]) else: noteEventList.append([ event.absolute, 0, event.detail.note_no, event.detail.velocity ]) if (event.type == midiparser.voice.NoteOff) and (event.channel in channels): if event.channel not in channels: channels.add(event.channel) noteEventList.append([ event.absolute, 0, event.detail.note_no, event.detail.velocity ]) # Finished with this track if len(channels) > 0: msg = ', '.join(['%2d' % ch for ch in sorted(channels)]) #print 'Processed track %d, containing channels numbered: [%s ]' % (track.number, msg) all_channels = all_channels.union(channels) # List all channels encountered if len(all_channels) > 0: msg = ', '.join(['%2d' % ch for ch in sorted(all_channels)]) #print 'The file as a whole contains channels numbered: [%s ]' % msg # We now have entire file's notes with abs time from all channels # We don't care which channel/voice is which, but we do care about having all the notes in order # so sort event list by abstime to dechannelify noteEventList.sort() # print noteEventList # print len(noteEventList) last_time = -0 active_notes = { } # make this a dict so we can add and remove notes by name # Start the output #Init blocks blocks = [] block = Block(self.name) block.append("(Midi2CNC)") block.append("(Midi:%s)" % fileName) block.append(CNC.zsafe()) block.append(CNC.grapid(0, 0)) block.append(CNC.zenter(0)) for note in noteEventList: # note[timestamp, note off/note on, note_no, velocity] if last_time < note[0]: freq_xyz = [0, 0, 0] feed_xyz = [0, 0, 0] distance_xyz = [0, 0, 0] duration = 0 # "i" ranges from 0 to "the number of active notes *or* the number of active axes, # whichever is LOWER". Note that the range operator stops # short of the maximum, so this means 0 to 2 at most for a 3-axis machine. # E.g. only look for the first few active notes to play despite what # is going on in the actual score. for i in range(0, min(len(active_notes.values()), active_axes)): # Which axis are should we be writing to? # j = self.axes_dict.get(axes)[i] # Debug # print"Axes %s: item %d is %d" % (axes_dict.get(args.axes), i, j) # Sound higher pitched notes first by sorting by pitch then indexing by axis # nownote = sorted(active_notes.values(), reverse=True)[i] # MIDI note 69 = A4(440Hz) # 2 to the power (69-69) / 12 * 440 = A4 440Hz # 2 to the power (64-69) / 12 * 440 = E4 329.627Hz # freq_xyz[j] = pow( 2.0, (nownote - 69 + transpose[j]) / 12.0) * 440.0 # Here is where we need smart per-axis feed conversions # to enable use of X/Y *and* Z on a Makerbot # # feed_xyz[0] = X; feed_xyz[1] = Y; feed_xyz[2] = Z; # # Feed rate is expressed in mm / minutes so 60 times # scaling factor is required. feed_xyz[j] = (freq_xyz[j] * 60.0) / ppu[j] # Get the duration in seconds from the MIDI values in divisions, at the given tempo duration = (((note[0] - last_time) + 0.0) / (midi.division + 0.0) * (tempo / 1000000.0)) # Get the actual relative distance travelled per axis in mm distance_xyz[j] = (feed_xyz[j] * duration) / 60.0 # Now that axes can be addressed in any order, need to make sure # that all of them are silent before declaring a rest is due. if distance_xyz[0] + distance_xyz[1] + distance_xyz[2] > 0: # At least one axis is playing, so process the note into # movements combined_feedrate = math.sqrt(feed_xyz[0]**2 + feed_xyz[1]**2 + feed_xyz[2]**2) # Turn around BEFORE crossing the limits of the # safe working envelope if self.reached_limit(x, distance_xyz[0], x_dir, safemin[0], safemax[0]): x_dir = x_dir * -1 x = (x + (distance_xyz[0] * x_dir)) if self.reached_limit(y, distance_xyz[1], y_dir, safemin[1], safemax[1]): y_dir = y_dir * -1 y = (y + (distance_xyz[1] * y_dir)) if self.reached_limit(z, distance_xyz[2], z_dir, safemin[2], safemax[2]): z_dir = z_dir * -1 z = (z + (distance_xyz[2] * z_dir)) v = (x, y, z) block.append(CNC.glinev(1, v, combined_feedrate)) else: # Handle 'rests' in addition to notes. duration = (((note[0] - last_time) + 0.0) / (midi.division + 0.0)) * (tempo / 1000000.0) block.append(CNC.gcode(4, [("P", duration)])) # finally, set this absolute time as the new starting time last_time = note[0] if note[1] == 1: # Note on if active_notes.has_key(note[2]): pass else: # key and value are the same, but we don't really care. active_notes[note[2]] = note[2] elif note[1] == 0: # Note off if (active_notes.has_key(note[2])): active_notes.pop(note[2]) blocks.append(block) active = app.activeBlock() if active == 0: active = 1 app.gcode.insBlocks(active, blocks, "Midi2CNC") app.refresh() app.setStatus(_("Generated Midi2CNC, ready to play?"))
def make(self,app, XStart=0.0, YStart=0.0, FlatWidth=10., FlatHeight=10., \ FlatDepth=0, BorderPass=False, CutDirection="Climb", PocketType="Raster"): #GCode Blocks blocks = [] #Check parameters if CutDirection is "": app.setStatus(_("Flatten abort: Cut Direction is undefined")) return if PocketType is "": app.setStatus(_("Flatten abort: Pocket Type is undefined")) return if FlatWidth <= 0 or FlatHeight <= 0 : app.setStatus(_("Flatten abort: Flatten Area dimensions must be > 0")) return if FlatDepth > 0 : app.setStatus(_("Flatten abort: Hey this is only for subtractive machine! Check depth!")) return #Add Region disabled to show worked area block = Block(self.name + " Outline") block.enable = False block.append(CNC.zsafe()) xR,yR = self.RectPath(XStart,YStart,FlatWidth,FlatHeight) for x,y in zip(xR,yR): block.append(CNC.gline(x,y)) blocks.append(block) # Load tool and material settings toolDiam = CNC.vars['diameter'] toolRadius = toolDiam / 2. #Calc tool diameter with Maximum Step Over allowed StepOverInUnitMax = toolDiam * CNC.vars['stepover'] / 100.0 #Offset for Border Cut BorderXStart = XStart + toolRadius BorderYStart = YStart + toolRadius BorderWidth = FlatWidth - toolDiam BorderHeight = FlatHeight - toolDiam BorderXEnd = XStart + FlatWidth - toolRadius BorderYEnd = YStart + FlatHeight - toolRadius PocketXStart = BorderXStart PocketYStart = BorderYStart PocketXEnd = BorderXEnd PocketYEnd = BorderYEnd #Calc space to work with/without border cut WToWork = FlatWidth - toolDiam HToWork = FlatHeight - toolDiam if(WToWork < toolRadius or HToWork < toolRadius): app.setStatus(_("Flatten abort: Flatten area is too small for this End Mill.")) return #Prepare points for pocketing xP=[] yP=[] #and border xB=[] yB=[] #--------------------------------------------------------------------- #Raster approach if PocketType == "Raster": #Correct sizes if border is used if(BorderPass): PocketXStart += StepOverInUnitMax PocketYStart += StepOverInUnitMax PocketXEnd -= StepOverInUnitMax PocketYEnd -= StepOverInUnitMax WToWork -= (StepOverInUnitMax) HToWork -= (StepOverInUnitMax) #Calc number of pass VerticalCount = (int)(HToWork / StepOverInUnitMax) #Calc step minor of Max step StepOverInUnit = HToWork / (VerticalCount +1) flip = False ActualY = PocketYStart #Zig zag if StepOverInUnit==0 : StepOverInUnit=0.001 #avoid infinite while loop while (True): #Zig xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd)) yP.append(ActualY) flip = not flip #Zag xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd)) yP.append(ActualY) if(ActualY >= PocketYEnd - StepOverInUnitMax + StepOverInUnit): break #Up ActualY += StepOverInUnit xP.append(self.ZigZag(flip,PocketXStart,PocketXEnd)) yP.append(ActualY) #Points for border cut depends on Zig/Zag end if(BorderPass): if flip: xB,yB = self.RectPath(BorderXStart,BorderYEnd,BorderWidth,-BorderHeight) else: xB,yB = self.RectPath(BorderXEnd,BorderYEnd,-BorderWidth,-BorderHeight) #Reverse in case of Climb if CutDirection == "Climb": xB = xB[::-1] yB = yB[::-1] #--------------------------------------------------------------------- #Offset approach if PocketType == "Offset": #Calc number of pass VerticalCount = (int)(HToWork / StepOverInUnitMax) HorrizontalCount = (int)(WToWork / StepOverInUnitMax) #Make them odd if VerticalCount%2 == 0 : VerticalCount += 1 if HorrizontalCount%2 == 0 : HorrizontalCount += 1 #Calc step minor of Max step StepOverInUnitH = HToWork / (VerticalCount) StepOverInUnitW = WToWork / (HorrizontalCount) #Start from border to center xS = PocketXStart yS = PocketYStart wS = WToWork hS = HToWork xC = 0 yC = 0 while (xC<=HorrizontalCount/2 and yC<=VerticalCount/2): #Pocket offset points xO,yO = self.RectPath(xS, yS, wS, hS) if CutDirection == "Conventional": xO = xO[::-1] yO = yO[::-1] xP = xP + xO yP = yP + yO xS+=StepOverInUnitH yS+=StepOverInUnitW hS-=2.0*StepOverInUnitH wS-=2.0*StepOverInUnitW xC += 1 yC += 1 #Reverse point to start from inside (less stres on the tool) xP = xP[::-1] yP = yP[::-1] #Blocks for pocketing block = Block(self.name) block.append("(Flatten from X=%g Y=%g)"%(XStart,YStart)) block.append("(W=%g x H=%g x D=%g)"%(FlatWidth,FlatHeight,FlatDepth)) block.append("(Approach: %s %s)" % (PocketType,CutDirection)) if BorderPass : block.append("(with border)") #Move safe to first point block.append(CNC.zsafe()) block.append(CNC.grapid(xP[0],yP[0])) #Init Depth currDepth = 0. stepz = CNC.vars['stepz'] if stepz==0 : stepz=0.001 #avoid infinite while loop #Create GCode from points while True: currDepth -= stepz if currDepth < FlatDepth : currDepth = FlatDepth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) #Pocketing for x,y in zip(xP,yP): block.append(CNC.gline(x,y)) #Border cut if request for x,y in zip(xB,yB): block.append(CNC.gline(x,y)) #Verify exit condition if currDepth <= FlatDepth : break #Move to the begin in a safe way block.append(CNC.zsafe()) block.append(CNC.grapid(xP[0],yP[0])) #Zsafe block.append(CNC.zsafe()) blocks.append(block) return blocks
def make(self): d = self.thick # Convert to external dimensions if self.dx < 0: dx = -self.dx - d * 2 # external to internal else: dx = self.dx if self.dy < 0: dy = -self.dy - d * 2 # external to internal else: dy = self.dy if self.dz < 0: dz = -self.dz - d * 2 # external to internal else: dz = self.dz blocks = [] block = Block("%s-Bottom" % (self.name)) block.append("(Box: %g x %g x %g)" % (self.dx, self.dy, self.dz)) block.append("(Fingers: %d x %d x %d)" % (self.nx, self.ny, self.nz)) self._rectangle(block, 0., -d, dx, dy, self.nx, -self.ny, 0, d) blocks.append(block) block = Block("%s-Left" % (self.name)) self._rectangle(block, -(dz + 5 * d), -d, dz, dy, self.nz, self.ny, d, d) blocks.append(block) block = Block("%s-Right" % (self.name)) self._rectangle(block, dx + 3 * d, -d, dz, dy, self.nz, self.ny, d, d) blocks.append(block) block = Block("%s-Front" % (self.name)) self._rectangle(block, 0, -(dz + 4 * d), dx, dz, -self.nx, -self.nz, 0, 0) blocks.append(block) block = Block("%s-Back" % (self.name)) self._rectangle(block, 0, dy + 4 * d, dx, dz, -self.nx, -self.nz, 0, 0) blocks.append(block) block = Block("%s-Top" % (self.name)) self._rectangle(block, dx + dz + 8 * d, -d, dx, dy, self.nx, -self.ny, 0, d) blocks.append(block) return blocks
def make(self,RExt=50., RInt=33., ROff=13. , Depth=0): self.RExt = RExt self.RInt = RInt self.ROff = ROff if RExt>RInt : self.Spins = self.lcm(RExt,RInt) / max(RExt,RInt) else: self.Spins = self.lcm(RExt,RInt) / min(RExt,RInt) self.Depth = Depth self.PI = math.pi self.theta = 0.0 blocks = [] block = Block(self.name) block.append("(External Radius = %g)"%(self.RExt)) block.append("(Internal Radius = %g)"%(self.RInt)) block.append("(Offset Radius = %g)"%(self.ROff)) xi,yi = zip(*(self.calc_dots())) block.append(CNC.zsafe()) block.append(CNC.grapid(xi[0],yi[0])) currDepth = 0. stepz = CNC.vars['stepz'] if stepz==0 : stepz=0.001 #avoid infinite while loop while True: currDepth -= stepz if currDepth < self.Depth : currDepth = self.Depth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) for x,y in zip(xi,yi): block.append(CNC.gline(x,y)) block.append(CNC.gline(xi[0],yi[0])) if currDepth <= self.Depth : break block.append(CNC.zsafe()) blocks.append(block) return blocks
def make(self, Nlines, LineLen, StartEndLen, Step, CornerRes, Depth): blocks = [] block = Block(self.name) points = self.zigzag(Nlines, LineLen, StartEndLen, Step, CornerRes) block.append(CNC.zsafe()) block.append(CNC.grapid(points[0][0],points[0][1])) currDepth = 0. stepz = CNC.vars['stepz'] if stepz==0 : stepz=0.001 #avoid infinite while loop while True: currDepth -= stepz if currDepth < Depth : currDepth = Depth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) for (x,y) in points: block.append(CNC.gline(x,y)) if currDepth <= Depth : break block.append(CNC.zsafe()) blocks.append(block) return blocks
def calc(self, D, res, pocket): blocks = [] block = Block(self.name) # Load tool and material settings toolDiam = CNC.vars['diameter'] toolRadius = toolDiam/2. stepz = CNC.vars['stepz'] stepxy = toolDiam*(CNC.vars['stepover']/100.) if toolDiam <= 0 or stepxy <= 0 or stepz <= 0 or D <= 0 or res <= 0: return blocks currDepth = 0. def setCutFeedrate(): block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) def addCircumference(radius): block.append(CNC.garc(2,radius, 0., i=-radius)) # Mills a circle, pocketing it if needed def addSingleCircle(radius, depth): if pocket: block.append(CNC.grapid(0., 0.)) block.append(CNC.zenter(depth)) setCutFeedrate() currRadius = 0. while radius > currRadius+stepxy: currRadius += stepxy block.append(CNC.gline(currRadius, 0)) addCircumference(currRadius) if radius-currRadius > 0: block.append(CNC.gline(radius, 0)) addCircumference(radius) else: block.append(CNC.grapid(radius, 0.)) block.append(CNC.zenter(depth)) setCutFeedrate() addCircumference(radius) # Mills a circle in steps of height "stepz" def addCircle(radius, depth, currDepth): while depth < currDepth-stepz: currDepth -= stepz addSingleCircle(radius, currDepth) if currDepth-depth > 0: addSingleCircle(radius, depth) return depth block.append(CNC.zsafe()) r = D/2. r -= toolRadius # Removes offset of ball-end tool angleInc = res currAngle = 0. angle = math.pi/2. # 90 degrees while angle > currAngle+angleInc: currAngle += angleInc radius = r * math.cos(-currAngle) depth = r * math.sin(-currAngle) - toolRadius # Removes vertical offset (centers the ball tool in Z=0, rather than the tip) currDepth = addCircle(radius, depth, currDepth) if angle-currAngle > 0: radius = r * math.cos(-angle) depth = r * math.sin(-angle) - toolRadius currDepth = addCircle(radius, depth, currDepth) blocks.append(block) return blocks
def execute(self, app): # info =xnew,ynew,znew,dxy,dz xscale= self["xscale"] if xscale=="":xscale=1 yscale= self["yscale"] if yscale=="":yscale=1 zscale= self["zscale"] if zscale=="":zscale=1 surface = CNC.vars["surface"] if zscale>0: surface*=zscale feed = self["feed"] zfeed = CNC.vars["cutfeedz"] rpm = self["rpm"] if self["zfeed"]: zfeed = self["zfeed"] #zup = self["zup"] centered = self["centered"] # zbeforecontact=surface+CNC.vars["zretract"] # hardcrust = surface - CNC.vars["hardcrust"] # feedbeforecontact = CNC.vars["feedbeforecontact"]/100.0 # hardcrustfeed = CNC.vars["hardcrustfeed"]/100.0 # Get selected blocks from editor selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Scaling abort: Please select some path")) return elements=len(app.editor.getSelectedBlocks()) print("elements",elements) for bid in app.editor.getSelectedBlocks(): if len(app.gcode.toPath(bid)) < 1: continue path = app.gcode.toPath(bid)[0] if centered: center = path.center() else: center=0,0 print ("center",center[0],center[1]) # if elements>=2: # center=0,0 #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks)[0] name_block = self.extractAllSegments(app,selBlocks)[1] # num_block = self.extractAllSegments(app,selBlocks)[2] #Create holes locations all_blocks=[] for bidSegment in allSegments: if len(bidSegment)==0: continue # all_blocks = [] n = self["name"] # if not n or n=="default": n="Trochoidal_3D" if elements>1: n="scale " else: if centered: n="center scale "+str(name_block) else: n="scale "+str(name_block) bid_block = Block(n) for idx, segm in enumerate(bidSegment): # if idx >= 0: # bid_block.append("(idx "+str(idx)+" -------------- )") info=self.scaling(segm,center,xscale,yscale,zscale) if idx == 0: bid_block.append("(---- Scale (x "+str(xscale)+" : 1.0),(y "+str(yscale)+" : 1.0),(z "+str(zscale)+" : 1.0) ---- )") bid_block.append("(center "+str(center[0])+" ,"+str(center[1])+" )") bid_block.append("M03") bid_block.append("S "+str(rpm)) bid_block.append(CNC.zsafe()) bid_block.append("F "+str(zfeed)) bid_block.append("g0 x "+str(info[0])+" y "+str(info[1])) currentfeed=oldfeed=zfeed else: # if B[5]>=0: #<< zsign # currentfeed=feed # else: #relationship if info[4]>=0: currentfeed=feed else: rel=info[3]/(info[3]+abs(info[4])) currentfeed=int(rel*feed+(1-rel)*zfeed) if segm[0][2]> surface and segm[1][2]>=surface: bid_block.append("g0 x "+str(info[0])+" y "+str(info[1])+ " z "+str(info[2])) else: if currentfeed!=oldfeed: bid_block.append("F "+str(currentfeed)) bid_block.append("g1 x "+str(info[0])+" y "+str(info[1])+ " z "+str(info[2])) oldfeed=currentfeed bid_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material all_blocks.append(bid_block) # print "bid", bid_block.name(), bid_block,"*****************" self.finish_blocks(app, all_blocks,elements)
def make(self,n = 2, size = 100, depth = 0): self.n = n self.size = size self.depth = depth blocks = [] block = Block(self.name) xi,yi = zip(*(self.hilbert(0.0,0.0,size,0.0,0.0,size,n))) block.append(CNC.zsafe()) block.append(CNC.grapid(xi[0],yi[0])) currDepth = 0. stepz = CNC.vars['stepz'] if stepz==0 : stepz=0.001 #avoid infinite while loop while True: currDepth -= stepz if currDepth < self.depth : currDepth = self.depth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) for x,y in zip(xi,yi): block.append(CNC.gline(x,y)) if currDepth <= self.depth : break block.append(CNC.zsafe()) blocks.append(block) return blocks
def execute(self, app): try: from PIL import Image except: app.setStatus(_("Sketch abort: This plugin requires PIL/Pillow to read image data")) return n = self["name"] if not n or n=="default": n="Sketch" #Calc desired size grundgy =self["Grundgy"] maxSize = self["MaxSize"] squiggleTotal = self["SquiggleTotal"] squiggleLength = self["SquiggleLength"] depth = self["Depth"] drawBorder = self["DrawBorder"] channel = self["Channel"] radius = 1 if grundgy == "Low": radius = 2 elif grundgy == "Medium": radius = 3 elif grundgy == "High": radius = 6 elif grundgy == "Very High": radius = 9 #Check parameters if maxSize < 1: app.setStatus(_("Sketch abort: Too small to draw anything!")) return if squiggleTotal < 1: app.setStatus(_("Sketch abort: Please let me draw at least 1 squiggle")) return if squiggleLength <= 0: app.setStatus(_("Sketch abort: Squiggle Length must be > 0")) return fileName = self["File"] try: img = Image.open(fileName) except: app.setStatus(_("Sketch abort: Can't read image file")) return #Create a scaled image to work faster with big image and better with small ones iWidth,iHeight = img.size resampleRatio = 800.0 / iHeight img = img.resize((int(iWidth *resampleRatio) ,int(iHeight * resampleRatio)), Image.ANTIALIAS) if channel == 'Blue': img = img.convert('RGB') img = img.split()[0] elif channel == 'Green': img = img.convert('RGB') img = img.split()[1] elif channel == 'Red': img = img.convert('RGB') img = img.split()[2] else: img = img.convert ('L') #to calculate luminance img = img.transpose(Image.FLIP_TOP_BOTTOM) #ouput correct image pix = img.load() #Get image size self.imgWidth, self.imgHeight = img.size self.ratio = 1 if (iWidth > iHeight): self.ratio = maxSize / float(self.imgWidth) else: self.ratio = maxSize / float(self.imgHeight) #Init blocks blocks = [] #Border block block = Block("%s-border"%(self.name)) block.enable = drawBorder block.append(CNC.zsafe()) block.append(CNC.grapid(0,0)) block.append(CNC.zenter(depth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) block.append(CNC.gline(self.imgWidth * self.ratio, 0)) block.append(CNC.gline(self.imgWidth * self.ratio, self.imgHeight*self.ratio)) block.append(CNC.gline(0, self.imgHeight*self.ratio)) block.append(CNC.gline(0,0)) blocks.append(block) #Draw block block = Block(self.name) block.append("(Sketch size W=%d x H=%d x distance=%d)" % (self.imgWidth * self.ratio , self.imgHeight * self.ratio , depth)) block.append("(Channel = %s)" %(channel)) #choose a nice starting point x = self.imgWidth / 4. y = self.imgHeight / 4. #First round search in all image self.mostest = 256 x,y = self.findFirst(pix, True) #startAll = time.time() for c in range(squiggleTotal): #print c,x,y #start = time.time() x,y = self.findFirst(pix, False) #print 'Find mostest: %f' % (time.time() - start) #move there block.append(CNC.zsafe()) block.append(CNC.grapid(x*self.ratio, y*self.ratio)) #tool down block.append(CNC.zenter(depth)) #restore cut/draw feed block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) #start = time.time() s = 0 while (s < squiggleLength): x,y,distance = self.findInRange(x, y, pix, radius) s+= max(1,distance*self.ratio) #add traveled distance #move there block.append(CNC.gline(x*self.ratio,y*self.ratio)) self.fadePixel(x, y, pix) #adjustbrightness int the bright map #tool up block.append(CNC.zsafe()) #print 'Squiggle: %f' % (time.time() - start) #Gcode Zsafe block.append(CNC.zsafe()) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Sketch") app.refresh() app.setStatus(_("Generated Sketch size W=%d x H=%d x distance=%d, Total length:%d") % (self.imgWidth*self.ratio , self.imgHeight*self.ratio , depth, squiggleTotal*squiggleLength))
def calc(self, N, phi, Pc): N = abs(N) # Pitch Circle D = N * Pc / math.pi R = D / 2.0 # Diametrical pitch Pd = N / D # Base Circle Db = D * math.cos(phi) Rb = Db / 2.0 # Addendum a = 1.0 / Pd # Outside Circle Ro = R + a Do = 2.0 * Ro # Tooth thickness T = math.pi*D / (2*N) # undercut? U = 2.0 / (math.sin(phi) * (math.sin(phi))) needs_undercut = N < U # sys.stderr.write("N:%s R:%s Rb:%s\n" % (N,R,Rb)) # Clearance c = 0.0 # Dedendum b = a + c # Root Circle Rr = R - b Dr = 2.0*Rr two_pi = 2.0*math.pi half_thick_angle = two_pi / (4.0*N) pitch_to_base_angle = self.involute_intersect_angle(Rb, R) pitch_to_outer_angle = self.involute_intersect_angle(Rb, Ro) # pitch_to_base_angle points = [] for x in range(1,N+1): c = x * two_pi / N # angles pitch1 = c - half_thick_angle base1 = pitch1 - pitch_to_base_angle outer1 = pitch1 + pitch_to_outer_angle pitch2 = c + half_thick_angle base2 = pitch2 + pitch_to_base_angle outer2 = pitch2 - pitch_to_outer_angle # points b1 = self.point_on_circle(Rb, base1) p1 = self.point_on_circle(R, pitch1) o1 = self.point_on_circle(Ro, outer1) o2 = self.point_on_circle(Ro, outer2) p2 = self.point_on_circle(R, pitch2) b2 = self.point_on_circle(Rb, base2) if Rr >= Rb: pitch_to_root_angle = pitch_to_base_angle - self.involute_intersect_angle(Rb, Rr) root1 = pitch1 - pitch_to_root_angle root2 = pitch2 + pitch_to_root_angle r1 = self.point_on_circle(Rr, root1) r2 = self.point_on_circle(Rr, root2) points.append(r1) points.append(p1) points.append(o1) points.append(o2) points.append(p2) points.append(r2) else: r1 = self.point_on_circle(Rr, base1) r2 = self.point_on_circle(Rr, base2) points.append(r1) points.append(b1) points.append(p1) points.append(o1) points.append(o2) points.append(p2) points.append(b2) points.append(r2) first = points[0] del points[0] blocks = [] block = Block(self.name) blocks.append(block) block.append(CNC.grapid(first.x(), first.y())) block.append(CNC.zenter(0.0)) #print first.x(), first.y() for v in points: block.append(CNC.gline(v.x(), v.y())) #print v.x(), v.y() #print first.x(), first.y() block.append(CNC.gline(first.x(), first.y())) block.append(CNC.zsafe()) #block = Block("%s-center"%(self.name)) block = Block("%s-basecircle"%(self.name)) block.enable = False block.append(CNC.grapid(Db/2, 0.)) block.append(CNC.zenter(0.0)) block.append(CNC.garc(CW, Db/2, 0., i=-Db/2)) block.append(CNC.zsafe()) blocks.append(block) return blocks
def execute(self, app): n = self["name"] if not n or n == "default": n = "Pyrograph" #Import parameters toolSize = self.fromMm("ToolSize") if toolSize <= 0: app.setStatus(_("Pyrograph abort: Tool Size must be > 0")) return filename = self["File"] #Open gcode file if not (filename == ""): app.load(filename) inOut = self["In-Out"] xadd = self["xAdd"] yadd = self["yAdd"] if xadd == "": xadd = 1 if yadd == "": yadd = 1 #Create the external box if inOut == "Out": box = Block("Box") external_box = [] box.append( CNC.grapid(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd)) box.append( CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymax"] + yadd)) box.append( CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymax"] + yadd)) box.append( CNC.gline(CNC.vars["xmax"] + xadd, CNC.vars["ymin"] - yadd)) box.append( CNC.gline(CNC.vars["xmin"] - xadd, CNC.vars["ymin"] - yadd)) #Insert the external block external_box.append(box) app.gcode.insBlocks(1, external_box, "External_Box") app.refresh() #Value for creating an offset from the margins of the gcode margin = self.fromMm( "Margin" ) #GIVING RANDOM DECIMALS SHOULD AVOID COINCIDENT SEGMENTS BETWEEN ISLAND AND BASE PATHS THAT CONFUSE THE ALGORITHM. WORKS IN MOST CASES. #Add and subtract the margin max_x = CNC.vars["xmax"] + margin min_x = CNC.vars["xmin"] - margin max_y = CNC.vars["ymax"] + margin min_y = CNC.vars["ymin"] - margin #Difference between offtset margins dx = max_x - min_x dy = max_y - min_y #Number of vertical divisions according to the toolsize divisions = dy / toolSize #Distance between horizontal lines step_y = toolSize n_steps_y = int(divisions) + 1 #Create the snake pattern according to the number of divisions pattern = Block(self.name) pattern_base = [] for n in range(n_steps_y): if n == 0: pattern.append(CNC.grapid(min_x, min_y)) #go to bottom left else: y0 = min_y + step_y * (n - 1) y1 = min_y + step_y * (n) if not (n % 2 == 0): pattern.append(CNC.glinev( 1, [max_x, y0])) #write odd lines from left to right pattern.append(CNC.grapid(max_x, y1)) else: pattern.append(CNC.glinev( 1, [min_x, y0])) #write even lines from right to left pattern.append(CNC.grapid(min_x, y1)) #Insert the pattern block pattern_base.append(pattern) app.gcode.insBlocks(1, pattern_base, "pattern") app.refresh() #Mark pattern as island for bid in pattern_base: app.gcode.island([1]) #Select all blocks app.editor.selectAll() paths_base = [] paths_isl = [] points = [] #Compare blocks to separate island from other blocks for bid in app.editor.getSelectedBlocks(): if app.gcode[bid].operationTest('island'): paths_isl.extend(app.gcode.toPath(bid)) else: paths_base.extend(app.gcode.toPath(bid)) #Make intersection between blocks while len(paths_base) > 0: base = paths_base.pop() for island in paths_isl: #points.extend(base.intersectPath(island)) points.extend(island.intersectPath(base)) ###SORTING POINTS### x = [] y = [] #Get (x,y) intersection points for i in range(len(points)): x.append(points[i][2][0]) y.append(points[i][2][1]) #Save (x,y) intersection points in a matrix matrix = [[0 for i in range(2)] for j in range(len(x))] for i in range(len(x)): matrix[i][0] = x[i] matrix[i][1] = y[i] # for i in range(len(x)): # print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1]) #print(matrix) #Sort points in increasing y coordinate matrix.sort(key=itemgetter(1, 0), reverse=False) # for i in range(len(x)): # print('puntos',points[i][0],points[i][1],matrix[i][0], matrix[i][1]) #print(matrix) index = 0 pair = 0 new_matrix = [] for i in range(len(x)): if i == 0: index = index + 1 elif i < len(x) - 1: if matrix[i][1] == matrix[i - 1][1]: index = index + 1 else: if pair % 2 == 0: logic = False else: logic = True submatrix = matrix[i - index:i] submatrix.sort(key=itemgetter(0, 1), reverse=logic) new_matrix.extend(submatrix) index = 1 pair = pair + 1 else: #print('entered') if pair % 2 == 0: logic = False else: logic = True if matrix[i][1] == matrix[i - 1][1]: submatrix = matrix[i - index:] submatrix.sort(key=itemgetter(0, 1), reverse=logic) new_matrix.extend(submatrix) else: index = 1 submatrix = matrix[-1] new_matrix.extend(submatrix) # for i in range(len(x)): # print('puntos',new_matrix[i][0], new_matrix[i][1]) # for i in range(len(x)): # print('puntos',new_matrix[i][0], new_matrix[i][1]) #print(x, y) ###SORTING POINTS END### #Generate the gcode from points obtained blocks = [] block = Block(self.name) for i in range(len(x)): if i == 0: block.append(CNC.grapid(new_matrix[0][0], new_matrix[0][1])) inside = 0 else: if inside == 0: block.append(CNC.gline(new_matrix[i][0], new_matrix[i][1])) inside = 1 else: block.append(CNC.grapid(new_matrix[i][0], new_matrix[i][1])) inside = 0 # for i in range(len(x)): # print('puntos',x[i], y[i]) blocks.append(block) app.gcode.delBlockUndo(1) app.gcode.insBlocks(1, blocks, "Line to Line Burning") app.editor.disable() for block in blocks: block.enable = 1 #app.editor.enable() #app.editor.unselectAll() app.refresh() app.setStatus(_("Generated Line to Line Burning"))
def execute(self, app): rdoc = self["rdoc"] radius = self["dia"]/2 cw = self["cw"] circ = self["circ"] #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): #print(blocks[bid]) path = app.gcode.toPath(bid)[0] #print(path) block = Block("trochoid") entry = self["entry"] for segment in path: #print(segment.A) #block.append("g0 x0 y0") #block.append("g1 x10 y10") #block.append("g1 x20 y10") #block.append("g0 x0 y0") if entry: eblock = Block("trochoid-in") eblock.append("G0 Z0") eblock.append("G0 x"+str(segment.A[0])+" y"+str(segment.A[1]-radius)) eblock.append("G2 x"+str(segment.A[0])+" y"+str(segment.A[1]-radius)+" i"+str(0)+" j"+str(radius)) blocks.append(eblock) entry = False block.append("G0 Z0") block.extend(self.trochoid(segment, rdoc, radius, cw, circ)) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Trochoidal created") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Trochoidal")) #<<< feed back result
def execute(self, app): feed = self["feed"] zfeed = CNC.vars["cutfeedz"] rpm = self["rpm"] if self["zfeed"]: zfeed = self["zfeed"] zup = self["zup"] surface = CNC.vars["surface"] # zbeforecontact=surface+CNC.vars["zretract"] # hardcrust = surface - CNC.vars["hardcrust"] # feedbeforecontact = CNC.vars["feedbeforecontact"]/100.0 # hardcrustfeed = CNC.vars["hardcrustfeed"]/100.0 # Get selected blocks from editor selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Scaling abort: Please select some path")) return #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks) #Create holes locations # allHoles=[] for bidSegment in allSegments: if len(bidSegment)==0: continue blocks = [] n = self["name"] # if not n or n=="default": n="Trochoidal_3D" n="Scaling" scal_block = Block(n) for idx, segm in enumerate(bidSegment): if idx >= 0: if idx == 0: scal_block.append("M03") scal_block.append("S "+str(rpm)) scal_block.append(CNC.zsafe()) scal_block.append("F "+str(feed)) scal_block.append("(--------------------------------------------------)") B=self.scaling(segm) if segm[0][2]> surface and segm[1][2]>=surface: scal_block.append("g0 x "+str(B[0])+" y "+str(B[1])+ " z "+str(B[2])) else: scal_block.append("g1 x "+str(B[0])+" y "+str(B[1])+ " z "+str(B[2])) scal_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material blocks.append(scal_block) self.finish_blocks(app, blocks)
def execute(self, app): name = self['name'] if not name or name == 'default': name = 'Function' # Initialize blocks that will contain our gCode blocks = [] block = Block(name) #Variable definitions formula = self['form'] res = self['res'] # X resolution ran = [self['ranX'], self['ranY']] # Range of X,Y, from -10, to 10 range is 20 cent = [ self['centX'], self['centY'] ] # Coordinates X,Y of the center from bottom left of the coordinate system dim = [self['dimX'], self['dimY']] # Real dimensions in gcode units spacX = self['spacX'] # Spacing of X axis lines spacY = self['spacY'] # Spacing of Y axis lines lin = self['lin'] # Small value - length of a line in gcode units draw = self['draw'] # Draw the coordinate system block.append("(Generated with a script by kswiorek)\n") block.append("(Equation: " + formula + ")\n") block.append("(Resolution: " + str(res) + ")\n") block.append("(Range: " + str(ran) + ")\n") block.append("(Center: " + str(cent) + ")\n") block.append("(Dimensions: " + str(dim) + ")\n") block.append("(SpacingXY: " + str(spacX) + ", " + str(spacY) + ")\n") def mapc(var, axis): #Map coordinate systems return (var * (dim[axis] / ran[axis])) #Define coordinate system mins and maxes minX = -cent[0] maxX = ran[0] - cent[0] minY = -cent[1] maxY = ran[1] - cent[1] #Define domain and codomain X = [] Y = [] e_old = "" #Store old exception to comapre #Calculate values for arguments with a resolution for i in range(0, int(ran[0] / res + 1)): #Complaints about values beeing floats x = i * res + minX #Iterate x X.append(x) try: Y.append(eval(formula)) except Exception as exc: #Append None, not to loose sync with X Y.append(None) e = str(exc) if e != e_old: #If there is a different exception - display it print("Warning: " + str(e)) app.setStatus(_("Warning: " + str(e))) e_old = e raised = True # Z axis is raised at start #Clip values out of bounds, replace with None, not to loose sync with X for i, item in enumerate(Y): y = Y[i] if not y is None and (y < minY or y > maxY): Y[i] = None #Y without "None", min() and max() can't compare them Ynn = [] #Y no Nones for i, item in enumerate(Y): if not Y[i] is None: Ynn.append(Y[i]) block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])])) #Set feedrate if draw: #If the user selected to draw the coordinate system #X axis block.append(CNC.grapid(z=3)) block.append(CNC.grapid(0, mapc(cent[1], 1))) #1st point of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] + lin * 1.2, mapc( cent[1], 1))) #End of X axis line + a bit more for the arrow block.append( CNC.gline(dim[0] - lin / 2, mapc(cent[1], 1) - lin / 2)) #bottom part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(dim[0] + lin * 1.2, mapc(cent[1], 1), 0)) #End of X axis line block.append(CNC.grapid(z=0)) block.append( CNC.gline(dim[0] - lin / 2, mapc(cent[1], 1) + lin / 2)) #top part of the arrow block.append(CNC.grapid(z=3)) #Y axis, just inverted x with y block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), 0)) #1st point of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline( mapc(cent[0], 0), dim[1] + lin * 1.2)) #End of Y axis line + a bit more for the arrow block.append( CNC.gline(mapc(cent[0], 0) - lin / 2, dim[1] - lin / 2)) #left part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), dim[1] + lin * 1.2)) #End of Y axis line block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(cent[0], 0) + lin / 2, dim[1] - lin / 2)) #right part of the arrow block.append(CNC.grapid(z=3)) #X axis number lines i = 0 while i < ran[0] - cent[0]: #While i is on the left of the arrow i += spacX #Add line spacing #Draw lines right of the center block.append( CNC.grapid(mapc(i + cent[0], 0), mapc(cent[1], 1) + lin / 2)) block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(i + cent[0], 0), mapc(cent[1], 1) - lin / 2)) block.append(CNC.grapid(z=3)) i = 0 while i > -cent[ 0]: #While i is lower than center coordinate, inverted for easier math i -= spacX #Add line spacing #Draw lines left of the center block.append( CNC.grapid(mapc(i + cent[0], 0), mapc(cent[1], 1) + lin / 2)) block.append(CNC.grapid(z=0)) block.append( CNC.gline(mapc(i + cent[0], 0), mapc(cent[1], 1) - lin / 2)) block.append(CNC.grapid(z=3)) #Y axis number lines i = 0 while i < ran[1] - cent[ 1]: #While i is between the center and the arrow i += spacX #Add line spacing #Draw lines top of the center (everything just inverted) block.append( CNC.grapid( mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=0)) block.append( CNC.gline( mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=3)) i = 0 while i > -1 * cent[1]: i -= spacX #Add line spacing #Draw lines bottom of the center block.append( CNC.grapid( mapc(cent[0], 0) + lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=0)) block.append( CNC.gline( mapc(cent[0], 0) - lin / 2, mapc(i + cent[1], 1))) block.append(CNC.grapid(z=3)) raised = True #Z was raised #Draw graph for i, item in enumerate(Y): if not Y[i] is None: x = mapc(X[i] + cent[0], 0) #Take an argument y = mapc(Y[i] + cent[1], 1) #Take a value else: y = Y[i] #only for tne None checks next if y is None and not raised: #If a None "period" just started raise Z raised = True block.append(CNC.grapid(z=3)) elif not y is None and raised: #If Z was raised and the None "period" ended move to new coordinates block.append(CNC.grapid(round(x, 2), round(y, 2))) block.append(CNC.grapid(z=0)) #Lower Z raised = False elif not y is None and not raised: #Nothing to do with Nones? Just draw block.append(CNC.gline(round(x, 2), round(y, 2))) block.append(CNC.grapid(z=3)) #Raise on the end blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, 'Function inserted' ) #insert blocks over active block in the editor app.refresh() #refresh editor app.setStatus(_('Generated function graph')) #feed back result print()
def execute(self, app): name = self['name'] if not name or name == 'default': name = 'Function' # Initialize blocks that will contain our gCode blocks = [] block = Block(name) #Variable definitions formula = self['form'] res = self['res'] # X resolution ran = [self['ranX'], self['ranY']] # Range of X,Y, from -10, to 10 range is 20 cent = [self['centX'], self['centY']] # Coordinates X,Y of the center from bottom left of the coordinate system dim = [self['dimX'], self['dimY']] # Real dimensions in gcode units spacX = self['spacX'] # Spacing of X axis lines spacY = self['spacY'] # Spacing of Y axis lines lin = self['lin'] # Small value - length of a line in gcode units draw = self['draw'] # Draw the coordinate system block.append("(Generated with a script by kswiorek)\n") block.append("(Equation: " + formula +")\n") block.append("(Resolution: " + str(res) +")\n") block.append("(Range: " + str(ran) +")\n") block.append("(Center: " + str(cent) +")\n") block.append("(Dimensions: " + str(dim) +")\n") block.append("(SpacingXY: " + str(spacX) +", " + str(spacY) +")\n") def mapc(var, axis): #Map coordinate systems return (var * (dim[axis]/ran[axis])) #Define coordinate system mins and maxes minX = -cent[0] maxX = ran[0]-cent[0] minY = -cent[1] maxY = ran[1]-cent[1] #Define domain and codomain X = [] Y = [] e_old = "" #Store old exception to comapre #Calculate values for arguments with a resolution for i in range(0, int(ran[0]/res+1)): #Complaints about values beeing floats x = i*res + minX #Iterate x X.append(x) try: Y.append(eval(formula)) except Exception as exc: #Append None, not to loose sync with X Y.append(None) e = str(exc) if e != e_old: #If there is a different exception - display it print("Warning: " + str(e)) app.setStatus(_("Warning: " + str(e))) e_old = e raised = True # Z axis is raised at start #Clip values out of bounds, replace with None, not to loose sync with X for i, item in enumerate(Y): y = Y[i] if not y is None and (y < minY or y > maxY): Y[i] = None #Y without "None", min() and max() can't compare them Ynn = [] #Y no Nones for i, item in enumerate(Y): if not Y[i] is None: Ynn.append(Y[i]) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) #Set feedrate if draw: #If the user selected to draw the coordinate system #X axis block.append(CNC.grapid(z=3)) block.append(CNC.grapid(0, mapc(cent[1], 1))) #1st point of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] + lin*1.2, mapc(cent[1], 1))) #End of X axis line + a bit more for the arrow block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) - lin / 2)) #bottom part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(dim[0] + lin*1.2, mapc(cent[1], 1), 0)) #End of X axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(dim[0] - lin/2, mapc(cent[1], 1) + lin / 2)) #top part of the arrow block.append(CNC.grapid(z=3)) #Y axis, just inverted x with y block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), 0)) #1st point of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line + a bit more for the arrow block.append(CNC.gline(mapc(cent[0], 0) - lin / 2, dim[1] - lin/2)) #left part of the arrow block.append(CNC.grapid(z=3)) block.append(CNC.grapid(mapc(cent[0], 0), dim[1] + lin*1.2)) #End of Y axis line block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) + lin / 2, dim[1] - lin/2)) #right part of the arrow block.append(CNC.grapid(z=3)) #X axis number lines i = 0 while i < ran[0] - cent[0]: #While i is on the left of the arrow i +=spacX #Add line spacing #Draw lines right of the center block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2)) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2)) block.append(CNC.grapid(z=3)) i = 0 while i > -cent[0]: #While i is lower than center coordinate, inverted for easier math i -=spacX #Add line spacing #Draw lines left of the center block.append(CNC.grapid(mapc(i+cent[0],0), mapc(cent[1], 1) + lin/2)) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(i+cent[0],0), mapc(cent[1], 1) - lin/2)) block.append(CNC.grapid(z=3)) #Y axis number lines i = 0 while i < ran[1] - cent[1]: #While i is between the center and the arrow i +=spacX #Add line spacing #Draw lines top of the center (everything just inverted) block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=3)) i = 0 while i > -1*cent[1]: i -=spacX #Add line spacing #Draw lines bottom of the center block.append(CNC.grapid(mapc(cent[0], 0) + lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=0)) block.append(CNC.gline(mapc(cent[0], 0) - lin/2, mapc(i+cent[1],1))) block.append(CNC.grapid(z=3)) raised = True #Z was raised #Draw graph for i, item in enumerate(Y): if not Y[i] is None: x = mapc(X[i]+cent[0], 0) #Take an argument y = mapc(Y[i]+cent[1], 1) #Take a value else: y = Y[i] #only for tne None checks next if y is None and not raised: #If a None "period" just started raise Z raised = True block.append(CNC.grapid(z=3)) elif not y is None and raised: #If Z was raised and the None "period" ended move to new coordinates block.append(CNC.grapid(round(x, 2),round(y, 2))) block.append(CNC.grapid(z=0)) #Lower Z raised = False elif not y is None and not raised: #Nothing to do with Nones? Just draw block.append(CNC.gline(round(x, 2),round(y, 2))) block.append(CNC.grapid(z=3)) #Raise on the end blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, 'Function inserted') #insert blocks over active block in the editor app.refresh() #refresh editor app.setStatus(_('Generated function graph')) #feed back result print()
def execute(self, app): #Get inputs fontSize = self.fromMm("FontSize") depth = self.fromMm("Depth") textToWrite = self["Text"] fontFileName = self["FontFile"] imageFileName = self["ImageToAscii"] charsWidth = self["CharsWidth"] #Check parameters!!! if fontSize <=0: app.setStatus(_("Text abort: please input a Font size > 0")) return if fontFileName == "": app.setStatus(_("Text abort: please select a font file")) return if imageFileName != "": try: textToWrite = self.asciiArt(imageFileName,charsWidth) except: pass if textToWrite == "": textToWrite = "Nel mezzo del cammin di nostra vita..." return #Init blocks blocks = [] n = self["name"] if not n or n == "default": n = "Text" block = Block(n) if(u'\n' in textToWrite): block.append("(Text:)") for line in textToWrite.splitlines(): block.append("(%s)" % line) else: block.append("(Text: %s)" % textToWrite) try: import ttf font = ttf.TruetypeInfo(fontFileName) except: app.setStatus(_("Text abort: That embarrassing, I can't read this font file!")) return cmap = font.get_character_map() kern = None try: kern = font.get_glyph_kernings() except: pass adv = font.get_glyph_advances() xOffset = 0 yOffset = 0 glyphIndxLast = cmap[' '] for c in textToWrite: #New line if c == u'\n': xOffset = 0.0 yOffset -= 1#offset for new line continue if c in cmap: glyphIndx = cmap[c] if (kern and (glyphIndx,glyphIndxLast) in kern): k = kern[(glyphIndx,glyphIndxLast)] #FIXME: use kern for offset?? #Get glyph contours as line segmentes and draw them gc = font.get_glyph_contours(glyphIndx) if(not gc): gc = font.get_glyph_contours(0)#standard glyph for missing glyphs (complex glyph) if(gc and not c==' '): #FIXME: for some reason space is not mapped correctly!!! self.writeGlyphContour(block, font, gc, fontSize, depth, xOffset, yOffset) if glyphIndx < len(adv): xOffset += adv[glyphIndx] else: xOffset += 1 glyphIndxLast = glyphIndx #Remeber to close Font font.close() #Gcode Zsafe block.append(CNC.zsafe()) blocks.append(block) active = app.activeBlock() if active==0: active=1 app.gcode.insBlocks(active, blocks, "Text") app.refresh() app.setStatus("Generated Text")
def execute(self, app): # ae = self.fromMm("ae") if self["splicesteps"] =="" or self["splicesteps"]<4: steps=4/(2*pi) else: steps=self["splicesteps"]/(2*pi) # manualsetting = self["manualsetting"] manualsetting = 1 #=========== Converted to comment and changed for current compatibility ============================== # cutradius = CNC.vars["trochcutdiam"]/2.0 cutradius = self["diam"]/2.0 # cutradius = CNC.vars["trochcutdiam"]/2.0 #========================================================================================= zfeed = CNC.vars["cutfeedz"] feed =CNC.vars["cutfeed"] minimfeed =CNC.vars["cutfeed"] if manualsetting: if self["diam"]: cutradius = self["diam"]/2.0 if self["zfeed"] and self["zfeed"]!="": zfeed = self["zfeed"] # if self["minimfeed"] and self["minimfeed"]!="": # minimfeed = min (self["minimfeed"],feed) if self["feed"] and self["feed"]!="": feed = self["feed"] if self["endmill"]: self.master["endmill"].makeCurrent(self["endmill"]) # radius = CNC.vars["cutdiam"]/2.0 # radius = self["diam"]/2.0 toolRadius = CNC.vars["diameter"]/2.0 radius = max(0,cutradius-toolRadius) oldradius=radius #----------------------------------------------------------- # helicalRadius = self["helicalDiam"]/2.0 # if helicalRadius=="": # helicalRadius=radius # else: # helicalRadius=max(0,helicalRadius- toolRadius) helicalRadius=radius #----------------------------------------------------------- # helicalRadius=min(0.99*toolRadius,helicalRadius) # if radius!=0: # helicalRadius= min(helicalRadius,radius) helicalPerimeter=pi*2.0*helicalRadius # helicalangle = self["helicalangle"] # if helicalangle>89.5: # helicalangle=89.5 # if helicalangle<0.01: # helicalangle=0.01 # downPecking=helicalPerimeter*tan(radians(helicalangle)) cw = self["cw"] surface = CNC.vars["surface"] #=========== Converted to comment and changed for current compatibility ============================== # zbeforecontact=surface+CNC.vars["zretract"] # zbeforecontact=surface+CNC.vars["zretract"] # hardcrust = surface - CNC.vars["hardcrust"] # feedbeforecontact = CNC.vars["feedbeforecontact"]/100.0 # hardcrustfeed = CNC.vars["hardcrustfeed"]/100.0 zbeforecontact=surface zbeforecontact=surface hardcrust = surface feedbeforecontact = zfeed hardcrustfeed = feed #===================================================================================================== t_splice = self["TypeSplice"] dtadaptative = 0.0001 adaptativepolice=0 # minimradius = min(radius, toolRadius*self["MinTrochDiam"]/(100)) # minimradius = min(radius, toolRadius*self["MinTrochDiam"]/(100)) # minimradius = min(radius, toolRadius*CNC.vars["mintrochdiam"]/(100)) atot = self.fromMm("ae") # spiral_twists=(radius-helicalRadius)/atot#<<spiral ae smaller than ae (aprox 50%) # if (radius-helicalRadius)%atot: spiral_twists=1+(radius-helicalRadius)//atot spiral_twists=ceil(radius-helicalRadius)/atot#<<spiral ae smaller than ae (aprox 50%) rpm = self["rpm"] downPecking=helicalPerimeter*zfeed/feed helicalangle=degrees(atan2(downPecking,helicalPerimeter)) # steps=self["splicesteps"]/2*pi # K_Z = self["K_Z"] # if K_Z == "": # K_Z = 1.0 # K_XY = self["K_XY"] # if K_XY == "": # K_XY = 1.0 # s_z = self["S_z"] # s_xy = self["S_xy"] # xyfeed = CNC.vars["cutfeed"] # zfeed *= K_Z # xyfeed *=K_XY # Get selected blocks from editor # def trochprofile_bcnc(self, cutDiam=0.0, direction=None, offset=0.0, overcut=False,adaptative=False, adaptedRadius=0.0, tooldiameter=0.0, name=None): # app.trochprofile_bcnc(trochcutdiam, direction, self["offset"], self["overcut"], self["adaptative"], cornerradius, CNC.vars["diameter"], name) #<< diameter only to information # cornerradius = (cutradius - CNC.vars["diameter"]/2.0 direction=self["direction"] if direction!="on (3d Path)": targetDepth=self["targetDepth"] depthIncrement=self["depthIncrement"] # tabsnumber=self["tabsnumber"] # tabsWidth=self["tabsWidth"] # tabsHeight=self["tabsHeight"] tabsnumber=tabsWidth=tabsHeight=0 app.trochprofile_bcnc(2*cutradius, direction,self["offset"], self["overcut"], self["adaptative"], radius, CNC.vars["diameter"],\ targetDepth, depthIncrement, tabsnumber, tabsWidth, tabsHeight) app.refresh() # app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() # if not selBlocks: # app.editor.selectAll() # selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Trochoid abort: Please select some path")) return #Check inputs if cutradius <= toolRadius: app.setStatus(_("Trochoid Cut Diameter has to be greater than End mill")) return if helicalRadius <= 0.0: app.setStatus(_("Helical Descent Diameter has to be greater than End mill")) return if feed <= 0: app.setStatus(_("Feed has to be greater than 0")) return if zfeed <= 0: app.setStatus(_("Plunge Feed has to be greater than 0")) return if minimfeed <= 0: app.setStatus(_("Minimum Adaptative Feed has to be greater than 0")) return #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks) #Create holes locations # allHoles=[] for bidSegment in allSegments: if len(bidSegment)==0: continue blocks = [] # n = self["name"] # if not n or n=="default": n="Trochoidal_3D" # newname = Block.operationName(path.name) n="Troch3d" tr_block = Block(n) phi=oldphi=0# oldadaptativephi=0 oldsegm=[[0,0,0],[0,0,0]] # segments --------------------------------------------- for idx, segm in enumerate(bidSegment): if idx >= 0: if cw: u = 1 arc = "G2" else: u = -1 arc = "G3" # ////////////--------------------------------------------------------------------- # information: --------------------------------------------------------------------- segLength = self.calcSegmentLength(segm) # --------------------------------------------- # tr_block.append("(seg length "+str(round(segLength,4))+" )") # ----------------------------------------------------------------------------- # ////////---------------------------------------------------------------------- if idx == 0: # tr_block.append("(-------------- PARAMETERS ------------------------)") tr_block.append("(Cut diam "+str( cutradius*2 )+" (troch "+str(radius*2.0)+"+End mill "+str(toolRadius*2.0)+" ) Advance "+str(atot)+" )") # tr_block.append("(Cut diam "+str(CNC.vars["trochcutdiam"])+" (troch "+str(radius*2.0)+" + End mill " + str(toolRadius*2.0)+" ) Advance "+str(atot)+" )") # tr_block.append("(Min troch "+str(int(CNC.vars["mintrochdiam"]))+"% = "+str(minimradius*2.0)+"mm , min cut diam "+str(2*(minimradius+toolRadius))+"mm )") tr_block.append("(Feed "+str(feed)+" Plunge feed "+ str(zfeed)+" )") #tr_block.append("(Helical diam "+str(round((helicalRadius+toolRadius)*2,2))+" ( helical diam "+str(helicalRadius*2.0)+"+End mill "+str(toolRadius*2.0)+" )") tr_block.append("(Helical descent angle " + str(round(helicalangle,2)) +" cut diam " + str(round(helicalRadius*2.0,3))+" drop by lap "\ + str(round(downPecking,2)) + " )") tr_block.append("(--------------------------------------------------)") tr_block.append("(M06 T0 "+str(toolRadius*2.0)+" mm)") tr_block.append("M03") tr_block.append("S "+str(rpm)) tr_block.append("F "+str(feed)) # phi = atan2(segm[1][1]-segm[0][1], segm[1][0]-segm[0][0]) # oldphi=phi #<< declare initial angle # l = self.pol2car(radius, phi+radians(90*u)) # r = self.pol2car(radius, phi+radians(-90*u)) # B = segm[1][0],segm[1][1],segm[1][2] # bl = self.pol2car(radius, phi+radians(90*u), B) # br = self.pol2car(radius, phi+radians(-90*u), B) tr_block.append("( Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+" )")#+ " oldphi "+str(round(oldphi*57.29,2))+" )") tr_block.append("(Starting point)") if (round(segm[1][1]-segm[0][1],4)==0 and round(segm[1][0]-segm[0][0],4)==0): phi=1234567890 tr_block.append("(The original first movement is vertical)") else: tr_block.append("(The original first movement is not vertical)") tr_block.append(CNC.zsafe()) # tr_block.append("g0 x "+str(B[0])+" y"+str(B[1])+" )")#" z "+str(B[2])+" )") # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" R "+str(radius/2.0)+" z"+str(B[2])) # tr_block.append(arc+" x"+str(br[0])+" y"+str(br[1])+" i"+str(r[0]/2.0)+" j"+str(r[1]/2.0)) #<< as cutting # tr_block.append(("g1 x "+str(br[0])+" y"+str(br[1])+" z"+str(B[2]))) # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" i"+str(l[0])+" j"+str(l[1])) # tr_block.append(arc+" x"+str(br[0])+" y"+str(br[1])+" i"+str(r[0])+" j"+str(r[1])+" z"+str(round(B[2],5))) #<< as cutting # if t_splice=="Circular both sides rectified": # tr_block.append(arc+" x"+str(bl[0])+" y"+str(bl[1])+" i"+str(-r[0])+" j"+str(-r[1])) tr_block.append("(--------------------------------------------------)") # tr_block.append(CNC.grapid(br[0],br[1],B[2])) # tr_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material # tr_block.append(CNC.zenter(surface)) # <<< TROCHOID CENTER # tr_block.append(CNC.grapid(segm[1][0],segm[1][1],segm[1][2])) # tr_block.append(CNC.zbeforecontact()) # <<< TROCHOID CENTER # tr_block.append(CNC.xyslowentersurface(0,-45.0)) # <<< TROCHOID CENTER # tr_block.append(("g0 z "+str(zbeforecontact))) # tr_block.append("( new segment begins )") # distance to trochoid center # if there is movement in xy plane phi calculate if (segm[1][1]-segm[0][1]!=0 or segm[1][0]-segm[0][0]!=0): phi = atan2(segm[1][1]-segm[0][1], segm[1][0]-segm[0][0]) # On surface # if segm[0][2]>zbeforecontact and segm[1][2]>zbeforecontact: if segm[0][2]>surface and segm[1][2]>surface: tr_block.append("(Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+ " On Surface)" ) tr_block.append(CNC.grapid(segm[1][0],segm[1][1],segm[1][2])) else: tr_distance = self.center_distance(segm,atot) A = segm[0][0],segm[0][1],segm[0][2] d=segLength ae = tr_distance[4] # ////////////--------------------------------------------------------------------- # information: --------------------------------------------------------------------- adv = tr_distance[3] #<<< ap = tr_distance[2] # << =zadd # --------------------------------------------- tr_block.append("(-----------------------------------------)") control_cameback = self.came_back(segm, oldsegm) if control_cameback: tr_block.append("(-------------> Came back !! <------------- )")#+str(control_cameback)+" )") # tr_block.append("( old Ax "+str(round(oldsegm[0][0],3))+" Ay "+str(round(oldsegm[0][1],3))+" Bx "+ str(round(oldsegm[1][0],3))+" By "+ str(round(oldsegm[1][1],3))+" )") # tr_block.append("( curr Ax "+str(round(segm[0][0],3))+" Ay "+str(round(segm[0][1],3))+" Bx "+ str(round(segm[1][0],3))+" By "+ str(round(segm[1][1],3))+" )") if round(segLength,5) <= dtadaptative: adaptativepolice+=1.0 tr_block.append("(Seg "+str(idx)+" adaptativepolice " +str(adaptativepolice)+" length "+str(round(segLength,5))+" )") # /////////// Trochoid method ////////////////////////////////////////////////////////////////////////////// if adaptativepolice==0 or adaptativepolice >2.5: tr_block.append("( Seg: "+str(idx)+" phi "+str(round(degrees(phi),2))+ " oldphi "+str(round(degrees(oldphi),2))+" length "+str(round(segLength,5))+" )") tr_block.append("(ae: "+str(round(ae,5))+" dz: "+str(round(ap,4))+"adv: "+str(round(adv,4))+" )") # tr_block.append("( Bx "+str(round(segm[1][0],2))+ " By "+ str(round(segm[1][1],2))) # ----------------------------------------------------------------------------- # ////////---------------------------------------------------------------------- if control_cameback: # adaptativepolice+=0.5 B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) t_splice="came_back" # tr_block.extend(self.trochoid(t_splice,A,B,minimradius,radius,oldphi,phi,cw)) tr_block.extend(self.trochoid(t_splice,A,B,0.0,radius,oldphi,phi,cw)) tr_block.append("F "+ str(feed)) t_splice = self["TypeSplice"] else: # from POINT A -- to ---> POINT B if segLength<=adv: tr_block.append("(Only one trochoid, oldphi "+str(round(degrees(oldphi),2))+" )") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,oldphi,phi,cw)) while d >adv: # first trochoid # tr_block.append("d "+ str(d)) B = A[0]+tr_distance[0], A[1]+tr_distance[1], A[2]+tr_distance[2] # intermediates points = trochoids points # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER # tr_block.extend(self.trochoid(A,B,radius,phi,oldphi,cw)) tr_block.append("(distance to end segment "+str(round(d,4))+" )") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,oldphi,phi,cw)) A=B d-=adv oldphi=phi # last point if B[0] != segm[1][0] or B[1] != segm[1][1] or B[2] != segm[1][2]: B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER tr_block.append("(---last trochoid, distance to end segment "+str(round(d,4))+" ---)") tr_block.extend(self.trochoid(t_splice,A,B,oldradius,radius,phi,phi,cw)) adaptativepolice=0 # /////// Adapative method ////////////////////////////////////////////////////////////////////////////////////////////////////////// # if oldphi==3600: else: if adaptativepolice==1: #goes to de two warning movements lastphi=oldphi tr_block.append("( Alarm "+ str(adaptativepolice)+" Seg: "+str(idx)+" phi " + str(round(degrees(phi),2))\ + "oldphi "+str(round(degrees(oldphi),2))+ " )") # difangle=(phi-oldadaptativephi) # tr_block.append("(dif angle:"+str(round(difangle,4))+" )") # oldadaptativephi=oldphi=phi # round(difangle,5)==round(pi,5): elif adaptativepolice==2: phi=lastphi if control_cameback:# abs(round(difangle,6)) == (round(pi,6)): tr_block.append("(Starts adaptative trochoids"+" adaptativepolice "+str(adaptativepolice) ) adaptativepolice +=0.5 elif adaptativepolice==2.5: # tr_block.append("(-----------------------------------------)") # adaptradius=minimradius tr_block.append("(Adaptative Seg: "+str(idx)+" length "+str(round(segLength,5))+" phi "+str(round(degrees(phi),2))\ +" oldphi "+str(round(degrees(oldphi),2))+" )") # tr_block.append("( Ax "+str(round(segm[0][0],2))+ " Ay "+ str(round(segm[0][1],2))) # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) # from POINT A -- to ---> POINT B # if adaptativepolice==1: tr_distance = self.center_distance(segm,atot/3.0) #<<< short advanc distances A = segm[0][0],segm[0][1],segm[0][2] d=segLength ae = tr_distance[4] adv = tr_distance[3] #<<< d-=adv while d >0:#adv: # first trochoid if d!=segLength-adv: oldphi=phi # tr_block.append("d "+ str(d)) B = A[0]+tr_distance[0], A[1]+tr_distance[1], A[2]+tr_distance[2] #------------------------------ # adaptradius= a*d + minimradius # if d=0 : adaptradius=minimradius # if d=seglength : adaptradius=radius # a=(radius-minimradius)/segLength # adaptradius=a*d+minimradius a=radius/segLength adaptradius=(self.roundup(a*d,4))#+minimradius #------------------------------ if t_splice!="Splices": t_splice="Warpedarc" tr_block.append("(from trochoid distance to end segment "+str(round(d,4))+" )") tr_block.append("(adaptradius "+ str(round(adaptradius,4))+" radius " + str(radius)+" )") # tr_block.append("F "+ str(feed*adaptradius//radius)) tr_block.append("F "+ str(minimfeed+(feed-minimfeed) *adaptradius//radius)) if adaptradius>0.0: tr_block.extend(self.trochoid(t_splice,A,B,oldradius,adaptradius,oldphi,phi,cw)) else: tr_block.append("(R= "+str(adaptradius)+ "not sent )") # tr_block.append("G1 x"+str(round(B[0],4))+" y "+str(round(B[1],4))+" z "+str(round(B[2],4))) A=B d-=adv oldradius=adaptradius # oldadaptativephi=0 #REVISAR, A COMENTADO # last point # d=0 # oldradius=adaptradius # adaptradius=minimradius # if B[0] != segm[1][0] or B[1] != segm[1][1] or B[2] != segm[1][2]: # B = segm[1][0],segm[1][1],segm[1][2] # tr_block.append(CNC.gline(B[0],B[1],B[2])) # <<< TROCHOID CENTER # tr_block.append("(last trochoid, from trochoid distance to end segment "+str(round(d,4))+" )") # tr_block.append("(adaptradius "+ str(adaptradius)+" )") # tr_block.append("F "+ str(feed*adaptradius//radius)) # tr_block.extend(self.trochoid(t_splice,A,B,oldradius,adaptradius,phi,phi,cw)) adaptativepolice=0 tr_block.append("(Adaptative Completed)") tr_block.append("F "+ str(feed//3)) # if adaptativepolice>1: t_splice = self["TypeSplice"] # adaptativepolice=0 oldradius=radius oldsegm=segm oldphi=phi # /////// Vertical movement /////////////////////////////////////////////////////////////////////////////////////////////////////////////// elif idx!=0: tr_block.append("(Seg: "+str(idx)+" length "+str(round(segLength,4))+" phi "+str(round(degrees(phi),2))+" oldphi "+str(round(degrees(oldphi),2))+" )" ) tr_block.append("(Helical descent") # descent A=segm[0][0],segm[0][1],segm[0][2] if segm[0][2] > segm[1][2]: if segm[0][2] >zbeforecontact:# and segm[1][2]<=surface: if segm[1][2]<=zbeforecontact: B = segm[1][0],segm[1][1],max(segm[1][2],zbeforecontact) tr_block.append("(Rapid helical to z before contact "+"helicalRadius "+str(helicalRadius)+" )") if idx==1 and oldphi==1234567890: tr_block.append("g0 x "+str(B[0])+" y"+str(B[1])+" )")#" z "+str(B[2])+" )") tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) # Instead of decreasing the speed, to avoid the jerkl, decrease the drop by lap if segm[0][2] >surface:# and segm[1][2]<=surface: if segm[1][2]<=surface: tr_block.append("(Slow helical to surface )" ) A=A[0],A[1],zbeforecontact d=A[2]-surface adv=downPecking * feedbeforecontact while d > adv: B = segm[1][0],segm[1][1],max(segm[1][2],A[2]-adv) tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],surface tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) if segm[0][2] >hardcrust:# and segm[1][2]<=surface: if hardcrust< surface: if segm[1][2]<=hardcrust: tr_block.append("(Helical in hard crust)" ) A=A[0],A[1],surface d=A[2]-hardcrust adv=downPecking * hardcrustfeed while d > adv: B = segm[1][0],segm[1][1],max(segm[1][2],A[2]-adv) tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],hardcrust tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) tr_block.append("(Helical to target )" ) A=A[0],A[1],hardcrust d=A[2]-segm[1][2] adv=downPecking while d > adv: B = segm[1][0],segm[1][1],A[2]-adv tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) A=A[0],A[1],B[2] d-=adv B = segm[1][0],segm[1][1],segm[1][2] tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) tr_block.append("(Flatten)") tr_block.extend(self.helical(B,B,helicalRadius,phi,u)) if round(helicalRadius,4)!=round(radius,4): tr_block.append("(Spiral adjustement)") # tr_block.extend(self.trochoid(t_splice,B,B,radius,helicalRadius,phi,phi+4*pi,cw)) # steps=max(1,int(steps*radius*(spiral_twists)/2.0)) # steps=min(steps, 12*spiral_twists) # steps*=spiral_twists # tr_block.append("(Spiral steps "+str(steps)+" in "+str(int((spiral_twists/2.)+1))+" twists)") # tr_block.append("(Spiral "+str(int((spiral_twists/2.)+1))+" twists)") tr_block.append("(Spiral "+str(spiral_twists)+" twists)") tr_block.extend(self.splice_generator(B,B,helicalRadius,radius,phi,phi-spiral_twists*2*pi, radians(-90),radians(-90),u,1.2*steps)) tr_block.append("(Target diameter)") # tr_block.extend(self.helical(B,B,radius,phi,u)) tr_block.extend(self.trochoid(t_splice,B,B,radius,radius,phi,phi,cw)) # ascent elif segm[1][2] > segm[0][2]: tr_block.append("(Helical rapid ascentt "+"helicalRadius "+str(helicalRadius)+" )" ) B = segm[1][0],segm[1][1],segm[1][2] tr_block.extend(self.helical(A,B,helicalRadius,phi,u)) # tr_block.append(CNC.grapid(center[0],center[1],center[2])) # tr_block.extend(CNC.grapid(center)) # end of segment # tr_block.append(CNC.gline(segm[1][0],segm[1][1],segm[1][2])) # oldsegm=segm tr_block.append("(-----------------------------------------)") tr_block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material blocks.append(tr_block) self.finish_blocks(app, blocks)
def make(self,app, XStart=0.0, YStart=0.0, ZStart=30., AlignAxis="Y", \ RotAxis="A", StockLeng=20, ReduceDepth=-1, PassDepth=1, \ Stepover=1, ZApproach=35, SpiralType="Spiral", CutBoth="True", LiftPass="******"): #GCode Blocks blocks = [] # Load tool and material settings toolDiam = CNC.vars['diameter'] toolRadius = toolDiam / 2. #Calc tool diameter with Maximum Step Over allowed StepOverInUnitMax = toolDiam * CNC.vars['stepover'] / 100.0 #Check parameters if RotAxis == "": app.setStatus(_("Spiral abort: Rotary Axis is undefined")) return if SpiralType == "": app.setStatus(_("Spiral abort: Spiral Type is undefined")) return if ZApproach <= ZStart : app.setStatus(_("Spiral abort: Approach height must be greater than Z Start")) return if ReduceDepth > 0 : app.setStatus(_("Spiral abort: Depth Reduction must be negative")) return if Stepover > StepOverInUnitMax and SpiralType == "Spiral": #if Type is Lines then stepover is degrees not mm app.setStatus(_("Spiral abort: Step Over exceeds tool limits")) return elif Stepover > StepOverInUnitMax and SpiralType == "Lines": # This could cause a tool crash, but could also be used to make faceted shapes. dr=tkMessageBox.askyesno("Crash Risk","WARNING: Using a larger stepover value than tool's maximum with lines operation may result in a tool crash. Do you want to continue?") sys.stdout.write("%s"%(dr)) if dr == True or dr == "yes" : app.setStatus(_("Risk Accepted")) #Using positive logic, if python returns ANYTHING other than True/yes this will not make g-code. Incase Python uses No instead of False else: return if StockLeng <= 0 : app.setStatus(_("Spiral abort: Stock Length to cut must be positive")) return #Add Region disabled to show worked area block = Block(self.name + " Outline") block.enable = False block.append(CNC.grapid(CNC.vars["wx"],CNC.vars["wy"],ZApproach)) ## Cannot trust Safe-Z with 4th axis!! if AlignAxis == "X": outlineWidth = StockLeng else: outlineWidth = 0 if AlignAxis == "Y": outlineHeight = StockLeng else: outlineHeight = 0 xR,yR = self.RectPath(XStart,YStart,outlineWidth,outlineHeight) for x,y in zip(xR,yR): block.append(CNC.gline(x,y)) blocks.append(block) if StockLeng < toolDiam : app.setStatus(_("Spiral abort: Stock Length is too small for this End Mill.")) return #Prepare points for pocketing xP=[] yP=[] rP=[] zP=[] gP=[] #--------------------------------------------------------------------- #Line approach if SpiralType == "Lines": #Calc number of indexes IndexNum = math.ceil(360/Stepover) # Using the step over as Degrees #Calc number of pass VerticalCount = math.ceil(abs(ReduceDepth) / PassDepth) #Calc even depths of cut EvenCutDepths = ReduceDepth / VerticalCount currentR = 0 currentZ = ZStart - EvenCutDepths direction = 1 if AlignAxis == "X" : currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return while (currentZ >= (ZStart + ReduceDepth)): #sys.stdout.write("~~~~~%s,%s,%s,%s,%s!"%(currentZ,ZStart,ReduceDepth,EvenCutDepths,VerticalCount)) while (currentR < 360): #sys.stdout.write("~~~~~%s,%s,%s,%s,%s!"%(currentR,Stepover,currentX,currentY,VerticalCount)) #Plunge in gP.append(1) rP.append(currentR) zP.append(currentZ) xP.append(currentX) yP.append(currentY) if direction == 1: if AlignAxis == "X" : currentX = StockLeng - toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = StockLeng - toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return if CutBoth == "True" : direction = -1 else : if AlignAxis == "X" : currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return direction = 1 gP.append(1) zP.append(currentZ) xP.append(currentX) yP.append(currentY) rP.append(currentR) # Lift before rotating if required, useful to make non-round shape if CutBoth == "False" : # Return to start #Lift Before return gP.append(0) rP.append(currentR) zP.append(ZApproach) xP.append(currentX) yP.append(currentY) #Return to start if AlignAxis == "X" : currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return gP.append(0) xP.append(currentX) yP.append(currentY) rP.append(currentR) zP.append(ZApproach) #Rotate currentR += Stepover gP.append(0) xP.append(currentX) yP.append(currentY) rP.append(currentR) zP.append(ZApproach) elif LiftPass == "True" and CutBoth == "True" : gP.append(0) rP.append(currentR) zP.append(ZApproach) xP.append(currentX) yP.append(currentY) currentR += Stepover gP.append(0) xP.append(currentX) yP.append(currentY) rP.append(currentR) zP.append(ZApproach) elif LiftPass == "False" and CutBoth == "True" : currentR += Stepover gP.append(0) xP.append(currentX) yP.append(currentY) rP.append(currentR) zP.append(ZApproach) currentR=0 gP.append(0) xP.append(currentX) yP.append(currentY) rP.append(currentR) zP.append(ZApproach) #Step Down currentZ += EvenCutDepths #--------------------------------------------------------------------- #Spiral approach if SpiralType == "Spiral": #Calc number of pass StepsPerRot = math.ceil(StockLeng/Stepover) TotalRot = 360 * StepsPerRot #Calc steps in depth VerticalCount = math.ceil(abs(ReduceDepth) / PassDepth) #Calc even depths of cut EvenCutDepths = ReduceDepth / VerticalCount direction = 1 currentZ = ZStart - EvenCutDepths if AlignAxis == "X" : currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return currentR = 0 while (currentZ >= (ZStart + ReduceDepth)): # Plunge to depth currentR += 90 # Ramp the Plunge gP.append(1) rP.append(currentR) zP.append(currentZ) xP.append(currentX) yP.append(currentY) # One Full Rotation for a clean shoulder currentR += 360 gP.append(1) rP.append(currentR) zP.append(currentZ) xP.append(currentX) yP.append(currentY) if AlignAxis == "X" : if direction == 1: currentX = StockLeng - toolRadius else: currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart if direction == 1: currentY = StockLeng - toolRadius else: currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return currentR += TotalRot gP.append(1) rP.append(currentR) zP.append(currentZ) xP.append(currentX) yP.append(currentY) # One Full Rotation for a clean shoulder currentR += 360 gP.append(1) rP.append(currentR) zP.append(currentZ) xP.append(currentX) yP.append(currentY) if CutBoth == "True" : direction *= - 1 else: #Retract gP.append(0) rP.append(currentR) zP.append(ZApproach) xP.append(currentX) yP.append(currentY) # Return and Rewind gP.append(0) rP.append(currentR) zP.append(ZApproach) if AlignAxis == "X" : currentX = XStart + toolRadius currentY = YStart elif AlignAxis == "Y": currentX = XStart currentY = YStart + toolRadius else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return xP.append(currentX) yP.append(currentY) currentZ += EvenCutDepths #Start G-Code Processes #Blocks for pocketing block = Block(self.name) block.append("(Reduce Rotary by Y=%g)"%(ReduceDepth)) block.append("(Approach: %s )" % (SpiralType)) #Move safe to first point block.append(CNC.grapid(CNC.vars["mx"],CNC.vars["my"],ZApproach)) ## Cannot trust Safe-Z with 4th axis!! if AlignAxis == "X" : block.append(CNC.grapid(XStart + toolRadius,YStart)) elif AlignAxis == "Y": block.append(CNC.grapid(XStart,YStart + toolRadius)) else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return block.append(CNC.zenter(ZApproach)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) for g,x,y,z,r in zip(gP, xP,yP,zP, rP): if RotAxis == "A" : if g==0: block.append(CNC.grapidABC(x,y,z,r,CNC.vars["wb"],CNC.vars["wc"])) #sys.stdout.write("%s,%s,%s,%s,%s"%(g,x,y,z,r)) else: block.append(CNC.glineABC(x,y,z,r,CNC.vars["wb"],CNC.vars["wc"])) #sys.stdout.write("%s,%s,%s,%s,%s"%(g,x,y,z,r)) elif RotAxis == "B" : if g==0: block.append(CNC.grapidABC(x,y,z,CNC.vars["wa"],r,CNC.vars["wc"])) else: block.append(CNC.glineABC(x,y,z,CNC.vars["wa"],r,CNC.vars["wc"])) elif RotAxis == "C" : if g==0: block.append(CNC.grapidABC(x,y,z,CNC.vars["wa"],CNC.vars["wb"],r)) else: block.append(CNC.glineABC(x,y,z,CNC.vars["wa"],CNC.vars["wb"],r)) block.append(CNC.grapid(CNC.vars["wx"],CNC.vars["wy"],ZApproach)) ## Cannot trust Safe-Z with 4th axis!! if AlignAxis == "X" : block.append(CNC.grapid(XStart + toolRadius,YStart)) elif AlignAxis == "Y": block.append(CNC.grapid(XStart,YStart + toolRadius)) else: app.setStatus(_("Spiral abort: Rotary Axis Not Assigned.")) return block.append(CNC.zexit(ZApproach)) blocks.append(block) tkMessageBox.showinfo("Crash Risk","WARNING: Check CAM file Header for Z move. If it exists, remove it to prevent tool crash.") return blocks
def execute(self, app): if Image is None: app.setStatus(_("Halftone abort: This plugin requires PIL/Pillow to read image data")) return n = self["name"] if not n or n=="default": n="Halftone" #Calc desired size channel = self["Channel"] invert = self["Invert"] drawSize = self["DrawSize"] cellSize = self["CellSize"] dMax = self["DiameterMax"] dMin = self["DiameterMin"] angle = self["Angle"] drawBorder = self["DrawBorder"] depth = self["Depth"] conical = self["Conical"] #Check parameters if drawSize < 1: app.setStatus(_("Halftone abort: Size too small to draw anything!")) return if dMin > dMax: app.setStatus(_("Halftone abort: Minimum diameter must be minor then Maximum")) return if dMax < 1: app.setStatus(_("Halftone abort: Maximum diameter too small")) return if cellSize < 1: app.setStatus(_("Halftone abort: Cell size too small")) return tool = app.tools["EndMill"] tool_shape = tool["shape"] if conical: if tool_shape== "V-cutting": try: v_angle = float(tool["angle"]) except: app.setStatus(_("Halftone abort: Angle in V-Cutting end mill is missing")) return else: app.setStatus(_("Halftone abort: Conical path need V-Cutting end mill")) return #Open picture file fileName = self["File"] try: img = Image.open(fileName) except: app.setStatus(_("Halftone abort: Can't read image file")) return #Create a scaled image to work faster with big image and better with small ones squareNorm = True if channel == 'Blue(sqrt)': img = img.convert('RGB') img = img.split()[0] elif channel == 'Green(sqrt)': img = img.convert('RGB') img = img.split()[1] elif channel == 'Red(sqrt)': img = img.convert('RGB') img = img.split()[2] else: img = img.convert ('L') #to calculate luminance squareNorm = False #flip image to ouput correct coordinates img = img.transpose(Image.FLIP_TOP_BOTTOM) #Calc divisions for halftone divisions = drawSize / cellSize #Get image size self.imgWidth, self.imgHeight = img.size if (self.imgWidth > self.imgHeight): scale = drawSize / float(self.imgWidth) sample = int(self.imgWidth / divisions) else: scale = drawSize / float(self.imgHeight) sample = int(self.imgHeight / divisions) self.ratio = scale #Halftone circles = self.halftone(img, sample, scale, angle, squareNorm, invert) #Init blocks blocks = [] #Border block if drawBorder: block = Block("%s-border"%(self.name)) block.append(CNC.zsafe()) block.append(CNC.grapid(0,0)) block.append(CNC.zenter(depth)) block.append(CNC.gcode(1, [("f",CNC.vars["cutfeed"])])) block.append(CNC.gline(self.imgWidth * self.ratio, 0)) block.append(CNC.gline(self.imgWidth * self.ratio, self.imgHeight*self.ratio)) block.append(CNC.gline(0, self.imgHeight*self.ratio)) block.append(CNC.gline(0,0)) blocks.append(block) #Draw block block = Block(self.name) #Change color if channel == 'Blue(sqrt)': block.color = "#0000ff" elif channel == 'Green(sqrt)': block.color = "#00ff00" elif channel == 'Red(sqrt)': block.color = "#ff0000" block.append("(Halftone size W=%d x H=%d x D=%d ,Total points:%i)" % (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles))) block.append("(Channel = %s)" % channel) for c in circles: x,y,r = c r = min(dMax/2.0,r) if (r >= dMin/2.): block.append(CNC.zsafe()) block.append(CNC.grapid(x+r,y)) block.append(CNC.zenter(depth)) block.append(CNC.garc(CW,x+r,y,i=-r,)) block.append(CNC.zsafe()) if conical: block.enable = False blocks.append(block) if conical: blockCon = Block("%s-Conical"%(self.name)) for c in circles: x,y,r = c blockCon.append(CNC.zsafe()) blockCon.append(CNC.grapid(x,y)) dv = r / math.tan(math.radians(v_angle/2.)) blockCon.append(CNC.zenter(-dv)) blockCon.append(CNC.zsafe()) blocks.append(blockCon) #Gcode Zsafe active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Halftone") app.refresh() app.setStatus(_("Generated Halftone size W=%d x H=%d x D=%d ,Total points:%i" % (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles))))
def execute(self, app): #Get inputs fontSize = self["FontSize"] depth = self["Depth"] textToWrite = self["Text"] fontFileName = self["FontFile"] imageFileName = self["ImageToAscii"] charsWidth = self["CharsWidth"] #Check parameters!!! if fontSize <= 0: app.setStatus(_("Text abort: please input a Font size > 0")) return if fontFileName == "": app.setStatus(_("Text abort: please select a font file")) return if imageFileName != "": try: textToWrite = self.asciiArt(imageFileName, charsWidth) except: pass if textToWrite == "": textToWrite = "Nel mezzo del cammin di nostra vita..." return #Init blocks blocks = [] n = self["name"] if not n or n == "default": n = "Text" block = Block(n) if (u'\n' in textToWrite): block.append("(Text:)") for line in textToWrite.splitlines(): block.append("(%s)" % line) else: block.append("(Text: %s)" % textToWrite) try: import ttf font = ttf.TruetypeInfo(fontFileName) except: app.setStatus( _("Text abort: That embarrassing, I can't read this font file!" )) return cmap = font.get_character_map() kern = None try: kern = font.get_glyph_kernings() except: pass adv = font.get_glyph_advances() xOffset = 0 yOffset = 0 glyphIndxLast = cmap[' '] for c in textToWrite: #New line if c == u'\n': xOffset = 0.0 yOffset -= 1 #offset for new line continue if c in cmap: glyphIndx = cmap[c] if (kern and (glyphIndx, glyphIndxLast) in kern): k = kern[(glyphIndx, glyphIndxLast)] #FIXME: use kern for offset?? #Get glyph contours as line segmentes and draw them gc = font.get_glyph_contours(glyphIndx) if (not gc): gc = font.get_glyph_contours( 0) #standard glyph for missing glyphs (complex glyph) if ( gc and not c == ' ' ): #FIXME: for some reason space is not mapped correctly!!! self.writeGlyphContour(block, font, gc, fontSize, depth, xOffset, yOffset) if glyphIndx < len(adv): xOffset += adv[glyphIndx] else: xOffset += 1 glyphIndxLast = glyphIndx #Remeber to close Font font.close() #Gcode Zsafe block.append(CNC.zsafe()) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Text") app.refresh() app.setStatus("Generated Text")
def execute(self, app): #Get inputs holesDistance = self.fromMm("HolesDistance") targetDepth = self.fromMm("TargetDepth") peck = self.fromMm("Peck") dwell = self["Dwell"] zSafe = CNC.vars["safe"] #Check inputs if holesDistance <=0: app.setStatus(_("Driller abort: Distance must be > 0")) return if peck <0: app.setStatus(_("Driller abort: Peck must be >= 0")) return if dwell <0: app.setStatus(_("Driller abort: Dwell time >= 0, here time runs only forward!")) return # Get selected blocks from editor selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.setStatus(_("Driller abort: Please select some path")) return #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks) #Create holes locations allHoles=[] for bidSegment in allSegments: if len(bidSegment)==0: continue #Summ all path length fullPathLength = 0.0 for s in bidSegment: fullPathLength += s[3] #Calc rest holes = fullPathLength // holesDistance rest = fullPathLength - (holesDistance * (holes)) #Travel along the path elapsedLength = rest / 2.0 #equaly distribute rest, as option??? bidHoles = [] while elapsedLength <= fullPathLength: #Search best segment to apply line interpolation bestSegment = bidSegment[0] segmentsSum = 0.0 perc = 0.0 for s in bidSegment: bestSegment = s segmentLength = bestSegment[3] perc = (elapsedLength-segmentsSum) / segmentLength segmentsSum += segmentLength if segmentsSum > elapsedLength : break #Fist point x1 = bestSegment[0][0] y1 = bestSegment[0][1] z1 = bestSegment[0][2] #Last point x2 = bestSegment[1][0] y2 = bestSegment[1][1] z2 = bestSegment[1][2] #Check if segment is not excluded if not bestSegment[2]: newHolePoint = (x1 + perc*(x2-x1) , y1 + perc*(y2-y1), z1 + perc*(z2-z1)) bidHoles.append(newHolePoint) #Go to next hole elapsedLength += holesDistance #Add bidHoles to allHoles allHoles.append(bidHoles) #Write gcommands from allSegments to the drill block n = self["name"] if not n or n=="default": n="Driller" blocks = [] block = Block(self.name) holesCount = 0 for bid in allHoles: for xH,yH,zH in bid: holesCount += 1 block.append(CNC.grapid(None,None,zH + zSafe)) block.append(CNC.grapid(xH,yH)) if (peck != 0) : z = 0 while z > targetDepth: z = max(z-peck, targetDepth) block.append(CNC.zenter(zH + z)) block.append(CNC.grapid(None,None,zH + zSafe)) block.append(CNC.zenter(zH + targetDepth)) #dwell time only on last pass if dwell != 0: block.append(CNC.gcode(4, [("P",dwell)])) #Gcode Zsafe on finish block.append(CNC.zsafe()) blocks.append(block) #Insert created block active = app.activeBlock() if active==0: active=1 app.gcode.insBlocks(active, blocks, "Driller") app.refresh() app.setStatus(_("Generated Driller: %d holes")%holesCount)
def paste(self, event=None): try: clipboard = self.selection_get(selection='CLIPBOARD') except: return ypos = self.yview()[0] # paste them after the last selected item # bid,lid push them to self so it can be accessed from addLines() # python3 might fix this with the inner scope try: self._bid, self._lid = self._items[self.curselection()[-1]] except: try: self._bid, self._lid = self._items[-1] except: self._bid = 0 self._lid = None selitems = [] undoinfo = [] def addLines(lines): for line in lines.splitlines(): # Create a new block if self._lid is None: self._bid += 1 if self._bid > len(self.gcode.blocks): self._bid = len(self.gcode.blocks) self._lid = MAXINT block = Block() undoinfo.append(self.gcode.addBlockUndo(self._bid,block)) selitems.append((self._bid, None)) else: block = self.gcode.blocks[self._bid] if self._lid == MAXINT: self._lid = len(block) selitems.append((self._bid, len(block))) else: self._lid += 1 selitems.append((self._bid, self._lid)) undoinfo.append(self.gcode.insLineUndo(self._bid, self._lid, line)) try: # try to unpickle it unpickler = pickle.Unpickler(StringIO(clipboard)) try: while True: obj = unpickler.load() if isinstance(obj,tuple): block = Block.load(obj) self._bid += 1 undoinfo.append(self.gcode.addBlockUndo(self._bid, block)) selitems.append((self._bid,None)) self._lid = None else: addLines(obj) except EOFError: pass except pickle.UnpicklingError: # Paste as text addLines(clipboard) if not undoinfo: return self.gcode.addUndo(undoinfo) self.selection_clear(0,END) self.fill() self.yview_moveto(ypos) self.select(selitems, clear=True) #self.selection_set(ACTIVE) #self.see(ACTIVE) self.winfo_toplevel().event_generate("<<Modified>>")
def execute(self, app): name = self["name"] if not name or name=="default": name="Default Name" sel_Blocks = self["Sel_Blocks"] #Get inputs x = self["X"] y = self["Y"] z = self["Z"] if z == "": z=CNC.vars["surface"] cutDiam = self["CutDiam"] cutRadius = cutDiam/2.0 if self["endmill"]: self.master["endmill"].makeCurrent(self["endmill"]) toolDiam = CNC.vars["diameter"] #Radio = self["RadioHelix"] pitch = self["Pitch"] Depth = self["Depth"] Mult_F_Z = self["Mult_Feed_Z"] helicalCut = self["HelicalCut"] clearanceEntry = self["ClearanceEntry"] clearanceExit = self["ClearanceExit"] clearance = clearanceEntry entry = self["Entry"] returnToSafeZ = self["ReturnToSafeZ"] toolDiam = CNC.vars['diameter'] toolRadius = toolDiam/2.0 Radio = cutRadius - toolRadius if(Radio < 0): Radio = 0 toolDiam = CNC.vars['diameter'] toolRadius = toolDiam/2.0 Radio = cutRadius - toolRadius if clearanceEntry =="": clearanceEntry =0 if clearanceExit =="": clearanceExit =0 if helicalCut == "Helical Cut": turn = 2 p="HelicalCut " elif helicalCut == "Internal Right Thread": turn = 2 p= "IntRightThread " elif helicalCut == "Internal Left Thread": turn = 3 p= "IntLeftThread " elif helicalCut == "External Right Thread": Radio = cutRadius + toolRadius turn = 2 p= "ExtRightThread " elif helicalCut == "External Left Thread": Radio = cutRadius + toolRadius turn = 3 p= "ExtLeftThread " # ------------------------------------------------------------------------------------------------------------------ #Check inputs if sel_Blocks == 0: if x == "" or y == "" : app.setStatus(_("If block selected false, please make a value of x")) return elif helicalCut == "": app.setStatus(_("Helical Abort: Please select helical type")) return elif cutDiam < toolDiam or cutDiam == "": app.setStatus(_("Helical Abort: Helix diameter must be greater than the end mill")) return elif cutDiam <= 0: app.setStatus(_("Helical Abort: Helix diameter must be positive")) return elif pitch <= 0 or pitch =="": app.setStatus(_("Helical Abort: Drop must be greater than 0")) return elif Mult_F_Z <= 0 or Mult_F_Z == "": app.setStatus(_("Helical Abort: Z Feed Multiplier must be greater than 0")) return elif entry == "": app.setStatus(_("Helical Abort: Please selecte Entry and Exit type")) return elif clearanceEntry < 0 or clearanceEntry == "": app.setStatus(_("Helical Abort: Entry Edge Clearence may be positive")) return elif clearanceExit < 0 or clearanceExit == "": app.setStatus(_("Helical Abort: Exit Edge Clearence may be positive")) return # ------------------------------------------------------------------------------------------------------------------ #Initialize blocks that will contain our gCode blocks = [] #block = Block(name) block = Block( p + str(cutDiam) + " Pitch " + str(pitch) + " Bit " + str(toolDiam) + " depth " + str(Depth)) cutFeed = CNC.vars["cutfeedz"] #<<< Get cut feed Z for the current material cutFeedMax = CNC.vars["cutfeed"] #<<< Get cut feed XY for the current material # ------------------------------------------------------------------------------------------------------------------ # Get selected blocks from editor selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() if not selBlocks: if sel_Blocks == 1: app.setStatus(_("Helical abort: Please select some path")) return # ------------------------------------------------------------------------------------------------------------------ # Get selected blocks from editor if sel_Blocks == 1: selBlocks = app.editor.getSelectedBlocks() if not selBlocks: app.editor.selectAll() selBlocks = app.editor.getSelectedBlocks() #Get all segments from gcode allSegments = self.extractAllSegments(app,selBlocks) #Create holes locations allHoles=[] for bidSegment in allSegments: if len(bidSegment)==0: continue bidHoles = [] for idx, anchor in enumerate(bidSegment): if idx ==2: newHolePoint = (anchor[0][0],anchor[0][1],anchor[0][2]) bidHoles.append(newHolePoint) #Add bidHoles to allHoles allHoles.append(bidHoles) # ------------------------------------------------------------------------------------------------------------------ holesCount = 0 for bid in allHoles: for xH,yH,zH in bid: x = xH y = yH # ------------------------------------------------------------------------------------------------------------------ # Init: Adjust feed and rapid move to Z safe if Mult_F_Z is"": Mult_F_Z = 1 if Mult_F_Z == 0: Mult_F_Z = 1 if Mult_F_Z * cutFeed > cutFeedMax: cutFeed = cutFeedMax else: cutFeed = cutFeed*Mult_F_Z block.append(CNC.zsafe()) #<<< Move rapid Z axis to the safe height in Stock Material # Move rapid to X and Y coordinate if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread": if entry == "Center": block.append(CNC.grapid(x,y)) else: block.append(CNC.grapid(x-Radio+clearance ,y)) if helicalCut == "External Right Thread" or helicalCut == "External Left Thread": if entry == "Center": clearance = 0.0 block.append(CNC.grapid(x-Radio-clearance ,y)) #cutFeed = int(cutFeed) block.append(CNC.fmt("f",cutFeed)) #<<< Set cut feed # block.append(CNC.gline(x,y) # while (z < 1): block.append(CNC.zenter(z)) block.append(CNC.gline(x-Radio,y)) # cutFeed = int((CNC.vars["cutfeed"] + CNC.vars["cutfeedz"])/2) #<<< Get cut feed for the current material #cutFeed = int(cutFeed) block.append(CNC.fmt("F",cutFeed)) #<<< Set cut feed #----------------------------------------------------------------------------------------------------- # Uncomment for first flat pass if helicalCut == "Helical Cut": block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)])) #----------------------------------------------------------------------------------------------------- if (z < Depth): pitch = -pitch while ((z-pitch) < Depth) : z = z-pitch block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)])) else: while ((z-pitch) >= Depth) : z = z-pitch block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)])) #Target Level if entry == "Center": clearanceExit = 0.0 clearance = clearanceExit alpha= round(Depth / pitch, 4 ) - round(Depth / pitch, 0) alpha = alpha * 2*pi Radiox = Radio * cos(alpha) Radioy = Radio * sin(alpha) xsi = Radiox - clearance* cos(alpha) ysi =Radioy - clearance* sin(alpha) xse = Radiox + clearance* cos(alpha) yse =Radioy + clearance* sin(alpha) z = Depth if helicalCut == "Helical Cut": block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)])) #Last flat pass block.append(CNC.gcode(turn, [("X",x-Radio),("Y",y),("Z", z),("I",Radio), ("J",0)])) elif helicalCut == "Internal Right Thread" or helicalCut == "External Right Thread": block.append(CNC.gcode(turn, [("X",x-Radiox),("Y",y-Radioy),("Z", z),("I",Radio), ("J",0)])) elif helicalCut == "Internal Left Thread" or helicalCut == "External Left Thread": block.append(CNC.gcode(turn, [("X",x-Radiox),("Y",y+Radioy),("Z", z),("I",Radio), ("J",0)])) # Exit clearance if helicalCut == "Internal Right Thread": block.append(CNC.gline(x-xsi,y-ysi)) elif helicalCut == "Internal Left Thread": block.append(CNC.gline(x-xsi,y+ysi)) if helicalCut == "External Right Thread": block.append(CNC.gline(x-xse,y-yse)) elif helicalCut == "External Left Thread": block.append(CNC.gline(x-xse,y+yse)) # Return to Z Safe if returnToSafeZ == 1: if helicalCut == "Helical Cut" or helicalCut == "Internal Right Thread" or helicalCut == "Internal Left Thread": if entry == "Center": block.append(CNC.gline(x,y)) block.append(CNC.zsafe()) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Helical_Descent inserted") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Helical_Descent Result")) #<<< feed back result
def make(self, RExt=50., RInt=33., ROff=13., Depth=0): self.RExt = RExt self.RInt = RInt self.ROff = ROff if RExt > RInt: self.Spins = self.lcm(RExt, RInt) / max(RExt, RInt) else: self.Spins = self.lcm(RExt, RInt) / min(RExt, RInt) self.Depth = Depth self.PI = math.pi self.theta = 0.0 blocks = [] block = Block(self.name) block.append("(External Radius = %g)" % (self.RExt)) block.append("(Internal Radius = %g)" % (self.RInt)) block.append("(Offset Radius = %g)" % (self.ROff)) xi, yi = zip(*(self.calc_dots())) block.append(CNC.zsafe()) block.append(CNC.grapid(xi[0], yi[0])) currDepth = 0. stepz = CNC.vars['stepz'] if stepz == 0: stepz = 0.001 #avoid infinite while loop while True: currDepth -= stepz if currDepth < self.Depth: currDepth = self.Depth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])])) for x, y in zip(xi, yi): block.append(CNC.gline(x, y)) block.append(CNC.gline(xi[0], yi[0])) if currDepth <= self.Depth: break block.append(CNC.zsafe()) blocks.append(block) return blocks
def GetStitches(self, app, FileName ): try: from struct import * except: app.setStatus("Embroidery abort: no module named struct") return print(FileName) try: f = open(FileName,'rb') except: app.setStatus(" Embroidery abort: Can't read image file") return app.setStatus(" Embroidery: file %s sucsessfully opened"%f.name) #DST header struct checking - parsing format = "3s16sc3s7sc3s3sc3s5sc3s5sc3s5sc3s5sc3s6sc3s6sc" data=f.read(94) LAN,LA,C,STN,ST,C,CLN,CL,C,POSX,posx,C,NEGX,negx,C,POSY,posy,C,NEGY,negy,C,AX,ax,C,AY,ay,c=unpack(format, data) CL=int(CL) ST=int(ST) if (LAN !='LA:'): app.setStatus(" Embroidery abort: Not a DST") print (LA) print(" St count: %d color changes=%d"%(ST ,CL)) f.seek(512); coordX=0;coordY=0;#initial coordinates to start sewing cnt=0;#just counter color = 0;#color code format="1b1b1b"# 3 unsigned bytes from data field prevCol=self.color i=0 blocks = [] for ColorCycles in range (0 , CL+1): #color cycles block = Block(self.name) while prevCol==self.color: ff=f.read(3);#read 24 bits cnt+=1 if len(ff)<3: break b0,b1,b2=unpack(format, ff) #data field unpacked with "format" to b0 b1 b2 dx = decode_dx(b0, b1, b2) dy = decode_dy(b0, b1, b2) coordX+=dx coordY+=dy block.color = colors[self.color] block.append(self.decode_flags( b2)(coordX,coordY)) block.append(CNC.zsafe())#safe height prevCol = self.color print("Stitches read=: %d"%cnt)#counter blocks.append(block) try: dx = float(self["dx"]) except: dx = 0.0 try: dy = float(self["dy"]) except: dy = 0.0 return blocks
def make(self, n=2, size=100, depth=0): self.n = n self.size = size self.depth = depth blocks = [] block = Block(self.name) xi, yi = zip(*(self.hilbert(0.0, 0.0, size, 0.0, 0.0, size, n))) block.append(CNC.zsafe()) block.append(CNC.grapid(xi[0], yi[0])) currDepth = 0. stepz = CNC.vars['stepz'] if stepz == 0: stepz = 0.001 #avoid infinite while loop while True: currDepth -= stepz if currDepth < self.depth: currDepth = self.depth block.append(CNC.zenter(currDepth)) block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])])) for x, y in zip(xi, yi): block.append(CNC.gline(x, y)) if currDepth <= self.depth: break block.append(CNC.zsafe()) blocks.append(block) return blocks
def execute(self, app): # Try import PIL try: from PIL import Image except: app.setStatus(_("Heightmap abort: This plugin requires PIL/Pillow")) return # Try read image fileName = self["File"] try: img = Image.open(fileName) img = img.convert("L") # Luminance except: app.setStatus(_("Heightmap abort: Can't read image file")) return if self["Depth"] >= 0: app.setStatus(_("Heightmap abort: depth must be < 0")) return # Define type of matrix manipulation NUMPY = True if NUMPY == True: try: import numpy except: NUMPY = False if NUMPY == True: Image_Matrix = Image_Matrix_Numpy else: Image_Matrix = Image_Matrix_List # print "Install NumPy will speed up heightmap creation" MAT = Image_Matrix() MAT.FromImage(img, True) maxSize = self["MaxSize"] w, h = img.size if w > h: ratio = float(w) / float(h) image_w = maxSize image_h = maxSize / ratio else: ratio = float(h) / float(w) image_w = maxSize / ratio image_h = maxSize # Calc pixel size pixel_size = image_h / (float(MAT.width) - 1.0) tolerance = 0.1 safe_z = CNC.vars["safe"] splitstep = 0.0 # Offset Stepover toptol = -0.1 # Top Tolerance depth = -self["Depth"] Cont_Angle = 45.0 # Contact angle , only with "Lace Bounding" # Cut perimeter/border cutperim = 0 if self["CutBorder"]: cutperim = 1 ###################################################### tool = app.tools["EndMill"] tool_shape = tool["shape"] tool_diameter = CNC.vars["diameter"] feed_rate = CNC.vars["cutfeed"] zStep = CNC.vars["stepz"] rough_offset = 0.0 rough_feed = CNC.vars["cutfeed"] plunge_feed = CNC.vars["cutfeedz"] stepover = tool_diameter * CNC.vars["stepover"] / 100.0 step = max(1, int(math.floor(float(stepover) / pixel_size))) edge_offset = 0 ###################################################### if tool_shape == "Square End" or tool_shape == "Fishtail" or tool_shape == "Radiused": TOOL = make_tool_shape(NUMPY, endmill, tool_diameter, pixel_size) elif tool_shape == "V-cutting": try: v_angle = float(tool["angle"]) except: app.setStatus(_("Heightmap abort: angle not defined for selected End Mill")) return TOOL = make_tool_shape(NUMPY, vee_common(v_angle), tool_diameter, pixel_size) else: # "Ball End" TOOL = make_tool_shape(NUMPY, ball_tool, tool_diameter, pixel_size) ###################################################### rows = 0 columns = 0 columns_first = 0 scanpat = self["Scan"] if scanpat != "Columns": rows = 1 if scanpat != "Rows": columns = 1 if scanpat == "C&R": columns_first = 1 ###################################################### # Options are "Alternating", "Positive" , "Negative", "Up Mill", "Down Mill" converter = self["ScanDir"] if converter == "Positive": conv_index = 0 elif converter == "Negative": conv_index = 1 elif converter == "Alternating": conv_index = 2 elif converter == "Up Mill": conv_index = 3 elif converter == "Down Mill": conv_index = 4 else: conv_index = 2 ###################################################### convert_makers = [ Convert_Scan_Increasing, Convert_Scan_Decreasing, Convert_Scan_Alternating, Convert_Scan_Upmill, Convert_Scan_Downmill, ] if rows: convert_rows = convert_makers[conv_index]() else: convert_rows = None if columns: convert_cols = convert_makers[conv_index]() else: convert_cols = None ###################################################### lace_bound_val = "None" # "None","Secondary","Full" if lace_bound_val != "None" and rows and columns: slope = tan(Cont_Angle * pi / 180) if columns_first: convert_rows = Reduce_Scan_Lace(convert_rows, slope, step + 1) else: convert_cols = Reduce_Scan_Lace(convert_cols, slope, step + 1) if lace_bound_val == "Full": if columns_first: convert_cols = Reduce_Scan_Lace(convert_cols, slope, step + 1) else: convert_rows = Reduce_Scan_Lace(convert_rows, slope, step + 1) ###################################################### ### START COMMON STUFF ### ###################################################### ## units = "mm" ## if units == "in": ## units = 'G20' ## else: ## units = 'G21' # Units not used units = "" ###################################################### cuttop = 1 if self["CutTop"]: cuttop = 0 if cuttop: if rows == 1: convert_rows = Reduce_Scan_Lace_new(convert_rows, toptol, 1) if columns == 1: convert_cols = Reduce_Scan_Lace_new(convert_cols, toptol, 1) ###################################################### # Force disable arcs disable_arcs = True # grbl doesn't like this, G91.1? if not disable_arcs: Entry_cut = ArcEntryCut(plunge_feed, 0.125) else: Entry_cut = SimpleEntryCut(plunge_feed) ###################################################### # Force normalize normalize = True if normalize: pass a = MAT.min() b = MAT.max() if a != b: MAT.minus(a) MAT.mult(1.0 / (b - a)) else: MAT.mult(1 / 255.0) xoffset = 0 yoffset = 0 ###################################################### MAT.mult(depth) ########################################## # ORIGIN LOCATING STUFF # ########################################## minx = 0 maxx = image_w miny = 0 maxy = image_h midx = (minx + maxx) / 2 midy = (miny + maxy) / 2 # Force origin, we can move it later origin = "Bot-Left" CASE = str(origin) if CASE == "Top-Left": x_zero = minx y_zero = maxy elif CASE == "Top-Center": x_zero = midx y_zero = maxy elif CASE == "Top-Right": x_zero = maxx y_zero = maxy elif CASE == "Mid-Left": x_zero = minx y_zero = midy elif CASE == "Mid-Center": x_zero = midx y_zero = midy elif CASE == "Mid-Right": x_zero = maxx y_zero = midy elif CASE == "Bot-Left": x_zero = minx y_zero = miny elif CASE == "Bot-Center": x_zero = midx y_zero = miny elif CASE == "Bot-Right": x_zero = maxx y_zero = miny elif CASE == "Arc-Center": x_zero = 0 y_zero = 0 else: # "Default" x_zero = 0 y_zero = 0 xoffset = xoffset - x_zero yoffset = yoffset - y_zero ###################################################### invert = self["Invert"] if invert: MAT.mult(-1.0) else: MAT.minus(depth) ###################################################### gcode = [] MAT.pad_w_zeros(TOOL) header = "" postscript = "" gcode = convert( self, MAT, units, TOOL, pixel_size, step, safe_z, tolerance, feed_rate, convert_rows, convert_cols, columns_first, cutperim, Entry_cut, zStep, rough_feed, xoffset, yoffset, splitstep, header, postscript, edge_offset, disable_arcs, ) # Gcode n = self["name"] if not n or n == "default": n = "Heightmap" block = Block(n) block.append("(Size: %d x %d x %d)" % (image_w, image_h, depth)) block.append("(Endmill shape: %s , Diameter: %.3f)" % (tool_shape, tool_diameter)) for line in gcode: block.append(line) blocks = [] blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, n) app.refresh() app.setStatus(_("Generated Heightmap %d x %d x %d ") % (image_w, image_h, depth))
def calc(self, N, phi, Pc): N = abs(N) # Pitch Circle D = N * Pc / math.pi R = D / 2.0 # Diametrical pitch Pd = N / D # Base Circle Db = D * math.cos(phi) Rb = Db / 2.0 # Addendum a = 1.0 / Pd # Outside Circle Ro = R + a Do = 2.0 * Ro # Tooth thickness T = math.pi * D / (2 * N) # undercut? U = 2.0 / (math.sin(phi) * (math.sin(phi))) needs_undercut = N < U # sys.stderr.write("N:%s R:%s Rb:%s\n" % (N,R,Rb)) # Clearance c = 0.0 # Dedendum b = a + c # Root Circle Rr = R - b Dr = 2.0 * Rr two_pi = 2.0 * math.pi half_thick_angle = two_pi / (4.0 * N) pitch_to_base_angle = self.involute_intersect_angle(Rb, R) pitch_to_outer_angle = self.involute_intersect_angle( Rb, Ro) # pitch_to_base_angle points = [] for x in range(1, N + 1): c = x * two_pi / N # angles pitch1 = c - half_thick_angle base1 = pitch1 - pitch_to_base_angle outer1 = pitch1 + pitch_to_outer_angle pitch2 = c + half_thick_angle base2 = pitch2 + pitch_to_base_angle outer2 = pitch2 - pitch_to_outer_angle # points b1 = self.point_on_circle(Rb, base1) p1 = self.point_on_circle(R, pitch1) o1 = self.point_on_circle(Ro, outer1) o2 = self.point_on_circle(Ro, outer2) p2 = self.point_on_circle(R, pitch2) b2 = self.point_on_circle(Rb, base2) if Rr >= Rb: pitch_to_root_angle = pitch_to_base_angle - self.involute_intersect_angle( Rb, Rr) root1 = pitch1 - pitch_to_root_angle root2 = pitch2 + pitch_to_root_angle r1 = self.point_on_circle(Rr, root1) r2 = self.point_on_circle(Rr, root2) points.append(r1) points.append(p1) points.append(o1) points.append(o2) points.append(p2) points.append(r2) else: r1 = self.point_on_circle(Rr, base1) r2 = self.point_on_circle(Rr, base2) points.append(r1) points.append(b1) points.append(p1) points.append(o1) points.append(o2) points.append(p2) points.append(b2) points.append(r2) first = points[0] del points[0] blocks = [] block = Block(self.name) blocks.append(block) block.append(CNC.grapid(first.x(), first.y())) block.append(CNC.zenter(0.0)) #print first.x(), first.y() for v in points: block.append(CNC.gline(v.x(), v.y())) #print v.x(), v.y() #print first.x(), first.y() block.append(CNC.gline(first.x(), first.y())) block.append(CNC.zsafe()) #block = Block("%s-center"%(self.name)) block = Block("%s-basecircle" % (self.name)) block.enable = False block.append(CNC.grapid(Db / 2, 0.)) block.append(CNC.zenter(0.0)) block.append(CNC.garc(CW, Db / 2, 0., i=-Db / 2)) block.append(CNC.zsafe()) blocks.append(block) return blocks
def execute(self, app): try: from PIL import Image except: app.setStatus(_("Pyrograph abort: This plugin requires PIL/Pillow")) return n = self["name"] if not n or n=="default": n="Pyrograph" #Calc desired size toolSize = self.fromMm("ToolSize") maxSize = self.fromMm("MaxSize") feedMin = self["FeedMin"] feedMax = self["FeedMax"] depth = self.fromMm("Depth") direction = self["Direction"] drawBorder = self["DrawBorder"] #Check parameters if direction is "": app.setStatus(_("Pyrograph abort: please define a scan Direction")) return if toolSize <=0: app.setStatus(_("Pyrograph abort: Tool Size must be > 0")) return if feedMin <=0 or feedMax <=0 : app.setStatus(_("Pyrograph abort: Please check feed rate parameters")) return #divisions divisions = maxSize / toolSize fileName = self["File"] try: img = Image.open(fileName) img = img.convert ('RGB') #be sure to have color to calculate luminance except: app.setStatus(_("Pyrograph abort: Can't read image file")) return iWidth,iHeight = img.size newWidth = iWidth newHeight = iHeight ratio = 1 if (iWidth > iHeight): ratio = float(iWidth) / float(iHeight) newWidth = int(divisions) newHeight = int(divisions / ratio) else: ratio = float(iHeight) / float(iWidth) newWidth = int(divisions / ratio) newHeight = int(divisions) #Create a thumbnail image to work faster img.thumbnail((newWidth,newHeight), Image.ANTIALIAS) newWidth,newHeight = img.size #img.save("thumb.png") pixels = list(img.getdata()) #Extract luminance gMap = [] for x in range(0,newWidth): gRow = [] for y in range(0,newHeight): R,G,B = pixels[(y * newWidth) + x ] L = (0.299*R + 0.587*G + 0.114*B) #Luminance (Rec. 601 standard) gRow.append(L) gMap.append(gRow) #Init blocks blocks = [] block = Block(self.name) block.append("(Pyrograph W=%g x H=%g x D=%g)" % (newWidth * toolSize , newHeight * toolSize , depth)) #Create points for vertical scan xH = [] yH = [] fH = [] if (direction=="Vertical" or direction=="Both"): r = range(0,newHeight) for x in range(0,newWidth): r = r[::-1] fPrec = -1 for y in r: f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0)) if(f != fPrec or y==0 or y==newHeight-1): xH.append(x * toolSize) yH.append((newHeight-y) * toolSize) fH.append(f) fPrec = f #Create points for horizontal scan xV = [] yV = [] fV = [] if (direction=="Horizontal" or direction=="Both"): r = range(0,newWidth) for y in reversed(range(0,newHeight)): fPrec = -1 for x in r: f = int(feedMin + ((feedMax - feedMin) * gMap[x][y] / 255.0)) if(f != fPrec or x==0 or x==newWidth-1): xV.append(x * toolSize) yV.append((newHeight-y) * toolSize) fV.append(f) fPrec = f r = r[::-1] #Gcode Horizontal if (len(xH)>1 and len(yH)>1): block.append(CNC.zsafe()) block.append(CNC.grapid(xH[0],yH[0])) block.append(CNC.zenter(depth)) for x,y,f in zip(xH,yH,fH): v = (x,y,depth) block.append(CNC.glinev(1,v,f)) #Gcode Vertical if (len(xV)>1 and len(yV)>1): block.append(CNC.zsafe()) block.append(CNC.grapid(xV[0],yV[0])) block.append(CNC.zenter(depth)) for x,y,f in zip(xV,yV,fV): v = (x,y,depth) block.append(CNC.glinev(1,v,f)) #Draw Border if required if drawBorder: block.append(CNC.zsafe()) block.append(CNC.grapid(0,0)) block.append(CNC.zenter(depth)) block.append(CNC.gcode(1, [("f",feedMin)])) block.append(CNC.gline(newWidth * toolSize - toolSize,0)) block.append(CNC.gline(newWidth * toolSize - toolSize ,newHeight* toolSize)) block.append(CNC.gline(0,newHeight* toolSize )) block.append(CNC.gline(0,0)) #Gcode Zsafe block.append(CNC.zsafe()) blocks.append(block) active = app.activeBlock() if active==0: active=1 app.gcode.insBlocks(active, blocks, "Pyrograph") app.refresh() app.setStatus(_("Generated Pyrograph W=%g x H=%g x D=%g") % (newWidth * toolSize , newHeight * toolSize , depth))
def execute(self, app): feed = self["feed"] rdoc = self["rdoc"] radius = self["dia"]/2 cw = self["cw"] circ = self["circ"] evenspacing = self["evenspacing"] if cw: cwtext = 'cw' else: cwtext = 'ccw' if cw: arcg = 'g2' else: arcg = 'g3' #print("go!") blocks = [] for bid in app.editor.getSelectedBlocks(): #print(blocks[bid]) path = app.gcode.toPath(bid)[0] #print(path) block = Block("trochoid "+cwtext+" "+str(radius*2)+"+"+str(rdoc)) block.append("F"+str(feed)) entry = self["entry"] A=path[0].A block.append("g0 x"+str(A[0])+" y"+str(A[1])) block.append("G1 Z0") for segment in path: #print(segment.A) #block.append("g0 x0 y0") #block.append("g1 x10 y10") #block.append("g1 x20 y10") #block.append("g0 x0 y0") if entry: eblock = Block("trochoid-in") eblock.append("G0 Z0") eblock.append("G0 x"+str(segment.A[0])+" y"+str(segment.A[1]-radius)) eblock.append("G2 x"+str(segment.A[0])+" y"+str(segment.A[1]-radius)+" i"+str(0)+" j"+str(radius)) blocks.append(eblock) entry = False #Continuity BEGINING block.append("g1 x"+str(segment.A[0])+" y"+str(segment.A[1])) #block.append(arcg+" x"+str(segment.A[0])+" y"+str(segment.A[1])+" r"+str(radius/2)) phi = atan2(segment.B[1]-segment.A[1], segment.B[0]-segment.A[0]) #TODO: handle arc segments #if segment.type == Segment.LINE: #if segment.type in (Segment.CW, Segment.CCW): #Compensate for uneven spacing srdoc = rdoc if evenspacing: subsegs = segment.length()//rdoc remainder = segment.length()%rdoc if remainder != 0: srdoc = segment.length()/(subsegs+1) #Loop over subsegmnents of segment i=0 while i<(segment.length()+srdoc): pos=min(segment.length(), i) B = segment.distPoint(pos) block.extend(self.trochoid(A,B,radius,cw,circ)) A = B i+=srdoc #Continuity END #block.append("g1 x"+str(segment.B[0])+" y"+str(segment.B[1])) block.append(arcg+" x"+str(segment.B[0])+" y"+str(segment.B[1])+" r"+str(radius/2)) blocks.append(block) active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Trochoidal created") #<<< insert blocks over active block in the editor app.refresh() #<<< refresh editor app.setStatus(_("Generated: Trochoidal")) #<<< feed back result
def paste(self, event=None): try: clipboard = self.selection_get(selection='CLIPBOARD') except: return ypos = self.yview()[0] # paste them after the last selected item # bid,lid push them to self so it can be accessed from addLines() # python3 might fix this with the inner scope try: self.__bid, self.__lid = self._items[self.curselection()[-1]] except: try: self.__bid, self.__lid = self._items[-1] except: self.__bid = 0 self.__lid = None selitems = [] undoinfo = [] def addLines(lines): for line in lines.splitlines(): # Create a new block if self.__lid is None: self.__bid += 1 self.__lid = sys.maxint block = Block() undoinfo.append(self.gcode.addBlockUndo(self.__bid,block)) selitems.append((self.__bid, None)) else: block = self.gcode.blocks[self.__bid] if self.__lid == sys.maxint: selitems.append((self.__bid, len(block))) else: self.__lid += 1 selitems.append((self.__bid, self.__lid)) undoinfo.append(self.gcode.insLineUndo(self.__bid, self.__lid, line)) try: # try to unpickle it unpickler = pickle.Unpickler(StringIO(clipboard)) try: while True: obj = unpickler.load() if isinstance(obj,tuple): block = Block.load(obj) self.__bid += 1 undoinfo.append(self.gcode.addBlockUndo(self.__bid, block)) selitems.append((self.__bid,None)) self.__lid = None else: addLines(obj) except EOFError: pass except pickle.UnpicklingError: # Paste as text addLines(clipboard) if not undoinfo: return self.gcode.addUndo(undoinfo) self.selection_clear(0,END) self.fill() self.yview_moveto(ypos) self.select(selitems, clear=True) #self.selection_set(ACTIVE) #self.see(ACTIVE) self.app.event_generate("<<Modified>>")
def execute(self, app): if Image is None: app.setStatus( _("Halftone abort: This plugin requires PIL/Pillow to read image data" )) return n = self["name"] if not n or n == "default": n = "Halftone" # Calc desired size channel = self["Channel"] invert = self["Invert"] drawSize = self["DrawSize"] cellSize = self["CellSize"] dMax = self["DiameterMax"] dMin = self["DiameterMin"] angle = self["Angle"] drawBorder = self["DrawBorder"] depth = self["Depth"] conical = self["Conical"] # Check parameters if drawSize < 1: app.setStatus( _("Halftone abort: Size too small to draw anything!")) return if dMin > dMax: app.setStatus( _("Halftone abort: Minimum diameter must be minor then Maximum" )) return if dMax < 1: app.setStatus(_("Halftone abort: Maximum diameter too small")) return if cellSize < 1: app.setStatus(_("Halftone abort: Cell size too small")) return tool = app.tools["EndMill"] tool_shape = tool["shape"] if conical: if tool_shape == "V-cutting": try: v_angle = float(tool["angle"]) except: app.setStatus( _("Halftone abort: Angle in V-Cutting end mill is missing" )) return else: app.setStatus( _("Halftone abort: Conical path need V-Cutting end mill")) return # Open picture file fileName = self["File"] try: img = Image.open(fileName) except: app.setStatus(_("Halftone abort: Can't read image file")) return # Create a scaled image to work faster with big image and better with small ones squareNorm = True if channel == 'Blue(sqrt)': img = img.convert('RGB') img = img.split()[0] elif channel == 'Green(sqrt)': img = img.convert('RGB') img = img.split()[1] elif channel == 'Red(sqrt)': img = img.convert('RGB') img = img.split()[2] else: img = img.convert('L') # to calculate luminance squareNorm = False # flip image to ouput correct coordinates img = img.transpose(Image.FLIP_TOP_BOTTOM) # Calc divisions for halftone divisions = drawSize / cellSize # Get image size self.imgWidth, self.imgHeight = img.size if (self.imgWidth > self.imgHeight): scale = drawSize / float(self.imgWidth) sample = int(self.imgWidth / divisions) else: scale = drawSize / float(self.imgHeight) sample = int(self.imgHeight / divisions) self.ratio = scale # Halftone circles = self.halftone(img, sample, scale, angle, squareNorm, invert) # Init blocks blocks = [] # Border block if drawBorder: block = Block("%s-border" % (self.name)) block.append(CNC.zsafe()) block.append(CNC.grapid(0, 0)) block.append(CNC.zenter(depth)) block.append(CNC.gcode(1, [("f", CNC.vars["cutfeed"])])) block.append(CNC.gline(self.imgWidth * self.ratio, 0)) block.append( CNC.gline(self.imgWidth * self.ratio, self.imgHeight * self.ratio)) block.append(CNC.gline(0, self.imgHeight * self.ratio)) block.append(CNC.gline(0, 0)) blocks.append(block) # Draw block block = Block(self.name) # Change color if channel == 'Blue(sqrt)': block.color = "#0000ff" elif channel == 'Green(sqrt)': block.color = "#00ff00" elif channel == 'Red(sqrt)': block.color = "#ff0000" block.append("(Halftone size W=%d x H=%d x D=%d ,Total points:%i)" % (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles))) block.append("(Channel = %s)" % channel) for c in circles: x, y, r = c r = min(dMax / 2.0, r) if (r >= dMin / 2.): block.append(CNC.zsafe()) block.append(CNC.grapid(x + r, y)) block.append(CNC.zenter(depth)) block.append(CNC.garc( CW, x + r, y, i=-r, )) block.append(CNC.zsafe()) if conical: block.enable = False blocks.append(block) if conical: blockCon = Block("%s-Conical" % (self.name)) for c in circles: x, y, r = c blockCon.append(CNC.zsafe()) blockCon.append(CNC.grapid(x, y)) dv = r / math.tan(math.radians(v_angle / 2.)) blockCon.append(CNC.zenter(-dv)) blockCon.append(CNC.zsafe()) blocks.append(blockCon) # Gcode Zsafe active = app.activeBlock() app.gcode.insBlocks(active, blocks, "Halftone") app.refresh() app.setStatus( _("Generated Halftone size W=%d x H=%d x D=%d ,Total points:%i" % (self.imgWidth * self.ratio, self.imgHeight * self.ratio, depth, len(circles))))
def generate(self, board_width, board_height, number_of_pieces, random_seed = 0, tap_shape = 'basic', threshold = 3.0): blocks = [] block = Block(self.name) random.seed(random_seed) Arc.reset_used_arcs() Arc.set_diff_threshold(threshold) puzzle_cuts = self.__class__.make_puzzle_cuts(board_width, board_height, number_of_pieces, tap_shape, threshold) # Draw puzzle cuts x = 0 y = 0 for i in range(0, int(self.thickness / self.step_z)): for cut in puzzle_cuts: block.append(CNC.zsafe()) block.append(CNC.grapid(x + cut[0].x, y + cut[0].y)) block.append(CNC.zenter(0.0)) block.append(CNC.fmt("f", self.cut_feed)) block.append(CNC.zenter(-(i + 1) * self.step_z)) for arc in cut: if arc.r: block.append(CNC.garc(arc.direction, x + arc.x, y + arc.y, r=arc.r)) blocks.append(block) # Draw border block = Block(self.name + "_border") block.append(CNC.zsafe()) block.append(CNC.grapid(x, y)) for i in range(0, int(self.thickness / self.step_z)): block.append(CNC.fmt("f",self.cut_feed)) block.append(CNC.zenter(-(i + 1) * self.step_z)) block.append(CNC.gline(x + board_width, y)) block.append(CNC.gline(x + board_width, y + board_height)) block.append(CNC.gline(x, y + board_height)) block.append(CNC.gline(x, y)) block.append(CNC.zsafe()) blocks.append(block) return blocks