
% Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
%     - Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%
%     - Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the
%       distribution.
%
%     - Neither the name of The Numerical ALgorithms Group Ltd. nor the
%       names of its contributors may be used to endorse or promote products
%       derived from this software without specific prior written permission.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
% IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
% TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
% PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
% OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES-- LOSS OF USE, DATA, OR
% PROFITS-- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


\setcounter{chapter}{5} % Appendix F
%% use \begin{xmpLines} etc, not \begin{figXmpLines}
%% see use of \labelSpace below when heading crashes into text
%% you've repeat one of the section labels (ugFknot)

% *********************************************************************
\head{chapter}{Programs for FriCAS Images}{ugAppGraphics}
% *********************************************************************
%
This appendix contains the \Language{} programs used to generate
the images in the \Gallery{} color insert of this book.
All these input files are included
with the \Language{} system.
To produce the images
on page 6 of the \Gallery{} insert, for example, issue the command:
\begin{verbatim}
)read images6
\end{verbatim}

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 \Language{}-generated
PostScript output.  The images were reproduced from slides made on an Agfa
ChromaScript PostScript interpreter with a Matrix Instruments QCR camera.

% *********************************************************************
\head{section}{images1.input}{ugFimagesOne}
% *********************************************************************

\labelSpace{3pc}

\begin{xmpLinesPlain}
\xmpLine{)read tknot}{Read torus knot program.}
\xmpLine{}{}
\xmpLine{torusKnot(15,17, 0.1, 6, 700)}{{\bf A (15,17) torus knot.}}
\end{xmpLinesPlain}
\index{torus knot}

\newpage
% *********************************************************************
\head{section}{images2.input}{ugFimagesTwo}
% *********************************************************************

These images illustrate how Newton's method converges when computing the
\index{Newton iteration}
complex cube roots of 2.   Each point in the \smath{(x,y)}-plane represents the
complex number \smath{x + iy,} 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.

\begin{xmpLinesPlain}
\xmpLine{)read newton}{Read the programs from}
\xmpLine{)read vectors}{\quad{}Chapter 10.}
\xmpLine{f := newtonStep(x^3 - 2)}{Create a Newton's iteration}
\xmpLine{}{\quad{}function for $x^3 = 2$.}
\end{xmpLinesPlain}

The function \texht{$f^n$}{f^n} computes $n$ steps of Newton's method.

\begin{xmpLinesNoResetPlain}
\xmpLine{clipValue := 4}{Clip values with magnitude > 4.}
\xmpLine{drawComplexVectorField(f^3, -3..3, -3..3)}{\bf{The vector field for $f^3$}}
\xmpLine{drawComplex(f^3, -3..3, -3..3)}{\bf{The surface for $f^3$}}
\xmpLine{drawComplex(f^4, -3..3, -3..3)}{\bf{The surface for $f^4$}}
\end{xmpLinesNoResetPlain}

% *********************************************************************
\head{section}{images3.input}{ugFimagesThree}
% *********************************************************************

\begin{xmpLinesPlain}
\xmpLine{)r tknot}{}
\xmpLine{for i in 0..4 repeat torusKnot(2, 2 + i/4, 0.5, 25, 250)}{}
\end{xmpLinesPlain}

% *********************************************************************
\head{section}{images5.input}{ugFimagesFive}
% *********************************************************************

The parameterization of the Etruscan Venus is due to George Frances.
\index{Etruscan Venus}

\begin{xmpLinesPlain}
\xmpLine{venus(a,r,steps) ==}{}
\xmpLine{  surf := (u:DFLOAT, v:DFLOAT): Point DFLOAT +->}{}
\xmpLine{    cv := cos(v)}{}
\xmpLine{    sv := sin(v)}{}
\xmpLine{    cu := cos(u)}{}
\xmpLine{    su := sin(u)}{}
\xmpLine{    x := r * cos(2*u) * cv + sv * cu}{}
\xmpLine{    y := r * sin(2*u) * cv - sv * su}{}
\xmpLine{    z := a * cv}{}
\xmpLine{    point [x,y,z]}{}
\xmpLine{  draw(surf, 0..\%pi, -\%pi..\%pi, var1Steps==steps,}{}
\xmpLine{       var2Steps==steps, title == "Etruscan Venus")}{}
\xmpLine{}{}
\xmpLine{venus(5/2, 13/10, 50)}{\bf{The Etruscan Venus}}
\end{xmpLinesPlain}

The Figure-8 Klein Bottle
\index{Klein bottle}
parameterization is from
``Differential Geometry and Computer Graphics'' by Thomas Banchoff,
in {\it Perspectives in Mathematics,} Anniversary of Oberwolfasch 1984,
Birkh\"{a}user-Verlag, Basel, pp. 43-60.

\begin{xmpLinesNoResetPlain}
\xmpLine{klein(x,y) ==}{}
\xmpLine{  cx := cos(x)}{}
\xmpLine{  cy := cos(y)}{}
\xmpLine{  sx := sin(x)}{}
\xmpLine{  sy := sin(y)}{}
\xmpLine{  sx2 := sin(x/2)}{}
\xmpLine{  cx2 := cos(x/2)}{}
\xmpLine{  sq2 := sqrt(2.0@DFLOAT)}{}
\xmpLine{  point [cx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), \_}{}
\xmpLine{         sx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), \_}{}
\xmpLine{         -sx2 * (sq2 + cy) + cx2 * sy * cy]}{}
\xmpLine{}{}
\xmpLine{draw(klein, 0..4*\%pi, 0..2*\%pi, var1Steps==50,}{\bf{Figure-8 Klein bottle}}
\xmpLine{     var2Steps==50,title=="Figure Eight Klein Bottle")}{}
\end{xmpLinesNoResetPlain}

The next two images are examples of generalized tubes.

\begin{xmpLinesNoResetPlain}
\xmpLine{)read ntube}{}
\xmpLine{rotateBy(p, theta) ==}{Rotate a point $p$ by}
\xmpLine{  c := cos(theta)}{\quad{}$\theta$ around the origin.}
\xmpLine{  s := sin(theta)}{}
\xmpLine{  point [p.1*c - p.2*s, p.1*s + p.2*c]}{}
\xmpLine{}{}
\xmpLine{bcircle t == }{A circle in three-space.}
\xmpLine{  point [3*cos t, 3*sin t, 0]}{}
\xmpLine{ }{}
\xmpLine{twist(u, t) ==}{An ellipse that twists}
\xmpLine{  theta := 4*t}{\quad{}around four times as}
\xmpLine{  p := point [sin u, cos(u)/2]}{\quad{}\spad{t} revolves once.}
\xmpLine{  rotateBy(p, theta)}{}
\xmpLine{ }{}
\xmpLine{ntubeDrawOpt(bcircle, twist, 0..2*\%pi, 0..2*\%pi,}{\bf{Twisted Torus}}
\xmpLine{             var1Steps == 70, var2Steps == 250)}{}
\xmpLine{}{}
\xmpLine{twist2(u, t) ==}{Create a twisting circle.}
\xmpLine{  theta := t}{}
\xmpLine{  p := point [sin u, cos(u)]}{}
\xmpLine{  rotateBy(p, theta)}{}
\xmpLine{}{}
\xmpLine{cf(u,v) == sin(21*u)}{Color function with \spad{21} stripes.}
\xmpLine{}{}
\xmpLine{ntubeDrawOpt(bcircle, twist2, 0..2*\%pi, 0..2*\%pi,}{\bf{Striped Torus}}
\xmpLine{  colorFunction == cf, var1Steps == 168,}{}
\xmpLine{  var2Steps == 126)}{}
\end{xmpLinesNoResetPlain}

% *********************************************************************
\head{section}{images6.input}{ugFimagesSix}
% *********************************************************************

\labelSpace{3pc}
\begin{xmpLinesPlain}
\xmpLine{gam(x,y) == }{The height and color are the}
\xmpLine{  g := Gamma complex(x,y)}{\quad{}real and argument parts}
\xmpLine{  point [x,y,max(min(real g, 4), -4), argument g]}{\quad{}of the Gamma function,}
\xmpLine{}{\quad{}respectively.}
\xmpLine{}{}
\xmpLine{draw(gam, -\%pi..\%pi, -\%pi..\%pi, }{\bf{The Gamma Function}}
\xmpLine{     title == "Gamma(x + \%i*y)", \_}{}
\xmpLine{     var1Steps == 100, var2Steps == 100)}{}
\xmpLine{}{}
\xmpLine{b(x,y) == Beta(x,y)}{}
\xmpLine{}{}
\xmpLine{draw(b, -3.1..3, -3.1 .. 3, title == "Beta(x,y)")}{\bf{The Beta Function}}
\xmpLine{}{}
\xmpLine{atf(x,y) == }{}
\xmpLine{  a := atan complex(x,y)}{}
\xmpLine{  point [x,y,real a, argument a]}{}
\xmpLine{}{}
\xmpLine{draw(atf, -3.0..\%pi, -3.0..\%pi)}{\bf{The Arctangent function}}
\end{xmpLinesPlain}
\index{function!Gamma}
\index{function!Euler Beta}
\index{Euler!Beta function}


% *********************************************************************
\head{section}{images7.input}{ugFimagesSeven}
% *********************************************************************

First we look at the conformal
\index{conformal map}
map \texht{$z \mapsto z + 1/z$}{z +-> z + 1/z}.
\labelSpace{2pc}
\begin{xmpLinesPlain}
\xmpLine{)read conformal}{Read program for drawing}
\xmpLine{}{\quad{}conformal maps.}
\xmpLine{}{}
\xmpLine{f z == z}{The coordinate grid for the }
\xmpLine{}{\quad{}complex plane.}
\xmpLine{conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian")}{\bf{Mapping 1: Source}}
\xmpLine{}{}
\xmpLine{f z == z + 1/z}{The map $z \mapsto z + 1/z$}
\xmpLine{ }{}
\xmpLine{conformalDraw(f, -2..2, -2..2, 9, 9, "cartesian")}{\bf{Mapping 1: Target}}
\end{xmpLinesPlain}

The map \texht{$z \mapsto -(z+1)/(z-1)$}{z +-> -(z+1)/(z-1)} maps
the unit disk to the right half-plane, as shown
\index{Riemann!sphere}
on the Riemann sphere.

\begin{xmpLinesNoResetPlain}
\xmpLine{f z == z}{The unit disk.}
\xmpLine{}{}
\xmpLine{riemannConformalDraw(f,0.1..0.99,0..2*\%pi,7,11,"polar")}{\bf{Mapping 2: Source}}
\xmpLine{}{}
\xmpLine{f z == -(z+1)/(z-1)}{The map $x \mapsto -(z+1)/(z-1)$.}
\xmpLine{}{}
\xmpLine{riemannConformalDraw(f,0.1..0.99,0..2*\%pi,7,11,"polar")}{\bf{Mapping 2: Target}}
\xmpLine{}{}
\xmpLine{riemannSphereDraw(-4..4, -4..4, 7, 7, "cartesian")}{\bf{Riemann Sphere Mapping}}
\end{xmpLinesNoResetPlain}

% *********************************************************************
\head{section}{images8.input}{ugFimagesEight}
% *********************************************************************

\labelSpace{1pc}
\begin{xmpLinesPlain}
\xmpLine{)read dhtri}{}
\xmpLine{)read tetra}{}
\xmpLine{drawPyramid 4}{\bf{Sierpinsky's Tetrahedron}}
\xmpLine{}{}
\index{Sierpinsky's Tetrahedron}
\xmpLine{)read antoine}{}
\xmpLine{drawRings 2}{\bf{Antoine's Necklace}}
\xmpLine{}{}
\index{Antoine's Necklace}
\xmpLine{)read scherk}{}
\xmpLine{drawScherk(3,3)}{\bf{Scherk's Minimal Surface}}
\xmpLine{}{}
\index{Scherk's minimal surface}
\xmpLine{)read ribbonsNew}{}
\xmpLine{drawRibbons([x^i for i in 1..5], x=-1..1, y=0..2)}{\bf{Ribbon Plot}}
\end{xmpLinesPlain}


%\input{gallery/conformal.htex}
% *********************************************************************
\head{section}{conformal.input}{ugFconformal}
% *********************************************************************
%
The functions in this section draw conformal maps both on the
\index{conformal map}
plane and on the Riemann sphere.
\index{Riemann!sphere}

%-- Compile, don't interpret functions.
%\xmpLine{)set fun comp on}{}
\begin{xmpLinesPlain}
\xmpLine{C := Complex DoubleFloat}{Complex Numbers}
\xmpLine{S := Segment DoubleFloat}{Draw ranges}
\xmpLine{R3 := Point DFLOAT}{Points in 3-space}
\xmpLine{ }{}
\end{xmpLinesPlain}

\userfun{conformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)}
draws the image of the coordinate grid under {\it f} in the complex plane.
The grid may be given in either polar or Cartesian coordinates.
Argument {\it f} is the function to draw;
{\it rRange} is the range of the radius (in polar) or real (in Cartesian);
{\it tRange} is the range of \texht{$\theta$}{\theta} (in polar) or imaginary (in Cartesian);
{\it tSteps, rSteps}, are the number of intervals in the {\it r} and
\texht{$\theta$}{\theta} directions; and
{\it coord} is the coordinate system to use (either {\tt "polar"} or
{\tt "cartesian"}).

\begin{xmpLinesNoResetPlain}
\xmpLine{conformalDraw: (C -> C, S, S, PI, PI, String) -> VIEW3D}{}
\xmpLine{conformalDraw(f,rRange,tRange,rSteps,tSteps,coord) ==}{}
\xmpLine{  transformC :=}{Function for changing an \smath{(x,y)}}
\xmpLine{    coord = "polar" => polar2Complex}{\quad{}pair into a complex number.}
\xmpLine{    cartesian2Complex}{}
\xmpLine{  cm := makeConformalMap(f, transformC)}{}
\xmpLine{  sp := createThreeSpace()}{Create a fresh space.}
\xmpLine{  adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps)}{Plot the coordinate lines.}
\xmpLine{  makeViewport3D(sp, "Conformal Map")}{Draw the image.}
\end{xmpLinesNoResetPlain}

\userfun{riemannConformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)}
draws the image of the coordinate grid under {\it f} on the Riemann sphere.
The grid may be given in either polar or Cartesian coordinates.
Its arguments are the same as those for \userfun{conformalDraw}.
\begin{xmpLinesNoResetPlain}
\xmpLine{riemannConformalDraw:(C->C,S,S,PI,PI,String)->VIEW3D}{}
\xmpLine{riemannConformalDraw(f, rRange, tRange,}{}
\xmpLine{                     rSteps, tSteps, coord) ==}{}
\xmpLine{  transformC :=}{Function for changing an \smath{(x,y)}}
\xmpLine{    coord = "polar" => polar2Complex}{\quad{}pair into a complex number.}
\xmpLine{    cartesian2Complex}{}
\xmpLine{  sp := createThreeSpace()}{Create a fresh space.}
\xmpLine{  cm := makeRiemannConformalMap(f, transformC)}{}
\xmpLine{  adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps)}{Plot the coordinate lines.}
\xmpLine{  curve(sp,[point [0,0,2.0@DFLOAT,0],point [0,0,2.0@DFLOAT,0]])}{Add an invisible point at}
\xmpLine{  makeViewport3D(sp,"Map on the Riemann Sphere")}{\quad{}the north pole for scaling.}
\xmpLine{}{}
\xmpLine{adaptGrid(sp, f, uRange, vRange,  uSteps, vSteps) ==}{Plot the coordinate grid}
\xmpLine{  delU := (high(uRange) - low(uRange))/uSteps}{\quad{}using adaptive plotting for}
\xmpLine{  delV := (high(vRange) - low(vRange))/vSteps}{\quad{}coordinate lines, and draw}
\xmpLine{  uSteps := uSteps + 1; vSteps := vSteps + 1}{\quad{}tubes around the lines.}
\xmpLine{  u := low uRange}{}
\xmpLine{  for i in 1..uSteps repeat}{Draw coordinate lines in the \spad{v}}
\xmpLine{    c := curryLeft(f,u)}{\quad{}direction; curve \spad{c} fixes the}
\xmpLine{    cf := (t:DFLOAT):DFLOAT +-> 0}{\quad{}current value of \spad{u}.}
\xmpLine{    makeObject(c,vRange::SEG Float,colorFunction==cf,}{Draw the \spad{v} coordinate line.}
\xmpLine{      space == sp, tubeRadius == .02, tubePoints == 6)}{}
\xmpLine{    u := u + delU}{}
\xmpLine{  v := low vRange}{}
\xmpLine{  for i in 1..vSteps repeat}{Draw coordinate lines in the \spad{u}}
\xmpLine{    c := curryRight(f,v)}{\quad{}direction; curve \spad{c} fixes the}
\xmpLine{    cf := (t:DFLOAT):DFLOAT +-> 1}{\quad{}current value of \spad{v}.}
\xmpLine{    makeObject(c,uRange::SEG Float,colorFunction==cf,}{Draw the \spad{u} coordinate line.}
\xmpLine{      space == sp, tubeRadius == .02, tubePoints == 6)}{}
\xmpLine{    v := v + delV}{}
\xmpLine{  void()}{}
\xmpLine{}{}
\xmpLine{riemannTransform(z) ==}{Map a point in the complex}
\xmpLine{  r := sqrt norm z}{\quad{}plane to the Riemann sphere.}
\xmpLine{  cosTheta := (real z)/r}{}
\xmpLine{  sinTheta := (imag z)/r}{}
\xmpLine{  cp := 4*r/(4+r^2)}{}
\xmpLine{  sp := sqrt(1-cp*cp)}{}
\xmpLine{  if r>2 then sp := -sp}{}
\xmpLine{  point [cosTheta*cp, sinTheta*cp, -sp + 1]}{}
\xmpLine{ }{}
\xmpLine{cartesian2Complex(r:DFLOAT, i:DFLOAT):C ==}{Convert Cartesian coordinates to}
\xmpLine{  complex(r, i)}{\quad{}complex Cartesian form.}
\xmpLine{}{}
\xmpLine{polar2Complex(r:DFLOAT, th:DFLOAT):C == }{Convert polar coordinates to}
\xmpLine{  complex(r*cos(th), r*sin(th))}{\quad{}complex Cartesian form.}
\xmpLine{}{}
\xmpLine{makeConformalMap(f, transformC) ==}{Convert complex function \spad{f}}
\xmpLine{  (u:DFLOAT,v:DFLOAT):R3 +-> }{\quad{}to a mapping: (\spadtype{DFLOAT},\spadtype{DFLOAT}) $\mapsto$ \pspadtype{R3}}
\xmpLine{    z := f transformC(u, v)}{\quad{}in the complex plane.}
\xmpLine{    point [real z, imag z, 0.0@DFLOAT]}{}
\xmpLine{ }{}
\xmpLine{makeRiemannConformalMap(f, transformC) ==}{Convert a complex function \spad{f}}
\xmpLine{  (u:DFLOAT, v:DFLOAT):R3 +->}{\quad{}to a mapping: (\spadtype{DFLOAT},\spadtype{DFLOAT}) $\mapsto$ \spadtype{R3}}
\xmpLine{    riemannTransform f transformC(u, v)}{\quad{}on the Riemann sphere.}
\xmpLine{}{}
\xmpLine{riemannSphereDraw: (S, S, PI, PI, String) -> VIEW3D}{Draw a picture of the mapping}
\xmpLine{riemannSphereDraw(rRange,tRange,rSteps,tSteps,coord) ==}{\quad{}of the complex plane to}
\xmpLine{  transformC :=}{\quad{}the Riemann sphere.}
\xmpLine{    coord = "polar" => polar2Complex}{}
\xmpLine{    cartesian2Complex}{}
\xmpLine{  grid := (u:DFLOAT, v:DFLOAT): R3 +-> }{Coordinate grid function.}
\xmpLine{    z1 := transformC(u, v)}{}
\xmpLine{    point [real z1, imag z1, 0]}{}
\xmpLine{  sp := createThreeSpace()}{Create a fresh space.}
\xmpLine{  adaptGrid(sp, grid, rRange, tRange, rSteps, tSteps)}{Draw the flat grid.}
\xmpLine{  connectingLines(sp,grid,rRange,tRange,rSteps,tSteps)}{}
\xmpLine{  makeObject(riemannSphere,0..2*\%pi,0..\%pi,space==sp)}{Draw the sphere.}
\xmpLine{  f := (z:C):C +-> z}{}
\xmpLine{  cm := makeRiemannConformalMap(f, transformC)}{}
\xmpLine{  adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps)}{Draw the sphere grid.}
\xmpLine{  makeViewport3D(sp, "Riemann Sphere")}{}
\xmpLine{ }{}
\xmpLine{connectingLines(sp,f,uRange,vRange,uSteps,vSteps) ==}{Draw the lines that connect}
\xmpLine{  delU := (high(uRange) - low(uRange))/uSteps}{\quad{}the points in the complex}
\xmpLine{  delV := (high(vRange) - low(vRange))/vSteps}{\quad{}plane to the north pole}
\xmpLine{  uSteps := uSteps + 1; vSteps := vSteps + 1}{\quad{}of the Riemann sphere.}
\xmpLine{  u := low uRange}{}
\xmpLine{  for i in 1..uSteps repeat}{For each u.}
\xmpLine{    v := low vRange}{}
\xmpLine{    for j in 1..vSteps repeat}{For each v.}
\xmpLine{      p1 := f(u,v)}{}
\xmpLine{      p2 := riemannTransform complex(p1.1, p1.2)}{Project p1 onto the sphere.}
\xmpLine{      fun := lineFromTo(p1,p2)}{Create a line function.}
\xmpLine{      cf := (t:DFLOAT):DFLOAT +-> 3}{}
\xmpLine{      makeObject(fun, 0..1,space==sp,tubePoints==4,}{Draw the connecting line.}
\xmpLine{                 tubeRadius==0.01,colorFunction==cf)}{}
\xmpLine{      v := v + delV}{}
\xmpLine{    u := u + delU}{}
\xmpLine{  void()}{}
\xmpLine{ }{}
\xmpLine{riemannSphere(u,v) == }{A sphere sitting on the}
\xmpLine{  sv := sin(v)}{\quad{}complex plane, with radius 1.}
\xmpLine{  0.99@DFLOAT*(point [cos(u)*sv,sin(u)*sv,cos(v),0.0@DFLOAT])+}{}
\xmpLine{    point [0.0@DFLOAT, 0.0@DFLOAT, 1.0@DFLOAT, 4.0@DFLOAT]}{}
\xmpLine{ }{}
\xmpLine{lineFromTo(p1, p2) ==}{Create a line function}
\xmpLine{  d := p2 - p1}{\quad{}that goes from p1 to p2}
\xmpLine{  (t:DFLOAT):Point DFLOAT +->}{}
\xmpLine{    p1 + t*d}{}
\end{xmpLinesNoResetPlain}

%\input{gallery/tknot.htex}
% *********************************************************************
\head{section}{tknot.input}{ugFtknot}
% *********************************************************************
%
Create a $(p,q)$ torus-knot with radius $r$ around the curve.
The formula was derived by Larry Lambe.

\begin{xmpLinesPlain}
\xmpLine{)read ntube}{}
\xmpLine{torusKnot: (DFLOAT, DFLOAT, DFLOAT, PI, PI) -> VIEW3D}{}
\xmpLine{torusKnot(p, q ,r, uSteps, tSteps) ==}{}
\xmpLine{  knot := (t:DFLOAT):Point DFLOAT +-> }{Function for the torus knot.}
\xmpLine{    fac := 4/(2.2@DFLOAT-sin(q*t))}{}
\xmpLine{    fac * point [cos(p*t), sin(p*t), cos(q*t)]}{}
\xmpLine{  circle := (u:DFLOAT, t:DFLOAT): Point DFLOAT +->}{The cross section.}
\xmpLine{    r * point [cos u, sin u]}{}
\xmpLine{  ntubeDrawOpt(knot, circle, 0..2*\%pi, 0..2*\%pi,}{Draw the circle around the knot.}
\xmpLine{               var1Steps == uSteps, var2Steps == tSteps)}{}
\xmpLine{}{}
\end{xmpLinesPlain}

%\input{gallery/ntube.htex}
% *********************************************************************
\head{section}{ntube.input}{ugFntube}
% *********************************************************************
%
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.

\begin{xmpLinesPlain}
\xmpLine{R3 := Point DFLOAT}{Points in 3-Space}
\xmpLine{R2 := Point DFLOAT}{Points in 2-Space}
\xmpLine{S := Segment Float}{Draw ranges}
\xmpLine{}{Introduce types for functions for:}
\xmpLine{ThreeCurve := DFLOAT -> R3}{\quad{}---the space curve function}
\xmpLine{TwoCurve := (DFLOAT, DFLOAT) -> R2}{\quad{}---the plane curve function}
\xmpLine{Surface := (DFLOAT, DFLOAT) -> R3}{\quad{}---the surface function}
\xmpLine{}{Frenet frames define a}
\xmpLine{FrenetFrame := }{\quad{}coordinate system around a}
\xmpLine{   Record(value:R3,tangent:R3,normal:R3,binormal:R3)}{\quad{}point on a space curve.}
\xmpLine{frame: FrenetFrame}{The current Frenet frame}
\xmpLine{}{\quad{}for a point on a curve.}
\end{xmpLinesPlain}

\userfun{ntubeDraw}{\it (spaceCurve, planeCurve,}
$u_0 .. u_1,$ $t_0 .. t_1)$
draws {\it planeCurve} in the normal planes of {\it spaceCurve.}
The parameter $u_0 .. u_1$ specifies
the parameter range for {\it planeCurve}
and $t_0 .. t_1$ specifies the parameter range for {\it spaceCurve}.
Additionally, the plane curve function takes
a second parameter: the current parameter of {\it spaceCurve}.
This allows the plane curve to change shape
as it goes around the space curve.
See \spadref{ugFimagesFive} for an example of this.
%
\begin{xmpLinesNoResetPlain}
\xmpLine{ntubeDraw: (ThreeCurve,TwoCurve,S,S) -> VIEW3D}{}
\xmpLine{ntubeDraw(spaceCurve,planeCurve,uRange,tRange) ==}{}
\xmpLine{  ntubeDrawOpt(spaceCurve, planeCurve, uRange, \_}{}
\xmpLine{               tRange, []\$List DROPT)}{}
\xmpLine{ }{}
\xmpLine{ntubeDrawOpt: (ThreeCurve,TwoCurve,S,S,List DROPT)}{}
\xmpLine{    -> VIEW3D}{}
\xmpLine{ntubeDrawOpt(spaceCurve,planeCurve,uRange,tRange,l) ==}{This function is similar}
\xmpLine{          }{\quad{}to \userfun{ntubeDraw}, but takes}
\xmpLine{  delT:DFLOAT := (high(tRange) - low(tRange))/10000}{\quad{}optional parameters that it}
\xmpLine{  oldT:DFLOAT := low(tRange) - 1}{\quad{}passes to the \spadfun{draw} command.}
\xmpLine{  fun := ngeneralTube(spaceCurve,planeCurve,delT,oldT)}{}
\xmpLine{  draw(fun, uRange, tRange, l)}{}
\xmpLine{}{}
\end{xmpLinesNoResetPlain}

\userfun{nfrenetFrame}{\it (c, t, delT)}
numerically computes the Frenet frame
about the curve {\it c} at {\it t}.
Parameter {\it delT} is a small number used to
compute derivatives.
\begin{xmpLinesNoResetPlain}
\xmpLine{nfrenetFrame(c, t, delT) ==}{}
\xmpLine{  f0 := c(t)}{}
\xmpLine{  f1 := c(t+delT)}{}
\xmpLine{  t0 := f1 - f0}{The tangent.}
\xmpLine{  n0 := f1 + f0                }{}
\xmpLine{  b := cross(t0, n0)}{The binormal.}
\xmpLine{  n := cross(b,t0)}{The normal.}
\xmpLine{  ln := length n}{}
\xmpLine{  lb := length b}{}
\xmpLine{  ln = 0 or lb = 0 =>}{}
\xmpLine{      error "Frenet Frame not well defined"}{}
\xmpLine{  n := (1/ln)*n}{Make into unit length vectors.}
\xmpLine{  b := (1/lb)*b}{}
\xmpLine{  [f0, t0, n, b]\$FrenetFrame}{}
\end{xmpLinesNoResetPlain}

\userfun{ngeneralTube}{\it (spaceCurve, planeCurve,}{\it  delT, oltT)}
creates a function that can be passed to the system \spadfun{draw} command.
The function is a parameterized surface for the general tube
around {\it spaceCurve}.  {\it delT} is a small number used to compute
derivatives. {\it oldT} is used to hold the current value of the
{\it t} parameter for {\it spaceCurve.}  This is an efficiency measure
to ensure that frames are only computed once for each value of {\it t}.
\begin{xmpLinesNoResetPlain}
\xmpLine{ngeneralTube: (ThreeCurve, TwoCurve, DFLOAT, DFLOAT) -> Surface}{}
\xmpLine{ngeneralTube(spaceCurve, planeCurve, delT, oldT) ==}{}
\xmpLine{  free frame}{Indicate that \spad{frame} is global.}
\xmpLine{  (v:DFLOAT, t: DFLOAT): R3 +->}{}
\xmpLine{    if (t \texht{$\sim$}{~}= oldT) then}{If not already computed,}
\xmpLine{      frame := nfrenetFrame(spaceCurve, t, delT)}{\quad{}compute new frame.}
\xmpLine{      oldT := t}{}
\xmpLine{    p := planeCurve(v, t)}{}
\xmpLine{    frame.value + p.1*frame.normal + p.2*frame.binormal}{Project \spad{p} into the normal plane.}
\end{xmpLinesNoResetPlain}

%\input{gallery/dhtri.htex}
% *********************************************************************
\head{section}{dhtri.input}{ugFdhtri}
% *********************************************************************
%
Create affine transformations (DH matrices) that transform
a given triangle into another.

\begin{xmpLinesPlain}
\xmpLine{tri2tri: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT)}{Compute a \spadtype{DHMATRIX} that}
\xmpLine{tri2tri(t1, t2) ==}{\quad{}transforms \spad{t1} to \spad{t2,} where}
\xmpLine{  n1 := triangleNormal(t1)}{\quad{}\spad{t1} and \spad{t2} are the vertices}
\xmpLine{  n2 := triangleNormal(t2)}{\quad{}of two triangles in 3-space.}
\xmpLine{  tet2tet(concat(t1, n1), concat(t2, n2))}{}
\xmpLine{ }{}
\xmpLine{tet2tet: (List Point DFLOAT, List Point DFLOAT) -> DHMATRIX(DFLOAT)}{Compute a \spadtype{DHMATRIX} that}
\xmpLine{tet2tet(t1, t2) ==}{\quad{}transforms \spad{t1} to \spad{t2,}}
\xmpLine{  m1 := makeColumnMatrix t1}{\quad{}where \spad{t1} and \spad{t2} are the}
\xmpLine{  m2 := makeColumnMatrix t2}{\quad{}vertices of two tetrahedrons}
\xmpLine{  m2 * inverse(m1)}{\quad{}in 3-space.}
\xmpLine{ }{}
\xmpLine{makeColumnMatrix(t) ==}{Put the vertices of a tetra-}
\xmpLine{  m := new(4,4,0)\$DHMATRIX(DFLOAT)}{\quad{}hedron into matrix form.}
\xmpLine{  for x in t for i in 1..repeat}{}
\xmpLine{    for j in 1..3 repeat}{}
\xmpLine{      m(j,i) := x.j}{}
\xmpLine{    m(4,i) := 1}{}
\xmpLine{  m}{}
\xmpLine{ }{}
\xmpLine{triangleNormal(t) ==}{Compute a vector normal to}
\xmpLine{  a := triangleArea t}{\quad{}the given triangle, whose}
\xmpLine{  p1 := t.2 - t.1}{\quad{}length is the square root}
\xmpLine{  p2 := t.3 - t.2}{\quad{}of the area of the triangle.}
\xmpLine{  c := cross(p1, p2)}{}
\xmpLine{  len := length(c)}{}
\xmpLine{  len = 0 => error "degenerate triangle!"}{}
\xmpLine{  c := (1/len)*c}{}
\xmpLine{  t.1 + sqrt(a) * c}{}
\xmpLine{ }{}
\xmpLine{triangleArea t ==}{Compute the area of a}
\xmpLine{  a := length(t.2 - t.1)}{\quad{}triangle using Heron's}
\xmpLine{  b := length(t.3 - t.2)}{\quad{}formula.}
\xmpLine{  c := length(t.1 - t.3)}{}
\xmpLine{  s := (a+b+c)/2}{}
\xmpLine{  sqrt(s*(s-a)*(s-b)*(s-c))}{}
\end{xmpLinesPlain}


% *********************************************************************
\head{section}{tetra.input}{ugFtetra}
% *********************************************************************
%
%\input{gallery/tetra.htex}
%\outdent{Sierpinsky's Tetrahedron}

\labelSpace{3pc}

\begin{xmpLinesPlain}
\xmpLine{)set expose add con DenavitHartenbergMatrix}{Bring DH matrices into the}
\xmpLine{}{\quad{}environment.}
\xmpLine{x1:DFLOAT := sqrt(2.0@DFLOAT/3.0@DFLOAT)}{Set up the coordinates of the}
\xmpLine{x2:DFLOAT := sqrt(3.0@DFLOAT)/6}{\quad{}corners of the tetrahedron.}
\xmpLine{}{}
\xmpLine{p1 := point [-0.5@DFLOAT, -x2, 0.0@DFLOAT]}{Some needed points.}
\xmpLine{p2 := point [0.5@DFLOAT, -x2, 0.0@DFLOAT]}{}
\xmpLine{p3 := point [0.0@DFLOAT, 2*x2, 0.0@DFLOAT]}{}
\xmpLine{p4 := point [0.0@DFLOAT, 0.0@DFLOAT, x1]}{}
\xmpLine{ }{}
\xmpLine{baseTriangle  := [p2, p1, p3]}{The base of the tetrahedron.}
\xmpLine{}{}
\xmpLine{mt  := [0.5@DFLOAT*(p2+p1), 0.5@DFLOAT*(p1+p3), 0.5@DFLOAT*(p3+p2)]}{The ``middle triangle'' inscribed}
\xmpLine{}{\quad{}in the base of the tetrahedron.}
\xmpLine{bt1 := [mt.1, p1, mt.2]}{The bases of the triangles of}
\xmpLine{bt2 := [p2, mt.1, mt.3]}{\quad{}the subdivided tetrahedron.}
\xmpLine{bt3 := [mt.2, p3, mt.3]}{}
\xmpLine{bt4 := [0.5@DFLOAT*(p2+p4), 0.5@DFLOAT*(p1+p4), 0.5@DFLOAT*(p3+p4)]}{}
\xmpLine{}{}
\xmpLine{tt1 := tri2tri(baseTriangle, bt1)}{Create the transformations}
\xmpLine{tt2 := tri2tri(baseTriangle, bt2)}{\quad{}that bring the base of the}
\xmpLine{tt3 := tri2tri(baseTriangle, bt3)}{\quad{}tetrahedron to the bases of}
\xmpLine{tt4 := tri2tri(baseTriangle, bt4)}{\quad{}the subdivided tetrahedron.}
\xmpLine{}{}
\xmpLine{drawPyramid(n) ==}{Draw a Sierpinsky tetrahedron}
\xmpLine{  s := createThreeSpace()}{\quad{}with \spad{n} levels of recursive}
\xmpLine{  dh := rotatex(0.0@DFLOAT)}{\quad{}subdivision.}
\xmpLine{  drawPyramidInner(s, n, dh)}{}
\xmpLine{  makeViewport3D(s, "Sierpinsky Tetrahedron")}{}
\xmpLine{}{}
\xmpLine{drawPyramidInner(s, n, dh) ==}{Recursively draw a Sierpinsky}
\xmpLine{  n = 0 => makeTetrahedron(s, dh, n)}{\quad{}tetrahedron.}
\xmpLine{  drawPyramidInner(s, n-1, dh * tt1)}{Draw the 4 recursive pyramids.}
\xmpLine{  drawPyramidInner(s, n-1, dh * tt2)}{}
\xmpLine{  drawPyramidInner(s, n-1, dh * tt3)}{}
\xmpLine{  drawPyramidInner(s, n-1, dh * tt4)}{}
\xmpLine{}{}
\xmpLine{makeTetrahedron(sp, dh, color) ==}{Draw a tetrahedron into the}
\xmpLine{  w1 := dh*p1}{\quad{}given space with the given}
\xmpLine{  w2 := dh*p2}{\quad{}color, transforming it by}
\xmpLine{  w3 := dh*p3}{\quad{}the given DH matrix.}
\xmpLine{  w4 := dh*p4}{}
\xmpLine{  polygon(sp, [w1, w2, w4])}{}
\xmpLine{  polygon(sp, [w1, w3, w4])}{}
\xmpLine{  polygon(sp, [w2, w3, w4])}{}
\xmpLine{  void()}{}
\end{xmpLinesPlain}
\index{Sierpinsky's Tetrahedron}


%\input{gallery/antoine.htex}
% *********************************************************************
\head{section}{antoine.input}{ugFantoine}
% *********************************************************************
%
Draw Antoine's Necklace.
\index{Antoine's Necklace}
Thank you to Matthew Grayson at IBM's T.J Watson Research Center for the idea.

\begin{xmpLinesPlain}
\xmpLine{)set expose add con DenavitHartenbergMatrix}{Bring DH matrices into}
\xmpLine{}{\quad{}the environment.}
\xmpLine{torusRot: DHMATRIX(DFLOAT)}{The current transformation for}
\xmpLine{}{\quad{}drawing a sub ring.}
\xmpLine{}{}
\xmpLine{drawRings(n) ==}{Draw Antoine's Necklace with \spad{n}}{}
\xmpLine{  s := createThreeSpace()}{\quad{}levels of recursive subdivision.}
\xmpLine{  dh:DHMATRIX(DFLOAT) := identity()}{\quad{}The number of subrings is $10^n$.}
\xmpLine{  drawRingsInner(s, n, dh)}{Do the real work.}
\xmpLine{  makeViewport3D(s, "Antoine's Necklace")}{}
\xmpLine{}{}
\end{xmpLinesPlain}

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 \spadtype{DHMATRIX} operations are used to build up
the proper matrix composing all these transformations.

\begin{xmpLinesNoResetPlain}
\xmpLine{drawRingsInner(s, n, dh) ==}{Recursively draw Antoine's}
\xmpLine{  n = 0 =>}{\quad{}Necklace.}
\xmpLine{    drawRing(s, dh)}{}
\xmpLine{    void()}{}
\xmpLine{  t := 0.0@DFLOAT}{Angle around ring.}
\xmpLine{  p := 0.0@DFLOAT}{Angle of subring from plane.}
\xmpLine{  tr := 1.0@DFLOAT}{Amount to translate subring.}
\xmpLine{  inc := 0.1@DFLOAT}{The translation increment.}{}
\xmpLine{  for i in 1..10 repeat}{Subdivide into 10 linked rings.}
\xmpLine{    tr := tr + inc}{}
\xmpLine{    inc := -inc}{}
\xmpLine{    dh' := dh*rotatez(t)*translate(tr,0.0@DFLOAT,0.0@DFLOAT)*}{Transform ring in center}
\xmpLine{           rotatey(p)*scale(0.35@DFLOAT, 0.48@DFLOAT, 0.4@DFLOAT)}{\quad{}to a link.}
\xmpLine{    drawRingsInner(s, n-1, dh')}{}
\xmpLine{    t := t + 36.0@DFLOAT}{}
\xmpLine{    p := p + 90.0@DFLOAT}{}
\xmpLine{  void()}{}
\xmpLine{}{}
\xmpLine{drawRing(s, dh) ==}{Draw a single ring into}
\xmpLine{  free torusRot}{\quad{}the given subspace,}
\xmpLine{  torusRot := dh}{\quad{}transformed by the given}
\xmpLine{  makeObject(torus, 0..2*\%pi, 0..2*\%pi, var1Steps == 6,}{\quad{}\spadtype{DHMATRIX}.}
\xmpLine{             space == s, var2Steps == 15)}{}
\xmpLine{}{}
\xmpLine{torus(u ,v) ==}{Parameterization of a torus,}{}
\xmpLine{  cu := cos(u)/6}{\quad{}transformed by the}
\xmpLine{  torusRot*point [(1+cu)*cos(v),(1+cu)*sin(v),(sin u)/6]}{\quad{}\spadtype{DHMATRIX} in \spad{torusRot.}}
\end{xmpLinesNoResetPlain}

%\input{gallery/scherk.htex}
% *********************************************************************
\head{section}{scherk.input}{ugFscherk}
% *********************************************************************
%

Scherk's minimal surface, defined by:
\index{Scherk's minimal surface}
\texht{$e^z \cos(x) = \cos(y)$}{\spad{exp(z) * cos(x) = cos(y)}}.
See: {\it A Comprehensive Introduction to Differential Geometry,} Vol. 3,
by Michael Spivak, Publish Or Perish, Berkeley, 1979, pp. 249-252.

\begin{xmpLinesPlain}
\xmpLine{(xOffset, yOffset):DFLOAT}{Offsets for a single piece}
\xmpLine{ }{\quad{}of Scherk's minimal surface.}
\xmpLine{}{}
\xmpLine{drawScherk(m,n) ==}{Draw Scherk's minimal surface}
\xmpLine{  free xOffset, yOffset}{\quad{}on an \spad{m} by \spad{n} patch.}
\xmpLine{  space := createThreeSpace()}{}
\xmpLine{  for i in 0..m-1 repeat}{}
\xmpLine{    xOffset := i*\%pi}{}
\xmpLine{    for j in 0 .. n-1 repeat}{}
\xmpLine{      rem(i+j, 2) = 0 => 'iter}{Draw only odd patches.}
\xmpLine{      yOffset := j*\%pi}{}
\xmpLine{      drawOneScherk(space)}{Draw a patch.}
\xmpLine{  makeViewport3D(space, "Scherk's Minimal Surface")}{}
\xmpLine{}{}
\xmpLine{scherk1(u,v) ==}{The first patch that makes}
\xmpLine{  x := cos(u)/exp(v)}{\quad{}up a single piece of}
\xmpLine{  point [xOffset + acos(x), yOffset + u, v, abs(v)]}{\quad{}Scherk's minimal surface.}
\xmpLine{ }{}
\xmpLine{scherk2(u,v) ==}{The second patch.}
\xmpLine{  x := cos(u)/exp(v)}{}
\xmpLine{  point [xOffset - acos(x), yOffset + u, v, abs(v)]}{}
\xmpLine{ }{}
\xmpLine{scherk3(u,v) == }{The third patch.}
\xmpLine{  x := exp(v) * cos(u)}{}
\xmpLine{  point [xOffset + u, yOffset + acos(x), v, abs(v)]}{}
\xmpLine{ }{}
\xmpLine{scherk4(u,v) == }{The fourth patch.}
\xmpLine{  x := exp(v) * cos(u)}{}
\xmpLine{  point [xOffset + u, yOffset - acos(x), v, abs(v)]}{}
\xmpLine{ }{}
\xmpLine{drawOneScherk(s) ==}{Draw the surface by}
\xmpLine{  makeObject(scherk1,-\%pi/2..\%pi/2,0..\%pi/2,space==s,}{\quad{}breaking it into four}
\xmpLine{             var1Steps == 28, var2Steps == 28)}{\quad{}patches and then drawing}
\xmpLine{  makeObject(scherk2,-\%pi/2..\%pi/2,0..\%pi/2,space==s,}{\quad{}the patches.}
\xmpLine{             var1Steps == 28, var2Steps == 28)}{}
\xmpLine{  makeObject(scherk3,-\%pi/2..\%pi/2,-\%pi/2..0,space==s,}{}
\xmpLine{             var1Steps == 28, var2Steps == 28)}{}
\xmpLine{  makeObject(scherk4,-\%pi/2..\%pi/2,-\%pi/2..0,space==s,}{}
\xmpLine{             var1Steps == 28, var2Steps == 28)}{}
\xmpLine{  void()}{}
\end{xmpLinesPlain}
