21 Programs for AXIOM Images
This appendix contains the Axiom programs used to generate
the images in the gallery color insert of this book.
All these input files are included
with the Axiom system.
To produce the images
on page 6 of the gallery insert, for example, issue the command:
)read images6
These images were produced on an IBM RS/6000 model 530 with a
standard color graphics adapter. The smooth shaded images
were made from X Window System screen dumps.
The remaining images were produced with Axiom-generated
PostScript output. The images were reproduced from slides made on an Agfa
ChromaScript PostScript interpreter with a Matrix Instruments QCR camera.
21.1 images1.input
)read tknot Read torus knot program
torusKnot(15,17, 0.1, 6, 700) A (15,17) torus knot
torus knot
21.2 images2.input
These images illustrate how Newton's method converges when computing the
Newton iteration
complex cube roots of 2. Each point in the -plane represents the
complex number which is given as a starting point for Newton's
method. The poles in these images represent bad starting values.
The flat areas are the regions of convergence to the three roots.
)read newton Read the programs from
)read vectors Chapter 10
f := newtonStep(x**3 - 2) Create a Newton's iteration
function for
The function computes steps of Newton's method.
clipValue := 4 Clip values with magnitude > 4
drawComplexVectorField(f**3, -3..3, -3..3) The vector field for
drawComplex(f**3, -3..3, -3..3) The surface for
drawComplex(f**4, -3..3, -3..3) The surface for
21.3 images3.input
)r tknot
for i in 0..4 repeat torusKnot(2, 2 + i/4, 0.5, 25, 250)
21.4 images5.input
The parameterization of the Etruscan Venus is due to George Frances.
Etruscan Venus
venus(a,r,steps) ==
surf := (u:DFLOAT, v:DFLOAT): Point DFLOAT +->
cv := cos(v)
sv := sin(v)
cu := cos(u)
su := sin(u)
x := r * cos(2*u) * cv + sv * cu
y := r * sin(2*u) * cv - sv * su
z := a * cv
point [x,y,z]
draw(surf, 0..%pi, -%pi..%pi, var1Steps==steps,
var2Steps==steps, title == "Etruscan Venus")
venus(5/2, 13/10, 50) The Etruscan Venus
The Figure-8 Klein Bottle
Klein bottle
parameterization is from
``Differential Geometry and Computer Graphics'' by Thomas Banchoff,
in Perspectives in Mathematics, Anniversary of Oberwolfasch 1984,
Birkh\"{a}user-Verlag, Basel, pp. 43-60.
klein(x,y) ==
cx := cos(x)
cy := cos(y)
sx := sin(x)
sy := sin(y)
sx2 := sin(x/2)
cx2 := cos(x/2)
sq2 := sqrt(2.0@DFLOAT)
point [cx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), _
sx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), _
-sx2 * (sq2 + cy) + cx2 * sy * cy]
draw(klein, 0..4*%pi, 0..2*%pi, var1Steps==50, Figure-8 Klein bottle
var2Steps==50,title=="Figure Eight Klein Bottle")
The next two images are examples of generalized tubes.
)read ntube
rotateBy(p, theta) == Rotate a point by
c := cos(theta) around the origin
s := sin(theta)
point [p.1*c - p.2*s, p.1*s + p.2*c]
bcircle t == A circle in three-space
point [3*cos t, 3*sin t, 0]
twist(u, t) == An ellipse that twists
theta := 4*t around four times as
p := point [sin u, cos(u)/2] revolves once
rotateBy(p, theta)
ntubeDrawOpt(bcircle, twist, 0..2*%pi, 0..2*%pi, Twisted Torus
var1Steps == 70, var2Steps == 250)
twist2(u, t) == Create a twisting circle
theta := t
p := point [sin u, cos(u)]
rotateBy(p, theta)
cf(u,v) == sin(21*u) Color function with stripes
ntubeDrawOpt(bcircle, twist2, 0..2*%pi, 0..2*%pi, Striped Torus
colorFunction == cf, var1Steps == 168,
var2Steps == 126)
21.5 images6.input
gam(x,y) == The height and color are the
g := Gamma complex(x,y) real and argument parts
point [x,y,max(min(real g, 4), -4), argument g] of the Gamma function,
respectively.
draw(gam, -%pi..%pi, -%pi..%pi, The Gamma Function
title == "Gamma(x + %i*y)", _
var1Steps == 100, var2Steps == 100)
b(x,y) == Beta(x,y)
draw(b, -3.1..3, -3.1 .. 3, title == "Beta(x,y)") The Beta Function
atf(x,y) ==
a := atan complex(x,y)
point [x,y,real a, argument a]
draw(atf, -3.0..%pi, -3.0..%pi) The Arctangent function
function:Gamma
function:Euler Beta
Euler:Beta function
21.6 images7.input
First we look at the conformal
conformal map
map .
)read conformal Read program for drawing
conformal maps
f z == z The coordinate grid for the
complex plane
conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian") Mapping 1: Source
f z == z + 1/z The map
conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian") Mapping 1: Target
The map maps
the unit disk to the right half-plane, as shown
Riemann:sphere
on the Riemann sphere.
f z == z The unit disk
riemannConformalDraw(f,0.1..0.99,0..2*%pi,7,11,"polar") Mapping 2: Source
f z == -(z+1)/(z-1) The map
riemannConformalDraw(f,0.1..0.99,0..2*%pi,7,11,"polar") Mapping 2: Target
riemannSphereDraw(-4..4, -4..4, 7, 7, "cartesian") Riemann Sphere Mapping
21.7 images8.input
)read dhtri
)read tetra
drawPyramid 4 Sierpinsky's Tetrahedron
Sierpinsky's Tetrahedron
)read antoine
drawRings 2 Antoine's Necklace
Aintoine's Necklace
)read scherk
drawScherk(3,3) Scherk's Minimal Surface
)read ribbonsNew
drawRibbons([x**i for i in 1..5], x=-1..1, y=0..2) Ribbon Plot
Scherk's minimal surface
21.8 conformal.input
The functions in this section draw conformal maps both on the
conformal map
plane and on the Riemann sphere.
Riemann:sphere
C := Complex DoubleFloat Complex Numbers
S := Segment DoubleFloat Draw ranges
R3 := Point DFLOAT Points in 3-space
conformalDraw(f, rRange, tRange, rSteps, tSteps, coord)
draws the image of the coordinate grid under f in the complex plane.
The grid may be given in either polar or Cartesian coordinates.
Argument f is the function to draw;
rRange is the range of the radius (in polar) or real (in Cartesian);
tRange is the range of (in polar) or imaginary (in Cartesian);
tSteps, rSteps, are the number of intervals in the r and
directions; and
coord is the coordinate system to use (either "polar" or
"cartesian").
conformalDraw: (C -> C, S, S, PI, PI, String) -> VIEW3D
conformalDraw(f,rRange,tRange,rSteps,tSteps,coord) ==
transformC := Function for changing an
coord = "polar" => polar2Complex pair into a complex number
cartesian2Complex
cm := makeConformalMap(f, transformC)
sp := createThreeSpace() Create a fresh space
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Plot the coordinate lines
makeViewport3D(sp, "Conformal Map") Draw the image
riemannConformalDraw(f, rRange, tRange, rSteps, tSteps, coord)
draws the image of the coordinate grid under f on the Riemann sphere.
The grid may be given in either polar or Cartesian coordinates.
Its arguments are the same as those for conformalDraw.
riemannConformalDraw:(C->C,S,S,PI,PI,String)->VIEW3D
riemannConformalDraw(f, rRange, tRange,
rSteps, tSteps, coord) ==
transformC := Function for changing an
coord = "polar" => polar2Complex pair into a complex number
cartesian2Complex
sp := createThreeSpace() Create a fresh space
cm := makeRiemannConformalMap(f, transformC)
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Plot the coordinate lines
curve(sp,[point [0,0,2.0@DFLOAT,0],point [0,0,2.0@DFLOAT,0] ])
Add an invisible point at
makeViewport3D(sp,"Map on the Riemann Sphere") the north pole for scaling
adaptGrid(sp, f, uRange, vRange, uSteps, vSteps) == Plot the coordinate grid
delU := (hi(uRange) - lo(uRange))/uSteps using adaptive plotting for
delV := (hi(vRange) - lo(vRange))/vSteps coordinate lines, and draw
uSteps := uSteps + 1; vSteps := vSteps + 1 tubes around the lines
u := lo uRange
for i in 1..uSteps repeat Draw coordinate lines in the
c := curryLeft(f,u) direction; curve fixes the
cf := (t:DFLOAT):DFLOAT +-> 0 current value of
makeObject(c,vRange::SEG Float,colorFunction==cf,
Draw the coordinate line
space == sp, tubeRadius == .02, tubePoints == 6)
u := u + delU
v := lo vRange
for i in 1..vSteps repeat Draw coodinate lines in the
c := curryRight(f,v) direction; curve fixes the
cf := (t:DFLOAT):DFLOAT +-> 1 current value of
makeObject(c,uRange::SEG Float,colorFunction==cf,
Draw the coordinate line
space == sp, tubeRadius == .02, tubePoints == 6)
v := v + delV
void()
riemannTransform(z) == Map a point in the complex
r := sqrt norm z plane to the Riemann sphere
cosTheta := (real z)/r
sinTheta := (imag z)/r
cp := 4*r/(4+r**2)
sp := sqrt(1-cp*cp)
if r>2 then sp := -sp
point [cosTheta*cp, sinTheta*cp, -sp + 1]
cartesian2Complex(r:DFLOAT, i:DFLOAT):C == Convert Cartesian coordinates to
complex(r, i) complex Cartesian form
polar2Complex(r:DFLOAT, th:DFLOAT):C == Convert polar coordinates to
complex(r*cos(th), r*sin(th)) complex Cartesian form
makeConformalMap(f, transformC) == Convert complex function
(u:DFLOAT,v:DFLOAT):R3 +-> to a mapping:
(DFLOAT,DFLOAT) R3
z := f transformC(u, v) in the complex plane
point [real z, imag z, 0.0@DFLOAT]
makeRiemannConformalMap(f, transformC) == Convert a complex function
(u:DFLOAT, v:DFLOAT):R3 +-> to a mapping:
(DFLOAT,DFLOAT) R3
riemannTransform f transformC(u, v) on the Riemann sphere
riemannSphereDraw: (S, S, PI, PI, String) -> VIEW3D
Draw a picture of the mapping
of the complex plane to
the Riemann sphere
riemannSphereDraw(rRange,tRange,rSteps,tSteps,coord) ==
transformC :=
coord = "polar" => polar2Complex
cartesian2Complex
grid := (u:DFLOAT, v:DFLOAT): R3 +-> Coordinate grid function
z1 := transformC(u, v)
point [real z1, imag z1, 0]
sp := createThreeSpace() Create a fresh space
adaptGrid(sp, grid, rRange, tRange, rSteps, tSteps) Draw the flat grid
connectingLines(sp,grid,rRange,tRange,rSteps,tSteps)
makeObject(riemannSphere,0..2*%pi,0..%pi,space==sp) Draw the sphere
f := (z:C):C +-> z
cm := makeRiemannConformalMap(f, transformC)
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Draw the sphere grid
makeViewport3D(sp, "Riemann Sphere")
connectingLines(sp,f,uRange,vRange,uSteps,vSteps) ==
Draw the lines that connect
delU := (hi(uRange) - lo(uRange))/uSteps the points in the complex
delV := (hi(vRange) - lo(vRange))/vSteps plane to the north pole
uSteps := uSteps + 1; vSteps := vSteps + 1 of the Riemann sphere
u := lo uRange
for i in 1..uSteps repeat For each u
v := lo vRange
for j in 1..vSteps repeat For each v
p1 := f(u,v)
p2 := riemannTransform complex(p1.1, p1.2) Project p1 onto the sphere
fun := lineFromTo(p1,p2) Create a line function
cf := (t:DFLOAT):DFLOAT +-> 3
makeObject(fun, 0..1,space==sp,tubePoints==4, Draw the connecting line
tubeRadius==0.01,colorFunction==cf)
v := v + delV
u := u + delU
void()
riemannSphere(u,v) == A sphere sitting on the
sv := sin(v) complex plane, with radius 1
0.99@DFLOAT*(point [cos(u)*sv,sin(u)*sv,cos(v),0.0@DFLOAT])+
point [0.0@DFLOAT, 0.0@DFLOAT, 1.0@DFLOAT, 4.0@DFLOAT]
lineFromTo(p1, p2) == Create a line function
d := p2 - p1 that goes from p1 to p2
(t:DFLOAT):Point DFLOAT +->
p1 + t*d
21.9 tknot.input
Create a torus-knot with radius around the curve.
The formula was derived by Larry Lambe.
)read ntube
torusKnot: (DFLOAT, DFLOAT, DFLOAT, PI, PI) -> VIEW3D
torusKnot(p, q ,r, uSteps, tSteps) ==
knot := (t:DFLOAT):Point DFLOAT +-> Function for the torus knot
fac := 4/(2.2@DFLOAT-sin(q*t))
fac * point [cos(p*t), sin(p*t), cos(q*t)]
circle := (u:DFLOAT, t:DFLOAT): Point DFLOAT +-> The cross section
r * point [cos u, sin u]
ntubeDrawOpt(knot, circle, 0..2*%pi, 0..2*%pi,
Draw the circle around the knot
var1Steps == uSteps, var2Steps == tSteps)
21.10 ntube.input
The functions in this file create generalized tubes (also known as generalized
cylinders).
These functions draw a 2-d curve in the normal
planes around a 3-d curve.
R3 := Point DFLOAT Points in 3-Space
R2 := Point DFLOAT Points in 2-Space
S := Segment Float Draw ranges
Introduce types for functions for:
ThreeCurve := DFLOAT -> R3 --the space curve function
TwoCurve := (DFLOAT, DFLOAT) -> R2 --the plane curve function
Surface := (DFLOAT, DFLOAT) -> R3 --the surface function
Frenet frames define a
FrenetFrame := coordinate system around a
Record(value:R3,tangent:R3,normal:R3,binormal:R3)
point on a space curve
frame: FrenetFrame The current Frenet frame
for a point on a curve
ntubeDraw(spaceCurve, planeCurve,
draws planeCurve in the normal planes of spaceCurve.
The parameter specifies
the parameter range for planeCurve
and specifies the parameter range for spaceCurve.
Additionally, the plane curve function takes
a second parameter: the current parameter of spaceCurve.
This allows the plane curve to change shape
as it goes around the space curve.
See ugFimagesFive for an example of this.
ntubeDraw: (ThreeCurve,TwoCurve,S,S) -> VIEW3D
ntubeDraw(spaceCurve,planeCurve,uRange,tRange) ==
ntubeDrawOpt(spaceCurve, planeCurve, uRange, _
tRange, []$List DROPT)
ntubeDrawOpt: (ThreeCurve,TwoCurve,S,S,List DROPT)
-> VIEW3D
ntubeDrawOpt(spaceCurve,planeCurve,uRange,tRange,l) ==
This function is similar
to ntubeDraw, but takes
delT:DFLOAT := (hi(tRange) - lo(tRange))/10000 optional parameters that it
oldT:DFLOAT := lo(tRange) - 1 passes to the draw command
fun := ngeneralTube(spaceCurve,planeCurve,delT,oldT)
draw(fun, uRange, tRange, l)
nfrenetFrame(c, t, delT)
numerically computes the Frenet frame
about the curve c at t.
Parameter delT is a small number used to
compute derivatives.
nfrenetFrame(c, t, delT) ==
f0 := c(t)
f1 := c(t+delT)
t0 := f1 - f0 The tangent
n0 := f1 + f0
b := cross(t0, n0) The binormal
n := cross(b,t0) The normal
ln := length n
lb := length b
ln = 0 or lb = 0 =>
error "Frenet Frame not well defined"
n := (1/ln)*n Make into unit length vectors
b := (1/lb)*b
[f0, t0, n, b]$FrenetFrame
ngeneralTube(spaceCurve, planeCurve, delT, oltT)
creates a function that can be passed to the system axiomFun{draw} command.
The function is a parameterized surface for the general tube
around spaceCurve. delT is a small number used to compute
derivatives. oldT is used to hold the current value of the
t parameter for spaceCurve. This is an efficiency measure
to ensure that frames are only computed once for each value of t.
ngeneralTube: (ThreeCurve, TwoCurve, DFLOAT, DFLOAT) -> Surface
ngeneralTube(spaceCurve, planeCurve, delT, oldT) ==
free frame Indicate that is global
(v:DFLOAT, t: DFLOAT): R3 +->
if (t $\sim$= oldT) then If not already computed
frame := nfrenetFrame(spaceCurve, t, delT) compute new frame
oldT := t
p := planeCurve(v, t)
frame.value + p.1*frame.normal + p.2*frame.binormal
Project into the normal plane
21.11 dhtri.input
Create affine transformations (DH matrices) that transform
a given triangle into another.
tri2tri: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT)
Compute a DHMATRIX that
tri2tri(t1, t2) == transforms to where
n1 := triangleNormal(t1) and are the vertices
n2 := triangleNormal(t2) of two triangles in 3-space
tet2tet(concat(t1, n1), concat(t2, n2))
tet2tet: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT)
Compute a DHMATRIX that
tet2tet(t1, t2) == transforms to
m1 := makeColumnMatrix t1 where and are the
m2 := makeColumnMatrix t2 vertices of two tetrahedrons
m2 * inverse(m1) in 3-space
makeColumnMatrix(t) == Put the vertices of a tetra-
m := new(4,4,0)$DHMATRIX(DFLOAT) hedron into matrix form
for x in t for i in 1..repeat
for j in 1..3 repeat
m(j,i) := x.j
m(4,i) := 1
m
triangleNormal(t) == Compute a vector normal to
a := triangleArea t the given triangle, whose
p1 := t.2 - t.1 length is the square root
p2 := t.3 - t.2 of the area of the triangle
c := cross(p1, p2)
len := length(c)
len = 0 => error "degenerate triangle!"
c := (1/len)*c
t.1 + sqrt(a) * c
triangleArea t == Compute the area of a
a := length(t.2 - t.1) triangle using Heron's
b := length(t.3 - t.2) formula
c := length(t.1 - t.3)
s := (a+b+c)/2
sqrt(s*(s-a)*(s-b)*(s-c))
21.12 tetra.input
)set expose add con DenavitHartenbergMatrix Bring DH matrices into the
environment
x1:DFLOAT := sqrt(2.0@DFLOAT/3.0@DFLOAT) Set up the coordinates of the
x2:DFLOAT := sqrt(3.0@DFLOAT)/6 corners of the tetrahedron.
p1 := point [-0.5@DFLOAT, -x2, 0.0@DFLOAT] Some needed points
p2 := point [0.5@DFLOAT, -x2, 0.0@DFLOAT]
p3 := point [0.0@DFLOAT, 2*x2, 0.0@DFLOAT]
p4 := point [0.0@DFLOAT, 0.0@DFLOAT, x1]
baseTriangle := [p2, p1, p3] The base of the tetrahedron
mt := [0.5@DFLOAT*(p2+p1), 0.5@DFLOAT*(p1+p3), 0.5@DFLOAT*(p3+p2)]
The middle triangle inscribed
in the base of the tetrahedron
bt1 := [mt.1, p1, mt.2] The bases of the triangles of
bt2 := [p2, mt.1, mt.3] the subdivided tetrahedron
bt3 := [mt.2, p3, mt.3]
bt4 := [0.5@DFLOAT*(p2+p4), 0.5@DFLOAT*(p1+p4), 0.5@DFLOAT*(p3+p4)]
tt1 := tri2tri(baseTriangle, bt1) Create the transformations
tt2 := tri2tri(baseTriangle, bt2) that bring the base of the
tt3 := tri2tri(baseTriangle, bt3) tetrahedron to the bases of
tt4 := tri2tri(baseTriangle, bt4) the subdivided tetrahedron
drawPyramid(n) == Draw a Sierpinsky tetrahedron
s := createThreeSpace() with levels of recursive
dh := rotatex(0.0@DFLOAT) subdivision
drawPyramidInner(s, n, dh)
makeViewport3D(s, "Sierpinsky Tetrahedron")
drawPyramidInner(s, n, dh) == Recursively draw a Sierpinsky
n = 0 => makeTetrahedron(s, dh, n) tetrahedron
drawPyramidInner(s, n-1, dh * tt1) Draw the 4 recursive pyramids
drawPyramidInner(s, n-1, dh * tt2)
drawPyramidInner(s, n-1, dh * tt3)
drawPyramidInner(s, n-1, dh * tt4)
makeTetrahedron(sp, dh, color) == Draw a tetrahedron into the
w1 := dh*p1 given space with the given
w2 := dh*p2 color, transforming it by
w3 := dh*p3 the given DH matrix
w4 := dh*p4
polygon(sp, [w1, w2, w4])
polygon(sp, [w1, w3, w4])
polygon(sp, [w2, w3, w4])
void()
Sierpinsky's Tetrahedron
21.13 antoine.input
Draw Antoine's Necklace.
Antoine's Necklace
Thank you to Matthew Grayson at IBM's T.J Watson Research Center for the idea.
)set expose add con DenavitHartenbergMatrix Bring DH matrices into
the environment
torusRot: DHMATRIX(DFLOAT) The transformation for
drawing a sub ring
drawRings(n) == Draw Antoine's Necklace with
s := createThreeSpace() levels of recursive subdivision
dh:DHMATRIX(DFLOAT) := identity() The number of subrings is
drawRingsInner(s, n, dh) Do the real work
makeViewport3D(s, "Antoine's Necklace")
In order to draw Antoine rings, we take one ring, scale it down to
a smaller size, rotate it around its central axis, translate it
to the edge of the larger ring and rotate it around the edge to
a point corresponding to its count (there are 10 positions around
the edge of the larger ring). For each of these new rings we
recursively perform the operations, each ring becoming 10 smaller
rings. Notice how the DHMATRIX operations are used to build up
the proper matrix composing all these transformations.
drawRingsInner(s, n, dh) == Recursively draw Antoine's
n = 0 => Necklace
drawRing(s, dh)
void()
t := 0.0@DFLOAT Angle around ring
p := 0.0@DFLOAT Angle of subring from plane
tr := 1.0@DFLOAT Amount to translate subring
inc := 0.1@DFLOAT The translation increment
for i in 1..10 repeat Subdivide into 10 linked rings
tr := tr + inc
inc := -inc
dh' := dh*rotatez(t)*translate(tr,0.0@DFLOAT,0.0@DFLOAT)*
Transform ring in center
to a link
rotatey(p)*scale(0.35@DFLOAT, 0.48@DFLOAT, 0.4@DFLOAT)
drawRingsInner(s, n-1, dh')
t := t + 36.0@DFLOAT
p := p + 90.0@DFLOAT
void()
drawRing(s, dh) == Draw a single ring into
free torusRot the given subspace,
torusRot := dh transformed by the given
DHMATRIX
makeObject(torus, 0..2*%pi, 0..2*%pi, var1Steps == 6,
space == s, var2Steps == 15)
torus(u ,v) == Parameterization of a torus,
cu := cos(u)/6 transformed by the
DHMATRIX in .
torusRot*point [(1+cu)*cos(v),(1+cu)*sin(v),(sin u)/6]
21.14 scherk.input
Scherk's minimal surface, defined by:
Scherk's minimal surface
.
See: A Comprehensive Introduction to Differential Geometry, Vol. 3,
by Michael Spivak, Publish Or Perish, Berkeley, 1979, pp. 249-252.
(xOffset, yOffset):DFLOAT Offsets for a single piece
of Scherk's minimal surface
drawScherk(m,n) == Draw Scherk's minimal surface
free xOffset, yOffset on an by patch
space := createThreeSpace()
for i in 0..m-1 repeat
xOffset := i*%pi
for j in 0 .. n-1 repeat
rem(i+j, 2) = 0 => 'iter Draw only odd patches
yOffset := j*%pi
drawOneScherk(space) Draw a patch
makeViewport3D(space, "Scherk's Minimal Surface")
scherk1(u,v) == The first patch that makes
x := cos(u)/exp(v) up a single piece of
point [xOffset + acos(x), yOffset + u, v, abs(v)] Scherk's minimal surface
scherk2(u,v) == The second patch
x := cos(u)/exp(v)
point [xOffset - acos(x), yOffset + u, v, abs(v)]
scherk3(u,v) == The third patch
x := exp(v) * cos(u)
point [xOffset + u, yOffset + acos(x), v, abs(v)]
scherk4(u,v) == The fourth patch
x := exp(v) * cos(u)
point [xOffset + u, yOffset - acos(x), v, abs(v)]
drawOneScherk(s) == Draw the surface by
breaking it into four
patches and then drawing
the patches
makeObject(scherk1,-%pi/2..%pi/2,0..%pi/2,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk2,-%pi/2..%pi/2,0..%pi/2,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk3,-%pi/2..%pi/2,-%pi/2..0,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk4,-%pi/2..%pi/2,-%pi/2..0,space==s,
var1Steps == 28, var2Steps == 28)
void()