|
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
|