1 2% Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. 3% All rights reserved. 4% 5% Redistribution and use in source and binary forms, with or without 6% modification, are permitted provided that the following conditions are 7% met: 8% 9% - Redistributions of source code must retain the above copyright 10% notice, this list of conditions and the following disclaimer. 11% 12% - Redistributions in binary form must reproduce the above copyright 13% notice, this list of conditions and the following disclaimer in 14% the documentation and/or other materials provided with the 15% distribution. 16% 17% - Neither the name of The Numerical ALgorithms Group Ltd. nor the 18% names of its contributors may be used to endorse or promote products 19% derived from this software without specific prior written permission. 20% 21% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22% IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23% TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 24% PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 25% OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES-- LOSS OF USE, DATA, OR 28% PROFITS-- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33% ********************************************************************* 34\head{chapter}{Programs for FriCAS Images}{ugAppGraphics} 35% ********************************************************************* 36% 37This appendix contains the \Language{} programs used to generate 38the images in the \Gallery{} color insert of this book. 39All these input files are included 40with the \Language{} system. 41To produce the images 42on page 6 of the \Gallery{} insert, for example, issue the command: 43\begin{verbatim} 44)read images6 45\end{verbatim} 46 47These images were produced on an IBM RS/6000 model 530 with a 48standard color graphics adapter. The smooth shaded images 49were made from X Window System screen dumps. 50The remaining images were produced with \Language{}-generated 51PostScript output. The images were reproduced from slides made on an Agfa 52ChromaScript PostScript interpreter with a Matrix Instruments QCR camera. 53 54% ********************************************************************* 55\head{section}{images1.input}{ugFimagesOne} 56% ********************************************************************* 57 58\begin{xmpLinesPlain} 59)read tknot -- Read torus knot program. 60 61torusKnot(15,17, 0.1, 6, 700) -- {\bf A (15,17) torus knot.} 62\end{xmpLinesPlain} 63\index{torus knot} 64 65\newpage 66% ********************************************************************* 67\head{section}{images2.input}{ugFimagesTwo} 68% ********************************************************************* 69 70These images illustrate how Newton's method converges when computing the 71\index{Newton iteration} 72complex cube roots of 2. Each point in the \smath{(x,y)}-plane represents the 73complex number \smath{x + iy,} which is given as a starting point for Newton's 74method. The poles in these images represent bad starting values. 75The flat areas are the regions of convergence to the three roots. 76 77\begin{xmpLinesPlain} 78)read newton -- Read the programs from 79)read vectors -- \quad{}Chapter 10. 80f := newtonStep(x^3 - 2) -- Create a Newton's iteration 81 -- \quad{}function for $x^3 = 2$. 82\end{xmpLinesPlain} 83 84The function \texht{$f^n$}{f^n} computes $n$ steps of Newton's method. 85 86\begin{xmpLinesNoResetPlain} 87clipValue := 4 -- Clip values with magnitude $> 4$. 88drawComplexVectorField(f^3, -3..3, -3..3) -- The vector field for $f^3$ 89drawComplex(f^3, -3..3, -3..3) -- The surface for $f^3$ 90drawComplex(f^4, -3..3, -3..3) -- The surface for $f^4$ 91\end{xmpLinesNoResetPlain} 92 93% ********************************************************************* 94\head{section}{images3.input}{ugFimagesThree} 95% ********************************************************************* 96 97\begin{xmpLinesPlain} 98)r tknot 99for i in 0..4 repeat torusKnot(2, 2 + i/4, 0.5, 25, 250) 100\end{xmpLinesPlain} 101 102% ********************************************************************* 103\head{section}{images5.input}{ugFimagesFive} 104% ********************************************************************* 105 106The parameterization of the Etruscan Venus is due to George Frances. 107\index{Etruscan Venus} 108 109\begin{xmpLinesPlain} 110venus(a,r,steps) == 111 surf := (u:DFLOAT, v:DFLOAT): Point DFLOAT +-> 112 cv := cos(v) 113 sv := sin(v) 114 cu := cos(u) 115 su := sin(u) 116 x := r * cos(2*u) * cv + sv * cu 117 y := r * sin(2*u) * cv - sv * su 118 z := a * cv 119 point [x,y,z] 120 draw(surf, 0..%pi, -%pi..%pi, var1Steps==steps, 121 var2Steps==steps, title == "Etruscan Venus") 122 123venus(5/2, 13/10, 50) -- \textbf{The Etruscan Venus} 124\end{xmpLinesPlain} 125 126The Figure-8 Klein Bottle 127\index{Klein bottle} 128parameterization is from 129``Differential Geometry and Computer Graphics'' by Thomas Banchoff, 130in {\it Perspectives in Mathematics,} Anniversary of Oberwolfasch 1984, 131Birkh\"{a}user-Verlag, Basel, pp. 43-60. 132 133\begin{xmpLinesNoResetPlain} 134klein(x,y) == 135 cx := cos(x) 136 cy := cos(y) 137 sx := sin(x) 138 sy := sin(y) 139 sx2 := sin(x/2) 140 cx2 := cos(x/2) 141 sq2 := sqrt(2.0@DFLOAT) 142 point [cx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), _ 143 sx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), _ 144 -sx2 * (sq2 + cy) + cx2 * sy * cy] 145 146draw(klein, 0..4*%pi, 0..2*%pi, var1Steps==50, -- \textbf{Figure-8 Klein bottle} 147 var2Steps==50,title=="Figure Eight Klein Bottle") 148\end{xmpLinesNoResetPlain} 149 150The next two images are examples of generalized tubes. 151 152\begin{xmpLinesNoResetPlain} 153)read ntube 154rotateBy(p, theta) == -- Rotate a point $p$ by 155 c := cos(theta) -- \quad{}$\theta$ around the origin. 156 s := sin(theta) 157 point [p.1*c - p.2*s, p.1*s + p.2*c] 158 159bcircle t == -- A circle in three-space. 160 point [3*cos t, 3*sin t, 0] 161 162twist(u, t) == -- An ellipse that twists 163 theta := 4*t -- \quad{}around four times as 164 p := point [sin u, cos(u)/2] -- \quad{}\spad{t} revolves once. 165 rotateBy(p, theta) 166 167ntubeDrawOpt(bcircle, twist, 0..2*%pi, 0..2*%pi, -- \bf{Twisted Torus} 168 var1Steps == 70, var2Steps == 250) 169 170twist2(u, t) == -- Create a twisting circle. 171 theta := t 172 p := point [sin u, cos(u)] 173 rotateBy(p, theta) 174 175cf(u,v) == sin(21*u) -- Color function with \spad{21} stripes. 176 177ntubeDrawOpt(bcircle, twist2, 0..2*%pi, 0..2*%pi, -- \textbf{Striped Torus} 178 colorFunction == cf, var1Steps == 168, 179 var2Steps == 126) 180\end{xmpLinesNoResetPlain} 181 182% ********************************************************************* 183\head{section}{images6.input}{ugFimagesSix} 184% ********************************************************************* 185 186\begin{xmpLinesPlain} 187gam(x,y) == -- The height and color are the 188 g := Gamma complex(x,y) -- \quad{}real and argument parts 189 point [x,y,max(min(real g, 4), -4), argument g] -- \quad{}of the Gamma function, 190 -- \quad{}respectively. 191 192draw(gam, -%pi..%pi, -%pi..%pi, -- \textbf{The Gamma Function} 193 title == "Gamma(x + %i*y)", _ 194 var1Steps == 100, var2Steps == 100) 195 196b(x,y) == Beta(x,y) 197 198draw(b, -3.1..3, -3.1 .. 3, title == "Beta(x,y)") -- \textbf{The Beta Function} 199 200atf(x,y) == 201 a := atan complex(x,y) 202 point [x,y,real a, argument a] 203 204draw(atf, -3.0..%pi, -3.0..%pi) -- \textbf{The Arctangent function} 205\end{xmpLinesPlain} 206\index{function!Gamma} 207\index{function!Euler Beta} 208\index{Euler!Beta function} 209 210 211% ********************************************************************* 212\head{section}{images7.input}{ugFimagesSeven} 213% ********************************************************************* 214 215First we look at the conformal 216\index{conformal map} 217map \texht{$z \mapsto z + 1/z$}{z +-> z + 1/z}. 218 219\begin{xmpLinesPlain} 220)read conformal -- Read program for drawing 221 -- \quad{}conformal maps. 222 223f z == z -- The coordinate grid for the 224 -- \quad{}complex plane. 225conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian") -- \textbf{Mapping 1: Source} 226 227f z == z + 1/z -- The map $z \mapsto z + 1/z$ 228 229conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian") -- \bf{Mapping 1: Target} 230\end{xmpLinesPlain} 231 232The map \texht{$z \mapsto -(z+1)/(z-1)$}{z +-> -(z+1)/(z-1)} maps 233the unit disk to the right half-plane, as shown 234\index{Riemann!sphere} 235on the Riemann sphere. 236 237\begin{xmpLinesNoResetPlain} 238f z == z -- The unit disk. 239 240riemannConformalDraw(f,0.1..0.99,0..2*%pi,7,11,"polar") -- \textbf{Mapping 2: Source} 241 242f z == -(z+1)/(z-1) -- The map $x\mapsto -(z+1)/(z-1)$. 243riemannConformalDraw(f,0.1..0.99,0..2*%pi,7,11,"polar") -- \textbf{Mapping 2: Target} 244 245riemannSphereDraw(-4..4, -4..4, 7, 7, "cartesian") -- \textbf{Riemann Sphere Mapping} 246\end{xmpLinesNoResetPlain} 247 248% ********************************************************************* 249\head{section}{images8.input}{ugFimagesEight} 250% ********************************************************************* 251 252\begin{xmpLinesPlain} 253)read dhtri 254)read tetra 255drawPyramid 4 -- \textbf{Sierpinsky's Tetrahedron} 256 257\index{Sierpinsky's Tetrahedron} 258)read antoine 259drawRings 2 -- \textbf{Antoine's Necklace} 260 261\index{Antoine's Necklace} 262)read scherk 263drawScherk(3,3) -- \textbf{Scherk's Minimal Surface} 264 265\index{Scherk's minimal surface} 266)read ribbonsNew 267drawRibbons([x^i for i in 1..5], x=-1..1, y=0..2) -- \bf{Ribbon Plot} 268\end{xmpLinesPlain} 269 270 271%\input{gallery/conformal.htex} 272% ********************************************************************* 273\head{section}{conformal.input}{ugFconformal} 274% ********************************************************************* 275% 276The functions in this section draw conformal maps both on the 277\index{conformal map} 278plane and on the Riemann sphere. 279\index{Riemann!sphere} 280 281% -- Compile, don't interpret functions. 282%\xmpLine{)set fun comp on}{} 283\begin{xmpLinesPlain} 284C := Complex DoubleFloat -- Complex Numbers 285S := Segment DoubleFloat -- Draw ranges 286R3 := Point DFLOAT -- Points in 3-space 287 288\end{xmpLinesPlain} 289 290\userfun{conformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)} 291draws the image of the coordinate grid under {\it f} in the complex plane. 292The grid may be given in either polar or Cartesian coordinates. 293Argument {\it f} is the function to draw; 294{\it rRange} is the range of the radius (in polar) or real (in Cartesian); 295{\it tRange} is the range of \texht{$\theta$}{\theta} (in polar) or imaginary (in Cartesian); 296{\it tSteps, rSteps}, are the number of intervals in the {\it r} and 297\texht{$\theta$}{\theta} directions; and 298{\it coord} is the coordinate system to use (either {\tt "polar"} or 299{\tt "cartesian"}). 300 301\begin{xmpLinesNoResetPlain} 302conformalDraw: (C -> C, S, S, PI, PI, String) -> VIEW3D 303conformalDraw(f,rRange,tRange,rSteps,tSteps,coord) == 304 transformC := -- Function for changing an \smath{(x,y)} 305 coord = "polar" => polar2Complex -- \quad{}pair into a complex number. 306 cartesian2Complex 307 cm := makeConformalMap(f, transformC) 308 sp := createThreeSpace() -- Create a fresh space. 309 adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) -- Plot the coordinate lines. 310 makeViewport3D(sp, "Conformal Map") -- Draw the image. 311\end{xmpLinesNoResetPlain} 312 313\userfun{riemannConformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)} 314draws the image of the coordinate grid under {\it f} on the Riemann sphere. 315The grid may be given in either polar or Cartesian coordinates. 316Its arguments are the same as those for \userfun{conformalDraw}. 317\begin{xmpLinesNoResetPlain} 318riemannConformalDraw:(C->C,S,S,PI,PI,String)->VIEW3D 319riemannConformalDraw(f, rRange, tRange, 320 rSteps, tSteps, coord) == 321 transformC := -- Function for changing an \smath{(x,y)} 322 coord = "polar" => polar2Complex -- \quad{}pair into a complex number. 323 cartesian2Complex 324 sp := createThreeSpace() -- Create a fresh space. 325 cm := makeRiemannConformalMap(f, transformC) 326 adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) -- Plot the coordinate lines. 327 curve(sp,[point [0,0,2.0@DFLOAT,0],point [0,0,2.0@DFLOAT,0]]) -- Add an invisible point at 328 makeViewport3D(sp,"Map on the Riemann Sphere") -- \quad{}the north pole for scaling. 329 330adaptGrid(sp, f, uRange, vRange, uSteps, vSteps) == -- Plot the coordinate grid 331 delU := (high(uRange) - low(uRange))/uSteps -- \quad{}using adaptive plotting for 332 delV := (high(vRange) - low(vRange))/vSteps -- \quad{}coordinate lines, and draw 333 uSteps := uSteps + 1; vSteps := vSteps + 1 -- \quad{}tubes around the lines. 334 u := low uRange 335 for i in 1..uSteps repeat -- Draw coordinate lines in the \spad{v} 336 c := curryLeft(f,u) -- \quad{}direction; curve \spad{c} fixes the 337 cf := (t:DFLOAT):DFLOAT +-> 0 -- \quad{}current value of \spad{u}. 338 makeObject(c,vRange::SEG Float,colorFunction==cf, -- Draw the \spad{v} coordinate line. 339 space == sp, tubeRadius == .02, tubePoints == 6) 340 u := u + delU 341 v := low vRange 342 for i in 1..vSteps repeat -- Draw coordinate lines in the \spad{u} 343 c := curryRight(f,v) -- \quad{}direction; curve \spad{c} fixes the 344 cf := (t:DFLOAT):DFLOAT +-> 1 -- \quad{}current value of \spad{v}. 345 makeObject(c,uRange::SEG Float,colorFunction==cf, -- Draw the \spad{u} coordinate line. 346 space == sp, tubeRadius == .02, tubePoints == 6) 347 v := v + delV 348 void() 349 350riemannTransform(z) == -- Map a point in the complex 351 r := sqrt norm z -- \quad{}plane to the Riemann sphere. 352 cosTheta := (real z)/r 353 sinTheta := (imag z)/r 354 cp := 4*r/(4+r^2) 355 sp := sqrt(1-cp*cp) 356 if r>2 then sp := -sp 357 point [cosTheta*cp, sinTheta*cp, -sp + 1] 358 359cartesian2Complex(r:DFLOAT, i:DFLOAT):C == -- Convert Cartesian coordinates to 360 complex(r, i) -- \quad{}complex Cartesian form. 361 362polar2Complex(r:DFLOAT, th:DFLOAT):C == -- Convert polar coordinates to 363 complex(r*cos(th), r*sin(th)) -- \quad{}complex Cartesian form. 364 365makeConformalMap(f, transformC) == -- Convert complex function \spad{f} to a 366 (u:DFLOAT,v:DFLOAT):R3 +-> -- \quad{}mapping: (\spadtype{DFLOAT},\spadtype{DFLOAT}) $\to$ \pspadtype{R3} 367 z := f transformC(u, v) -- \quad{}in the complex plane. 368 point [real z, imag z, 0.0@DFLOAT] 369 370makeRiemannConformalMap(f, transformC) == -- Convert a complex function \spad{f} to a 371 (u:DFLOAT, v:DFLOAT):R3 +-> -- \quad{}mapping: (\spadtype{DFLOAT},\spadtype{DFLOAT}) $\to$ \spadtype{R3} 372 riemannTransform f transformC(u, v) -- \quad{}on the Riemann sphere. 373 374riemannSphereDraw: (S, S, PI, PI, String) -> VIEW3D -- Draw a picture of the mapping 375riemannSphereDraw(rRange,tRange,rSteps,tSteps,coord) == -- \quad{}of the complex plane to 376 transformC := -- \quad{}the Riemann sphere. 377 coord = "polar" => polar2Complex 378 cartesian2Complex 379 grid := (u:DFLOAT, v:DFLOAT): R3 +-> -- Coordinate grid function. 380 z1 := transformC(u, v) 381 point [real z1, imag z1, 0] 382 sp := createThreeSpace() -- Create a fresh space. 383 adaptGrid(sp, grid, rRange, tRange, rSteps, tSteps) -- Draw the flat grid. 384 connectingLines(sp,grid,rRange,tRange,rSteps,tSteps) 385 makeObject(riemannSphere,0..2*%pi,0..%pi,space==sp) -- Draw the sphere. 386 f := (z:C):C +-> z 387 cm := makeRiemannConformalMap(f, transformC) 388 adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) -- Draw the sphere grid. 389 makeViewport3D(sp, "Riemann Sphere") 390 391connectingLines(sp,f,uRange,vRange,uSteps,vSteps) == -- Draw the lines that connect 392 delU := (high(uRange) - low(uRange))/uSteps -- \quad{}the points in the complex 393 delV := (high(vRange) - low(vRange))/vSteps -- \quad{}plane to the north pole 394 uSteps := uSteps + 1; vSteps := vSteps + 1 -- \quad{}of the Riemann sphere. 395 u := low uRange 396 for i in 1..uSteps repeat -- For each u. 397 v := low vRange 398 for j in 1..vSteps repeat -- For each v. 399 p1 := f(u,v) 400 p2 := riemannTransform complex(p1.1, p1.2) -- Project p1 onto the sphere. 401 fun := lineFromTo(p1,p2) -- Create a line function. 402 cf := (t:DFLOAT):DFLOAT +-> 3 403 makeObject(fun, 0..1,space==sp,tubePoints==4, -- Draw the connecting line. 404 tubeRadius==0.01,colorFunction==cf) 405 v := v + delV 406 u := u + delU 407 void() 408 409riemannSphere(u,v) == -- A sphere sitting on the 410 sv := sin(v) -- \quad{}complex plane, with radius 1. 411 0.99@DFLOAT*(point [cos(u)*sv,sin(u)*sv,cos(v),0.0@DFLOAT])+ 412 point [0.0@DFLOAT, 0.0@DFLOAT, 1.0@DFLOAT, 4.0@DFLOAT] 413 414lineFromTo(p1, p2) == -- Create a line function 415 d := p2 - p1 -- \quad{}that goes from p1 to p2 416 (t:DFLOAT):Point DFLOAT +-> 417 p1 + t*d 418\end{xmpLinesNoResetPlain} 419 420%\input{gallery/tknot.htex} 421% ********************************************************************* 422\head{section}{tknot.input}{ugFtknot} 423% ********************************************************************* 424% 425Create a $(p,q)$ torus-knot with radius $r$ around the curve. 426The formula was derived by Larry Lambe. 427 428\begin{xmpLinesPlain} 429)read ntube 430torusKnot: (DFLOAT, DFLOAT, DFLOAT, PI, PI) -> VIEW3D 431torusKnot(p, q ,r, uSteps, tSteps) == 432 knot := (t:DFLOAT):Point DFLOAT +-> -- Function for the torus knot. 433 fac := 4/(2.2@DFLOAT-sin(q*t)) 434 fac * point [cos(p*t), sin(p*t), cos(q*t)] 435 circle := (u:DFLOAT, t:DFLOAT): Point DFLOAT +-> -- The cross section. 436 r * point [cos u, sin u] 437 ntubeDrawOpt(knot, circle, 0..2*%pi, 0..2*%pi, -- Draw the circle around the knot. 438 var1Steps == uSteps, var2Steps == tSteps) 439 440\end{xmpLinesPlain} 441 442%\input{gallery/ntube.htex} 443% ********************************************************************* 444\head{section}{ntube.input}{ugFntube} 445% ********************************************************************* 446% 447The functions in this file create generalized tubes (also known as generalized 448cylinders). 449These functions draw a 2-d curve in the normal 450planes around a 3-d curve. 451 452\begin{xmpLinesPlain} 453R3 := Point DFLOAT -- Points in 3-Space 454R2 := Point DFLOAT -- Points in 2-Space 455S := Segment Float -- Draw ranges 456 -- Introduce types for functions for: 457ThreeCurve := DFLOAT -> R3 -- \quad{}---the space curve function 458TwoCurve := (DFLOAT, DFLOAT) -> R2 -- \quad{}---the plane curve function 459Surface := (DFLOAT, DFLOAT) -> R3 -- \quad{}---the surface function 460 -- Frenet frames define a 461FrenetFrame := -- \quad{}coordinate system around a 462 Record(value:R3,tangent:R3,normal:R3,binormal:R3) -- \quad{}point on a space curve. 463frame: FrenetFrame -- The current Frenet frame 464 -- \quad{}for a point on a curve. 465\end{xmpLinesPlain} 466 467\userfun{ntubeDraw}{\it (spaceCurve, planeCurve,} 468$u_0 .. u_1,$ $t_0 .. t_1)$ 469draws {\it planeCurve} in the normal planes of {\it spaceCurve.} 470The parameter $u_0 .. u_1$ specifies 471the parameter range for {\it planeCurve} 472and $t_0 .. t_1$ specifies the parameter range for {\it spaceCurve}. 473Additionally, the plane curve function takes 474a second parameter: the current parameter of {\it spaceCurve}. 475This allows the plane curve to change shape 476as it goes around the space curve. 477See \spadref{ugFimagesFive} for an example of this. 478% 479\begin{xmpLinesNoResetPlain} 480ntubeDraw: (ThreeCurve,TwoCurve,S,S) -> VIEW3D 481ntubeDraw(spaceCurve,planeCurve,uRange,tRange) == 482 ntubeDrawOpt(spaceCurve, planeCurve, uRange, _ 483 tRange, []$List DROPT) 484 485ntubeDrawOpt: (ThreeCurve,TwoCurve,S,S,List DROPT) 486 -> VIEW3D 487ntubeDrawOpt(spaceCurve,planeCurve,uRange,tRange,l) == -- This function is similar 488 -- \quad{}to \userfun{ntubeDraw}, but takes 489 delT:DFLOAT := (high(tRange) - low(tRange))/10000 -- \quad{}optional parameters that it 490 oldT:DFLOAT := low(tRange) - 1 -- \quad{}passes to the \spadfun{draw} command. 491 fun := ngeneralTube(spaceCurve,planeCurve,delT,oldT) 492 draw(fun, uRange, tRange, l) 493 494\end{xmpLinesNoResetPlain} 495 496\userfun{nfrenetFrame}{\it (c, t, delT)} 497numerically computes the Frenet frame 498about the curve {\it c} at {\it t}. 499Parameter {\it delT} is a small number used to 500compute derivatives. 501\begin{xmpLinesNoResetPlain} 502nfrenetFrame(c, t, delT) == 503 f0 := c(t) 504 f1 := c(t+delT) 505 t0 := f1 - f0 -- The tangent. 506 n0 := f1 + f0 507 b := cross(t0, n0) -- The binormal. 508 n := cross(b,t0) -- The normal. 509 ln := length n 510 lb := length b 511 ln = 0 or lb = 0 => 512 error "Frenet Frame not well defined" 513 n := (1/ln)*n -- Make into unit length vectors. 514 b := (1/lb)*b 515 [f0, t0, n, b]$FrenetFrame 516\end{xmpLinesNoResetPlain} 517 518\userfun{ngeneralTube}{\it (spaceCurve, planeCurve,}{\it delT, oltT)} 519creates a function that can be passed to the system \spadfun{draw} command. 520The function is a parameterized surface for the general tube 521around {\it spaceCurve}. {\it delT} is a small number used to compute 522derivatives. {\it oldT} is used to hold the current value of the 523{\it t} parameter for {\it spaceCurve.} This is an efficiency measure 524to ensure that frames are only computed once for each value of {\it t}. 525\begin{xmpLinesNoResetPlain} 526ngeneralTube: (ThreeCurve, TwoCurve, DFLOAT, DFLOAT) -> Surface 527ngeneralTube(spaceCurve, planeCurve, delT, oldT) == 528 free frame -- Indicate that \spad{frame} is global. 529 (v:DFLOAT, t: DFLOAT): R3 +-> 530 if (t ~= oldT) then -- If not already computed, 531 frame := nfrenetFrame(spaceCurve, t, delT) -- \quad{}compute new frame. 532 oldT := t 533 p := planeCurve(v, t) 534 frame.value + p.1*frame.normal + p.2*frame.binormal -- Project \spad{p} into the normal plane. 535\end{xmpLinesNoResetPlain} 536 537%\input{gallery/dhtri.htex} 538% ********************************************************************* 539\head{section}{dhtri.input}{ugFdhtri} 540% ********************************************************************* 541% 542Create affine transformations (DH matrices) that transform 543a given triangle into another. 544 545\begin{xmpLinesPlain} 546tri2tri: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT) 547 -- Compute a \spadtype{DHMATRIX} that 548tri2tri(t1, t2) == -- \quad{}transforms \spad{t1} to \spad{t2,} where 549 n1 := triangleNormal(t1) -- \quad{}\spad{t1} and \spad{t2} are the vertices 550 n2 := triangleNormal(t2) -- \quad{}of two triangles in 3-space. 551 tet2tet(concat(t1, n1), concat(t2, n2)) 552 553tet2tet: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT) 554 -- Compute a \spadtype{DHMATRIX} that 555tet2tet(t1, t2) == -- \quad{}transforms \spad{t1} to \spad{t2,} 556 m1 := makeColumnMatrix t1 -- \quad{}where \spad{t1} and \spad{t2} are the 557 m2 := makeColumnMatrix t2 -- \quad{}vertices of two tetrahedrons 558 m2 * inverse(m1) -- \quad{}in 3-space. 559 560makeColumnMatrix(t) == -- Put the vertices of a tetra- 561 m := new(4,4,0)$DHMATRIX(DFLOAT) -- \quad{}hedron into matrix form. 562 for x in t for i in 1..repeat 563 for j in 1..3 repeat 564 m(j,i) := x.j 565 m(4,i) := 1 566 m 567 568triangleNormal(t) == -- Compute a vector normal to 569 a := triangleArea t -- \quad{}the given triangle, whose 570 p1 := t.2 - t.1 -- \quad{}length is the square root 571 p2 := t.3 - t.2 -- \quad{}of the area of the triangle. 572 c := cross(p1, p2) 573 len := length(c) 574 len = 0 => error "degenerate triangle!" 575 c := (1/len)*c 576 t.1 + sqrt(a) * c 577 578triangleArea t == -- Compute the area of a 579 a := length(t.2 - t.1) -- \quad{}triangle using Heron's 580 b := length(t.3 - t.2) -- \quad{}formula. 581 c := length(t.1 - t.3) 582 s := (a+b+c)/2 583 sqrt(s*(s-a)*(s-b)*(s-c)) 584\end{xmpLinesPlain} 585 586 587% ********************************************************************* 588\head{section}{tetra.input}{ugFtetra} 589% ********************************************************************* 590% 591%\input{gallery/tetra.htex} 592%\outdent{Sierpinsky's Tetrahedron} 593 594\begin{xmpLinesPlain} 595)set expose add con DenavitHartenbergMatrix -- Bring DH matrices into the 596 -- \quad{}environment. 597x1:DFLOAT := sqrt(2.0@DFLOAT/3.0@DFLOAT) -- Set up the coordinates of the 598x2:DFLOAT := sqrt(3.0@DFLOAT)/6 -- \quad{}corners of the tetrahedron. 599 600z := 0.0@DFLOAT 601h := 0.5@DFLOAT 602 603p1 := point [-h, -x2, z] -- Some needed points. 604p2 := point [h, -x2, z] 605p3 := point [z, 2*x2, z] 606p4 := point [z, z, x1] 607 608baseTriangle := [p2, p1, p3] -- The base of the tetrahedron. 609 610mt := [h*(p2+p1), h*(p1+p3), h*(p3+p2)] -- The ``middle triangle'' inscribed 611 -- \quad{}in the base of the tetrahedron. 612bt1 := [mt.1, p1, mt.2] -- The bases of the triangles of 613bt2 := [p2, mt.1, mt.3] -- \quad{}the subdivided tetrahedron. 614bt3 := [mt.2, p3, mt.3] 615bt4 := [h*(p2+p4), h*(p1+p4), h*(p3+p4)] 616 617tt1 := tri2tri(baseTriangle, bt1) -- Create the transformations 618tt2 := tri2tri(baseTriangle, bt2) -- \quad{}that bring the base of the 619tt3 := tri2tri(baseTriangle, bt3) -- \quad{}tetrahedron to the bases of 620tt4 := tri2tri(baseTriangle, bt4) -- \quad{}the subdivided tetrahedron. 621 622drawPyramid(n) == -- Draw a Sierpinsky tetrahedron 623 s := createThreeSpace() -- \quad{}with \spad{n} levels of recursive 624 dh := rotatex(0.0@DFLOAT) -- \quad{}subdivision. 625 drawPyramidInner(s, n, dh) 626 makeViewport3D(s, "Sierpinsky Tetrahedron") 627 628drawPyramidInner(s, n, dh) == -- Recursively draw a Sierpinsky 629 n = 0 => makeTetrahedron(s, dh, n) -- \quad{}tetrahedron. 630 drawPyramidInner(s, n-1, dh * tt1) -- Draw the 4 recursive pyramids. 631 drawPyramidInner(s, n-1, dh * tt2) 632 drawPyramidInner(s, n-1, dh * tt3) 633 drawPyramidInner(s, n-1, dh * tt4) 634 635makeTetrahedron(sp, dh, color) == -- Draw a tetrahedron into the 636 w1 := dh*p1 -- \quad{}given space with the given 637 w2 := dh*p2 -- \quad{}color, transforming it by 638 w3 := dh*p3 -- \quad{}the given DH matrix. 639 w4 := dh*p4 640 polygon(sp, [w1, w2, w4]) 641 polygon(sp, [w1, w3, w4]) 642 polygon(sp, [w2, w3, w4]) 643 void() 644\end{xmpLinesPlain} 645\index{Sierpinsky's Tetrahedron} 646 647 648%\input{gallery/antoine.htex} 649% ********************************************************************* 650\head{section}{antoine.input}{ugFantoine} 651% ********************************************************************* 652% 653Draw Antoine's Necklace. 654\index{Antoine's Necklace} 655Thank you to Matthew Grayson at IBM's T.J Watson Research Center for the idea. 656 657\begin{xmpLinesPlain} 658)set expose add con DenavitHartenbergMatrix -- Bring DH matrices into 659 -- \quad{}the environment. 660torusRot: DHMATRIX(DFLOAT) -- The current transformation for 661 -- \quad{}drawing a sub ring. 662 663drawRings(n) == -- Draw Antoine's Necklace with \spad{n} 664 s := createThreeSpace() -- \quad{}levels of recursive subdivision. 665 dh:DHMATRIX(DFLOAT) := identity() -- \quad{}The number of subrings is $10^n$. 666 drawRingsInner(s, n, dh) -- Do the real work. 667 makeViewport3D(s, "Antoine's Necklace") 668 669\end{xmpLinesPlain} 670 671In order to draw Antoine rings, we take one ring, scale it down to 672a smaller size, rotate it around its central axis, translate it 673to the edge of the larger ring and rotate it around the edge to 674a point corresponding to its count (there are 10 positions around 675the edge of the larger ring). For each of these new rings we 676recursively perform the operations, each ring becoming 10 smaller 677rings. Notice how the \spadtype{DHMATRIX} operations are used to build up 678the proper matrix composing all these transformations. 679 680\begin{xmpLinesNoResetPlain} 681F ==> DFLOAT 682drawRingsInner(s, n, dh) == -- Recursively draw Antoine's 683 n = 0 => -- \quad{}Necklace. 684 drawRing(s, dh) 685 void() 686 t := 0.0@F -- Angle around ring. 687 p := 0.0@F -- Angle of subring from plane. 688 tr := 1.0@F -- Amount to translate subring. 689 inc := 0.1@F -- The translation increment. 690 for i in 1..10 repeat -- Subdivide into 10 linked rings. 691 tr := tr + inc 692 inc := -inc 693 dh' := dh*rotatez(t)*translate(tr,0.0@F,0.0@F)* -- Transform ring in center 694 rotatey(p)*scale(0.35@F, 0.48@F, 0.4@F) -- \quad{}to a link. 695 drawRingsInner(s, n-1, dh') 696 t := t + 36.0@F 697 p := p + 90.0@F 698 void() 699 700drawRing(s, dh) == -- Draw a single ring into 701 free torusRot -- \quad{}the given subspace, 702 torusRot := dh -- \quad{}transformed by the given 703 makeObject(torus, 0..2*%pi, 0..2*%pi, var1Steps == 6, -- \quad{}\spadtype{DHMATRIX}. 704 space == s, var2Steps == 15) 705 706torus(u ,v) == -- Parameterization of a torus, 707 cu := cos(u)/6 -- \quad{}transformed by the 708 torusRot*point [(1+cu)*cos(v),(1+cu)*sin(v),(sin u)/6] -- \quad{}\spadtype{DHMATRIX} in \spad{torusRot.} 709\end{xmpLinesNoResetPlain} 710 711%\input{gallery/scherk.htex} 712% ********************************************************************* 713\head{section}{scherk.input}{ugFscherk} 714% ********************************************************************* 715% 716 717Scherk's minimal surface, defined by: 718\index{Scherk's minimal surface} 719\texht{$e^z \cos(x) = \cos(y)$}{\spad{exp(z) * cos(x) = cos(y)}}. 720See: {\it A Comprehensive Introduction to Differential Geometry,} Vol. 3, 721by Michael Spivak, Publish Or Perish, Berkeley, 1979, pp. 249-252. 722 723\begin{xmpLinesPlain} 724(xOffset, yOffset):DFLOAT -- Offsets for a single piece 725 -- \quad{}of Scherk's minimal surface. 726 727drawScherk(m,n) == -- Draw Scherk's minimal surface 728 free xOffset, yOffset -- \quad{}on an \spad{m} by \spad{n} patch. 729 space := createThreeSpace() 730 for i in 0..m-1 repeat 731 xOffset := i*%pi 732 for j in 0 .. n-1 repeat 733 rem(i+j, 2) = 0 => 'iter -- Draw only odd patches. 734 yOffset := j*%pi 735 drawOneScherk(space) -- Draw a patch. 736 makeViewport3D(space, "Scherk's Minimal Surface") 737 738scherk1(u,v) == -- The first patch that makes 739 x := cos(u)/exp(v) -- \quad{}up a single piece of 740 point [xOffset + acos(x), yOffset + u, v, abs(v)] -- \quad{}Scherk's minimal surface. 741 742scherk2(u,v) == -- The second patch. 743 x := cos(u)/exp(v) 744 point [xOffset - acos(x), yOffset + u, v, abs(v)] 745 746scherk3(u,v) == -- The third patch. 747 x := exp(v) * cos(u) 748 point [xOffset + u, yOffset + acos(x), v, abs(v)] 749 750scherk4(u,v) == -- The fourth patch. 751 x := exp(v) * cos(u) 752 point [xOffset + u, yOffset - acos(x), v, abs(v)] 753 754drawOneScherk(s) == -- Draw the surface by 755 makeObject(scherk1,-%pi/2..%pi/2,0..%pi/2,space==s, -- \quad{}breaking it into four 756 var1Steps == 28, var2Steps == 28) -- \quad{}patches and then drawing 757 makeObject(scherk2,-%pi/2..%pi/2,0..%pi/2,space==s, -- \quad{}the patches. 758 var1Steps == 28, var2Steps == 28) 759 makeObject(scherk3,-%pi/2..%pi/2,-%pi/2..0,space==s, 760 var1Steps == 28, var2Steps == 28) 761 makeObject(scherk4,-%pi/2..%pi/2,-%pi/2..0,space==s, 762 var1Steps == 28, var2Steps == 28) 763 void() 764\end{xmpLinesPlain} 765