\documentclass{article}
\usepackage{open-axiom}
\begin{document}
\title{\$SPAD/src/algebra drawpak.spad}
\author{The Axiom Team}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{package DRAWCX DrawComplex}
<<package DRAWCX DrawComplex>>=
)abbrev package DRAWCX DrawComplex
++ Description: \axiomType{DrawComplex} provides some facilities
++ for drawing complex functions.
C ==> Complex DoubleFloat
S ==> Segment DoubleFloat
PC ==> Record(rr:SF, th:SF)
INT ==> Integer
SF ==> DoubleFloat
NNI ==> NonNegativeInteger
VIEW3D ==> ThreeDimensionalViewport
ARRAY2 ==> TwoDimensionalArray
 
DrawComplex(): Exports == Implementation where
  Exports == with
    drawComplex: (C -> C,S,S,Boolean) -> VIEW3D
      ++ drawComplex(f,rRange,iRange,arrows?)
      ++ draws a complex function as a height field.
      ++ It uses the complex norm as the height and the complex argument as the color.
      ++ It will optionally draw arrows on the surface indicating the direction
      ++ of the complex value.\newline
      ++ Sample call:
      ++   \spad{f z == exp(1/z)}
      ++   \spad{drawComplex(f, 0.3..3, 0..2*%pi, false)}
      ++ Parameter descriptions:
      ++   f:  the function to draw
      ++   rRange : the range of the real values
      ++   iRange : the range of imaginary values
      ++   arrows? : a flag indicating whether to draw the phase arrows for f
      ++ Call the functions \axiomFunFrom{setRealSteps}{DrawComplex} and 
      ++ \axiomFunFrom{setImagSteps}{DrawComplex} to change the
      ++ number of steps used in each direction.
    drawComplexVectorField: (C -> C,S,S) -> VIEW3D
      ++ drawComplexVectorField(f,rRange,iRange)
      ++ draws a complex vector field using arrows on the \spad{x--y} plane.
      ++ These vector fields should be viewed from the top by pressing the
      ++ "XY" translate button on the 3-d viewport control panel.\newline
      ++ Sample call:
      ++    \spad{f z == sin z}
      ++    \spad{drawComplexVectorField(f, -2..2, -2..2)}
      ++ Parameter descriptions:
      ++   f : the function to draw
      ++   rRange : the range of the real values
      ++   iRange : the range of the imaginary values
      ++ Call the functions \axiomFunFrom{setRealSteps}{DrawComplex} and 
      ++ \axiomFunFrom{setImagSteps}{DrawComplex} to change the
      ++ number of steps used in each direction.
    setRealSteps: INT -> INT
      ++ setRealSteps(i)
      ++ sets to i the number of steps to use in the real direction 
      ++ when drawing complex functions. Returns i.
    setImagSteps: INT -> INT
      ++ setImagSteps(i)
      ++ sets to i  the number of steps to use in the imaginary direction
      ++ when drawing complex functions. Returns i.
    setClipValue: SF-> SF
      ++ setClipValue(x)
      ++ sets to x the maximum value to plot when drawing complex functions. Returns x.
  Implementation == add
    -- relative size of the arrow head compared to the length of the arrow
    arrowScale : SF := (0.125)::SF
    arrowAngle: SF := pi()-pi()/(20::SF)    -- angle of the arrow head
    realSteps: INT  := 11     -- the number of steps in the real direction
    imagSteps: INT  := 11     -- the number of steps in the imaginary direction
    clipValue: SF  := 10::SF -- the maximum length of a vector to draw
 
 
    -- Add an arrow head to a line segment, which starts at 'p1', ends at 'p2',
    -- has length 'len', and and angle 'arg'.  We pass 'len' and 'arg' as
    -- arguments since thet were already computed by the calling program
    makeArrow(p1:Point SF, p2:Point SF, len: SF, arg:SF):List List Point SF ==
      c1 := cos(arg + arrowAngle) 
      s1 := sin(arg + arrowAngle)
      c2 := cos(arg - arrowAngle) 
      s2 := sin(arg - arrowAngle)
      p3 := point [p2.1 + c1*arrowScale*len, p2.2 + s1*arrowScale*len, 
                   p2.3, p2.4]
      p4 := point [p2.1 + c2*arrowScale*len, p2.2 + s2*arrowScale*len, 
                   p2.3, p2.4]
      [[p1, p2, p3], [p2, p4]]
     
    -- clip a value in the interval (-clip...clip)
    clipFun(x:SF):SF == 
      min(max(x, -clipValue), clipValue)
 
    drawComplex(f, realRange, imagRange, arrows?) ==
      import Point SF
      delReal := (hi(realRange) - lo(realRange))/realSteps::SF
      delImag := (hi(imagRange) - lo(imagRange))/imagSteps::SF
      funTable: ARRAY2(PC) := 
         new((realSteps::NNI)+1, (imagSteps::NNI)+1, [0,0]$PC)
      real := lo(realRange)
      for i in 1..realSteps+1 repeat
        imag := lo(imagRange)
        for j in 1..imagSteps+1 repeat
          z := f complex(real, imag)
          funTable(i,j) := [clipFun(sqrt norm z), argument(z)]$PC
          imag := imag + delImag
        real := real + delReal
      llp := empty()$(List List Point SF)
      real := lo(realRange)
      for i in 1..realSteps+1 repeat
        imag := lo(imagRange)
        lp := empty()$(List Point SF)
        for j in 1..imagSteps+1 repeat
          p := point [real, imag, funTable(i,j).rr, funTable(i,j).th]
          lp := cons(p, lp)
          imag := imag + delImag
        real := real + delReal
        llp := cons(lp, llp)
      space := mesh(llp)$(ThreeSpace SF)
      if arrows? then 
        real := lo(realRange)
        for i in 1..realSteps+1 repeat
          imag := lo(imagRange)
          for j in 1..imagSteps+1 repeat
            arg := funTable(i,j).th
            p1 := point [real,imag, funTable(i,j).rr, arg]
            len := delReal*2.0::SF
            p2 := point [p1.1 + len*cos(arg), p1.2 + len*sin(arg), 
                         p1.3, p1.4]
            arrow := makeArrow(p1, p2, len, arg)
            for a in arrow repeat curve(space, a)$(ThreeSpace SF)
            imag := imag + delImag
          real := real + delReal
      makeViewport3D(space, "Complex Function")$VIEW3D
 
    drawComplexVectorField(f, realRange, imagRange): VIEW3D ==
      import Point SF
      -- compute the steps size of the grid
      delReal := (hi(realRange) - lo(realRange))/realSteps::SF
      delImag := (hi(imagRange) - lo(imagRange))/imagSteps::SF
      -- create the space to hold the arrows
      space := create3Space()$(ThreeSpace SF)
      real := lo(realRange)
      for i in 1..realSteps+1 repeat
        imag := lo(imagRange)
        for j in 1..imagSteps+1 repeat
          -- compute the function
          z := f complex(real, imag)
          -- get the direction of the arrow
          arg := argument z
          -- get the length of the arrow
          len := clipFun(sqrt norm z)
          -- create point at the base of the arrow
          p1 :=  point [real, imag, 0::SF, arg]
          -- scale the arrow length so it isn't too long
          scaleLen := delReal * len
          -- create the point at the top of the arrow
          p2 := point [p1.1 + scaleLen*cos(arg), p1.2 + scaleLen*sin(arg), 
                       0::SF, arg]
          -- make the pointer at the top of the arrow
          arrow := makeArrow(p1, p2, scaleLen, arg)
          -- add the line segments in the arrow to the space
          for a in arrow repeat curve(space, a)$(ThreeSpace SF)
          imag := imag + delImag
        real := real + delReal
      -- draw the vector feild
      makeViewport3D(space, "Complex Vector Field")$VIEW3D
 
    -- set the number of steps to use in the real direction
    setRealSteps(n) ==
      realSteps := n
     
    -- set the number of steps to use in the imaginary direction
    setImagSteps(n) ==
      imagSteps := n
     
    -- set the maximum value to plot 
    setClipValue clip ==
      clipValue := clip

@
\section{License}
<<license>>=
--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.
@
<<*>>=
<<license>>

<<package DRAWCX DrawComplex>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}