#!/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. # # DATE = "11/3/09" 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 = 400 # plot window size self.inches_per_unit = 1.0 # file units self.views = 'xyzr' self.cam = '' # CAM export type self.editor_width = 45 # editor width self.editor_height = 40 # 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('',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('',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('',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('',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('',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 = 0 string_image_zmin.set('0') cad.zmax = 0.01 string_image_zmax.set('0.01') cad.inches_per_unit = 1.0 string_image_units.set('1.0') 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]+'.g') cad.cam = 'g' cam_pack_forget() cam_file_frame.pack() cam_vector_frame.pack() string_tool_dia.set("0.125") cam_dia_frame.pack() cam_contour_frame.pack() string_g_feed_rate.set("5") string_g_spindle_speed.set("5000") string_g_tool.set("1") integer_g_cool.set("1") 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 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("T%dM06\n"%tool) # tool selection, tool change file.write("G90\n") # absolute positioning file.write("F%0.4f\n"%feed_rate) # feed rate file.write("S%0.4f\n"%spindle_speed) # spindle speed if (coolant == 1): file.write("M08\n") # coolant on file.write("G00Z%0.4f\n"%zup) # move up before starting spindle file.write("M03\n") # spindle on clockwise 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 # 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("G00X%0.4f"%x+"Y%0.4f"%y+"Z%0.4f"%zup+"\n") # rapid motion file.write("G01Z%0.4f"%zdown+"\n") # linear motion 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("X%0.4f"%x+"Y%0.4f"%y+"\n") dxy += sqrt((xold-x)**2+(yold-y)**2) xold = x yold = y file.write("Z%0.4f\n"%zup) file.write("G00Z%0.4f\n"%zup) # move up before stopping spindle file.write("M05\n") # spindle stop if (coolant == 1): file.write("M09\n") # coolant off file.write("M30\n") # program end and reset file.close() time = (dxy/feed_rate + dz/feed_rate)/60.0 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('',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('',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('',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('',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('',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('',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('',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('',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('',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('',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('',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('',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('',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('',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='.g (G codes)',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('',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('',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('',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('',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('',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('',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('',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()