Tue, 19 Jan 2021 20:45:09 +0100
updated main files to new github master version
#!/usr/bin/env python # # cad.py # # Neil Gershenfeld # # (c) Massachusetts Institute of Technology 2007 # Permission granted for experimental and personal use; # license for commercial sale available from MIT. # #Altered by Capo to output gcode with the '.gcode' extension as opposed to '.g' #and to work with a solenoid/Laser cutter. #For more information see http://capolight.wordpress.com/2012/04/29/converting_images_to_gcode/printers DATE = "29/04/2012" from numpy import * import scipy.signal.signaltools from string import * from Tkinter import * from tkFileDialog import * import Image, ImageTk, ImageDraw, ImageFont, ImageOps import os, struct #import time class point: # # an xyz point # def __init__(self,x,y,z=0): self.x = x self.y = y self.z = z class cad_variables: # # cad variables # def __init__(self): self.xmin = 0 # minimum x value to render self.xmax = 0 # maximum x value to render self.ymin = 0 # minimum y value to render self.ymax = 0 # maximum y value to render self.zmin = 0 # minimum z value to render self.zmax = 0 # maximum z value to render self.zlist = [] # z values to render self.nx = 0 # number of x points to render self.ny = 0 # number of y points to render self.nz = 1 # number of z points to render self.rz = 0 # perspective view z rotation (degrees) self.rx = 0 # perspective view x rotation (degrees) self.units = 'in' # file units self.function = '0' # cad function self.toolpaths = [] # toolpaths self.x = [] # x triangulation self.y = [] # y triangulation self.z = [] # z triangulation self.labels = [] # display labels self.image_r = array(0) # red array self.image_g = array(0) # green array self.image_b = array(0) # blue array self.image_min = 0 # image min value self.image_max = 0 # image max value self.stop = 0 # stop rendering self.nplot = 200 # plot window size self.inches_per_unit = 1 # file units self.views = 'xyzr' self.cam = '' # CAM export type self.editor_width = 30 # editor width self.editor_height = 10 # editor height def view(self,arg): global canvas_xy,canvas_yz,canvas_xz,canvas_xyz if (arg == 'xy'): view_frame2.grid_forget() view_frame3.grid_forget() canvas_xy.grid_forget() self.views = 'xy' self.nplot = 2*int(string_window_size.get()) # plot window size canvas_xy = Canvas(view_frame2, width=self.nplot, height=self.nplot) imxy = Image.new("RGBX",(self.nplot,self.nplot),'black') image_xy = ImageTk.PhotoImage(imxy) canvas_xy.create_image(self.nplot/2,self.nplot/2,image=image_xy) canvas_xy.bind('<Motion>',msg_xy) canvas_xy.grid(row=0,column=0) view_frame2.grid(row=2,column=0) elif (arg == 'xyzr'): view_frame2.grid_forget() view_frame3.grid_forget() canvas_xy.grid_forget() canvas_yz.grid_forget() canvas_xz.grid_forget() canvas_xyz.grid_forget() self.views = 'xyzr' self.nplot = int(string_window_size.get()) # plot window size canvas_xy = Canvas(view_frame3, width=self.nplot, height=self.nplot) canvas_yz = Canvas(view_frame3, width=self.nplot, height=self.nplot) canvas_xz = Canvas(view_frame3, width=self.nplot, height=self.nplot) canvas_xyz = Canvas(view_frame3, width=self.nplot, height=cad.nplot) imxy = Image.new("RGBX",(self.nplot,self.nplot),'black') image_xy = ImageTk.PhotoImage(imxy) canvas_xy.create_image(self.nplot/2,self.nplot/2,image=image_xy) canvas_xy.bind('<Motion>',msg_xy) canvas_xy.grid(row=0,column=0) imyz = Image.new("RGBX",(self.nplot,self.nplot),'black') image_yz = ImageTk.PhotoImage(imyz) canvas_yz.create_image(self.nplot/2,self.nplot/2,image=image_yz) canvas_yz.bind('<Motion>',msg_yz) canvas_yz.grid(row=0,column=1) imxz = Image.new("RGBX",(self.nplot,self.nplot),'black') image_xz = ImageTk.PhotoImage(imxz) canvas_xz.create_image(self.nplot/2,self.nplot/2,image=image_xz) canvas_xz.bind('<Motion>',msg_xz) canvas_xz.grid(row=1,column=0) imxyz = Image.new("RGBX",(self.nplot,self.nplot),'black') image_xyz = ImageTk.PhotoImage(imxyz) canvas_xyz.create_image(self.nplot/2,self.nplot/2,image=image_xyz) canvas_xyz.bind('<Motion>',msg_nomsg) canvas_xyz.grid(row=1,column=1) view_frame3.grid(row=2,column=0) else: print "view not supported" def nxplot(self): xwidth = self.xmax - self.xmin ywidth = self.ymax - self.ymin zwidth = self.zmax - self.zmin if ((xwidth >= ywidth) & (xwidth >= zwidth)): n = int(self.nplot*xwidth/float(xwidth)) elif ((ywidth >= xwidth) & (ywidth >= zwidth)): n = int(self.nplot*xwidth/float(ywidth)) else: n = int(self.nplot*xwidth/float(zwidth)) return n def nyplot(self): xwidth = self.xmax - self.xmin ywidth = self.ymax - self.ymin zwidth = self.zmax - self.zmin if ((xwidth >= ywidth) & (xwidth >= zwidth)): n = int(self.nplot*ywidth/float(xwidth)) elif ((ywidth >= xwidth) & (ywidth >= zwidth)): n = int(self.nplot*ywidth/float(ywidth)) else: n = int(self.nplot*ywidth/float(zwidth)) return n def nzplot(self): xwidth = self.xmax - self.xmin ywidth = self.ymax - self.ymin zwidth = self.zmax - self.zmin if ((xwidth >= ywidth) & (xwidth >= zwidth)): n = int(self.nplot*zwidth/float(xwidth)) elif ((ywidth >= xwidth) & (ywidth >= zwidth)): n = int(self.nplot*zwidth/float(ywidth)) else: n = int(self.nplot*zwidth/float(zwidth)) return n cad = cad_variables() class cad_text: def __init__(self,x,y,z=0,text='',size=10,color='#ff0000',anchor=CENTER): self.x = x self.y = y self.z = z self.text = text self.size = size self.color = color self.anchor = anchor class im_class: # # for PIL images # def __init__(self): self.xy = 0 self.xz = 0 self.yz = 0 self.xyz = 0 self.intensity_xy = 0 self.intensity_xz = 0 self.intensity_yz = 0 self.intensity_xyz = 0 im = im_class() class images_class: # # for PhotoImages # def __init__(self): self.xy = 0 self.xz = 0 self.yz = 0 self.xyz = 0 images = images_class() class CA_states: # # CA state definition class # def __init__(self): self.empty = 0 self.interior = 1 self.edge = (1 << 1) # 2 self.north = (1 << 2) # 4 self.west = (2 << 2) # 8 self.east = (3 << 2) # 12 self.south = (4 << 2) # 16 self.stop = (5 << 2) # 20 self.corner = (6 << 2) # 24 class rule_table: # # CA rule table class # # 0 = empty # 1 = interior # 2 = edge # edge+direction = start # def __init__(self): self.table = zeros(2**(9*2),uint32) self.s = CA_states() # # 1 0: # # 011 # 111 # 111 self.add_rule(0,1,1,1,1,1,1,1,1,self.s.north) # 101 # 111 # 111 self.add_rule(1,0,1,1,1,1,1,1,1,self.s.east) # # 2 0's: # # 001 # 111 # 111 self.add_rule(0,0,1,1,1,1,1,1,1,self.s.east) # 100 # 111 # 111 self.add_rule(1,0,0,1,1,1,1,1,1,self.s.east) # 010 # 111 # 111 self.add_rule(0,1,0,1,1,1,1,1,1,self.s.east) # 011 # 110 # 111 self.add_rule(0,1,1,1,1,0,1,1,1,self.s.south) # 110 # 011 # 111 self.add_rule(1,1,0,0,1,1,1,1,1,self.s.east) # 101 # 011 # 111 self.add_rule(1,0,1,0,1,1,1,1,1,self.s.east) # 101 # 110 # 111 self.add_rule(1,0,1,1,1,0,1,1,1,self.s.south) # 011 # 111 # 110 self.add_rule(0,1,1,1,1,1,1,1,0,self.s.corner) # 011 # 111 # 101 self.add_rule(0,1,1,1,1,1,1,0,1,self.s.north) # 110 # 111 # 101 self.add_rule(1,1,0,1,1,1,1,0,1,self.s.west) # 101 # 111 # 110 self.add_rule(1,0,1,1,1,1,1,1,0,self.s.south) # 101 # 111 # 011 self.add_rule(1,0,1,1,1,1,0,1,1,self.s.east) # # 3 0's: # # 001 # 011 # 111 self.add_rule(0,0,1,0,1,1,1,1,1,self.s.east) # 010 # 011 # 111 self.add_rule(0,1,0,0,1,1,1,1,1,self.s.east) # 010 # 110 # 111 self.add_rule(0,1,0,1,1,0,1,1,1,self.s.south) # 010 # 111 # 011 self.add_rule(0,1,0,1,1,1,0,1,1,self.s.east) # 010 # 111 # 110 self.add_rule(0,1,0,1,1,1,1,1,0,self.s.south) # 110 # 011 # 011 self.add_rule(1,1,0,0,1,1,0,1,1,self.s.east) # 011 # 110 # 110 self.add_rule(0,1,1,1,1,0,1,1,0,self.s.south) # 101 # 011 # 011 self.add_rule(1,0,1,0,1,1,0,1,1,self.s.east) # 101 # 110 # 110 self.add_rule(1,0,1,1,1,0,1,1,0,self.s.south) # 011 # 011 # 011 self.add_rule(0,1,1,0,1,1,0,1,1,self.s.north) # # 4 0's: # # 001 # 011 # 011 self.add_rule(0,0,1,0,1,1,0,1,1,self.s.east) # 100 # 110 # 110 self.add_rule(1,0,0,1,1,0,1,1,0,self.s.south) # 010 # 011 # 011 self.add_rule(0,1,0,0,1,1,0,1,1,self.s.east) # 010 # 110 # 110 self.add_rule(0,1,0,1,1,0,1,1,0,self.s.south) # 001 # 110 # 110 self.add_rule(0,0,1,1,1,0,1,1,0,self.s.south) # 100 # 011 # 011 self.add_rule(1,0,0,0,1,1,0,1,1,self.s.east) # # 5 0's: # # 000 # 011 # 011 self.add_rule(0,0,0,0,1,1,0,1,1,self.s.east) # # edge states # # 200 # 211 # 211 self.add_rule(2,0,0,2,1,1,2,1,1,self.s.east+self.s.edge) # 201 # 211 # 211 self.add_rule(2,0,1,2,1,1,2,1,1,self.s.east+self.s.edge) # 210 # 211 # 211 self.add_rule(2,1,0,2,1,1,2,1,1,self.s.east+self.s.edge) # 002 # 112 # 112 self.add_rule(0,0,2,1,1,2,1,1,2,self.s.stop) # 102 # 112 # 112 self.add_rule(1,0,2,1,1,2,1,1,2,self.s.stop) # 002 # 112 # 102 self.add_rule(0,0,2,1,1,2,1,0,2,self.s.stop) # 012 # 112 # 112 self.add_rule(0,1,2,1,1,2,1,1,2,self.s.stop) # 012 # 112 # 102 self.add_rule(0,1,2,1,1,2,1,0,2,self.s.stop) def add_rule(self,nw,nn,ne,ww,cc,ee,sw,ss,se,rule): # # add a CA rule, with rotations # s = CA_states() # # add the rule # state = \ (nw << 0) + (nn << 2) + (ne << 4) + \ (ww << 6) + (cc << 8) + (ee << 10) + \ (sw << 12) + (ss << 14) + (se << 16) self.table[state] = rule # # rotate 90 degrees # state = \ (sw << 0) + (ww << 2) + (nw << 4) + \ (ss << 6) + (cc << 8) + (nn << 10) + \ (se << 12) + (ee << 14) + (ne << 16) if (rule == s.east): self.table[state] = s.south elif (rule == s.south): self.table[state] = s.west elif (rule == s.west): self.table[state] = s.north elif (rule == s.north): self.table[state] = s.east elif (rule == (s.east+s.edge)): self.table[state] = s.south+s.edge elif (rule == (s.south+s.edge)): self.table[state] = s.west+s.edge elif (rule == (s.west+s.edge)): self.table[state] = s.north+s.edge elif (rule == (s.north+s.edge)): self.table[state] = s.east+s.edge elif (rule == s.corner): self.table[state] = s.corner elif (rule == s.stop): self.table[state] = s.stop # # rotate 180 degrees # state = \ (se << 0) + (ss << 2) + (sw << 4) + \ (ee << 6) + (cc << 8) + (ww << 10) + \ (ne << 12) + (nn << 14) + (nw << 16) if (rule == s.east): self.table[state] = s.west elif (rule == s.south): self.table[state] = s.north elif (rule == s.west): self.table[state] = s.east elif (rule == s.north): self.table[state] = s.south elif (rule == (s.east+s.edge)): self.table[state] = s.west+s.edge elif (rule == (s.south+s.edge)): self.table[state] = s.north+s.edge elif (rule == (s.west+s.edge)): self.table[state] = s.east+s.edge elif (rule == (s.north+s.edge)): self.table[state] = s.south+s.edge elif (rule == s.corner): self.table[state] = s.corner elif (rule == s.stop): self.table[state] = s.stop # # rotate 270 degrees # state = \ (ne << 0) + (ee << 2) + (se << 4) + \ (nn << 6) + (cc << 8) + (ss << 10) + \ (nw << 12) + (ww << 14) + (sw << 16) if (rule == s.east): self.table[state] = s.north elif (rule == s.south): self.table[state] = s.east elif (rule == s.west): self.table[state] = s.south elif (rule == s.north): self.table[state] = s.west elif (rule == (s.east+s.edge)): self.table[state] = s.north+s.edge elif (rule == (s.south+s.edge)): self.table[state] = s.east+s.edge elif (rule == (s.west+s.edge)): self.table[state] = s.south+s.edge elif (rule == (s.north+s.edge)): self.table[state] = s.west+s.edge elif (rule == s.corner): self.table[state] = s.corner elif (rule == s.stop): self.table[state] = s.stop def evaluate_state(arr): # # assemble the state bit strings # (ny, nx) = shape(arr) s = CA_states() nn = concatenate(([s.edge+zeros(nx,uint32)],arr[:(ny-1)])) ss = concatenate((arr[1:],[s.edge+zeros(nx,uint32)])) ww = concatenate((reshape(s.edge+zeros(ny,uint32),(ny,1)),arr[:,:(nx-1)]),1) ee = concatenate((arr[:,1:],reshape(s.edge+zeros(ny,uint32),(ny,1))),1) cc = arr nw = concatenate(([s.edge+zeros(nx,uint32)],ww[:(ny-1)])) ne = concatenate(([s.edge+zeros(nx,uint32)],ee[:(ny-1)])) sw = concatenate((ww[1:],[s.edge+zeros(nx,uint32)])) se = concatenate((ee[1:],[s.edge+zeros(nx,uint32)])) state = (nw << 0) + (nn << 2) + (ne << 4) + \ (ww << 6) + (cc << 8) + (ee << 10) + \ (sw << 12) + (ss << 14) + (se << 16) return state def vectorize_toolpaths(arr): # # convert lattice toolpath directions to vectors # s = CA_states() toolpaths = [] max_dist = float(string_vector_error.get()) start_sites = (arr == (s.north+s.edge)) | (arr == (s.south+s.edge)) | \ (arr == (s.east+s.edge)) | (arr == (s.west+s.edge)) num_start_sites = sum(sum(1.0*start_sites)) path_sites = (arr == s.north) | (arr == s.south) | (arr == s.east) | \ (arr == s.west) num_path_sites = sum(sum(1.0*path_sites)) remaining_sites = num_start_sites + num_path_sites while (remaining_sites != 0): #print remaining_sites if (num_start_sites > 0): # # begin segment on a start state # if (argmax(start_sites[0,:],axis=0) != 0): x = argmax(start_sites[0,:],axis=0) y = 0 elif (argmax(start_sites[:,0],axis=0) != 0): x = 0 y = argmax(start_sites[:,0],axis=0) elif (argmax(start_sites[-1,:],axis=0) != 0): x = argmax(start_sites[-1,:],axis=0) y = cad.ny-1 elif (argmax(start_sites[:,-1],axis=0) != 0): x = cad.nx-1 y = argmax(start_sites[:,-1],axis=0) else: print "error: internal start" sys.exit() #print "start from ",x,y else: # # no start states; begin segment on upper-left boundary point # maxcols = argmax(path_sites,axis=1) y = argmax(argmax(path_sites,axis=1)) x = maxcols[y] arr[y][x] += s.edge #print "segment from ",x,y segment = [point(x,y)] vector = [point(x,y)] while 1: # # follow path # y = vector[-1].y x = vector[-1].x state = arr[y][x] # # if start state, set stop # if (state == (s.north + s.edge)): state = s.north arr[y][x] = s.stop elif (state == (s.south + s.edge)): state = s.south arr[y][x] = s.stop elif (state == (s.east + s.edge)): state = s.east arr[y][x] = s.stop elif (state == (s.west + s.edge)): state = s.west arr[y][x] = s.stop #print "x,y,state,arr: ",x,y,state,arr[y][x] # # move if a valid direction # if (state == s.north): direction = "north" #print "north" ynew = y - 1 xnew = x elif (state == s.south): direction = "south" #print "south" ynew = y + 1 xnew = x elif (state == s.east): direction = "east" #print "east" ynew = y xnew = x + 1 elif (state == s.west): direction = "west" #print "west" ynew = y xnew = x - 1 elif (state == s.corner): #print "corner" if (direction == "east"): #print "south" xnew = x ynew = y + 1 elif (direction == "west"): #print "north" xnew = x ynew = y - 1 elif (direction == "north"): #print "east" ynew = y xnew = x + 1 elif (direction == "south"): #print "west" ynew = y xnew = x - 1 else: # # not a valid direction, terminate segment on previous point # print "unexpected path termination at",x,y #sys.exit() segment.append(point(x,y)) toolpaths.append(segment) arr[y][x] = s.interior break #print "xnew,ynew,snew",xnew,ynew,arr[ynew][xnew] # # check if stop reached # if (arr[ynew][xnew] == s.stop): #print "stop at ",xnew,ynew segment.append(point(xnew,ynew)) toolpaths.extend([segment]) if (state != s.corner): arr[y][x] = s.interior arr[ynew][xnew] = s.interior break # # find max transverse distance from vector to new point # dmax = 0 dx = xnew - vector[0].x dy = ynew - vector[0].y norm = sqrt(dx**2 + dy**2) nx = dy / norm ny = -dx / norm for i in range(len(vector)): dx = vector[i].x - vector[0].x dy = vector[i].y - vector[0].y d = abs(nx*dx + ny*dy) if (d > dmax): dmax = d # # start new vector if transverse distance > max_dist # if (dmax >= max_dist): #print "max at ",x,y segment.append(point(x,y)) vector = [point(x,y)] # # otherwise add point to vector # else: #print "add ",xnew,ynew vector.append(point(xnew,ynew)) if ((arr[y][x] != s.corner) & (arr[y][x] != s.stop)): arr[y][x] = s.interior start_sites = (arr == (s.north+s.edge)) | (arr == (s.south+s.edge)) | \ (arr == (s.east+s.edge)) | (arr == (s.west+s.edge)) num_start_sites = sum(sum(1.0*start_sites)) path_sites = (arr == s.north) | (arr == s.south) | (arr == s.east) | \ (arr == s.west) num_path_sites = sum(sum(1.0*path_sites)) remaining_sites = num_start_sites + num_path_sites # # reverse segment order, to start from inside to out # newpaths = [] for segment in range(len(toolpaths)): newpaths.append(toolpaths[-1-segment]) root.update() return newpaths def evaluate(): # # evaluate .cad program/image # if (len(widget_cad_text.get("1.0",END)) > 1): # # .cad # cad.zlist = [] cad_text_string = widget_cad_text.get("1.0",END) exec cad_text_string in globals() widget_function_text.config(state=NORMAL) widget_function_text.delete("1.0",END) widget_function_text.insert("1.0",cad.function) widget_function_text.config(state=DISABLED) if (cad.image_r.size > 1): # # image # cad.xmin = float(string_image_xmin.get()) xwidth = float(string_image_xwidth.get()) cad.xmax = cad.xmin + xwidth cad.ymin = float(string_image_ymin.get()) yheight = float(string_image_yheight.get()) cad.ymax = cad.ymin + yheight cad.image_min = float(string_image_min.get()) cad.image_max = float(string_image_max.get()) cad.zmin = float(string_image_zmin.get()) cad.zmax = float(string_image_zmax.get()) cad.nz = int(string_image_nz.get()) cad.inches_per_unit = float(string_image_units.get()) def render(view='xyzr'): render_stop_flag = 0 cad.stop = 0 # # if .cad doesn't call render, delete windows and add stop button # if (find(widget_cad_text.get("1.0",END),"render(") == -1): string_msg.set("render ...") widget_stop.pack() delete_windows() # # initialize variables # cad.toolpaths = [] rx = pi*cad.rx/180. rz = pi*cad.rz/180. r = rule_table() s = CA_states() # # evaluate coordinate arrays # Xarray = outer(ones((cad.ny,1)),cad.xmin+(cad.xmax-cad.xmin)*arange(cad.nx)/(cad.nx-1.0)) Yarray = outer(cad.ymin+(cad.ymax-cad.ymin)*arange(cad.ny-1,-1,-1)/(cad.ny-1.0),ones((1,cad.nx))) if (cad.zlist == []): if ((cad.nz == 1) & (cad.image_r.size != 1)): cad.zlist = [cad.zmax] cad.view('xy') elif (cad.nz == 1): cad.zlist = [cad.zmin] cad.view('xy') else: cad.zlist = cad.zmin + (cad.zmax-cad.zmin)*arange(cad.nz)/(cad.nz-1.0) cad.view('xyzr') else: cad.nz = len(cad.zlist) cad.zmin = cad.zlist[0] cad.zmax = cad.zlist[-1] # # draw orthogonal views # X = Xarray Y = Yarray accum_r = zeros((cad.ny,cad.nx),uint32) accum_g = zeros((cad.ny,cad.nx),uint32) accum_b = zeros((cad.ny,cad.nx),uint32) im.intensity_yz = zeros((cad.ny,cad.nz),uint32) im.intensity_xz = zeros((cad.nz,cad.nx),uint32) im.intensity_xyz = zeros((cad.nz,cad.nx),uint32) for layer in range(cad.nz): # # check render stop button # if (cad.stop == 1): break # # xy view # Z = cad.zlist[layer] string_msg.set("render z = %.3f"%Z) # root.update() if (cad.image_r.size == 1): # # .cad # array_r = eval(cad.function) array_g = array_r array_b = array_r if ((cad.zmax == cad.zmin) | (cad.nz == 1)): zi = array([255],uint32) else: zi = array([55.0 + 200.0*layer/(cad.nz-1.0)],uint32) accum_r = where(((zi*array_r) > accum_r),(zi*array_r),accum_r) accum_g = where(((zi*array_g) > accum_g),(zi*array_g),accum_g) accum_b = where(((zi*array_b) > accum_b),(zi*array_b),accum_b) im.intensity_xy = (1 << 16)*accum_b + (1 << 8)*accum_g + (1 << 0)*accum_r else: # # bitmap # array_r = (cad.image_r[0,] >= (cad.image_min + (cad.image_max-cad.image_min)*(Z-cad.zmin)/float(cad.zmax-cad.zmin))) array_g = (cad.image_g[0,] >= (cad.image_min + (cad.image_max-cad.image_min)*(Z-cad.zmin)/float(cad.zmax-cad.zmin))) array_b = (cad.image_b[0,] >= (cad.image_min + (cad.image_max-cad.image_min)*(Z-cad.zmin)/float(cad.zmax-cad.zmin))) image_z = int(cad.image_min + (cad.image_max-cad.image_min)*(Z-cad.zmin)/float(cad.zmax-cad.zmin)) intensity_r = where((cad.image_r[0,] <= image_z),cad.image_r[0,],image_z) intensity_g = where((cad.image_g[0,] <= image_z),cad.image_g[0,],image_z) intensity_b = where((cad.image_b[0,] <= image_z),cad.image_b[0,],image_z) im.intensity_xy = (1 << 16)*intensity_b + (1 << 8)*intensity_g + (1 << 0)*intensity_r im.xy = Image.fromarray(im.intensity_xy,mode="RGBX") im.xy_draw = ImageDraw.Draw(im.xy) im.xy = im.xy.resize((cad.nxplot(),cad.nyplot())) images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) # root.update() # # find toolpaths if needed # ncontours = int(string_num_contours.get()) if (ncontours == -1): ncontours = 2**20 # a big number cad.toolpaths.append([]) """ if (ncontours != 0): # # grassfire convolve (to come) # interior = (array_r | array_g | array_b) print shape(X[interior]) conv_array = interior """ for contour in range(ncontours): # # check render stop button # if (cad.stop == 1): break # # convolve tool for contour # string_msg.set(" convolve tool ... ") # # FFT convolve # # root.update() tool_rad = float(string_tool_dia.get())/2.0 tool_dia = float(string_tool_dia.get()) tool_overlap = float(string_tool_overlap.get()) kernel_rad = tool_rad + contour*tool_overlap*tool_dia ikernel_rad = 1 + int(cad.nx*kernel_rad/(cad.xmax-cad.xmin)) if (ikernel_rad > (((cad.nx/2),(cad.ny/2))[(cad.ny/2) > (cad.nx/2)])): break kx = 1+outer(ones((2*ikernel_rad,1)),arange(2*ikernel_rad)) ky = 1+outer(arange(2*ikernel_rad),ones((1,2*ikernel_rad))) k = (((kx-ikernel_rad)**2 + (ky-ikernel_rad)**2) < ikernel_rad**2).astype('uint32') interior = (array_r == s.interior).astype('uint32') #tstart = time.time() conv = scipy.signal.signaltools.fftconvolve(interior,k,mode='same') conv = where(conv > 0.01,s.interior,0) conv_array = conv + (conv != s.interior)*array_r #tend = time.time() #print 'convolve:',tend-tstart # # use CA rule table to find edge directions # string_msg.set(" follow edges ... ") # root.update() state = evaluate_state(conv_array) toolpath = r.table[state] tool_array = toolpath + (toolpath == s.empty)*conv_array tool_intensity = \ ((0 << 16) + (0 << 8) + (0 << 0))*(tool_array == s.empty).astype('uint32') +\ ((255 << 16) + (255 << 8) + (255 << 0))*(tool_array == s.interior).astype('uint32') +\ (( 0 << 16) + ( 0 << 8) + (255 << 0))*(tool_array == s.north).astype('uint32') +\ (( 0 << 16) + (255 << 8) + ( 0 << 0))*(tool_array == s.south).astype('uint32') +\ ((255 << 16) + ( 0 << 8) + ( 0 << 0))*(tool_array == s.east).astype('uint32') +\ (( 0 << 16) + (255 << 8) + (255 << 0))*(tool_array == s.west ).astype('uint32') +\ ((128 << 16) + ( 0 << 8) + (128 << 0))*(tool_array == s.stop).astype('uint32') # # show CA # """ im.xy = Image.fromarray(tool_intensity,mode="RGBX") im.xy = im.xy.resize((cad.nplot,cad.nplot)) images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) """ # # vectorize contour # #tstart = time.time() string_msg.set(" vectorize ... ") # root.update() new_paths = vectorize_toolpaths(tool_array) if (len(new_paths) == 0): break cad.toolpaths[layer].extend(new_paths) #tend = time.time() #print 'vector:',tend-tstart # # draw toolpath # im.xy_draw = ImageDraw.Draw(im.xy) for segment in range(len(cad.toolpaths[layer])): x = cad.nxplot()*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx) y = cad.nyplot()*(cad.toolpaths[layer][segment][0].y+0.5)/float(cad.ny) for vertex in range(1,len(cad.toolpaths[layer][segment])): xnew = cad.nxplot()*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx) ynew = cad.nyplot()*(cad.toolpaths[layer][segment][vertex].y+0.5)/float(cad.ny) im.xy_draw.line([x,y,xnew,ynew],fill="#ffa0a0",width=1) x = xnew y = ynew # # show xy toolpath view # images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) # # add send_to button # string_send_to_time.set("") send_to_frame.pack() # root.update() # # draw labels # for label in range(len(cad.labels)): x = cad.nplot/2. + cad.nxplot()*(cad.labels[label].x-(cad.xmax+cad.xmin)/2.0)/(cad.xmax-cad.xmin) y = cad.nplot/2. - cad.nyplot()*(cad.labels[label].y-(cad.ymax+cad.ymin)/2.0)/(cad.ymax-cad.ymin) string = cad.labels[label].text size = cad.labels[label].size color = cad.labels[label].color anch = cad.labels[label].anchor canvas_xy.create_text(x,y,text=string,font=('arial',size,'bold'),fill=color,anchor=anch,justify=CENTER) # # draw origin # x0 = cad.nplot/2. + cad.nxplot()*(0-(cad.xmax+cad.xmin)/2.)/(cad.xmax-cad.xmin) y0 = cad.nplot/2. - cad.nyplot()*(0-(cad.ymax+cad.ymin)/2.)/(cad.ymax-cad.ymin) dxy = .025*cad.nplot canvas_xy.create_line([x0-dxy,y0,x0+dxy,y0],fill="green") canvas_xy.create_line([x0,y0-dxy,x0,y0+dxy],fill="green") # # yz view # if (cad.views == 'xyzr'): accum_yz_r = zeros(cad.ny,uint32) accum_yz_g = zeros(cad.ny,uint32) accum_yz_b = zeros(cad.ny,uint32) for vertex in range(cad.nx): xi = array([55.0 + 200.0*vertex/(cad.nx-1.0)],uint32) slice_r = array_r[:,vertex] slice_g = array_g[:,vertex] slice_b = array_b[:,vertex] accum_yz_r = where(((xi*slice_r) >= accum_yz_r),(xi*slice_r),accum_yz_r) accum_yz_g = where(((xi*slice_g) >= accum_yz_g),(xi*slice_g),accum_yz_g) accum_yz_b = where(((xi*slice_b) >= accum_yz_b),(xi*slice_b),accum_yz_b) im.intensity_yz[:,layer] = (1 << 16)*accum_yz_b + (1 << 8)*accum_yz_g + (1 << 0)*accum_yz_r im.yz = Image.fromarray(im.intensity_yz,mode="RGBX") im.yz = im.yz.transpose(Image.FLIP_LEFT_RIGHT) im.yz = im.yz.resize((cad.nzplot(),cad.nyplot())) images.yz = ImageTk.PhotoImage(im.yz) canvas_yz.create_image(cad.nplot/2,cad.nplot/2,image=images.yz) # # draw origin # z0 = cad.nplot/2. - cad.nzplot()*(0-(cad.zmax+cad.zmin)/2.)/(cad.zmax-cad.zmin) y0 = cad.nplot/2. - cad.nyplot()*(0-(cad.ymax+cad.ymin)/2.)/(cad.ymax-cad.ymin) canvas_yz.create_line([z0-dxy,y0,z0+dxy,y0],fill="green") canvas_yz.create_line([z0,y0-dxy,z0,y0+dxy],fill="green") # # xz view # if (cad.views == 'xyzr'): accum_xz_r = zeros(cad.nx,uint32) accum_xz_g = zeros(cad.nx,uint32) accum_xz_b = zeros(cad.nx,uint32) for vertex in range(cad.ny): yi = array([55.0+200.0*vertex/(cad.ny-1.0)],uint32) slice_r = array_r[vertex,:] slice_g = array_g[vertex,:] slice_b = array_b[vertex,:] accum_xz_r = where(((yi*slice_r) >= accum_xz_r),(yi*slice_r),accum_xz_r) accum_xz_g = where(((yi*slice_g) >= accum_xz_g),(yi*slice_g),accum_xz_g) accum_xz_b = where(((yi*slice_b) >= accum_xz_b),(yi*slice_b),accum_xz_b) im.intensity_xz[(cad.nz-1-layer),:] = (1 << 16)*accum_xz_b + (1 << 8)*accum_xz_g + (1 << 0)*accum_xz_r im.xz = Image.fromarray(im.intensity_xz,mode="RGBX") im.xz = im.xz.resize((cad.nxplot(),cad.nzplot())) images.xz = ImageTk.PhotoImage(im.xz) canvas_xz.create_image(cad.nplot/2,cad.nplot/2,image=images.xz) # # draw origin # x0 = cad.nplot/2. + cad.nxplot()*(0-(cad.xmax+cad.xmin)/2.)/(cad.xmax-cad.xmin) z0 = cad.nplot/2. - cad.nzplot()*(0-(cad.zmax+cad.zmin)/2.)/(cad.zmax-cad.zmin) canvas_xz.create_line([x0-dxy,z0,x0+dxy,z0],fill="green") canvas_xz.create_line([x0,z0-dxy,x0,z0+dxy],fill="green") # # draw it # root.update() # # rotated view # if ((cad.views == 'xyzr') & (cad.image_r.size == 1)): accum = zeros((cad.ny,cad.nx),uint32) for z in cad.zlist: # # check render stop button # if (cad.stop == 1): break string_msg.set("render z = %.3f"%z) dY = cos(rx)*(Yarray-(cad.ymax+cad.ymin)/2.0) - sin(rx)*(z-(cad.zmax+cad.zmin)/2.0) Z = (cad.zmax+cad.zmin)/2.0 + sin(rx)*(Yarray-(cad.ymax+cad.ymin)/2.0) + cos(rx)*(z-(cad.zmax+cad.zmin)/2.0) X = (cad.xmax+cad.xmin)/2.0 + cos(rz)*(Xarray-(cad.xmax+cad.xmin)/2.0) - sin(rz)*dY Y = (cad.ymax+cad.ymin)/2.0 + sin(rz)*(Xarray-(cad.xmax+cad.xmin)/2.0) + cos(rz)*dY arr = eval(cad.function) if (cad.zmax == cad.zmin): zi = array([255],uint32) else: zi = array([55.0 + 200.0*(z-cad.zmin)/(cad.zmax-cad.zmin)],uint32) accum = where(((zi*arr) > accum),(zi*arr),accum) im.intensity_xyz = ((1 << 16) + (1 << 8) + (1 << 0)) * accum im.xyz = Image.fromarray(im.intensity_xyz,mode="RGBX") im.xyz = im.xyz.resize((cad.nxplot(),cad.nyplot())) images.xyz = ImageTk.PhotoImage(im.xyz) canvas_xyz.create_image(cad.nplot/2,cad.nplot/2,image=images.xyz) root.update() # # return # cad.zwrite = cad.zlist cad.zlist = [] widget_stop.pack_forget() string_msg.set("done") root.update() return def draw_toolpath(): im.xy = Image.new("RGBX",(cad.nxplot(),cad.nyplot()),'white') im.xy_draw = ImageDraw.Draw(im.xy) for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): x = cad.nxplot()*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx) y = cad.nyplot()*(cad.toolpaths[layer][segment][0].y+0.5)/float(cad.ny) for vertex in range(1,len(cad.toolpaths[layer][segment])): xnew = cad.nxplot()*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx) ynew = cad.nyplot()*(cad.toolpaths[layer][segment][vertex].y+0.5)/float(cad.ny) im.xy_draw.line([x,y,xnew,ynew],fill="black") x = xnew y = ynew images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) def delete_windows(): im.xy = Image.new("RGBX",(cad.nplot,cad.nplot),'black') images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) im.yz = Image.new("RGBX",(cad.nplot,cad.nplot),'black') images.yz = ImageTk.PhotoImage(im.yz) canvas_yz.create_image(cad.nplot/2,cad.nplot/2,image=images.yz) im.xz = Image.new("RGBX",(cad.nplot,cad.nplot),'black') images.xz = ImageTk.PhotoImage(im.xz) canvas_xz.create_image(cad.nplot/2,cad.nplot/2,image=images.xz) im.xyz = Image.new("RGBX",(cad.nplot,cad.nplot),'black') images.xyz = ImageTk.PhotoImage(im.xyz) canvas_xyz.create_image(cad.nplot/2,cad.nplot/2,image=images.xyz) root.update() def select_cad(): image_x_frame.pack_forget() image_y_frame.pack_forget() image_z_frame.pack_forget() image_intensity_frame.pack_forget() image_units_frame.pack_forget() image_invert_frame.pack_forget() cad_input_frame.pack_forget() widget_cad_text.delete("1.0",END) widget_cad_text.insert("1.0",cad_template) editor_frame.pack() cad.image = array(0) cad_input_frame.pack() cad.toolpaths = [] string_num_contours.set('0') widget_cad_save.pack(side='left') delete_windows() def select_image(): editor_frame.pack_forget() cad_input_frame.pack_forget() image_x_frame.pack() image_y_frame.pack() image_z_frame.pack() image_intensity_frame.pack() image_units_frame.pack() image_invert_frame.pack() cad_input_frame.pack() cad.toolpaths = [] string_num_contours.set('0') widget_cad_save.pack_forget() delete_windows() def input_open(): filename = askopenfilename() string_input_file.set(filename) if (find(filename,'.cad') != -1): cad_load(0) elif ((find(filename,'.jpg') != -1) | (find(filename,'.JPG') != -1) | (find(filename,'.png') != -1) | (find(filename,'.PNG') != -1) | (find(filename,'.gif') != -1) | (find(filename,'.GIF') != -1)): widget_cad_text.delete("1.0",END) image_load(0) else: string_msg.set("unsupported input file format") root.update() def cad_load(event): global cad cad = cad_variables() cam_pack_forget() select_cad() input_file_name = string_input_file.get() input_file = open(input_file_name,'rb') cad_text_string = input_file.read() widget_cad_text.delete("1.0",END) widget_cad_text.insert("1.0",cad_text_string) input_file.close() cad.toolpaths = [] cad.image = array(0) cad.nz = 1 string_num_contours.set('0') evaluate() if (find(widget_cad_text.get("1.0",END),"render(") == -1): render() def image_load(event): global cad cad = cad_variables() cam_pack_forget() select_image() function_string_frame.pack_forget() input_file_name = string_input_file.get() input_file = open(input_file_name,'rb') input_file.close() cad.toolpaths = [] string_num_contours.set('0') image = Image.open(input_file_name) num_layers = 1 while 1: # check number of layers try: image.seek(image.tell()+1) num_layers += 1 except: break image = Image.open(input_file_name) if image.mode != "RGBX": image = image.convert("RGBX") (cad.nx,cad.ny) = image.size info = image.info if ('dpi' in info): (xdpi,ydpi) = info['dpi'] else: xdpi = cad.nx ydpi = xdpi string_image_nx.set(" nx = "+str(cad.nx)) string_image_ny.set(" ny = "+str(cad.ny)) cad.nz = 1 string_image_nz.set(str(cad.nz)) cad.xmin = 0 string_image_xmin.set('0') cad.xmax = cad.nx/float(xdpi) string_image_xwidth.set(str(cad.xmax-cad.xmin)) cad.ymin = 0 string_image_ymin.set('0') cad.ymax = cad.ny/float(ydpi) string_image_yheight.set(str(cad.ymax-cad.ymin)) cad.zmin = -.005 string_image_zmin.set('-0.05') cad.zmax = 0.05 string_image_zmax.set('0.05') cad.inches_per_unit = 1.0 string_image_units.set('25.4') data = zeros((num_layers,cad.nx*cad.ny,3),uint32) data[0,] = array(image.convert("RGB").getdata(),uint32) for layer in range(1,num_layers): image.seek(image.tell()+1) data[layer,] = array(image.convert("RGB").getdata(),uint32) cad.image_r = array(data[:,:,0],uint32) cad.image_r = cad.image_r.reshape((num_layers,cad.ny,cad.nx)) cad.image_g = array(data[:,:,1],uint32) cad.image_g = cad.image_g.reshape((num_layers,cad.ny,cad.nx)) cad.image_b = array(data[:,:,2],uint32) cad.image_b = cad.image_b.reshape((num_layers,cad.ny,cad.nx)) cad.image_min = 1 string_image_min.set(str(cad.image_min)) cad.image_max = 255 string_image_max.set(str(cad.image_max)) evaluate() render() def invert_image(event): cad.image_r = 255 - cad.image_r cad.image_g = 255 - cad.image_g cad.image_b = 255 - cad.image_b evaluate() render() def cad_save(event): input_file_name = string_input_file.get() input_file = open(input_file_name,'wb') cad_text_string = widget_cad_text.get("1.0",END) input_file.write(cad_text_string) input_file.close() string_msg.set(input_file_name+" saved") root.update() def render_button(event): cam_pack_forget() cad.cam = '' if (cad.image_r.size == 1): function_string_frame.pack() cad.toolpaths = [] string_num_contours.set('0') evaluate() if (find(widget_cad_text.get("1.0",END),"render(") == -1): render() def render_stop(event): cad.stop = 1 widget_stop.pack_forget() def cam(event): function_string_frame.pack_forget() cam_file_frame.pack() string_num_contours.set('1') root.update() def contour(event): evaluate() if (find(widget_cad_text.get("1.0",END),"render(") == -1): render() def triangulate(event): # # triangulate for STL # # evaluate .cad # evaluate() # # initialize variables # render_stop_flag = 0 cad.stop = 0 widget_stop.pack() delete_windows() cad.toolpaths = [] cad.zwrite = [] cad.x = zeros(0) cad.y = zeros(0) cad.z = zeros(0) ixlr = array([]) iylrs = array([]) iylre = array([]) izlr = array([]) ixfbs = array([]) ixfbe = array([]) iyfb = array([]) izfb = array([]) ixtbs = array([]) ixtbe = array([]) iytb = array([]) iztb = array([]) # # evaluate coordinate arrays # (IY,IX) = indices((cad.ny,cad.nx)) IY = IY[::-1,:] X = cad.xmin+(cad.xmax-cad.xmin)*IX/(cad.nx-1.0) Y = cad.ymin+(cad.ymax-cad.ymin)*IY/(cad.ny-1.0) cad.zwrite = cad.zmin + (cad.zmax-cad.zmin)*arange(cad.nz)/(cad.nz-1.0) # # set up drawing images # im.xy = Image.new("RGBX",(cad.nxplot(),cad.nyplot()),'white') im.xy_draw = ImageDraw.Draw(im.xy) im.xz = Image.new("RGBX",(cad.nxplot(),cad.nzplot()),'white') im.xz_draw = ImageDraw.Draw(im.xz) im.yz = Image.new("RGBX",(cad.nzplot(),cad.nyplot()),'white') im.yz_draw = ImageDraw.Draw(im.yz) # # loop over layers # Z = cad.zwrite[0] array0 = eval(cad.function) Z = cad.zwrite[1] array1 = eval(cad.function) for layer in range(2,len(cad.zwrite)): # # check render stop button # if (cad.stop == 1): break # # evaluate new layer # Z = cad.zwrite[layer] string_msg.set("triangulate z = %.3f"%Z) root.update() array2 = eval(cad.function) # # find left faces and merge y # elements = hstack((reshape((array1[:,0] == True),(cad.ny,1)),((array1[:,1:] == True) & (array1[:,:-1] == False)))) starts = vstack((((elements[:-1,:] == True) & (elements[1:,:] == False)),reshape((elements[-1,:] == True),(1,cad.nx)))) ends = vstack((reshape((elements[0,:] == True),(1,cad.nx)),((elements[1:,:] == True) & (elements[:-1,:] == False)))) IY_t = transpose(IY) # for starts and ends to be read in same row IX_t = transpose(IX) starts_t = transpose(starts) ends_t = transpose(ends) ixlr = append(ixlr,IX_t[starts_t]) iylrs = append(iylrs,IY_t[starts_t]) iylre = append(iylre,1+IY_t[ends_t]) izlr = append(izlr,(layer-1)*ones(len(IX_t[starts_t]))) # # find right faces and merge y # elements = hstack((((array1[:,1:] == False) & (array1[:,:-1] == True)),reshape((array1[:,1] == True),(cad.ny,1)))) starts = vstack((((elements[:-1,:] == True) & (elements[1:,:] == False)),reshape((elements[-1,:] == True),(1,cad.nx)))) ends = vstack((reshape((elements[0,:] == True),(1,cad.nx)),((elements[1:,:] == True) & (elements[:-1,:] == False)))) IY_t = transpose(IY) # for starts and ends to be read in same row IX_t = transpose(IX) starts_t = transpose(starts) ends_t = transpose(ends) ixlr = append(ixlr,1+IX_t[starts_t]) iylre = append(iylre,IY_t[starts_t]) iylrs = append(iylrs,1+IY_t[ends_t]) izlr = append(izlr,(layer-1)*ones(len(IX_t[starts_t]))) # # find front faces and merge x # elements = vstack((((array1[:-1,:] == True) & (array1[1:,:] == False)),reshape((array1[0,:] == True),(1,cad.nx)))) starts = hstack((reshape((elements[:,0] == True),(cad.ny,1)),((elements[:,1:] == True) & (elements[:,:-1] == False)))) ends = hstack((((elements[:,:-1] == True) & (elements[:,1:] == False)),reshape((elements[:,-1] == True),(cad.ny,1)))) ixfbs = append(ixfbs,IX[starts]) ixfbe = append(ixfbe,1+IX[ends]) iyfb = append(iyfb,IY[starts]) izfb = append(izfb,(layer-1)*ones(len(IX[starts]))) # # find back faces and merge x # elements = vstack((reshape((array1[-1,:] == True),(1,cad.nx)),((array1[1:,:] == True) & (array1[:-1,:] == False)))) starts = hstack((reshape((elements[:,0] == True),(cad.ny,1)),((elements[:,1:] == True) & (elements[:,:-1] == False)))) ends = hstack((((elements[:,:-1] == True) & (elements[:,1:] == False)),reshape((elements[:,-1] == True),(cad.ny,1)))) ixfbe = append(ixfbe,IX[starts]) ixfbs = append(ixfbs,1+IX[ends]) iyfb = append(iyfb,1+IY[starts]) izfb = append(izfb,(layer-1)*ones(len(IX[starts]))) # # find top faces and merge x # elements = ((array2 == False) & (array1 == True)) starts = hstack((reshape((elements[:,0] == True),(cad.ny,1)),((elements[:,1:] == True) & (elements[:,:-1] == False)))) ends = hstack((((elements[:,:-1] == True) & (elements[:,1:] == False)),reshape((elements[:,-1] == True),(cad.ny,1)))) ixtbs = append(ixtbs,IX[starts]) ixtbe = append(ixtbe,1+IX[ends]) iytb = append(iytb,IY[starts]) iztb = append(iztb,layer*ones(len(IX[starts]))) # # find bottom faces and merge x # elements = ((array0 == False) & (array1 == True)) starts = hstack((reshape((elements[:,0] == True),(cad.ny,1)),((elements[:,1:] == True) & (elements[:,:-1] == False)))) ends = hstack((((elements[:,:-1] == True) & (elements[:,1:] == False)),reshape((elements[:,-1] == True),(cad.ny,1)))) ixtbe = append(ixtbe,IX[starts]) ixtbs = append(ixtbs,1+IX[ends]) iytb = append(iytb,IY[starts]) iztb = append(iztb,(layer-1)*ones(len(IX[starts]))) # # push array stack # array0 = array1 array1 = array2 # # z merge front/back faces # index = lexsort(keys=(izfb,ixfbe,ixfbs,iyfb)) merge = (iyfb[index[1:]] == iyfb[index[:-1]]) & \ (ixfbe[index[1:]] == ixfbe[index[:-1]]) & \ (ixfbs[index[1:]] == ixfbs[index[:-1]]) & \ ((izfb[index[1:]] - izfb[index[:-1]]) == 1) merge = append(False,merge).astype(bool_) starts = ((merge[1:] == True) & (merge[:-1] == False)) starts = append(starts,False).astype(bool_) ends = ((merge[1:] == False) & (merge[:-1] == True)) if (merge[-1] == True): ends = append(ends,True) else: ends = append(ends,False) ends = ends.astype(bool_) xs = ixfbs[index][starts | ~merge] xe = ixfbe[index][starts | ~merge] y = iyfb[index][starts | ~merge] zs = izfb[index][starts | ~merge] ze = izfb[index][ends | ~(merge | starts)]+1 cad.x = ravel(transpose(vstack((xs,xe,xs,xs,xe,xe)))) cad.y = ravel(transpose(vstack((y,y,y,y,y,y)))) cad.z = ravel(transpose(vstack((zs,ze,ze,zs,zs,ze)))) # # z merge left/right faces # index = lexsort(keys=(izlr,iylre,iylrs,ixlr)) merge = (ixlr[index[1:]] == ixlr[index[:-1]]) & \ (iylre[index[1:]] == iylre[index[:-1]]) & \ (iylrs[index[1:]] == iylrs[index[:-1]]) & \ ((izlr[index[1:]] - izlr[index[:-1]]) == 1) merge = append(False,merge).astype(bool_) starts = ((merge[1:] == True) & (merge[:-1] == False)) starts = append(starts,False).astype(bool_) ends = ((merge[1:] == False) & (merge[:-1] == True)) if (merge[-1] == True): ends = append(ends,True) else: ends = append(ends,False) ends = ends.astype(bool_) x = ixlr[index][starts | ~merge] ys = iylrs[index][starts | ~merge] ye = iylre[index][starts | ~merge] zs = izlr[index][starts | ~merge] ze = izlr[index][ends | ~(merge | starts)]+1 cad.x = append(cad.x,ravel(transpose(vstack((x,x,x,x,x,x))))) cad.y = append(cad.y,ravel(transpose(vstack((ys,ye,ys,ys,ye,ye))))) cad.z = append(cad.z,ravel(transpose(vstack((zs,ze,ze,zs,zs,ze))))) # # y merge top/bottom faces # index = lexsort(keys=(iytb,ixtbe,ixtbs,iztb)) merge = (iztb[index[1:]] == iztb[index[:-1]]) & \ (ixtbe[index[1:]] == ixtbe[index[:-1]]) & \ (ixtbs[index[1:]] == ixtbs[index[:-1]]) & \ ((iytb[index[1:]] - iytb[index[:-1]]) == 1) merge = append(False,merge).astype(bool_) starts = ((merge[1:] == True) & (merge[:-1] == False)) starts = append(starts,False).astype(bool_) ends = ((merge[1:] == False) & (merge[:-1] == True)) if (merge[-1] == True): ends = append(ends,True) else: ends = append(ends,False) ends = ends.astype(bool_) xs = ixtbs[index][starts | ~merge] xe = ixtbe[index][starts | ~merge] ys = iytb[index][starts | ~merge] ye = iytb[index][ends | ~(merge | starts)]+1 z = iztb[index][starts | ~merge] cad.x = append(cad.x,ravel(transpose(vstack((xs,xe,xs,xs,xe,xe))))) cad.y = append(cad.y,ravel(transpose(vstack((ys,ye,ye,ys,ys,ye))))) cad.z = append(cad.z,ravel(transpose(vstack((z,z,z,z,z,z))))) # # draw triangulation # widget_stop.pack_forget() string_msg.set("draw ...") root.update() N = len(cad.x) for i in range(0,N,3): string_msg.set("draw triangle %d/%d"%(i/3,N/3)) root.update() x0 = cad.nxplot()*(cad.x[i]+0.5)/float(cad.nx) y0 = cad.nyplot()*(cad.ny-cad.y[i]+0.5)/float(cad.ny) z0 = cad.nzplot()*(cad.nz-cad.z[i]+0.5)/float(cad.nz) x1 = cad.nxplot()*(cad.x[i+1]+0.5)/float(cad.nx) y1 = cad.nyplot()*(cad.ny-cad.y[i+1]+0.5)/float(cad.ny) z1 = cad.nzplot()*(cad.nz-cad.z[i+1]+0.5)/float(cad.nz) x2 = cad.nxplot()*(cad.x[i+2]+0.5)/float(cad.nx) y2 = cad.nyplot()*(cad.ny-cad.y[i+2]+0.5)/float(cad.ny) z2 = cad.nzplot()*(cad.nz-cad.z[i+2]+0.5)/float(cad.nz) im.xy_draw.line([x0,y0,x1,y1,x2,y2,x0,y0],fill="black") im.xz_draw.line([x0,z0,x1,z1,x2,z2,x0,z0],fill="black") im.yz_draw.line([z0,y0,z1,y1,z2,y2,z0,y0],fill="black") images.xy = ImageTk.PhotoImage(im.xy) images.xz = ImageTk.PhotoImage(im.xz) images.yz = ImageTk.PhotoImage(im.yz) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) canvas_xz.create_image(cad.nplot/2,cad.nplot/2,image=images.xz) canvas_yz.create_image(cad.nplot/2,cad.nplot/2,image=images.yz) im.xyz = Image.new("RGBX",(cad.nplot,cad.nplot),'white') images.xyz = ImageTk.PhotoImage(im.xyz) canvas_xyz.create_image(cad.nplot/2,cad.nplot/2,image=images.xyz) string_msg.set("done") root.update() def flash(event): # # convert to Gerber flashes # # evaluate .cad # evaluate() # # initialize variables # render_stop_flag = 0 cad.stop = 0 widget_stop.pack() delete_windows() cad.toolpaths = [] cad.zwrite = [] cad.x = zeros(0) cad.y = zeros(0) cad.z = zeros(0) ixs = array([]) ixe = array([]) iy = array([]) iz = array([]) # # evaluate coordinate arrays # (IY,IX) = indices((cad.ny,cad.nx)) IY = IY[::-1,:] IZ = arange(cad.nz) X = cad.xmin+(cad.xmax-cad.xmin)*IX/(cad.nx-1.0) Y = cad.ymin+(cad.ymax-cad.ymin)*IY/(cad.ny-1.0) if (cad.zwrite == []): if (cad.nz > 1): cad.zwrite = cad.zmin + (cad.zmax-cad.zmin)*arange(cad.nz)/(cad.nz-1.0) else: cad.zwrite = [cad.zmin] # # set up drawing image # im.xy = Image.new("RGBX",(cad.nxplot(),cad.nyplot()),'white') im.xy_draw = ImageDraw.Draw(im.xy) # # loop over layers # for layer in range(len(cad.zwrite)): # # check render stop button # if (cad.stop == 1): break # # evaluate layer # Z = cad.zwrite[layer] string_msg.set("convert z = %.3f"%Z) root.update() elements = eval(cad.function) # # merge x # starts = hstack((reshape((elements[:,0] == TRUE),(cad.ny,1)),((elements[:,1:] == TRUE) & (elements[:,:-1] == FALSE)))) ends = hstack((((elements[:,:-1] == TRUE) & (elements[:,1:] == FALSE)),reshape((elements[:,-1] == TRUE),(cad.ny,1)))) ixs = append(ixs,IX[starts]) ixe = append(ixe,1+IX[ends]) iy = append(iy,IY[starts]) iz = append(iz,IZ[layer-1]*ones(len(IX[starts]))) # # merge y # index = lexsort(keys=(iy,ixe,ixs,iz)) merge = (iz[index[1:]] == iz[index[:-1]]) & \ (ixe[index[1:]] == ixe[index[:-1]]) & \ (ixs[index[1:]] == ixs[index[:-1]]) & \ ((iy[index[1:]] - iy[index[:-1]]) == 1) merge = append(FALSE,merge).astype(bool_) starts = ((merge[1:] == TRUE) & (merge[:-1] == FALSE)) starts = append(starts,FALSE).astype(bool_) ends = ((merge[1:] == FALSE) & (merge[:-1] == TRUE)) if (merge[-1] == TRUE): ends = append(ends,TRUE) else: ends = append(ends,FALSE) ends = ends.astype(bool_) xs = ixs[index][starts | ~merge] xe = ixe[index][starts | ~merge] ys = iy[index][starts | ~merge] ye = iy[index][ends | ~(merge | starts)]+1 cad.x = ravel(transpose(vstack((xs,xe)))) cad.y = ravel(transpose(vstack((ys,ye)))) # # draw flashes # widget_stop.pack_forget() cad.view('xy') string_msg.set("draw ...") root.update() N = len(cad.x) for i in range(0,N,2): string_msg.set("draw flash %d/%d"%(i/4,N/4)) root.update() x0 = cad.nxplot()*(cad.x[i]+0.5)/float(cad.nx) y0 = cad.nyplot()*(cad.ny-cad.y[i]+0.5)/float(cad.ny) x1 = cad.nxplot()*(cad.x[i]+0.5)/float(cad.nx) y1 = cad.nyplot()*(cad.ny-cad.y[i+1]+0.5)/float(cad.ny) x2 = cad.nxplot()*(cad.x[i+1]+0.5)/float(cad.nx) y2 = cad.nyplot()*(cad.ny-cad.y[i+1]+0.5)/float(cad.ny) x3 = cad.nxplot()*(cad.x[i+1]+0.5)/float(cad.nx) y3 = cad.nyplot()*(cad.ny-cad.y[i]+0.5)/float(cad.ny) im.xy_draw.line([x0,y0,x1,y1,x2,y2,x3,y3,x0,y0],fill="black") images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) string_msg.set("done") root.update() def select_epi(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.epi') cad.cam = 'epi' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() laser_frame1.pack() if ((cad.nz > 1) | (cad.image_r.size > 1)): laser_frame2.pack() laser_frame3.pack() string_laser_rate.set("2500") string_laser_power.set("90") string_laser_speed.set("50") string_laser_min_power.set("10") string_laser_max_power.set("100") string_tool_dia.set("0.01") root.update() def select_camm(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.camm') cad.cam = 'camm' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() cut_frame.pack() string_cut_force.set("45") string_cut_velocity.set("2") string_tool_dia.set("0.01") root.update() def select_ps(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.ps') cad.cam = 'ps' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() fill_frame.pack() string_tool_dia.set("0.0") root.update() def select_ord(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.ord') cad.cam = 'ord' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() string_tool_dia.set("0.01") waterjet_frame.pack() string_lead_in.set("0.05") string_quality.set("-3") root.update() def select_g(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.gcode') cad.cam = 'g' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() string_tool_dia.set("0.03") cam_dia_frame.pack() cam_contour_frame.pack() string_g_feed_rate.set("20") string_g_spindle_speed.set("5000") string_g_tool.set("1") integer_g_cool.set("0") g_frame.pack() root.update() def select_rml(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.rml') cad.cam = 'rml' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() speed_frame.pack() rml_move_frame.pack() string_tool_dia.set("0.0156") string_xy_speed.set("4") string_z_speed.set("4") string_rml_x_move.set("1") string_rml_y_move.set("1") root.update() def select_sbp(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.sbp') cad.cam = 'sbp' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() jog_frame.pack() speed_frame.pack() string_tool_dia.set("0.125") string_xy_speed.set("1.1") string_z_speed.set("1.1") string_jog_xy_speed.set("7") string_jog_z_speed.set("7") string_jog_z.set(".25") root.update() def select_oms(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.oms') cad.cam = 'oms' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() excimer_frame.pack() string_pulse_period.set("10000") string_tool_dia.set("0.001") string_cut_vel.set("0.1") string_cut_accel.set("5.0") root.update() def select_dxf(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.dxf') cad.cam = 'dxf' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() string_tool_dia.set("0.0") root.update() def select_uni(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.uni') cad.cam = 'uni' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() cam_dia_frame.pack() cam_contour_frame.pack() laser_frame1.pack() if ((cad.nz > 1) | (cad.image_r.size > 1)): laser_frame2.pack() string_laser_rate.set("500") string_laser_power.set("60") string_laser_speed.set("15") string_tool_dia.set("0.01") string_laser_min_power.set("10") string_laser_max_power.set("100") string_vector_error.set('1.1') root.update() def select_jpg(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.jpg') cad.cam = 'jpg' cam_pack_forget() cam_file_frame.pack() root.update() def select_png(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.png') cad.cam = 'png' cam_pack_forget() cam_file_frame.pack() root.update() def select_stl(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.stl') cad.cam = 'stl' cam_pack_forget() cam_file_frame.pack() STL_frame.pack() root.update() def select_gerber(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.grb') cad.cam = 'grb' cam_pack_forget() cam_file_frame.pack() Gerber_frame.pack() root.update() def select_excellon(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.drl') cad.cam = 'drl' cam_pack_forget() cam_file_frame.pack() Excellon_frame.pack() root.update() def select_ca(): input_file_name = string_input_file.get() string_cam_file.set(input_file_name[0:-4]+'.ca') cad.cam = 'ca' cam_pack_forget() cam_file_frame.pack() root.update() def cam_pack_forget(): cam_file_frame.pack_forget() cam_vector_frame.pack_forget() cam_dia_frame.pack_forget() cam_contour_frame.pack_forget() laser_frame1.pack_forget() laser_frame2.pack_forget() laser_frame3.pack_forget() cut_frame.pack_forget() speed_frame.pack_forget() jog_frame.pack_forget() rml_move_frame.pack_forget() waterjet_frame.pack_forget() excimer_frame.pack_forget() STL_frame.pack_forget() Gerber_frame.pack_forget() Excellon_frame.pack_forget() fill_frame.pack_forget() g_frame.pack_forget() send_to_frame.pack_forget() def save_cam(event): # # write toolpath # if (cad.cam == "epi"): write_epi() elif (cad.cam == "camm"): write_camm() elif (cad.cam == "ps"): write_ps() elif (cad.cam == "ord"): write_ord() elif (cad.cam == "g"): write_G() elif (cad.cam == "rml"): write_rml() elif (cad.cam == "sbp"): write_sbp() elif (cad.cam == "oms"): write_oms() elif (cad.cam == "dxf"): write_dxf() elif (cad.cam == "uni"): write_uni() elif (cad.cam == "jpg"): write_jpg() elif (cad.cam == "png"): write_png() elif (cad.cam == "stl"): write_stl() elif (cad.cam == "grb"): write_gerber() elif (cad.cam == "drl"): write_excellon() elif (cad.cam == "ca"): write_ca() else: string_msg.set("unsupported output file format") root.update() def write_epi(): # # Epilog lasercutter output # todo: try 1200 DPI # units = 600*cad.inches_per_unit filename = string_cam_file.get() file = open(filename, 'wb') if (integer_laser_autofocus.get() == 0): # # init with autofocus off # file.write("%-12345X@PJL JOB NAME="+string_cam_file.get()+"\r\nE@PJL ENTER LANGUAGE=PCL\r\n&y0A&l0U&l0Z&u600D*p0X*p0Y*t600R*r0F&y50P&z50S*r6600T*r5100S*r1A*rC%1BIN;XR"+string_laser_rate.get()+";YP"+string_laser_power.get()+";ZS"+string_laser_speed.get()+";") else: # # init with autofocus on # file.write("%-12345X@PJL JOB NAME="+string_cam_file.get()+"\r\nE@PJL ENTER LANGUAGE=PCL\r\n&y1A&l0U&l0Z&u600D*p0X*p0Y*t600R*r0F&y50P&z50S*r6600T*r5100S*r1A*rC%1BIN;XR"+string_laser_rate.get()+";YP"+string_laser_power.get()+";ZS"+string_laser_speed.get()+";") power = float(string_laser_power.get()) min_power = float(string_laser_min_power.get()) max_power = float(string_laser_max_power.get()) for layer in range(len(cad.toolpaths)): if ((len(cad.zwrite) > 1) & (len(cad.toolpaths[layer]) > 0)): fraction = (cad.zwrite[layer]-cad.zwrite[0])/(cad.zwrite[-1]-cad.zwrite[0]) layer_power = min_power + fraction*(max_power-min_power) file.write("YP%f;"%layer_power) for segment in range(len(cad.toolpaths[layer])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx))) y = int(units*(-cad.ymin - ((cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)))) file.write("PU"+str(x)+","+str(y)+";") for vertex in range(1,len(cad.toolpaths[layer][segment])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx))) y = int(units*(-cad.ymin - ((cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)))) file.write("PD"+str(x)+","+str(y)+";") file.write("%0B%1BPUE%-12345X@PJL EOJ \r\n") file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_camm(): filename = string_cam_file.get() file = open(filename, 'wb') units = 1016*cad.inches_per_unit file.write("PA;PA;!ST1;!FS"+string_cut_force.get()+";VS"+string_cut_velocity.get()+";") for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny))) file.write("PU"+str(x)+","+str(y)+";") for vertex in range(1,len(cad.toolpaths[layer][segment])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny))) file.write("PD"+str(x)+","+str(y)+";") file.write("PU0,0;") file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_ps(): # # Postscript output # units = cad.inches_per_unit filename = string_cam_file.get() file = open(filename, 'wb') file.write("%! cad.py output\n") file.write("%%%%BoundingBox: 0 0 %.3f %.3f\n"% (72.0*(cad.xmax-cad.xmin),72.0*(cad.ymax-cad.ymin))) file.write("/m {moveto} def\n") file.write("/l {lineto} def\n") file.write("72 72 scale\n") file.write(".005 setlinewidth\n") file.write("%f %f translate\n"%(0.5,0.5)) for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)) file.write("%f %f m\n"%(x,y)) for vertex in range(1,len(cad.toolpaths[layer][segment])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)) file.write("%f %f l\n"%(x,y)) if (integer_fill.get() == 0): file.write("stroke\n") else: file.write("fill\n") file.write("showpage\n") file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_ord(): # # OMAX waterjet output # units = cad.inches_per_unit lead_in = float(string_lead_in.get()) quality = int(string_quality.get()) filename = string_cam_file.get() file = open(filename, 'wb') xlead = [] ylead = [] for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): # # calculate and write lead-in # x0 = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx)) y0 = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)) x1 = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][1].x+0.5)/float(cad.nx)) y1 = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][1].y)+0.5)/float(cad.ny)) dx = x1 - x0 dy = y1 - y0 norm_x = -dy norm_y = dx norm = sqrt(norm_x**2 + norm_y**2) norm_x = norm_x/norm norm_y = norm_y/norm xlead.append(x0 + norm_x*lead_in) ylead.append(y0 + norm_y*lead_in) file.write("%f, %f, 0, %d\n"%(xlead[segment],ylead[segment],quality)) # # loop over segment # for vertex in range(len(cad.toolpaths[layer][segment])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)) file.write("%f, %f, 0, %d\n"%(x,y,quality)) # # write lead-out # file.write("%f, %f, 0, 0\n"%(x0,y0)) file.write("%f, %f, 0, 0\n"%(xlead[segment],ylead[segment])) file.close() # # draw toolpath with lead-in/out # im.xy = Image.new("RGBX",(cad.nxplot(),cad.nyplot()),'white') im.xy_draw = ImageDraw.Draw(im.xy) for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): x = cad.nxplot()*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx) y = cad.nyplot()*(cad.toolpaths[layer][segment][0].y+0.5)/float(cad.ny) xl = cad.nxplot()*(xlead[segment]-cad.xmin)/(cad.xmax-cad.xmin) yl = cad.nyplot()-cad.nyplot()*(ylead[segment]-cad.ymin)/(cad.ymax-cad.ymin) im.xy_draw.line([xl,yl,x,y],fill="black") for vertex in range(1,len(cad.toolpaths[layer][segment])): xnew = cad.nxplot()*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx) ynew = cad.nyplot()*(cad.toolpaths[layer][segment][vertex].y+0.5)/float(cad.ny) im.xy_draw.line([x,y,xnew,ynew],fill="black") x = xnew y = ynew images.xy = ImageTk.PhotoImage(im.xy) canvas_xy.create_image(cad.nplot/2,cad.nplot/2,image=images.xy) string_msg.set("wrote %s"%filename) root.update() def distance(x1, y1, x2, y2): return sqrt((x1-x2)**2+(y1-y2)**2) def write_G(): # # G code output # units = cad.inches_per_unit zup = units*cad.zmax feed_rate = float(string_g_feed_rate.get()) spindle_speed = float(string_g_spindle_speed.get()) coolant = integer_g_cool.get() tool = int(string_g_tool.get()) if (cad.nz == 1): cad.zwrite = [cad.zmin] filename = string_cam_file.get() file = open(filename, 'wb') file.write("""(---------------------------------------------------------------) (---------------------------------------------------------------) (Start of sheet header) G21 (metric) G92 X0 Y0 Z0 (zero all axes) (End of sheet header)\n""") dxy = 0 dz = 0 xold = 0 yold = 0 for layer in range(len(cad.zwrite)-1,-1,-1): zdown = units*cad.zwrite[layer] # # follow toolpaths CCW, for CW tool motion # unsorted_segments = cad.toolpaths[layer] sorted_segments = [] if len(unsorted_segments) > 0: sorted_segments.append(unsorted_segments.pop(0)) #starts with the first path in the list else: print "empty path --- strange" while len(unsorted_segments) > 0: #find closest start to the the last sorted segment start min_dist = 99999 min_dist_index = None for i in range(len(unsorted_segments)): dist = distance(sorted_segments[-1][0].x, sorted_segments[-1][0].y, unsorted_segments[i][0].x, unsorted_segments[i][0].y) if dist < min_dist: min_dist = dist min_dist_index = i #print "min_dist: %d index: %d" % (min_dist, min_dist_index) sorted_segments.append(unsorted_segments.pop(min_dist_index)) for segment in range(len(sorted_segments)): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(sorted_segments[segment][0].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-sorted_segments[segment][0].y)+0.5)/float(cad.ny)) file.write("M106 S255 (Pen Up)\n") file.write("G4 P120\n") file.write("G1 X%0.4f "%x+"Y%0.4f "%y+" F2000.00\n") # rapid motion file.write("M107 (Pen Down)\n") # linear motion file.write("G4 P120\n") dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y dz += zup-zdown for vertex in range(1,len(sorted_segments[segment])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(sorted_segments[segment][vertex].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-sorted_segments[segment][vertex].y)+0.5)/float(cad.ny)) file.write("G1 X%0.4f "%x+"Y%0.4f"%y+" F2000.00\n") dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y file.write("""(Start of sheet footer.) M106 (Pen Up) G4 P120 (wait 120ms) G0 X0 Y0 Z15 F3500.00 (go to position for retrieving platform -- increase Z to Z25 or similar if you have trouble avoiding tool) G4 P300 (wait 300ms) G0 Z0 F3500.00 (return to start position of current sheet) G4 P300 (wait 300ms) M18 (disengage drives) (End of sheet footer) M01 (Printing on the next sheet?) (yes, if dropping the default .1 mm to next sheet; no, if you will print again on same sheet) G0 Z-0.10 F3500.00 (drop 0.1mm to next sheet) M107 (Pen Down so as not to overheat solenoid) (Paste in further sheets below) (---------------------------------------------------------------) (---------------------------------------------------------------) """) file.close() print "Path length: %f" % dxy time = (dxy/feed_rate + dz/feed_rate) string_send_to_time.set(" estimated time: %.1f minutes"%time) draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_rml(): # # Roland Modela output # units = 1016*cad.inches_per_unit # 40/mm filename = string_cam_file.get() file = open(filename, 'wb') file.write("PA;PA;VS"+string_xy_speed.get()+";!VZ"+string_z_speed.get()+";!MC1;") zup = cad.zmax izup = int(units*zup) if (cad.nz == 1): cad.zwrite = [cad.zmin] xy_speed = float(string_xy_speed.get()) # mm/s z_speed = float(string_z_speed.get()) # mm/s dxy = 0 dz = 0 xold = 0 yold = 0 for layer in range(len(cad.zwrite)-1,-1,-1): zdown = cad.zwrite[layer] izdown = int(units*zdown) file.write("!PZ"+str(izdown)+","+str(izup)+";") # # follow toolpaths CCW, for CW tool motion # for segment in range(len(cad.toolpaths[layer])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny))) file.write("PU"+str(x)+","+str(y)+";") dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y dz += izup-izdown for vertex in range(1,len(cad.toolpaths[layer][segment])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny))) file.write("PD"+str(x)+","+str(y)+";") dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y file.write("PU"+str(x)+","+str(y)+";!MC0;") # # file padding hack for end-of-file buffering problems # for i in range(1000): file.write("!MC0;") file.close() time = ((dxy/40.0)/xy_speed + (dz/40.0)/z_speed)/60.0 string_send_to_time.set(" estimated time: %.1f minutes"%time) draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def rml_move(event): # # move Roland Modela # units = 1016*cad.inches_per_unit # 40/mm x = float(string_rml_x_move.get()) y = float(string_rml_y_move.get()) ix = int(units*x) iy = int(units*y) filename = "move.rml" file = open(filename, 'wb') file.write("PA;PA;!PZ0,400;VS10;!VZ10;!MC0;PU%d,%d;!MC0;"%(ix,iy)) file.close() send_to_file("move.rml") os.remove("move.rml") def write_sbp(): # # ShopBot output # units = cad.inches_per_unit filename = string_cam_file.get() file = open(filename, 'wb') file.write("SA\r\n") # set to absolute distances file.write("SO,1,1\r\n") # set output number 1 to on file.write("pause 2\r\n") # let spindle come up to speed xy_speed = units*float(string_xy_speed.get()) z_speed = units*float(string_z_speed.get()) file.write("MS %f,%f\r\n"%(xy_speed,z_speed)) # set xy,z speed jog_xy_speed = units*float(string_jog_xy_speed.get()) jog_z_speed = units*float(string_jog_z_speed.get()) file.write("JS %f,%f\r\n"%(jog_xy_speed,jog_z_speed)) # set jog xy,z speed zup = units*float(string_jog_z.get()) dxy = 0 dz = 0 xold = 0 yold = 0 for layer in range(len(cad.zwrite)-1,-1,-1): zdown = cad.zwrite[layer] # # follow toolpaths CCW, for CW tool motion # for segment in range(len(cad.toolpaths[layer])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)) file.write("JZ %f\r\n"%zup) file.write("J2 %f,%f\r\n"%(x,y)) file.write("MZ %f\r\n"%zdown) dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y dz += zup-zdown for vertex in range(1,len(cad.toolpaths[layer][segment])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)) file.write("M2 %f,%f\r\n"%(x,y)) dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y file.write("JZ %f\r\n"%zup) file.close() time = (dxy/xy_speed + dz/z_speed)/60.0 string_send_to_time.set(" estimated time: %.1f minutes"%time) draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_oms(): # # Resonetics excimer micromachining center output # units = 25.4*cad.inches_per_unit pulseperiod = float(string_pulse_period.get()) cutvel = float(string_cut_vel.get()) cutaccel = float(string_cut_accel.get()) slewvel = 1 slewaccel = 5 settle = 100 filename = string_cam_file.get() file = open(filename, 'wb') file.write("AA LP0,0,0,0,0\n") # set origin file.write("PP%d\n"%pulseperiod) # set pulse period for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)) file.write("VL%.1f,%.1f\n"%(slewvel,slewvel)) file.write("AC%.1f,%.1f\n"%(slewaccel,slewaccel)) file.write("MA%f,%f\n"%(x,y)) file.write("VL%.1f,%.1f\n"%(cutvel,cutvel)) file.write("AC%.1f,%.1f\n"%(cutaccel,cutaccel)) file.write("WT%d\n"%settle) # wait to settle for vertex in range(1,len(cad.toolpaths[layer][segment])): x = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx)) y = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)) file.write("CutAbs %f,%f\n"%(x,y)) file.write("END\n") file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_dxf(): # # DXF output # units = cad.inches_per_unit filename = string_cam_file.get() file = open(filename, 'wb') file.write("999\nDXF written by cad.py\n") file.write("0\nSECTION\n") file.write("2\nHEADER\n") file.write("9\n$EXTMIN\n") file.write("10\n%f\n"%cad.xmin) file.write("20\n%f\n"%cad.ymin) file.write("9\n$EXTMAX\n") file.write("10\n%f\n"%cad.xmax) file.write("20\n%f\n"%cad.ymax) file.write("0\nENDSEC\n") file.write("0\nSECTION\n") file.write("2\nTABLES\n") file.write("0\nTABLE\n") file.write("2\nLTYPE\n70\n1\n") file.write("0\nLTYPE\n") file.write("2\nCONTINUOUS\n") file.write("70\n64\n3\n") file.write("Solid line\n") file.write("72\n65\n73\n0\n40\n0.000000\n") file.write("0\nENDTAB\n") file.write("0\nTABLE\n2\nLAYER\n70\n1\n") file.write("0\nLAYER\n2\ndefault\n70\n64\n62\n7\n6\n") file.write("CONTINUOUS\n0\nENDTAB\n") file.write("0\nENDSEC\n") file.write("0\nSECTION\n") file.write("2\nBLOCKS\n") file.write("0\nENDSEC\n") file.write("0\nSECTION\n") file.write("2\nENTITIES\n") for layer in range(len(cad.toolpaths)): for segment in range(len(cad.toolpaths[layer])): for vertex in range(1,len(cad.toolpaths[layer][segment])): x0 = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex-1].x+0.5)/float(cad.nx)) y0 = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex-1].y)+0.5)/float(cad.ny)) x1 = units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx)) y1 = units*(cad.ymin + (cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)) file.write("0\nLINE\n") file.write("10\n%f\n"%x0) file.write("20\n%f\n"%y0) file.write("11\n%f\n"%x1) file.write("21\n%f\n"%y1) file.write("0\nENDSEC\n") file.write("0\nEOF\n") file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_uni(): # # Universal lasercutter output # units = 1000*cad.inches_per_unit filename = string_cam_file.get() file = open(filename, 'wb') file.write("Z") # initialize file.write("t%s~;"%filename) # title file.write("IN;DF;PS0;DT~") # initialize ppibyte = int(float(string_laser_rate.get())/10) file.write("s%c"%ppibyte) # PPI speed_hibyte = int(648*float(string_laser_speed.get()))/256 speed_lobyte = int(648*float(string_laser_speed.get()))%256 file.write("v%c%c"%(speed_hibyte,speed_lobyte)) # speed power = float(string_laser_power.get()) min_power = float(string_laser_min_power.get()) max_power = float(string_laser_max_power.get()) power_hibyte = (320*int(power))/256 power_lobyte = (320*int(power))%256 file.write("p%c%c"%(power_hibyte,power_lobyte)) # power file.write("a%c"%2) # air assist on high for layer in range(len(cad.toolpaths)): if ((len(cad.zwrite) > 1) & (len(cad.toolpaths[layer]) > 0)): fraction = (cad.zwrite[layer]-cad.zwrite[0])/(cad.zwrite[-1]-cad.zwrite[0]) layer_power = min_power + fraction*(max_power-min_power) power_hibyte = (320*int(layer_power))/256 power_lobyte = (320*int(layer_power))%256 file.write("p%c%c"%(power_hibyte,power_lobyte)) # power for segment in range(len(cad.toolpaths[layer])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][0].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + ((cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][0].y)+0.5)/float(cad.ny)))) file.write("PU;PA"+str(x)+","+str(y)+";PD;") for vertex in range(1,len(cad.toolpaths[layer][segment])): x = int(units*(cad.xmin + (cad.xmax-cad.xmin)*(cad.toolpaths[layer][segment][vertex].x+0.5)/float(cad.nx))) y = int(units*(cad.ymin + ((cad.ymax-cad.ymin)*((cad.ny-cad.toolpaths[layer][segment][vertex].y)+0.5)/float(cad.ny)))) file.write("PA"+str(x)+","+str(y)+";") file.write("e") # end of file file.close() draw_toolpath() string_msg.set("wrote %s"%filename) root.update() def write_jpg(): # # JPG image output # if (cad.views == "xy"): filename = string_cam_file.get() im.xy = Image.fromarray(im.intensity_xy,mode="RGBX") im_rgb_xy = im.xy.convert("RGB") dpi = int(cad.nx/float(cad.xmax-cad.xmin)) im_rgb_xy.save(filename,dpi=(dpi,dpi)) string_msg.set("wrote %s"%filename) elif (cad.views == "xyzr"): border = 5 filename = string_cam_file.get() im.xy = Image.fromarray(im.intensity_xy,mode="RGBX") im.xz = Image.fromarray(im.intensity_xz,mode="RGBX") im.yz = Image.fromarray(im.intensity_yz,mode="RGBX") im.yz = im.yz.transpose(Image.FLIP_LEFT_RIGHT) im.xyz = Image.fromarray(im.intensity_xyz,mode="RGBX") (nx,ny) = im.xy.size ny = (nx*cad.nyplot())/cad.nxplot() nz = (nx*cad.nzplot())/cad.nxplot() im.xy = im.xy.resize((nx,ny)) im.yz = im.yz.resize((nz,ny)) im.xz = im.xz.resize((nx,nz)) im.xyz = im.xyz.resize((nx,ny)) im_rgb_xy = im.xy.convert("RGB") im_rgb_xz = im.xz.convert("RGB") im_rgb_yz = im.yz.convert("RGB") im_rgb_xyz = im.xyz.convert("RGB") img = Image.new("RGB",(nx+border+nx,ny+border+ny),"white") img.paste(im_rgb_xy,(0,0)) img.paste(im_rgb_xz,(0,border+ny)) img.paste(im_rgb_yz,(border+nx,0)) img.paste(im_rgb_xyz,(border+nx,border+ny)) img.save(filename) string_msg.set("wrote %s"%filename) else: string_msg.set("unknown view") def write_png(): # # PNG image output # if (cad.views == "xy"): filename = string_cam_file.get() im.xy = Image.fromarray(im.intensity_xy,mode="RGBX") im_rgb_xy = im.xy.convert("RGB") dpi = int(cad.nx/float(cad.xmax-cad.xmin)) im_rgb_xy.save(filename,dpi=(dpi,dpi)) string_msg.set("wrote %s"%filename) elif (cad.views == "xyzr"): border = 5 filename = string_cam_file.get() im.xy = Image.fromarray(im.intensity_xy,mode="RGBX") im.xz = Image.fromarray(im.intensity_xz,mode="RGBX") im.yz = Image.fromarray(im.intensity_yz,mode="RGBX") im.yz = im.yz.transpose(Image.FLIP_LEFT_RIGHT) im.xyz = Image.fromarray(im.intensity_xyz,mode="RGBX") (nx,ny) = im.xy.size ny = (nx*cad.nyplot())/cad.nxplot() nz = (nx*cad.nzplot())/cad.nxplot() im.xy = im.xy.resize((nx,ny)) im.yz = im.yz.resize((nz,ny)) im.xz = im.xz.resize((nx,nz)) im.xyz = im.xyz.resize((nx,ny)) im_rgb_xy = im.xy.convert("RGB") im_rgb_xz = im.xz.convert("RGB") im_rgb_yz = im.yz.convert("RGB") im_rgb_xyz = im.xyz.convert("RGB") img = Image.new("RGB",(nx+border+nx,ny+border+ny),"white") img.paste(im_rgb_xy,(0,0)) img.paste(im_rgb_xz,(0,border+ny)) img.paste(im_rgb_yz,(border+nx,0)) img.paste(im_rgb_xyz,(border+nx,border+ny)) img.save(filename) string_msg.set("wrote %s"%filename) else: string_msg.set("unknown view") def write_stl(): # # STL output # filename = string_cam_file.get() file = open(filename, 'wb') units = cad.inches_per_unit x = cad.xmin+(cad.xmax-cad.xmin)*(cad.x+0.5)/float(cad.nx) y = cad.ymin+(cad.ymax-cad.ymin)*(cad.y+0.5)/float(cad.ny) z = cad.zmin+(cad.zmax-cad.zmin)*(cad.z+0.5)/float(cad.nz) # # header # file.write('cad.py') file.write('a'*74) # # length # N = len(cad.x) file.write(struct.pack('L',N/3)) # # triangles # for i in range(0,N,3): string_msg.set("write triangle %d/%d"%(i/3,N/3)) root.update() # # normals # file.write(struct.pack('f',0)) file.write(struct.pack('f',0)) file.write(struct.pack('f',0)) # # vertices # file.write(struct.pack('f',x[i]*units)) file.write(struct.pack('f',y[i]*units)) file.write(struct.pack('f',z[i]*units)) file.write(struct.pack('f',x[i+1]*units)) file.write(struct.pack('f',y[i+1]*units)) file.write(struct.pack('f',z[i+1]*units)) file.write(struct.pack('f',x[i+2]*units)) file.write(struct.pack('f',y[i+2]*units)) file.write(struct.pack('f',z[i+2]*units)) # # padding # file.write(struct.pack('xx')) file.close() string_msg.set("wrote %s"%filename) root.update() def write_gerber(): # # Gerber (RS-274X) output # filename = string_cam_file.get() file = open(filename, 'wb') units = cad.inches_per_unit # # write parameters # file.write("%FSLAX24Y24*%\n") # leading zeros omitted, absolute coordinates, 2.4 file.write("%MOIN*%\n") # inches units file.write("%OFA0B0*%\n") # no offset # # find and write apertures # ixs = cad.x[::2] xs = cad.xmin+(cad.xmax-cad.xmin)*(ixs+0.5)/float(cad.nx) ixe = cad.x[1::2] xe = cad.xmin+(cad.xmax-cad.xmin)*(ixe+0.5)/float(cad.nx) idx = ixe - ixs dx = xe - xs iys = cad.y[::2] ys = cad.ymin+(cad.ymax-cad.ymin)*(iys+0.5)/float(cad.ny) iye = cad.y[1::2] ye = cad.ymin+(cad.ymax-cad.ymin)*(iye+0.5)/float(cad.ny) idy = iye - iys dy = ye - ys mins = where((idx < idy),idx,idy) uniques = unique(mins) apertures = (cad.xmax-cad.xmin)*uniques/float(cad.nx) index = searchsorted(uniques,mins) for i in range(len(uniques)): file.write("%%ADD%dR,%.4fX%.4f*%%\n"%(i+10,apertures[i],apertures[i])) # # write flashes # coords = arange(len(mins)) for i in range(len(uniques)): file.write("D%d*\n"%(i+10)) coord = coords[index == i] delta = apertures[i]/2. ixs = (10000*(xs+delta)).astype(int32) ixe = (10000*(xe-delta)).astype(int32) iys = (10000*(ys+delta)).astype(int32) iye = (10000*(ye-delta)).astype(int32) for j in range(len(coord)): n = coord[j] if (idx[n] == idy[n]): # # flash # file.write('X%dY%dD03*\n'%(ixs[n],iys[n])) elif (idx[n] > idy[n]): # # stroke horizontal # file.write('X%dY%dD02*\n'%(ixs[n],iys[n])) file.write('X%dY%dD01*\n'%(ixe[n],iys[n])) else: # # stroke vertical # file.write('X%dY%dD02*\n'%(ixs[n],iys[n])) file.write('X%dY%dD01*\n'%(ixs[n],iye[n])) file.write("M02*\n") # end of file file.close() string_msg.set("wrote %s (RS-274X)"%filename) root.update() def write_excellon(): # # Excellon (RS-) output # """ % Rewind and Stop X#Y# Move and Drill T# Tool Selection M30 End of Program M00 End of Program R#X#Y# Repeat Hole G05, G81 Select Drill Mode G90 Absolute Mode G91 Incremental Mode G92 X#Y# Set Zero G93 X#Y# Set Zero M48 Program Header to first "%" M72 English-Imperial Mode """ filename = string_cam_file.get() file = open(filename, 'wb') units = cad.inches_per_unit # # write parameters # file.write("%FSLAX24Y24*%\n") # leading zeros omitted, absolute coordinates, 2.4 file.write("%MOIN*%\n") # inches units file.write("%OFA0B0*%\n") # no offset # # find and write apertures # ixs = cad.x[::2] xs = cad.xmin+(cad.xmax-cad.xmin)*(ixs+0.5)/float(cad.nx) ixe = cad.x[1::2] xe = cad.xmin+(cad.xmax-cad.xmin)*(ixe+0.5)/float(cad.nx) idx = ixe - ixs dx = xe - xs iys = cad.y[::2] ys = cad.ymin+(cad.ymax-cad.ymin)*(iys+0.5)/float(cad.ny) iye = cad.y[1::2] ye = cad.ymin+(cad.ymax-cad.ymin)*(iye+0.5)/float(cad.ny) idy = iye - iys dy = ye - ys mins = where((idx < idy),idx,idy) uniques = unique(mins) apertures = (cad.xmax-cad.xmin)*uniques/float(cad.nx) index = searchsorted(uniques,mins) for i in range(len(uniques)): file.write("%%ADD%dR,%.4fX%.4f*%%\n"%(i+10,apertures[i],apertures[i])) # # write flashes # coords = arange(len(mins)) for i in range(len(uniques)): file.write("D%d*\n"%(i+10)) coord = coords[index == i] delta = apertures[i]/2. ixs = (10000*(xs+delta)).astype(int32) ixe = (10000*(xe-delta)).astype(int32) iys = (10000*(ys+delta)).astype(int32) iye = (10000*(ye-delta)).astype(int32) for j in range(len(coord)): n = coord[j] if (idx[n] == idy[n]): # # flash # file.write('X%dY%dD03*\n'%(ixs[n],iys[n])) elif (idx[n] > idy[n]): # # stroke horizontal # file.write('X%dY%dD02*\n'%(ixs[n],iys[n])) file.write('X%dY%dD01*\n'%(ixe[n],iys[n])) else: # # stroke vertical # file.write('X%dY%dD02*\n'%(ixs[n],iys[n])) file.write('X%dY%dD01*\n'%(ixs[n],iye[n])) file.write("M02*\n") # end of file file.close() string_msg.set("wrote %s (RS-274X)"%filename) root.update() def write_ca(): # # CA output # filename = string_cam_file.get() file = open(filename, 'wb') file.write(chr(0xB9)) # magic number 0xB9 file.write(chr(ca.nx/256)) # x size file.write(chr(ca.nx%256)) # file.write(chr(ca.ny/256)) # y size file.write(chr(ca.ny%256)) # file.write(chr(4)) # LED sub-array x file.write(chr(2)) # LED sub-array y for y in range(ca.nx): for x in range(ca.nx): if (ca.in1[y,x] == ca.E): config = 0 elif (ca.in1[y,x] == ca.NE): config = 1 elif (ca.in1[y,x] == ca.N): config = 2 elif (ca.in1[y,x] == ca.NW): config = 3 elif (ca.in1[y,x] == ca.W): config = 4 elif (ca.in1[y,x] == ca.SW): config = 5 elif (ca.in1[y,x] == ca.S): config = 6 elif (ca.in1[y,x] == ca.SE): config = 7 elif (ca.in1[y,x] == ca.empty): # XOR W W for empty config = 4 if (ca.in2[y,x] == ca.E): config += 0 elif (ca.in2[y,x] == ca.NE): config += (1 << 3) elif (ca.in2[y,x] == ca.N): config += (2 << 3) elif (ca.in2[y,x] == ca.NW): config += (3 << 3) elif (ca.in2[y,x] == ca.W): config += (4 << 3) elif (ca.in2[y,x] == ca.SW): config += (5 << 3) elif (ca.in2[y,x] == ca.S): config += (6 << 3) elif (ca.in2[y,x] == ca.SE): config += (7 << 3) elif (ca.in2[y,x] == ca.empty): # XOR W W for empty config += (4 << 3) if (ca.gates[y,x] == ca.AND): config += 0 elif (ca.gates[y,x] == ca.OR): config += (1 << 6) elif (ca.gates[y,x] == ca.XOR): config += (2 << 6) elif (ca.gates[y,x] == ca.NAND): config += (3 << 6) elif (ca.gates[y,x] == ca.empty): # XOR W W for empty config += (2 << 6) file.write(chr(config)) for y in range(ca.ny): for x in range((ca.nx/8)): state = \ (ca.states[y,8*x+0] << 7) \ + (ca.states[y,8*x+1] << 6) \ + (ca.states[y,8*x+2] << 5) \ + (ca.states[y,8*x+3] << 4) \ + (ca.states[y,8*x+4] << 3) \ + (ca.states[y,8*x+5] << 2) \ + (ca.states[y,8*x+6] << 1) \ + (ca.states[y,8*x+7] << 0) file.write(chr(state)) if ((ca.nx%8) != 0): x = cad.nx/8 state = 0 for i in range((ca.nx%8)): state += (ca.states[y,8*x+i] << (7-i)) file.write(chr(state)) file.close() string_msg.set("wrote %s"%filename) root.update() def msg_xy(event): x = (cad.xmin+cad.xmax)/2. + (cad.xmax-cad.xmin)*(1+event.x-cad.nplot/2.)/float(cad.nxplot()) y = (cad.ymin+cad.ymax)/2. + (cad.ymin-cad.ymax)*(1+event.y-cad.nplot/2.)/float(cad.nyplot()) string_msg.set("x = %.2f y = %.2f"%(x,y)) def msg_yz(event): if (cad.nz > 1): y = (cad.ymin+cad.ymax)/2. + (cad.ymin-cad.ymax)*(1+event.y-cad.nplot/2.)/float(cad.nyplot()) z = (cad.zmin+cad.zmax)/2. + (cad.zmin-cad.zmax)*(1+event.x-cad.nplot/2.)/float(cad.nzplot()) string_msg.set("y = %.2f z = %.2f"%(y,z)) else: string_msg.set("") def msg_xz(event): if (cad.nz > 1): x = (cad.xmin+cad.xmax)/2. + (cad.xmax-cad.xmin)*(1+event.x-cad.nplot/2.)/float(cad.nxplot()) z = (cad.zmin+cad.zmax)/2. + (cad.zmin-cad.zmax)*(1+event.y-cad.nplot/2.)/float(cad.nzplot()) string_msg.set("x = %.2f z = %.2f"%(x,z)) else: string_msg.set("") def msg_nomsg(event): string_msg.set("") def image_min_x(event): cad.xmin = float(string_image_xmin.get()) xwidth = float(string_image_xwidth.get()) cad.xmax = cad.xmin + xwidth root.update() def image_min_y(event): cad.ymin = float(string_image_ymin.get()) yheight = float(string_image_yheight.get()) cad.ymax = cad.ymin + yheight root.update() def image_scale_x(event): yheight = float(string_image_yheight.get()) xwidth = yheight*cad.nx/float(cad.ny) cad.xmax = cad.xmin + xwidth string_image_xwidth.set(str(xwidth)) root.update() def image_scale_y(event): xwidth = float(string_image_xwidth.get()) yheight = xwidth*cad.ny/float(cad.nx) cad.ymax = cad.ymin + yheight string_image_yheight.set(str(yheight)) root.update() def send_to(event): save_cam(0) cam_file_name = string_cam_file.get() send_to_file(cam_file_name) def send_to_file(cam_file_name): cad_path = os.path.dirname(sys.argv[0]) if (sys.argv[0] == "cad.py"): cfg_path = "cad.cfg" else: cfg_path = os.path.dirname(sys.argv[0])+"/cad.cfg" try: config_file = open(cfg_path, 'r') except: string_msg.set(cfg_path+" not found") root.update() return() dot = find(cam_file_name,".") while 1: new_dot = find(cam_file_name,".",dot+1) if (new_dot == -1): break else: dot = new_dot suffix = cam_file_name[dot+1:] while 1: line = config_file.readline() if (find(line,suffix) == 0): string_msg.set("sending "+cam_file_name+" ...") root.update() quote1 = find(line,"'") quote2 = find(line,"'",quote1+1) cmd = line[(quote1+1):quote2] if (os.name == 'nt'): cam_file_name = replace(cam_file_name,'/','\\') cmd = replace(cmd,'file','"'+cam_file_name+'"') os.system(cmd) string_msg.set(cam_file_name+" sent") root.update() config_file.close() root.update() return() elif (line == ""): string_msg.set(suffix+" driver not defined in "+cfg_path) config_file.close() root.update() return() def resize_window(event): # # resize drawing windows # cad.nplot = int(string_window_size.get()) cad.view(cad.views) render() def resize_editor(event): # # resize editing windows # cad.editor_height = int(string_editor_height.get()) widget_cad_text.config(height=cad.editor_height) cad.editor_width = int(string_editor_width.get()) widget_cad_text.config(width=cad.editor_width) widget_function_text.config(width=cad.editor_width) root.update() def reload(): # # reload input file # filename = string_input_file.get() if (find(filename,'.cad') != -1): cad_load(0) elif ((find(filename,'.jpg') != -1) | (find(filename,'.JPG') != -1) | (find(filename,'.png') != -1) | (find(filename,'.PNG') != -1) | (find(filename,'.gif') != -1) | (find(filename,'.GIF') != -1)): widget_cad_text.delete("1.0",END) image_load(0) else: string_msg.set("unsupported input file format") root.update() # # set up GUI # root = Tk() root.title('cad.py') # # message frame # msg_frame = Frame(root) string_msg = StringVar() widget_msg = Label(msg_frame, textvariable = string_msg) widget_msg.pack(side='right') Label(msg_frame, text=" ").pack(side='right') widget_stop = Button(msg_frame, text='stop', borderwidth=2) widget_stop.bind('<Button-1>',render_stop) msg_frame.grid(row=0,column=0) # # size frame # size_frame = Frame(root) Label(size_frame, text="window size: ").pack(side='left') string_window_size = StringVar() string_window_size.set(str(cad.nplot)) widget_window_size = Entry(size_frame, width=4, bg='white', textvariable=string_window_size) widget_window_size.bind('<Return>',resize_window) widget_window_size.pack(side='left') Label(size_frame, text=" editor width: ").pack(side='left') string_editor_width = StringVar() string_editor_width.set(str(cad.editor_width)) widget_editor_width = Entry(size_frame, width=3, bg='white', textvariable=string_editor_width) widget_editor_width.bind('<Return>',resize_editor) widget_editor_width.pack(side='left') Label(size_frame, text=" height: ").pack(side='left') string_editor_height = StringVar() string_editor_height.set(str(cad.editor_height)) widget_editor_height = Entry(size_frame, width=3, bg='white', textvariable=string_editor_height) widget_editor_height.bind('<Return>',resize_editor) widget_editor_height.pack(side='left') size_frame.grid(row=0,column=1) # # view frame # view_frame2 = Frame(root) view_frame3 = Frame(root) canvas_xy = Canvas(view_frame3) canvas_xz = Canvas(view_frame3) canvas_yz = Canvas(view_frame3) canvas_xyz = Canvas(view_frame3) cad.view('xyzr') # # I/O frame # io_frame = Frame(root) io_frame.grid(row=2,column=1,sticky=N) #cad_frame.bind('<Motion>',msg_nomsg) # # input frame # input_frame = Frame(io_frame) input_frame.pack() # # .cad editor # editor_frame = Frame(input_frame) widget_text_yscrollbar = Scrollbar(editor_frame) widget_cad_text = Text(editor_frame, bg='white', bd=5, width=cad.editor_width, height=cad.editor_height, yscrollcommand=widget_text_yscrollbar.set) widget_cad_text.grid(row=1,column=1) widget_text_yscrollbar.grid(row=1,column=2,sticky=N+S) widget_text_yscrollbar.config(command=widget_cad_text.yview) widget_cad_text.bind('<Motion>',msg_nomsg) editor_frame.pack() # # input file # cad_input_frame = Frame(input_frame) widget_input_file = Button(cad_input_frame, text="input:",command=input_open) widget_input_file.pack(side='left') string_input_file = StringVar() string_input_file.set('out.cad') widget_cad = Entry(cad_input_frame, width=17, bg='white', textvariable=string_input_file) widget_cad.pack(side='left') Label(cad_input_frame, text=" ").pack(side='left') widget_cad_save = Button(cad_input_frame, text="save") widget_cad_save.bind('<Button-1>',cad_save) widget_cad_save.pack(side='left') Label(cad_input_frame, text=" ").pack(side='left') widget_reload = Button(cad_input_frame, text="reload",command=reload) widget_reload.pack(side='left') cad_input_frame.pack() # # image x # image_x_frame = Frame(input_frame) Label(image_x_frame, text="x min: ").pack(side='left') string_image_xmin = StringVar() widget_image_xmin = Entry(image_x_frame, width=6, bg='white', textvariable=string_image_xmin) widget_image_xmin.bind('<Return>',image_min_x) widget_image_xmin.pack(side='left') Label(image_x_frame, text=" x width: ").pack(side='left') string_image_xwidth = StringVar() widget_image_xwidth = Entry(image_x_frame, width=6, bg='white', textvariable=string_image_xwidth) widget_image_xwidth.bind('<Return>',image_scale_y) widget_image_xwidth.pack(side='left') string_image_nx = StringVar() Label(image_x_frame, textvariable = string_image_nx).pack(side='left') # # image y # image_y_frame = Frame(input_frame) Label(image_y_frame, text="y min: ").pack(side='left') string_image_ymin = StringVar() widget_image_ymin = Entry(image_y_frame, width=6, bg='white', textvariable=string_image_ymin) widget_image_ymin.bind('<Return>',image_min_y) widget_image_ymin.pack(side='left') Label(image_y_frame, text=" y height: ").pack(side='left') string_image_yheight = StringVar() widget_image_yheight = Entry(image_y_frame, width=6, bg='white', textvariable=string_image_yheight) widget_image_yheight.bind('<Return>',image_scale_x) widget_image_yheight.pack(side='left') string_image_ny = StringVar() Label(image_y_frame, textvariable = string_image_ny).pack(side='left') # # image z # image_z_frame = Frame(input_frame) Label(image_z_frame, text="z min: ").pack(side='left') string_image_zmin = StringVar() widget_image_zmin = Entry(image_z_frame, width=6, bg='white', textvariable=string_image_zmin) widget_image_zmin.pack(side='left') Label(image_z_frame, text=" z max: ").pack(side='left') string_image_zmax = StringVar() widget_image_zmax = Entry(image_z_frame, width=6, bg='white', textvariable=string_image_zmax) widget_image_zmax.pack(side='left') Label(image_z_frame, text=" nz: ").pack(side='left') string_image_nz = StringVar() widget_image_nz = Entry(image_z_frame, width=6, bg='white', textvariable=string_image_nz) widget_image_nz.pack(side='left') # # image intensity # image_intensity_frame = Frame(input_frame) Label(image_intensity_frame, text="intensity min: ").pack(side='left') string_image_min = StringVar() widget_image_min = Entry(image_intensity_frame, width=6, bg='white', textvariable=string_image_min) widget_image_min.pack(side='left') Label(image_intensity_frame, text=" intensity max: ").pack(side='left') string_image_max = StringVar() widget_image_max = Entry(image_intensity_frame, width=6, bg='white', textvariable=string_image_max) widget_image_max.pack(side='left') # # image units # image_units_frame = Frame(input_frame) Label(image_units_frame, text="inches per unit: ").pack(side='left') string_image_units = StringVar() widget_image_units = Entry(image_units_frame, width=6, bg='white', textvariable=string_image_units) widget_image_units.pack(side='left') # # image invert # image_invert_frame = Frame(input_frame) Label(image_invert_frame, text=" ").pack(side='left') widget_image_invert = Button(image_invert_frame, text="invert image") widget_image_invert.pack(side='left') widget_image_invert.bind('<Button-1>',invert_image) # # output frame # output_frame = Frame(io_frame) output_frame.pack() # # controls # control_frame = Frame(output_frame) widget_render = Button(control_frame, text="render") widget_render.bind('<Button-1>',render_button) widget_render.pack(side='left') Label(control_frame, text=" ").pack(side='left') canvas_logo = Canvas(control_frame, width=26, height=26, background="white") canvas_logo.create_oval(2,2,8,8,fill="red",outline="") canvas_logo.create_rectangle(11,2,17,8,fill="blue",outline="") canvas_logo.create_rectangle(20,2,26,8,fill="blue",outline="") canvas_logo.create_rectangle(2,11,8,17,fill="blue",outline="") canvas_logo.create_oval(10,10,16,16,fill="red",outline="") canvas_logo.create_rectangle(20,11,26,17,fill="blue",outline="") canvas_logo.create_rectangle(2,20,8,26,fill="blue",outline="") canvas_logo.create_rectangle(11,20,17,26,fill="blue",outline="") canvas_logo.create_rectangle(20,20,26,26,fill="blue",outline="") canvas_logo.pack(side='left') control_text = " cad.py (%s) "%DATE Label(control_frame, text=control_text).pack(side='left') widget_cam = Button(control_frame, text="cam") widget_cam.bind('<Button-1>',cam) widget_cam.pack(side='left') Label(control_frame, text=" ").pack(side='left') widget_quit = Button(control_frame, text="quit", command='exit') widget_quit.pack(side='left') control_frame.pack() # # function string # function_string_frame = Frame(output_frame) Label(function_string_frame, text="function:").grid(row=1,column=1) widget_function_yscrollbar = Scrollbar(function_string_frame) widget_function_text = Text(function_string_frame, bg='white', bd=5, width=cad.editor_width, height=12, yscrollcommand=widget_function_yscrollbar.set, state=DISABLED) widget_function_text.grid(row=2,column=1) widget_function_yscrollbar.grid(row=2,column=2,sticky=N+S) widget_function_yscrollbar.config(command=widget_function_text.yview) function_string_frame.pack() # # CAM file # cam_file_frame = Frame(output_frame) widget_cam_menu_button = Menubutton(cam_file_frame,text="output format", relief=RAISED) widget_cam_menu_button.pack(side='left') widget_cam_menu = Menu(widget_cam_menu_button) widget_cam_menu.add_command(label='.epi (Epilog)',command=select_epi) widget_cam_menu.add_command(label='.camm (CAMM)',command=select_camm) widget_cam_menu.add_command(label='.rml (Modela)',command=select_rml) widget_cam_menu.add_command(label='.sbp (ShopBot)',command=select_sbp) widget_cam_menu.add_command(label='.gcode (Gcode)',command=select_g) widget_cam_menu.add_command(label='.ps (Postscript)',command=select_ps) widget_cam_menu.add_command(label='.ord (OMAX)',command=select_ord) widget_cam_menu.add_command(label='.oms (Resonetics)',command=select_oms) widget_cam_menu.add_command(label='.grb (Gerber)',command=select_gerber) widget_cam_menu.add_command(label='.drl (Excellon)',command=select_excellon) widget_cam_menu.add_command(label='.stl (STL)',command=select_stl) widget_cam_menu.add_command(label='.dxf (DXF)',command=select_dxf) widget_cam_menu.add_command(label='.jpg (JPG)',command=select_jpg) widget_cam_menu.add_command(label='.png (PNG)',command=select_png) widget_cam_menu.add_command(label='.ca (CA)',command=select_ca) widget_cam_menu.add_command(label='.uni (Universal)',command=select_uni) widget_cam_menu.add_command(label='.epb (Epilog bitmap)',state=DISABLED) widget_cam_menu_button['menu'] = widget_cam_menu Label(cam_file_frame, text=" output file: ").pack(side='left') string_cam_file = StringVar() widget_cam_file = Entry(cam_file_frame, width=12, bg='white', textvariable=string_cam_file) widget_cam_file.pack(side='left') Label(cam_file_frame, text=" ").pack(side='left') widget_cam_save = Button(cam_file_frame, text="save") widget_cam_save.bind('<Button-1>',save_cam) widget_cam_save.pack(side='left') # # vectorization # cam_vector_frame = Frame(output_frame) Label(cam_vector_frame, text="maximum vector fit error (lattice units): ").pack(side='left') string_vector_error = StringVar() string_vector_error.set('.75') widget_vector_error = Entry(cam_vector_frame, width=6, bg='white', textvariable=string_vector_error) widget_vector_error.pack(side='left') # # tool # cam_dia_frame = Frame(output_frame) Label(cam_dia_frame, text="tool diameter: ").pack(side='left') string_tool_dia = StringVar() string_tool_dia.set('0') widget_tool_dia = Entry(cam_dia_frame, width=6, bg='white', textvariable=string_tool_dia) widget_tool_dia.pack(side='left') Label(cam_dia_frame, text=" tool overlap: ").pack(side='left') string_tool_overlap = StringVar() string_tool_overlap.set('0.5') widget_tool_overlap = Entry(cam_dia_frame, width=6, bg='white', textvariable=string_tool_overlap) widget_tool_overlap.pack(side='left') # # contour # cam_contour_frame = Frame(output_frame) Label(cam_contour_frame, text=" # contours (-1 for max): ").pack(side='left') string_num_contours = StringVar() string_num_contours.set('0') widget_num_contours = Entry(cam_contour_frame, width=6, bg='white', textvariable=string_num_contours) widget_num_contours.pack(side='left') Label(cam_contour_frame, text=" ").pack(side='left') widget_cam_contour = Button(cam_contour_frame, text="contour") widget_cam_contour.pack(side='left') widget_cam_contour.bind('<Button-1>',contour) # # laser power # laser_frame1 = Frame(output_frame) Label(laser_frame1, text=" power:").pack(side='left') string_laser_power = StringVar() Entry(laser_frame1, width=6, bg='white', textvariable=string_laser_power).pack(side='left') Label(laser_frame1, text=" speed:").pack(side='left') string_laser_speed = StringVar() Entry(laser_frame1, width=6, bg='white', textvariable=string_laser_speed).pack(side='left') Label(laser_frame1, text=" rate: ").pack(side='left') string_laser_rate = StringVar() Entry(laser_frame1, width=6, bg='white', textvariable=string_laser_rate).pack(side='left') # # power range # laser_frame2 = Frame(output_frame) Label(laser_frame2, text=" min power:").pack(side='left') string_laser_min_power = StringVar() Entry(laser_frame2, width=6, bg='white', textvariable=string_laser_min_power).pack(side='left') Label(laser_frame2, text="% max power:").pack(side='left') string_laser_max_power = StringVar() Entry(laser_frame2, width=6, bg='white', textvariable=string_laser_max_power).pack(side='left') Label(laser_frame2, text="%").pack(side='left') # # autofocus # laser_frame3 = Frame(output_frame) integer_laser_autofocus = IntVar() widget_autofocus = Checkbutton(laser_frame3, text="Auto Focus", variable=integer_laser_autofocus).pack(side='left') # # cutting # cut_frame = Frame(output_frame) Label(cut_frame, text="force: ").pack(side='left') string_cut_force = StringVar() Entry(cut_frame, width=6, bg='white', textvariable=string_cut_force).pack(side='left') Label(cut_frame, text=" velocity:").pack(side='left') string_cut_velocity = StringVar() Entry(cut_frame, width=6, bg='white', textvariable=string_cut_velocity).pack(side='left') # # speed # speed_frame = Frame(output_frame) Label(speed_frame, text="xy speed:").pack(side='left') string_xy_speed = StringVar() Entry(speed_frame, width=4, bg='white', textvariable=string_xy_speed).pack(side='left') Label(speed_frame, text=" z speed:").pack(side='left') string_z_speed = StringVar() Entry(speed_frame, width=4, bg='white', textvariable=string_z_speed).pack(side='left') # # jog # jog_frame = Frame(output_frame) Label(jog_frame, text="jog xy speed:").pack(side='left') string_jog_xy_speed = StringVar() Entry(jog_frame, width=4, bg='white', textvariable=string_jog_xy_speed).pack(side='left') Label(jog_frame, text=" z speed:").pack(side='left') string_jog_z_speed = StringVar() Entry(jog_frame, width=4, bg='white', textvariable=string_jog_z_speed).pack(side='left') Label(jog_frame, text=" z:").pack(side='left') string_jog_z = StringVar() Entry(jog_frame, width=4, bg='white', textvariable=string_jog_z).pack(side='left') # # RML move # rml_move_frame = Frame(output_frame) Label(rml_move_frame, text="x: ").pack(side='left') string_rml_x_move = StringVar() Entry(rml_move_frame, width=6, bg='white', textvariable=string_rml_x_move).pack(side='left') Label(rml_move_frame, text=" y: ").pack(side='left') string_rml_y_move = StringVar() Entry(rml_move_frame, width=6, bg='white', textvariable=string_rml_y_move).pack(side='left') Label(rml_move_frame, text=" ").pack(side='left') widget_rml_move = Button(rml_move_frame, text="move") widget_rml_move.pack(side='left') widget_rml_move.bind('<Button-1>',rml_move) # # G codes # g_frame = Frame(output_frame) Label(g_frame, text=" feed rate:").pack(side="left") string_g_feed_rate = StringVar() Entry(g_frame, width=6, textvariable=string_g_feed_rate).pack(side="left") Label(g_frame, text=" spindle speed:").pack(side="left") string_g_spindle_speed = StringVar() Entry(g_frame, width=6, textvariable=string_g_spindle_speed).pack(side="left") Label(g_frame, text=" tool:").pack(side="left") string_g_tool = StringVar() Entry(g_frame, width=3, textvariable=string_g_tool).pack(side="left") integer_g_cool = IntVar() widget_g_cool = Checkbutton(g_frame, text="coolant", variable=integer_g_cool) widget_g_cool.pack(side="left") # # waterjet # waterjet_frame = Frame(output_frame) Label(waterjet_frame,text="lead-in/out: ").pack(side='left') string_lead_in = StringVar() widget_lead_in = Entry(waterjet_frame, width=4, bg='white', textvariable=string_lead_in) widget_lead_in.pack(side='left') Label(waterjet_frame,text="quality: ").pack(side='left') string_quality = StringVar() widget_quality = Entry(waterjet_frame, width=4, bg='white', textvariable=string_quality) widget_quality.pack(side='left') # # excimer # excimer_frame = Frame(output_frame) Label(excimer_frame,text="period (usec): ").pack(side='left') string_pulse_period = StringVar() widget_pulse_period = Entry(excimer_frame, width=5, bg='white', textvariable=string_pulse_period) widget_pulse_period.pack(side='left') Label(excimer_frame,text="velocity: ").pack(side='left') string_cut_vel = StringVar() widget_cut_vel = Entry(excimer_frame, width=4, bg='white', textvariable=string_cut_vel) widget_cut_vel.pack(side='left') Label(excimer_frame,text="acceleration: ").pack(side='left') string_cut_accel = StringVar() widget_cut_accel = Entry(excimer_frame, width=4, bg='white', textvariable=string_cut_accel) widget_cut_accel.pack(side='left') # # STL # STL_frame = Frame(output_frame) widget_STL_triangulate = Button(STL_frame, text="triangulate") widget_STL_triangulate.pack(side='left') widget_STL_triangulate.bind('<Button-1>',triangulate) # # Gerber # Gerber_frame = Frame(output_frame) widget_Gerber_convert = Button(Gerber_frame, text="convert") widget_Gerber_convert.pack(side='left') widget_Gerber_convert.bind('<Button-1>',flash) # # Excellon # Excellon_frame = Frame(output_frame) widget_Excellon_convert = Button(Excellon_frame, text="convert") widget_Excellon_convert.pack(side='left') widget_Excellon_convert.bind('<Button-1>',flash) # # filling # fill_frame = Frame(output_frame) integer_fill = IntVar() widget_fill = Checkbutton(fill_frame, text="fill polygons", variable=integer_fill).pack(side='left') # # send to # send_to_frame = Frame(output_frame) widget_send_to = Button(send_to_frame, text="send to machine") widget_send_to.bind('<Button-1>',send_to) widget_send_to.pack(side='left') string_send_to_time = StringVar() string_send_to_time.set("") Label(send_to_frame,textvariable=string_send_to_time).pack(side='left') # # define .cad template # cad_template = """# # .cad template # # # define shapes and transformation # # circle(x0, y0, r) # cylinder(x0, y0, z0, z1, r) # cone(x0, y0, z0, z1, r0) # sphere(x0, y0, z0, r) # torus(x0, y0, z0, r0, r1) # rectangle(x0, x1, y0, y1) # cube(x0, x1, y0, y1, z0, z1) # right_triangle(x0, y0, h) # triangle(x0, y0, x1, y1, x2, y2) (points in clockwise order) # pyramid(x0, x1, y0, y1, z0, z1) # function(Z_of_XY) # functions(upper_Z_of_XY,lower_Z_of_XY) # add(part1, part2) # subtract(part1, part2) # intersect(part1, part2) # move(part,dx,dy) # translate(part,dx,dy,dz) # rotate(part, angle) # rotate_x(part, angle) # rotate_y(part, angle) # rotate_z(part, angle) # rotate_90(part) # rotate_180(part) # rotate_270(part) # reflect_x(part) # reflect_y(part) # reflect_z(part) # reflect_xy(part) # reflect_xz(part) # reflect_yz(part) # scale_x(part, x0, sx) # scale_y(part, y0, sy) # scale_z(part, z0, sz) # scale_xy(part, x0, y0, sxy) # scale_xyz(part, x0, y0, z0, sxyz) # coscale_x_y(part, x0, y0, y1, angle0, angle1, amplitude, offset) # coscale_x_z(part, x0, z0, z1, angle0, angle1, amplitude, offset) # coscale_xy_z(part, x0, y0, z0, z1, angle0, angle1, amplitude, offset) # taper_x_y(part, x0, y0, y1, s0, s1) # taper_x_z(part, x0, z0, z1, s0, s1) # taper_xy_z(part, x0, y0, z0, z1, s0, s1) # shear_x_y(part, y0, y1, dx0, dx1) # shear_x_z(part, z0, z1, dx0, dx1) # (more to come) def circle(x0, y0, r): part = "(((X-x0)**2 + (Y-y0)**2) <= r**2)" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'r',str(r)) return part def cylinder(x0, y0, z0, z1, r): part = "(((X-x0)**2 + (Y-y0)**2 <= r**2) & (Z >= z0) & (Z <= z1))" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'r',str(r)) return part def cone(x0, y0, z0, z1, r0): part = cylinder(x0, y0, z0, z1, r0) part = taper_xy_z(part, x0, y0, z0, z1, 1.0, 0.0) return part def sphere(x0, y0, z0, r): part = "(((X-x0)**2 + (Y-y0)**2 + (Z-z0)**2) <= r**2)" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'r',str(r)) return part def torus(x0, y0, z0, r0, r1): part = "(((r0 - sqrt((X-x0)**2 + (Y-y0)**2))**2 + (Z-z0)**2) <= r1**2)" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'r0',str(r0)) part = replace(part,'r1',str(r1)) return part def rectangle(x0, x1, y0, y1): part = "((X >= x0) & (X <= x1) & (Y >= y0) & (Y <= y1))" part = replace(part,'x0',str(x0)) part = replace(part,'x1',str(x1)) part = replace(part,'y0',str(y0)) part = replace(part,'y1',str(y1)) return part def cube(x0, x1, y0, y1, z0, z1): part = "((X >= x0) & (X <= x1) & (Y >= y0) & (Y <= y1) & (Z >= z0) & (Z <= z1))" part = replace(part,'x0',str(x0)) part = replace(part,'x1',str(x1)) part = replace(part,'y0',str(y0)) part = replace(part,'y1',str(y1)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) return part def right_triangle(x0, y0, h): part = "((X > x0) & (X < x0 + h - (Y-y0)) & (Y > y0))" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'h',str(h)) return part def triangle(x0, y0, x1, y1, x2, y2): # points in clockwise order part = "((((y1-y0)*(X-x0)-(x1-x0)*(Y-y0)) >= 0) & (((y2-y1)*(X-x1)-(x2-x1)*(Y-y1)) >= 0) & (((y0-y2)*(X-x2)-(x0-x2)*(Y-y2)) >= 0))" part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'x1',str(x1)) part = replace(part,'y1',str(y1)) part = replace(part,'x2',str(x2)) part = replace(part,'y2',str(y2)) return part def pyramid(x0, x1, y0, y1, z0, z1): part = cube(x0, x1, y0, y1, z0, z1) part = taper_xy_z(part, (x0+x1)/2., (y0+y1)/2., z0, z1, 1.0, 0.0) return part def function(Z_of_XY): part = '(Z <= '+Z_of_XY+')' return part def functions(upper_Z_of_XY,lower_Z_of_XY): part = '(Z <= '+upper_Z_of_XY+') & (Z >= '+lower_Z_of_XY+')' return part def add(part1, part2): part = "part1 | part2" part = replace(part,'part1',part1) part = replace(part,'part2',part2) return part def subtract(part1, part2): part = "(part1) & ~(part2)" part = replace(part,'part1',part1) part = replace(part,'part2',part2) return part def intersect(part1, part2): part = "(part1) & (part2)" part = replace(part,'part1',part1) part = replace(part,'part2',part2) return part def move(part,dx,dy): part = replace(part,'X','(X-'+str(dx)+')') part = replace(part,'Y','(Y-'+str(dy)+')') return part def translate(part,dx,dy,dz): part = replace(part,'X','(X-'+str(dx)+')') part = replace(part,'Y','(Y-'+str(dy)+')') part = replace(part,'Z','(Z-'+str(dz)+')') return part def rotate(part, angle): angle = angle*pi/180 part = replace(part,'X','(cos(angle)*X+sin(angle)*y)') part = replace(part,'Y','(-sin(angle)*X+cos(angle)*y)') part = replace(part,'y','Y') part = replace(part,'angle',str(angle)) return part def rotate_x(part, angle): angle = angle*pi/180 part = replace(part,'Y','(cos(angle)*Y+sin(angle)*z)') part = replace(part,'Z','(-sin(angle)*Y+cos(angle)*z)') part = replace(part,'z','Z') part = replace(part,'angle',str(angle)) return part def rotate_y(part, angle): angle = angle*pi/180 part = replace(part,'X','(cos(angle)*X+sin(angle)*z)') part = replace(part,'Z','(-sin(angle)*X+cos(angle)*z)') part = replace(part,'z','Z') part = replace(part,'angle',str(angle)) return part def rotate_z(part, angle): angle = angle*pi/180 part = replace(part,'X','(cos(angle)*X+sin(angle)*y)') part = replace(part,'Y','(-sin(angle)*X+cos(angle)*y)') part = replace(part,'y','Y') part = replace(part,'angle',str(angle)) return part def rotate_90(part): part = reflect_xy(part) part = reflect_y(part) return part def rotate_180(part): part = reflect_xy(part) part = reflect_y(part) part = reflect_xy(part) part = reflect_y(part) return part def rotate_270(part): part = reflect_xy(part) part = reflect_y(part) part = reflect_xy(part) part = reflect_y(part) part = reflect_xy(part) part = reflect_y(part) return part def reflect_x(part): part = replace(part,'X','(-X)') return part def reflect_y(part): part = replace(part,'Y','(-Y)') return part def reflect_z(part): part = replace(part,'Z','(-Z)') return part def reflect_xy(part): part = replace(part,'X','temp') part = replace(part,'Y','X') part = replace(part,'temp','Y') return part def reflect_xz(part): part = replace(part,'X','temp') part = replace(part,'Z','X') part = replace(part,'temp','Z') return part def reflect_yz(part): part = replace(part,'Y','temp') part = replace(part,'Z','Y') part = replace(part,'temp','Z') return part def scale_x(part, x0, sx): part = replace(part,'X','(x0 + (X-x0)/sx)') part = replace(part,'x0',str(x0)) part = replace(part,'sx',str(sx)) return part def scale_y(part, y0, sy): part = replace(part,'Y','(y0 + (Y-y0)/sy)') part = replace(part,'y0',str(y0)) part = replace(part,'sy',str(sy)) return part def scale_z(part, z0, sz): part = replace(part,'Z','(z0 + (Z-z0)/sz)') part = replace(part,'z0',str(z0)) part = replace(part,'sz',str(sz)) return part def scale_xy(part, x0, y0, sxy): part = replace(part,'X','(x0 + (X-x0)/sxy)') part = replace(part,'Y','(y0 + (Y-y0)/sxy)') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'sxy',str(sxy)) return part def scale_xyz(part, x0, y0, z0, sxyz): part = replace(part,'X','(x0 + (X-x0)/sxyz)') part = replace(part,'Y','(y0 + (Y-y0)/sxyz)') part = replace(part,'Z','(z0 + (Z-z0)/sxyz)') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'sxyz',str(sxyz)) return part def coscale_x_y(part, x0, y0, y1, angle0, angle1, amplitude, offset): phase0 = pi*angle0/180. phase1 = pi*angle1/180. part = replace(part,'X','(x0 + (X-x0)/(offset + amplitude*cos(phase0 + (phase1-phase0)*(Y-y0)/(y1-y0))))') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'y1',str(y1)) part = replace(part,'phase0',str(phase0)) part = replace(part,'phase1',str(phase1)) part = replace(part,'amplitude',str(amplitude)) part = replace(part,'offset',str(offset)) return part def coscale_x_z(part, x0, z0, z1, angle0, angle1, amplitude, offset): phase0 = pi*angle0/180. phase1 = pi*angle1/180. part = replace(part,'X','(x0 + (X-x0)/(offset + amplitude*cos(phase0 + (phase1-phase0)*(Z-z0)/(z1-z0))))') part = replace(part,'x0',str(x0)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'phase0',str(phase0)) part = replace(part,'phase1',str(phase1)) part = replace(part,'amplitude',str(amplitude)) part = replace(part,'offset',str(offset)) return part def coscale_xy_z(part, x0, y0, z0, z1, angle0, angle1, amplitude, offset): phase0 = pi*angle0/180. phase1 = pi*angle1/180. part = replace(part,'X','(x0 + (X-x0)/(offset + amplitude*cos(phase0 + (phase1-phase0)*(Z-z0)/(z1-z0))))') part = replace(part,'Y','(y0 + (Y-y0)/(offset + amplitude*cos(phase0 + (phase1-phase0)*(Z-z0)/(z1-z0))))') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'phase0',str(phase0)) part = replace(part,'phase1',str(phase1)) part = replace(part,'amplitude',str(amplitude)) part = replace(part,'offset',str(offset)) return part def taper_x_y(part, x0, y0, y1, s0, s1): part = replace(part,'X','(x0 + (X-x0)*(y1-y0)/(s1*(Y-y0) + s0*(y1-Y)))') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'y1',str(y1)) part = replace(part,'s0',str(s0)) part = replace(part,'s1',str(s1)) return part def taper_x_z(part, x0, z0, z1, s0, s1): part = replace(part,'X','(x0 + (X-x0)*(z1-z0)/(s1*(Z-z0) + s0*(z1-Z)))') part = replace(part,'x0',str(x0)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'s0',str(s0)) part = replace(part,'s1',str(s1)) return part def taper_xy_z(part, x0, y0, z0, z1, s0, s1): part = replace(part,'X','(x0 + (X-x0)*(z1-z0)/(s1*(Z-z0) + s0*(z1-Z)))') part = replace(part,'Y','(y0 + (Y-y0)*(z1-z0)/(s1*(Z-z0) + s0*(z1-Z)))') part = replace(part,'x0',str(x0)) part = replace(part,'y0',str(y0)) part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'s0',str(s0)) part = replace(part,'s1',str(s1)) return part def shear_x_y(part, y0, y1, dx0, dx1): part = replace(part,'X','(X - dx0 - (dx1-dx0)*(Y-y0)/(y1-y0))') part = replace(part,'y0',str(y0)) part = replace(part,'y1',str(y1)) part = replace(part,'dx0',str(dx0)) part = replace(part,'dx1',str(dx1)) return part def shear_x_z(part, z0, z1, dx0, dx1): part = replace(part,'X','(X - dx0 - (dx1-dx0)*(Z-z0)/(z1-z0))') part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'dx0',str(dx0)) part = replace(part,'dx1',str(dx1)) return part def coshear_x_z(part, z0, z1, angle0, angle1, amplitude, offset): phase0 = pi*angle0/180. phase1 = pi*angle1/180. part = replace(part,'X','(X - offset - amplitude*cos(phase0 + (phase1-phase0)*(Z-z0)/(z1-z0)))') part = replace(part,'z0',str(z0)) part = replace(part,'z1',str(z1)) part = replace(part,'phase0',str(phase0)) part = replace(part,'phase1',str(phase1)) part = replace(part,'amplitude',str(amplitude)) part = replace(part,'offset',str(offset)) return part # # define part # d = .5 teapot = cylinder(0,0,-d,d,d) teapot = coscale_xy_z(teapot,0,0,-d,d,-90,90,.5,.75) handle = torus(0,0,0,3.5*d/5.,d/10.) handle = reflect_xz(handle) handle = reflect_xy(handle) handle = scale_x(handle,0,.75) handle = scale_y(handle,0,3) handle = translate(handle,-6*d/5.,0,0) teapot = add(teapot,handle) spout = torus(2.1*d,-.2*d,0,1.1*d,.2*d) spout = reflect_yz(spout) spout = intersect(spout,cube(-3*d,1.8*d,-3*d,3*d,0,3*d)) teapot = add(teapot,spout) interior = cylinder(0,0,.1-d,.1+d,d-.1) interior = coscale_xy_z(interior,0,0,-d,d,-90,90,.5,.75) teapot = subtract(teapot,interior) spout_interior = torus(2.1*d,-.2*d,0,1.1*d,.15*d) spout_interior = reflect_yz(spout_interior) spout_interior = intersect(spout_interior,cube(-3*d,1.8*d,-3*d,3*d,0,3*d)) teapot = subtract(teapot,spout_interior) part = teapot part = subtract(part,cube(0,3*d,-3*d,0,-3*d,3*d)) # # define limits and parameters # width = 2.5 x0 = 0 y0 = 0 z0 = 0 cad.xmin = x0-width/2. # min x to render cad.xmax = x0+width/2. # max x to render cad.ymin = y0-width/2. # min y to render cad.ymax = y0+width/2. # max y to render #cad.zmin = z0-width/4. # min z to render #cad.zmax = z0+width/4. # max x to render cad.zmin = z0-width/4. # min z to render cad.zmax = z0+width/4. # max x to render cad.rx = 30 # x view rotation (degrees) cad.rz = 20 # z view rotation (degrees) dpi = 100 # rendering resolution cad.nx = int(dpi*(cad.xmax-cad.xmin)) # x points to render cad.ny = int(dpi*(cad.ymax-cad.ymin)) # y points to render cad.nz = int(dpi*(cad.zmax-cad.zmin)) # z points to render cad.inches_per_unit = 1.0 # use inch units # # assign part to cad.function # cad.function = part """ # # check config file for window parameters # cad_path = os.path.dirname(sys.argv[0]) if (sys.argv[0] == "cad.py"): cfg_path = "cad.cfg" else: cfg_path = os.path.dirname(sys.argv[0])+"/cad.cfg" try: config_file = open(cfg_path, 'r') string_msg.set("found "+cfg_path) while 1: line = config_file.readline() if (find(line,"window size:") == 0): string_window_size.set(int(line[12:])) elif (find(line,"editor width:") == 0): string_editor_width.set(int(line[13:])) elif (find(line,"editor height:") == 0): string_editor_height.set(int(line[14:])) elif (line == ""): break config_file.close() resize_editor(0) except: string_msg.set(cfg_path+" not found") # # read input file if on command line, otherwise use template # if len(sys.argv) == 2: filename = sys.argv[1] string_input_file.set(filename) if (find(filename,'.cad') != -1): cad_load(0) elif ((find(filename,'.jpg') != -1) | (find(filename,'.JPG') != -1) | (find(filename,'.png') != -1) | (find(filename,'.PNG') != -1) | (find(filename,'.gif') != -1) | (find(filename,'.GIF') != -1)): widget_cad_text.delete("1.0",END) image_load(0) else: string_msg.set("unsupported input file format") root.update() else: widget_cad_text.insert("1.0",cad_template) # # start GUI # root.mainloop()