From: John K. <joh...@ho...> - 2003-02-27 21:32:02
|
I've finished a producing an ellipsoid object. I think it will add a little flexibility to the kind of things one can depict with VPython. Except for the normals, the program is a simple variation on Thom Ives's spherepart routine. I believe, but am not absolutely certain, that the normals are correct. I hope someone who is better than I am at geometry will take a look to verify. I would greatly appreciate that. Even if the ellipsoid generator is not perfect, I hope that you enjoy the demo program. Sincerely, John Here is the program: -------------------------------------------------------------- from visual import * # Ellipsoid # John W. Keck # February 2003 # based on "spherepart" by Thom Ives newframe = frame # this makes "newframe()" mean what "frame()" usually means class ellipsoid(object): # This routine draws an ellipsoid with axes given by size. # axis gives the orientation of x-axis, up rotates about the axis (i.e., "roll") # Default parameters draw an ellipsoid with dimensions 1x2x3 at origin. def __init__(self, frame=None, pos=(0,0,0), axis=(1,0,0), up=(0,1,0), size=(1,2,3), color=scene.foreground, incs=25): self.frame = newframe(pos=pos, axis=axis, frame=frame, up=up) self.__pos = vector(pos) self.__axis = norm(vector(axis)) self.__up = norm(vector(up)) self.__size = vector(size) self.f = 0.0 self.r = mag(self.axis) self.a = vector(size).x*0.5 # user specifies axes self.b = vector(size).y*0.5 # but use the semi-axes self.c = vector(size).z*0.5 # for "radii" self.phi_b = 1.5*pi self.phi_f = 0.5*pi self.__color = color self.incs = incs VertexList, NormalList = self.buildfaces() self.faces = faces(frame=self.frame, pos=VertexList, normal=NormalList, color=color) def buildfaces(self): VertexList = [] # Create an empty vertex list for the body's vertices. NormalList = [] # Ditto for the vertex normals. length = mag(self.axis) cosphi = cos(self.phi_b) sinphi0 = sin(self.phi_b) sinphi = cosphi**2 - 1 #sin(self.phi_b) # print sinphi, sinphi0 dphi = (self.phi_f - self.phi_b)/self.incs cosdphi = cos(dphi) sindphi = sin(dphi) # sindphi = 1 - cosdphi**2 #sin(dphi) p0 = vector(self.a*sinphi,0,0); n0 = (-1.0,0.0,0.0) p5 = vector(self.a,0,0); n5 = (1.0,0.0,0.0) a = self.a b = self.b c = self.c for i in range(self.incs): newcosphi = cosphi*cosdphi-sinphi*sindphi newsinphi = sinphi*cosdphi+cosphi*sindphi costheta = 1.0 sintheta = 0.0 dtheta = 2*pi/self.incs cosdtheta = cos(dtheta) # sindtheta = 1 - cosdtheta**2 #sin(dtheta) sindtheta = sin(dtheta) for j in range(self.incs): # Calculate four pts that form a small rectangle on each of the surfaces. # Use these points to make the vertices of two triangles that form each of these reactangles. # Find a normal to the rectangle. Store vertices and normals. # Repeat for the number of increments you want - more increments better visual quality. # recursion relations for cosine and sine of (theta+dtheta); avoid lots of trig functions newcostheta = costheta*cosdtheta-sintheta*sindtheta newsintheta = sintheta*cosdtheta+costheta*sindtheta # Vector / Vertices and Triangles p1 = vector(self.a*sinphi,self.b*costheta*cosphi,self.c*sintheta*cosphi) p2 = vector(self.a*sinphi,self.b*newcostheta*cosphi,self.c*newsintheta*cosphi) p3 = vector(self.a*newsinphi,self.b*newcostheta*newcosphi,self.c*newsintheta*newcosphi) p4 = vector(self.a*newsinphi,self.b*costheta*newcosphi,self.c*sintheta*newcosphi) # normals chosen for smoothing - an Oil of Olay technique # I'm don't think the immediately following normals work ## n1 = vector(sinphi/a**2,costheta*cosphi/b**2,sintheta*cosphi/c**2) ## n2 = vector(sinphi/a**2,newcostheta*cosphi/b**2,newsintheta*cosphi/c**2) ## n3 = vector(newsinphi/a**2,newcostheta*newcosphi/b**2,newsintheta*newcosphi/c**2) ## n4 = vector(newsinphi/a**2,costheta*newcosphi/b**2,sintheta*newcosphi/c**2) # I'm pretty sure the following are the correct normals n1 = vector(sinphi/a,costheta*cosphi/b,sintheta*cosphi/c) n2 = vector(sinphi/a,newcostheta*cosphi/b,newsintheta*cosphi/c) n3 = vector(newsinphi/a,newcostheta*newcosphi/b,newsintheta*newcosphi/c) n4 = vector(newsinphi/a,costheta*newcosphi/b,sintheta*newcosphi/c) if i > 0 and i < (self.incs-1): VertexList = VertexList + [p1,p2,p3,p1,p3,p4] NormalList = NormalList + [n1,n2,n3,n1,n3,n4] elif i == 0: VertexList = VertexList + [p0,p2,p1,p1,p2,p3,p1,p3,p4] NormalList = NormalList + [n0,n0,n0,n1,n2,n3,n1,n3,n4] elif i == (self.incs-1): VertexList = VertexList + [p1,p2,p3,p1,p3,p4,p4,p3,p5] NormalList = NormalList + [n1,n2,n3,n1,n3,n4,n5,n5,n5] sintheta = newsintheta costheta = newcostheta sinphi = newsinphi cosphi = newcosphi return VertexList, NormalList def getpos(self): return self.__pos def setpos(self, pos): self.frame.pos = self.__pos = vector(pos) pos = property(getpos, setpos) def getaxis(self): return self.__axis def setaxis(self, axis): # scale all points in front face k = mag(vector(axis))/mag(self.axis) self.frame.axis = self.__axis = vector(axis) for pos in self.faces.pos: pos[0] *= k; pos[1] *= k; pos[2] *= k axis = property(getaxis, setaxis) def rebuild(self): VertexList, NormalList = self.buildfaces() self.faces.pos = VertexList self.faces.normal = NormalList def getcolor(self): return self.__color def setcolor(self, color): self.__color = color self.faces.color = color color = property(getcolor, setcolor) def DrawNormal(self, scale): pos = self.faces.pos normal = self.faces.normal for i in range(len(pos)): arrow(pos=pos[i], axis=normal[i]*scale,color=color.yellow) if __name__ == '__main__': scene.title = "Golden Egg and Proud Hen" scene.background = (0.7,9.0,9.0) # Provide a simple program to illustrate how the ellipsoid object works. color.gold = (3,2,0.9) color.orange = (1.0,0.5,0) color.brown = (0.46,0.28,0.10) # which came first? # a golden egg egg = ellipsoid(pos=(4,3.6,0), axis=(1,1,0), size=(6,8.1,6),color=color.gold) # a comical chicken hen = frame() body = ellipsoid(frame=hen, pos=(-10,15,0), axis=(-1,0.2,0), size=(30,20,20), color=color.white, incs=25) wngl = ellipsoid(frame=hen, pos=(-7,18,7), size=(20,10,6), axis=(-1,0.1,0), up=(0,1,-0.5), color=color.white) wngr = ellipsoid(frame=hen, pos=(-7,18,-7), size=(20,10,6), axis=(-1,0.1,0), up=(0,1,0.5), color=color.white) head = ellipsoid(frame=hen, pos=(-19,23,0), axis=(-3,1,0), size=(8,18,8), color=color.white) comb = ellipsoid(frame=hen, pos=(-16,31,0), size=(4,4,2),color=(1.0,0.7,0.7)) tail = ellipsoid(frame=hen, pos=(4,15,0), axis=(-1,1,0), size=(2.5,8,8),color=color.white) beak = cone(frame=hen, pos=(-20,28,0), radius=1.2, length=4, axis=(-1,0,0), color=color.orange) eyel = sphere(frame=hen,pos=(-19,30,2), radius=0.7, color=color.blue) eyer = sphere(frame=hen,pos=(-19,30,-2), radius=0.7, color=color.blue) legl = curve(frame=hen,pos=[(-10,7,2),(-10,0,2),(-13,0,2)],color=color.orange, radius=0.3) ftl = curve(frame=hen,pos=[(-12.5,0,3),(-10,0,2),(-12.5,0,1)],color=color.orange, radius=0.3) legr = curve(frame=hen,pos=[(-10,7,-2),(-10,0,-2),(-13,0,-2)],color=color.orange, radius=0.3) ftr = curve(frame=hen,pos=[(-12.5,0,-3),(-10,0,-2),(-12.5,0,-1)],color=color.orange, radius=0.3) hen.pos = (-3,0,0) # the surroundings gnd = box(size=(40,2,20),pos=(-10,-1,0), color=color.green) _________________________________________________________________ The new MSN 8: smart spam protection and 2 months FREE* http://join.msn.com/?page=features/junkmail |