cyclone-pcb-factory/Software/PythonScripts/GcodeGenerators/cad.py

3856 lines
134 KiB
Python
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

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