IN_IDLE = 0 from Tkinter import * import random MAX_ITERATIONS = 3000 class osculator: def __init__(self): self.root = Tk() self.root.title("HIB - osculating spheres") self.params = Frame() font1 = ("Arial",10,"bold") font2 = ("Arial",10) # sphere properties self.v_num = StringVar() self.v_rmin = StringVar() self.v_rmax = StringVar() Label(self.params,text="\nSPHERES",font=font1).grid(column=0,row=0,columnspan=2) Label(self.params,text="number",font=font2).grid(column=0,row=1) Entry(self.params,width=4,textvariable=self.v_num,font=font2).grid(column=1,row=1) Label(self.params,text="r_min",font=font2).grid(column=0,row=2) Entry(self.params,width=4,textvariable=self.v_rmin,font=font2).grid(column=1,row=2) Label(self.params,text="r_max",font=font2).grid(column=0,row=3) Entry(self.params,width=4,textvariable=self.v_rmax,font=font2).grid(column=1,row=3) self.v_num.set("100") self.v_rmin.set("0.1") self.v_rmax.set("1.0") # texture properties self.v_texnum = StringVar() self.v_texscale = StringVar() Label(self.params,text="\n\nTEXTURES",font=font1).grid(column=0,row=4,columnspan=2) Label(self.params,text="number",font=font2).grid(column=0,row=5) Entry(self.params,width=4,textvariable=self.v_texnum,font=font2).grid(column=1,row=5) Label(self.params,text="scale",font=font2).grid(column=0,row=6) Entry(self.params,width=4,textvariable=self.v_texscale,font=font2).grid(column=1,row=6) self.v_texnum.set("44") self.v_texscale.set("0.5") # object size self.v_diameter = StringVar() Label(self.params,text="\n\nOBJECT",font=font1).grid(column=0,row=7,columnspan=2) Label(self.params,text="diameter",font=font2).grid(column=0,row=8) self.entry_diameter = Entry(self.params,width=4,textvariable=self.v_diameter,font=font2) self.entry_diameter.grid(column=1,row=8) self.v_diameter.set("10.0") # object prefs f_dim = Frame(self.params) self.v_dim = IntVar() Radiobutton(f_dim,text="flat",font=font2,value=2,variable=self.v_dim).grid(column=0,row=0) Radiobutton(f_dim,text="3D",font=font2,value=3,variable=self.v_dim).grid(column=1,row=0) self.v_dim.set(2) self.v_shape = IntVar() Radiobutton(f_dim,text="box",font=font2,value=1,variable=self.v_shape).grid(column=0,row=1) Radiobutton(f_dim,text="ball",font=font2,value=2,variable=self.v_shape).grid(column=1,row=1) self.v_shape.set(1) f_dim.grid(column=0,row=9,columnspan=2) # preview canvas self.c = Canvas(self.root,width=400+6,height=400+6,bg="#e0e0e0") self.mid = 400/2+3 # command frame f_cmd = Frame(self.root) b1 = Button(f_cmd,text="CALCULATE",font=font1,command=self.calc).pack(side=LEFT,padx=14) b2 = Button(f_cmd,text="Write to file:",font=font1,command=self.save).pack(side=LEFT,padx=2) self.v_filename = StringVar() Entry(f_cmd,width=30,textvariable=self.v_filename,font=font2).pack(side=LEFT,padx=2) self.v_filename.set(".\\osculating_object.inc") # pack up things f_cmd.pack(side=BOTTOM,pady=5) self.params.pack(side=LEFT) self.c.pack(side=RIGHT,padx=4,pady=4) self.spheres = [] self.busy = 0 if not IN_IDLE: self.root.mainloop() # show circle representing sphere def show(self,(x,h,y,r)): col = h/(self.diameter/2.0) if col>=0: color = "#%02x%02x%02x"%(80*col,80*col,55+200*col) else: col = -col color = "#%02x%02x%02x"%(55+200*col,80*col,80*col) scale = 400.0/self.diameter self.c.create_oval(self.mid+scale*x-scale*r,self.mid+scale*y-scale*r, self.mid+scale*x+scale*r,self.mid+scale*y+scale*r,outline=color ) self.c.update() # get new random position def new_xyz(self,m): x = -1.0+2.0*random.random() if self.dim==3: y = -1.0+2.0*random.random() else: y=0.0 z = -1.0+2.0*random.random() return x*m,y*m,z*m # calculate list of spheres def calc(self): if self.busy: return self.busy = 1 self.spheres = [] self.c.delete("all") # params for calculation n,rmin,rmax = int(self.v_num.get()),float(self.v_rmin.get()),float(self.v_rmax.get()) self.dim = int(self.v_dim.get()) self.diameter = float(self.v_diameter.get()) MAX = self.diameter/2.0 shape = int(self.v_shape.get()) # needed for writing self.texnum,self.texscale = int(self.v_texnum.get()),float(self.v_texscale.get()) numfound = 0 tries=0 spheres = [] while triesrmax): continue if shape==2: if (xn**2+yn**2+zn**2)**0.5 + rn > MAX: continue else: if (xn-rn<-MAX) or (xn+rn>MAX): continue if (yn-rn<-MAX) or (yn+rn>MAX): continue if (zn-rn<-MAX) or (zn+rn>MAX): continue spheres.append((xn,yn,zn,rn)) numfound += 1 self.root.title(str(numfound)+" ... working") self.show(spheres[-1]) if numfound >= n: break self.root.title(str(numfound)+" spheres found") self.spheres = spheres self.busy=0 # save list of spheres as povray union object def save(self): if self.spheres == []: return name = self.v_filename.get() f = open(name,"w") f.write("// automatic include file from osculating.py\n\n") f.write("#declare OscObject = union {\n\n") for x,z,y,r in self.spheres: f.write(" sphere {<%f,%f,%f>,%f "%(x,z,y,r)) if self.texnum>0: tex = random.randint(1,self.texnum) f.write("texture {Texture%02d scale %f} "%(tex,self.texscale)) f.write("}\n") f.write("}\n") f.close() self.root.title(name+" saved") o = osculator()