Projects a 3D object. The x, y and z axes are modelled as lines in red, green and blue respectively. Needs descartes.py for the graphics, which also needs draw_line.py to draw lines. __________________
Commands:
Toolbox: toggle between modes; in editor mode, displays the angles along every axis
In Observer Mode (Toolbox): Up Arrow: Increment camera angle along x-axis. Down Arrow: Excrement camera angle along x-axis. Left Arrow: Increment camera angle along y-axis. Right Arrrow: Excrement camera angle along y-axis. Right Parenthesis: Increment camera angle along z-axis. Left Parenthesis: Excrement camera angle along z-axis. Plus Key: Zoom in on the origin. Minus Key: Zoom out on the origin.
In Editor Mode (Toolbox): Var Key: Select an object Up Arrow: Increment object angle along x-axis. Down Arrow: Excrement object angle along x-axis. Left Arrow: Increment object angle along y-axis. Right Arrrow: Excrement object angle along y-axis. Right Parenthesis: Increment object angle along z-axis. Left Parenthesis: Excrement object angle along z-axis. Plus Key: Enlarge the object. Minus Key: Reduce the object.
More commands and improvements are yet to come; if you have any ideas please let me know on TI-Planet here: https://tiplanet.org/forum/viewtopic.php?f=100&t=27255
from math import * from descartes import * from ion import * from time import sleep from numpy import * def c(side): s=side cube=[ [[-s,s,s],[-s,s,-s]], [[-s,s,-s],[-s,-s,-s]], [[-s,-s,-s],[-s,-s,s]], [[-s,-s,s],[-s,s,s]], [[s,s,-s],[s,s,s]], [[s,s,s],[s,-s,s]], [[s,-s,s],[s,-s,-s]], [[s,-s,-s],[s,s,-s]], [[-s,s,-s],[s,s,-s]], [[-s,-s,-s],[s,-s,-s]], [[-s,-s,s],[s,-s,s]], [[-s,s,s],[s,s,s]] ] return cube def p(side): s=side tilt=1/tan(pi/3) pyramid=[ # Apex edges [[0,2*s*tilt,0],[0,s*-tilt,2*s*-tilt]], [[0,2*s*tilt,0],[-s,s*-tilt,s*tilt]], [[0,2*s*tilt,0],[s,s*-tilt,s*tilt]], # Base edges [[0,s*-tilt,2*s*-tilt],[-s,s*-tilt,s*tilt]], [[-s,s*-tilt,s*tilt],[s,s*-tilt,s*tilt]], [[s,s*-tilt,s*tilt],[0,s*-tilt,2*s*-tilt]] ] return pyramid def new(side): return c(side) def axes(xa,ya,za,bgcol): x_axis=R([[[-200,0,0],[200,0,0]]],xa,ya,za) y_axis=R([[[0,-200,0],[0,200,0]]],xa,ya,za) z_axis=R([[[0,0,-200],[0,0,200]]],xa,ya,za) x_axis.proj('red','black',1,False) y_axis.proj('green','black',1,False) z_axis.proj('blue','black',1,False) def vertex(x,y,col,bgcol): r,g,b=color(col) bgr,bgg,bgb=color(bgcol) r=(r+bgr)/2 g=(g+bgg)/2 b=(b+bgb)/2 fill(int(x)-2,int(y)+2,4,4,(r,g,b)) fill(int(x)-2,int(y)+1,4,2,col) fill(int(x)-1,int(y)+2,2,4,col) def proj(c,col,bgcol,zoom,vertices=True): c=sorted(c,key=lambda x: x[0][2]) c.reverse() for e in c: v0,v1=e[:2] # x0,y0=v0[:2] x0,y0,z0=v0 x1,y1=v1[:2] # x1,y1,z1=v1 line(x0*zoom,y0*zoom,x1*zoom,y1*zoom,col,bgcol,True) if vertices and 160>=x0>=-160 and 111>=y0>=-111: vertex(x0*zoom,y0*zoom,(255,0,0),bgcol) def Ra(xa,ya,za): return array([[cos(ya)*cos(za),-cos(ya)*sin(za),sin(ya)], [cos(xa)*sin(za)+sin(xa)*sin(ya)*cos(za),cos(xa)*cos(za)-sin(xa)*sin(ya)*sin(za),-sin(xa)*cos(ya)], [sin(xa)*sin(za)-cos(xa)*sin(ya)*cos(za),sin(xa)*cos(za)-cos(xa)*sin(ya)*sin(za),cos(xa)*cos(ya)]]) def R(c:Obj3d|list,xa,ya,za): pc=[] fig=c if type(c)==list else c.vertices for e in fig: v0,v1=e v0,v1=array(v0),array(v1) x0,y0,z0=v0 x1,y1,z1=v1 Ra=array([[cos(ya)*cos(za),-cos(ya)*sin(za),sin(ya)], [cos(xa)*sin(za)+sin(xa)*sin(ya)*cos(za),cos(xa)*cos(za)-sin(xa)*sin(ya)*sin(za),-sin(xa)*cos(ya)], [sin(xa)*sin(za)-cos(xa)*sin(ya)*cos(za),sin(xa)*cos(za)-cos(xa)*sin(ya)*sin(za),cos(xa)*cos(ya)]]) pv0=dot(Ra,v0) pv1=dot(Ra,v1) pc.append([pv0,pv1]) return Obj3d(pc,False) def f(x,y): try: return x**y except ZeroDivisionError: return 0 def plot_3d(f): for y in range(-2,2): for x in range(-3,3): yield [[x,y,f(x,y)],[x+1,y+1,f(x+1,y+1)]] class Obj3d: objects=[] def __init__(self,vertices,save=True): self.vertices=vertices if save: self.objects.append(self) def update(self,vertices): self.vertices=vertices def proj(self,col,bgcol,zoom,vertices=True): c=sorted(self.vertices,key=lambda x: x[0][2]) c.reverse() for e in c: v0,v1=e[:2] # x0,y0=v0[:2] x0,y0,z0=v0 x1,y1=v1[:2] # x1,y1,z1=v1 line(x0*zoom,y0*zoom,x1*zoom,y1*zoom,col,bgcol,True) if vertices and 160>=x0>=-160 and 111>=y0>=-111: vertex(x0*zoom,y0*zoom,(255,0,0),bgcol) def graph(): xa,ya,za=[0,0],[0,0],[0,0] dxa,dya,dza=[0,0],[0,0],[0,0] side=[50,50] func=[c,p] cx,cy,cz=0,0,-10 cxa,cya,cza=0,0,0 zoom=1 cube=Obj3d(c(side[0])) pyramid=Obj3d(p(side[1])) obj=0 editor=False draw=True while True: if keydown(KEY_UP): if editor: xa[obj]+=pi/40 dxa[obj]+=1 else: cxa+=pi/40 draw=True if keydown(KEY_DOWN): if editor: xa[obj]-=pi/40 dxa[obj]-=1 else: cxa-=pi/40 draw=True if keydown(KEY_RIGHT): if editor: ya[obj]-=pi/40 dya[obj]-=1 else: cya-=pi/40 draw=True if keydown(KEY_LEFT): if editor: ya[obj]+=pi/40 dya[obj]+=1 else: cya+=pi/40 draw=True if keydown(KEY_RIGHTPARENTHESIS): if editor: za[obj]+=pi/40 dza[obj]+=1 else: cza+=pi/40 draw=True if keydown(KEY_LEFTPARENTHESIS): if editor: za[obj]-=pi/40 dza[obj]-=1 else: cza-=pi/40 draw=True if keydown(KEY_PLUS): if editor: side[obj]+=1 else: zoom*=1.05 i=0 for o in Obj3d.objects: o.update(func[i](side[i])) i+=1 draw=True if keydown(KEY_MINUS): if editor: side[obj]-=1 else: zoom/=1.05 i=0 for o in Obj3d.objects: o.update(func[i](side[i])) i+=1 draw=True if keydown(KEY_XNT) and editor: obj=(obj+1)%len(Obj3d.objects) while keydown(KEY_XNT): pass draw=True if keydown(KEY_EXE): return print(xa,ya,za) if keydown(KEY_TOOLBOX): editor=not editor draw=True while keydown(KEY_TOOLBOX): pass if keydown(KEY_VAR) and editor: Obj3d(new(50)) xa.append(0) ya.append(0) za.append(0) dxa.append(0) dya.append(0) dza.append(0) side.append(30) func.append(new) while keydown(KEY_VAR): pass draw=True if keydown(KEY_BACKSPACE): dobj=Obj3d.objects[obj] Obj3d.objects.remove(dobj) del dobj while keydown(KEY_BACKSPACE): pass if draw: fill(-160,111,320,222,'black') if editor: mulx,divx=dxa[obj]//gcd(40,dxa[obj]),40//gcd(40,dxa[obj]) muly,divy=dya[obj]//gcd(40,dya[obj]),40//gcd(40,dya[obj]) mulz,divz=dza[obj]//gcd(40,dza[obj]),40//gcd(40,dza[obj]) if dxa[obj]==0: string('θx = 0',-150,100,'black','red') else: string('θx = '+(str(mulx)[:-1] if abs(mulx)==1 else str(mulx))+'π/'+str(divx),-150,100,'black','red') if dya[obj]==0: string('θy = 0',-150,80,'black','green') else: string('θy = '+(str(muly)[:-1] if abs(muly)==1 else str(muly))+'π/'+str(divy),-150,80,'black','green') if dza[obj]==0: string('θz = 0',-150,60,'black','blue') else: string('θz = '+(str(mulz)[:-1] if abs(mulz)==1 else str(mulz))+'π/'+str(divz),-150,60,'black','blue') string('x',140,100,'red','black') string('y',140,80,'green','black') string('z',140,60,'blue','black') axes(cxa,cya,cza,'black') i=0 for o in Obj3d.objects: R(o,xa[i]+cxa,ya[i]+cya,za[i]+cza).proj('gray' if editor and obj!=i else 'white','black',zoom) i+=1 draw=False sleep(0.05) graph()