\documentclass{article}
\usepackage{axiom}
\begin{document}
\title{\$SPAD/src/algebra view2D.spad}
\author{James Wen}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{domain GRIMAGE GraphImage}
<<domain GRIMAGE GraphImage>>=
)abbrev domain GRIMAGE GraphImage
++ Author: Jim Wen
++ Date Created: 27 April 1989
++ Date Last Updated: 1995 September 20, Mike Richardson (MGR)
++ Basic Operations:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description: TwoDimensionalGraph creates virtual two dimensional graphs
++ (to be displayed on TwoDimensionalViewports).
GraphImage (): Exports == Implementation where

  VIEW    ==> _$ViewportServer$Lisp
  sendI   ==> sockSendInt
  sendSF  ==> sockSendFloat
  sendSTR ==> sockSendString
  getI    ==> sockGetInt
  getSF   ==> sockGetFloat

  typeGRAPH  ==> 2
  typeVIEW2D ==> 3

  makeGRAPH  ==> (-1)$SingleInteger
  makeVIEW2D ==> (-1)$SingleInteger

  I   ==> Integer
  PI  ==> PositiveInteger
  NNI ==> NonNegativeInteger
  SF  ==> DoubleFloat
  F   ==> Float
  L   ==> List
  P   ==> Point(SF)
  V   ==> Vector
  SEG ==> Segment
  RANGESF   ==> L SEG SF
  RANGEF    ==> L SEG F
  UNITSF   ==> L SF
  UNITF    ==> L F
  PAL ==> Palette
  E   ==> OutputForm
  DROP ==> DrawOption
  PP ==> PointPackage(SF)
  COORDSYS ==> CoordinateSystems(SF)

  Exports ==> SetCategory with
    graphImage      :  ()                                        -> %
      ++ graphImage() returns an empty graph with 0 point lists
      ++ of the domain \spadtype{GraphImage}.  A graph image contains
      ++ the graph data component of a two dimensional viewport.
    makeGraphImage  :  %                                         -> %
      ++ makeGraphImage(gi) takes the given graph, \spad{gi} of the
      ++ domain \spadtype{GraphImage}, and sends it's data to the
      ++ viewport manager where it waits to be included in a two-dimensional
      ++ viewport window.  \spad{gi} cannot be an empty graph, and it's
      ++ elements must have been created using the \spadfun{point} or
      ++ \spadfun{component} functions, not by a previous
      ++ \spadfun{makeGraphImage}.
    makeGraphImage  :  (L L P)                                   -> %
      ++ makeGraphImage(llp) returns a graph of the domain
      ++ \spadtype{GraphImage} which is composed of the points and
      ++ lines from the list of lists of points, \spad{llp}, with
      ++ default point size and default point and line colours. The graph
      ++ data is then sent to the viewport manager where it waits to be
      ++ included in a two-dimensional viewport window.
    makeGraphImage  :  (L L P,L PAL,L PAL,L PI)                  -> %
      ++ makeGraphImage(llp,lpal1,lpal2,lp) returns a graph of the
      ++ domain \spadtype{GraphImage} which is composed of the points
      ++ and lines from the list of lists of points, \spad{llp}, whose
      ++ point colors are indicated by the list of palette colors,
      ++ \spad{lpal1}, and whose lines are colored according to the list
      ++ of palette colors, \spad{lpal2}.  The paramater lp is a list of
      ++ integers which denote the size of the data points.  The graph
      ++ data is then sent to the viewport manager where it waits to be
      ++ included in a two-dimensional viewport window.
    makeGraphImage  :  (L L P,L PAL,L PAL,L PI,L DROP)           -> %
      ++ makeGraphImage(llp,lpal1,lpal2,lp,lopt) returns a graph of
      ++ the domain \spadtype{GraphImage} which is composed of the
      ++ points and lines from the list of lists of points, \spad{llp},
      ++ whose point colors are indicated by the list of palette colors,
      ++ \spad{lpal1}, and whose lines are colored according to the list
      ++ of palette colors, \spad{lpal2}.  The paramater lp is a list of
      ++ integers which denote the size of the data points, and \spad{lopt}
      ++ is the list of draw command options.  The graph data is then sent
      ++ to the viewport manager where it waits to be included in a
      ++ two-dimensional viewport window.
    pointLists      :  %                                         -> L L P
      ++ pointLists(gi) returns the list of lists of points which compose
      ++ the given graph, \spad{gi}, of the domain \spadtype{GraphImage}.
    key             :  %                                         -> I
      ++ key(gi) returns the process ID of the given graph, \spad{gi},
      ++ of the domain \spadtype{GraphImage}.
    ranges          :  %                                         -> RANGEF
      ++ ranges(gi) returns the list of ranges of the point components from
      ++ the indicated graph, \spad{gi}, of the domain \spadtype{GraphImage}.
    ranges          :  (%,RANGEF)                                -> RANGEF
      ++ ranges(gi,lr) modifies the list of ranges for the given graph,
      ++ \spad{gi} of the domain \spadtype{GraphImage}, to be that of the
      ++ list of range segments, \spad{lr}, and returns the new range list
      ++ for \spad{gi}.
    units           :  %                                         -> UNITF
      ++ units(gi) returns the list of unit increments for the x and y
      ++ axes of the indicated graph, \spad{gi}, of the domain
      ++ \spadtype{GraphImage}.
    units           :  (%,UNITF)                                 -> UNITF
      ++ units(gi,lu) modifies the list of unit increments for the x and y
      ++ axes of the given graph, \spad{gi} of the domain
      ++ \spadtype{GraphImage}, to be that of the list of unit increments,
      ++ \spad{lu}, and returns the new list of units for \spad{gi}.
    component       :  (%,L P,PAL,PAL,PI)                        -> Void
      ++ component(gi,lp,pal1,pal2,p) sets the components of the
      ++ graph, \spad{gi} of the domain \spadtype{GraphImage}, to the
      ++ values given.  The point list for \spad{gi} is set to the list
      ++ \spad{lp}, the color of the points in \spad{lp} is set to
      ++ the palette color \spad{pal1}, the color of the lines which
      ++ connect the points \spad{lp} is set to the palette color
      ++ \spad{pal2}, and the size of the points in \spad{lp} is given
      ++ by the integer p.
    component       :  (%,P)                                     -> Void
      ++ component(gi,pt) modifies the graph \spad{gi} of the domain
      ++ \spadtype{GraphImage} to contain one point component, \spad{pt}
      ++ whose point color, line color and point size are determined by
      ++ the default functions \spadfun{pointColorDefault},
      ++ \spadfun{lineColorDefault}, and \spadfun{pointSizeDefault}.
    component       :  (%,P,PAL,PAL,PI)                          -> Void
      ++ component(gi,pt,pal1,pal2,ps) modifies the graph \spad{gi} of
      ++ the domain \spadtype{GraphImage} to contain one point component,
      ++ \spad{pt} whose point color is set to the palette color \spad{pal1},
      ++ line color is set to the palette color \spad{pal2}, and point
      ++ size is set to the positive integer \spad{ps}.
    appendPoint     :  (%,P)                                     -> Void
      ++ appendPoint(gi,pt) appends the point \spad{pt} to the end
      ++ of the list of points component for the graph, \spad{gi}, which is
      ++ of the domain \spadtype{GraphImage}.
    point           :  (%,P,PAL)                                 -> Void
      ++ point(gi,pt,pal) modifies the graph \spad{gi} of the domain
      ++ \spadtype{GraphImage} to contain one point component, \spad{pt}
      ++ whose point color is set to be the palette color \spad{pal}, and
      ++ whose line color and point size are determined by the default
      ++ functions \spadfun{lineColorDefault} and \spadfun{pointSizeDefault}.
    coerce          :  L L P                                     -> %
      ++ coerce(llp)
      ++ component(gi,pt) creates and returns a graph of the domain
      ++ \spadtype{GraphImage} which is composed of the list of list
      ++ of points given by \spad{llp}, and whose point colors, line colors
      ++ and point sizes are determined by the default functions
      ++ \spadfun{pointColorDefault}, \spadfun{lineColorDefault}, and
      ++ \spadfun{pointSizeDefault}.  The graph data is then sent to the
      ++ viewport manager where it waits to be included in a two-dimensional
      ++ viewport window.
    coerce          :  %                                         -> E
      ++ coerce(gi) returns the indicated graph, \spad{gi}, of domain
      ++ \spadtype{GraphImage} as output of the domain \spadtype{OutputForm}.
    putColorInfo    : (L L P,L PAL)                              -> L L P
      ++ putColorInfo(llp,lpal) takes a list of list of points, \spad{llp},
      ++ and returns the points with their hue and shade components
      ++ set according to the list of palette colors, \spad{lpal}.

  Implementation ==> add
    import Color()
    import Palette()
    import ViewDefaultsPackage()
    import PlotTools()
    import DrawOptionFunctions0
    import P
    import PP
    import COORDSYS

    Rep := Record(key: I, rangesField: RANGESF, unitsField: UNITSF, _
       llPoints: L L P, pointColors: L PAL, lineColors: L PAL, pointSizes: L PI, _
       optionsField: L DROP)

--%Internal Functions

    graph       : RANGEF                          -> %
    scaleStep   : SEG SF -> SF
    makeGraph   :  %                          -> %


    numberCheck(nums:Point SF):Void ==
      for i in minIndex(nums)..maxIndex(nums) repeat
        COMPLEXP(nums.(i::PositiveInteger))$Lisp =>
          error "An unexpected complex number was encountered in the calculations."


    doOptions(g:Rep):Void ==
      lr : RANGEF := ranges(g.optionsField,ranges g)
      if (#lr > 1$I) then
        g.rangesField := [segment(convert(lo(lr.1))@SF,convert(hi(lr.1))@SF)$(Segment(SF)),
                           segment(convert(lo(lr.2))@SF,convert(hi(lr.2))@SF)$(Segment(SF))]
      else
        g.rangesField := []
      lu : UNITF := units(g.optionsField,units g)
      if (#lu > 1$I) then
        g.unitsField := [convert(lu.1)@SF,convert(lu.2)@SF]
      else
        g.unitsField := []
    -- etc - graphimage specific stuff...

    putColorInfo(llp,listOfPalettes) ==
      llp2 : L L P := []
      for lp in llp for pal in listOfPalettes repeat
        lp2 : L P := []
        daHue   := (hue(hue pal))::SF
        daShade := (shade pal)::SF
        for p in lp repeat
          if (d := dimension p) < 3 then
            p := extend(p,[daHue,daShade])
          else
            p.3 := daHue
            d < 4 => p := extend(p,[daShade])
            p.4 := daShade
          lp2 := cons(p,lp2)
        llp2 := cons(reverse_! lp2,llp2)
      reverse_! llp2

    graph demRanges ==
      null demRanges =>  [ 0, [], [], [], [], [], [], [] ]
      demRangesSF : RANGESF := _
        [ segment(convert(lo demRanges.1)@SF,convert(hi demRanges.1)@SF)$(Segment(SF)), _
          segment(convert(lo demRanges.1)@SF,convert(hi demRanges.1)@SF)$(Segment(SF)) ]
      [ 0, demRangesSF, [], [], [], [], [], [] ]

    scaleStep(range_seg) ==                        -- MGR
      range := hi(range_seg) - lo(range_seg)

      adjust:NNI
      tryStep:SF
      scaleDown:SF
      numerals:String
      adjust := 0
      while range < 100.0::SF repeat
        adjust := adjust + 1
        range := range * 10.0::SF -- might as well take big steps
      tryStep := range/10.0::SF
      numerals := string(((retract(ceiling(tryStep)$SF)$SF)@I))$String
      scaleDown := (10@I ^$I (((#(numerals)@I) - 1$I) pretend PI))::SF
      scaleDown*ceiling(tryStep/scaleDown - 0.5::SF)/((10 ^$I adjust)::SF)

    figureUnits(ranges : RANGESF) : UNITSF ==
        [scaleStep(first(ranges)), scaleStep(second(ranges))]

    roundRange(range : SEG SF) : SEG SF ==
        single_eps := (2.0::SF)^(-19)
        low := lo(range)
        low :=
            abs(low) < 1 => low - single_eps
            low < 0 => (1.0::SF + single_eps)*low
            (1.0::SF - single_eps)*low
        high := hi(range)
        high :=
            abs(high) < 1 =>  high + single_eps
            high < 0 => (1.0::SF - single_eps)*high
            (1.0::SF + single_eps)*high
        low..high

    roundRanges(ranges : RANGESF) : RANGESF ==
        [roundRange(first(ranges)), roundRange(second(ranges))]

    plotLists(graf:Rep,listOfListsOfPoints:L L P,listOfPointColors:L PAL,listOfLineColors:L PAL,listOfPointSizes:L PI):% ==
      givenLen := #listOfListsOfPoints
        -- take out point lists that are actually empty
      listOfListsOfPoints := [ l for l in listOfListsOfPoints | not null l ]
      if (null listOfListsOfPoints) then
        error "GraphImage was given a list that contained no valid point lists"
      if ((len := #listOfListsOfPoints) ~= givenLen) then
        sayBrightly(["   Warning: Ignoring pointless point list"::E]$List(E))$Lisp
      graf.llPoints := listOfListsOfPoints
        -- do point colors
      if ((givenLen := #listOfPointColors) > len) then
         -- pad or discard elements if given list has length different from the point list
        graf.pointColors := concat(listOfPointColors,
            new((len - givenLen)::NonNegativeInteger + 1, pointColorDefault()))
      else graf.pointColors := first(listOfPointColors, len)
        -- do line colors
      if ((givenLen := #listOfLineColors) > len) then
        graf.lineColors := concat(listOfLineColors,
             new((len - givenLen)::NonNegativeInteger + 1, lineColorDefault()))
      else graf.lineColors := first(listOfLineColors, len)
        -- do point sizes
      if ((givenLen := #listOfPointSizes) > len) then
        graf.pointSizes := concat(listOfPointSizes,
             new((len - givenLen)::NonNegativeInteger + 1, pointSizeDefault()))
      else graf.pointSizes := first(listOfPointSizes, len)
      graf

    makeGraph graf ==
      doOptions(graf)
      (s := #(graf.llPoints)) = 0 =>
        error "You are trying to make a graph with no points"
      key graf ~= 0 =>
        error "You are trying to draw over an existing graph"
      transform := coord(graf.optionsField,cartesian$COORDSYS)$DrawOptionFunctions0
      graf.llPoints:= putColorInfo(graf.llPoints,graf.pointColors)
      if null(ranges graf) then  -- figure out best ranges for points
        graf.rangesField := calcRanges(graf.llPoints)  --::V SEG SF
      graf.rangesField := roundRanges(graf.rangesField)
      if null(units graf) then  -- figure out best ranges for points
        graf.unitsField := figureUnits(graf.rangesField)  --::V SEG SF
      sayBrightly(["   Graph data being transmitted to the viewport manager..."::E]$List(E))$Lisp
      sendI(VIEW,typeGRAPH)$Lisp
      sendI(VIEW,makeGRAPH)$Lisp
      tonto := (graf.rangesField)::RANGESF
      sendSF(VIEW,lo(first tonto))$Lisp
      sendSF(VIEW,hi(first tonto))$Lisp
      sendSF(VIEW,lo(second tonto))$Lisp
      sendSF(VIEW,hi(second tonto))$Lisp
      sendSF(VIEW,first (graf.unitsField))$Lisp
      sendSF(VIEW,second (graf.unitsField))$Lisp
      sendI(VIEW,s)$Lisp     -- how many lists of points are being sent
      for aList in graf.llPoints for pColor in graf.pointColors for lColor in graf.lineColors for s in graf.pointSizes repeat
        sendI(VIEW,#aList)$Lisp  -- how many points in this list
        for p in aList repeat
          aPoint := transform p
          sendSF(VIEW,xCoord aPoint)$Lisp
          sendSF(VIEW,yCoord aPoint)$Lisp
          sendSF(VIEW,hue(p)$PP)$Lisp  -- ?use aPoint as well...?
          sendSF(VIEW,shade(p)$PP)$Lisp
        hueShade := hue hue pColor + shade pColor * numberOfHues()
        sendI(VIEW,hueShade)$Lisp
        hueShade := (hue hue lColor -1)*5 + shade lColor
        sendI(VIEW,hueShade)$Lisp
        sendI(VIEW,s)$Lisp
      graf.key := getI(VIEW)$Lisp
      graf


--%Exported Functions
    makeGraphImage(graf:%)    == makeGraph graf
    key graf                  == graf.key
    pointLists graf           == graf.llPoints
    ranges graf                ==
      null graf.rangesField => []
      [segment(convert(lo graf.rangesField.1)@F,convert(hi graf.rangesField.1)@F), _
       segment(convert(lo graf.rangesField.2)@F,convert(hi graf.rangesField.2)@F)]
    ranges(graf,rangesList)     ==
      graf.rangesField :=
        [segment(convert(lo rangesList.1)@SF,convert(hi rangesList.1)@SF), _
         segment(convert(lo rangesList.2)@SF,convert(hi rangesList.2)@SF)]
      rangesList
    units graf                ==
      null(graf.unitsField) => []
      [convert(graf.unitsField.1)@F,convert(graf.unitsField.2)@F]
    units (graf,unitsToBe)    ==
      graf.unitsField := [convert(unitsToBe.1)@SF,convert(unitsToBe.2)@SF]
      unitsToBe
    graphImage                == graph []

    makeGraphImage(llp) ==
      makeGraphImage(llp,
        [pointColorDefault() for i in 1..(l:=#llp)],
         [lineColorDefault() for i in 1..l],
          [pointSizeDefault() for i in 1..l])

    makeGraphImage(llp,lpc,llc,lps) ==
      makeGraphImage(llp,lpc,llc,lps,[])

    makeGraphImage(llp,lpc,llc,lps,opts) ==
      graf := graph(ranges(opts,[]))
      graf.optionsField := opts
      graf := plotLists(graf,llp,lpc,llc,lps)
      transform := coord(graf.optionsField,cartesian$COORDSYS)$DrawOptionFunctions0
      for aList in graf.llPoints repeat
        for p in aList repeat
          aPoint := transform p
          numberCheck aPoint
      makeGraph graf

    component (graf:%,ListOfPoints:L P,PointColor:PAL,LineColor:PAL,PointSize:PI) ==
      graf.llPoints    := append(graf.llPoints,[ListOfPoints])
      graf.pointColors := append(graf.pointColors,[PointColor])
      graf.lineColors  := append(graf.lineColors,[LineColor])
      graf.pointSizes  := append(graf.pointSizes,[PointSize])

    component (graf,aPoint) ==
      component(graf,aPoint,pointColorDefault(),lineColorDefault(),pointSizeDefault())

    component (graf:%,aPoint:P,PointColor:PAL,LineColor:PAL,PointSize:PI) ==
      component (graf,[aPoint],PointColor,LineColor,PointSize)

    appendPoint (graf,aPoint) ==
      num : I  := #(graf.llPoints) - 1
      num < 0 => error "No point lists to append to!"
      (graf.llPoints.num) := append((graf.llPoints.num),[aPoint])

    point (graf,aPoint,PointColor) ==
      component(graf,aPoint,PointColor,lineColorDefault(),pointSizeDefault())

    coerce (llp : L L P) : % ==
      makeGraphImage(llp,
          [pointColorDefault() for i in 1..(l:=#llp)],
                [lineColorDefault() for i in 1..l],
                     [pointSizeDefault() for i in 1..l])

    coerce (graf : %) : E ==
      hconcat( ["Graph with " :: E,(p := # pointLists graf) :: E,
         (p=1 => " point list"; " point lists") :: E])

@
\section{domain VIEW2D TwoDimensionalViewport}
\subsection{Creating multiple graphs in a Viewport}
We want to graph $x^3 * (a+b*x)$ on the interval $x=-1\ldots1$
so we clear out the workspace
<<multigraph.input>>=
)clear all
@
We assign values to the constants
<<multigraph.input>>=
a:=0.5
b:=0.5
@
We draw the first case of the graph
<<multigraph.input>>=
y1:=draw(x^3*(a+b*x),x=-1..1,title=="2.2.10 explicit")
@
We fetch the graph of the first object
<<multigraph.input>>=
g1:=getGraph(y1,1)
@
We extract its points
<<multigraph.input>>=
pointLists g1
@

Now we create a second graph with a changed parameter
<<multigraph.input>>=
b:=1.0
@
We draw it
<<multigraph.input>>=
y2:=draw(x^3*(a+b*x),x=-1..1)
@
We fetch this new graph
<<multigraph.input>>=
g2:=getGraph(y2,1)
@
We get the points from this graph
<<multigraph.input>>=
pointLists g2
@
and we put these points, $g2$ onto the first graph $y1$ as graph $2$
<<multigraph.input>>=
putGraph(y1,g2,2)
@
And now we do the whole sequence again
<<multigraph.input>>=
b:=2.0
y3:=draw(x^3*(a+b*x),x=-1..1)
g3:=getGraph(y3,1)
pointLists g3
@
and put the third graphs points $g3$ onto the first graph $y1$ as graph $3$
<<multigraph.input>>=
putGraph(y1,g3,3)
@
Finally we show the combined result
<<multigraph.input>>=
vp:=makeViewport2D(y1)
@
<<domain VIEW2D TwoDimensionalViewport>>=
)abbrev domain VIEW2D TwoDimensionalViewport
++ Author: Jim Wen
++ Date Created: 28 April 1989
++ Date Last Updated: 29 October 1991, Jon Steinbach
++ Basic Operations:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description: TwoDimensionalViewport creates viewports to display graphs.
TwoDimensionalViewport ():Exports == Implementation where

  VIEW    ==> _$ViewportServer$Lisp
  sendI   ==> sockSendInt
  sendSF  ==> sockSendFloat
  sendSTR ==> sockSendString
  getI    ==> sockGetInt
  getSF   ==> sockGetFloat

  typeGRAPH  ==> 2
  typeVIEW2D ==> 3

  makeGRAPH  ==> (-1)$SingleInteger
  makeVIEW2D ==> (-1)$SingleInteger

  I    ==> Integer
  PI   ==> PositiveInteger
  NNI  ==> NonNegativeInteger
  XY   ==> Record( X:I, Y:I )
  XYP  ==> Record( X:PI, Y:PI )
  XYNN ==> Record( X:NNI, Y:NNI )
  F    ==> Float
  SF   ==> DoubleFloat
  STR  ==> String
  L    ==> List
  V    ==> Vector
  E    ==> OutputForm
  FLAG ==> Record( showCP:I )
  PAL  ==> Palette()
  B    ==> Boolean
  G    ==> GraphImage
  GS   ==> Record( scaleX:SF, scaleY:SF, deltaX:SF, deltaY:SF, _
                  points:I, connect:I, spline:I, _
                  axes:I, axesColor:PAL, units:I, unitsColor:PAL, _
                  showing:I)
  GU   ==> Union(G,"undefined")
  DROP ==> DrawOption
  POINT ==> Point(SF)

  TRANSLATE2D     ==> 0$I
  SCALE2D         ==> 1$I
  pointsOnOff     ==> 2
  connectOnOff    ==> 3
  spline2D        ==> 4   -- used for controlling regions, now
  reset2D         ==> 5
  hideControl2D   ==> 6
  closeAll2D      ==> 7
  axesOnOff2D     ==> 8
  unitsOnOff2D    ==> 9

  SPADBUTTONPRESS ==> 100
  MOVE            ==> 102
  RESIZE          ==> 103
  TITLE           ==> 104
  showing2D       ==> 105  -- as defined in include/actions.h
  putGraph2D      ==> 106
  writeView       ==> 110
  axesColor2D     ==> 112
  unitsColor2D    ==> 113
  getPickedPTS    ==> 119

  graphStart      ==> 13   -- as defined in include/actions.h

  noControl ==> 0$I

  yes       ==> 1$I
  no        ==> 0$I

  maxGRAPHS ==> 9::I   -- should be the same as maxGraphs in include/view2D.h

  fileTypeDefs ==> ["PIXMAP"]    -- see include/write.h for things to include

  Exports ==> SetCategory with
    getPickedPoints : % -> L POINT
      ++ getPickedPoints(x)
      ++ returns a list of small floats for the points the
      ++ user interactively picked on the viewport
      ++ for full integration into the system, some design
      ++ issues need to be addressed: e.g. how to go through
      ++ the GraphImage interface, how to default to graphs, etc.
    viewport2D     : ()                                     -> %
      ++ viewport2D() returns an undefined two-dimensional viewport
      ++ of the domain \spadtype{TwoDimensionalViewport} whose
      ++ contents are empty.
    makeViewport2D : %                                      -> %
      ++ makeViewport2D(v) takes the given two-dimensional viewport,
      ++ v, of the domain \spadtype{TwoDimensionalViewport} and
      ++ displays a viewport window on the screen which contains
      ++ the contents of v.
    options        : %                                      -> L DROP
      ++ options(v) takes the given two-dimensional viewport, v, of the
      ++ domain \spadtype{TwoDimensionalViewport} and returns a list
      ++ containing the draw options from the domain \spadtype{DrawOption}
      ++ for v.
    options        : (%,L DROP)                             -> %
      ++ options(v,lopt) takes the given two-dimensional viewport, v,
      ++ of the domain \spadtype{TwoDimensionalViewport} and returns
      ++ v with it's draw options modified to be those which are indicated
      ++ in the given list, \spad{lopt} of domain \spadtype{DrawOption}.
    makeViewport2D : (G,L DROP)                             -> %
      ++ makeViewport2D(gi,lopt) creates and displays a viewport window
      ++ of the domain \spadtype{TwoDimensionalViewport} whose graph
      ++ field is assigned to be the given graph, \spad{gi}, of domain
      ++ \spadtype{GraphImage}, and whose options field is set to be
      ++ the list of options, \spad{lopt} of domain \spadtype{DrawOption}.
    graphState     : (%,PI,SF,SF,SF,SF,I,I,I,I,PAL,I,PAL,I) -> Void
      ++ graphState(v,num,sX,sY,dX,dY,pts,lns,box,axes,axesC,un,unC,cP)
      ++ sets the state of the characteristics for the graph indicated
      ++ by \spad{num} in the given two-dimensional viewport v, of domain
      ++ \spadtype{TwoDimensionalViewport}, to the values given as
      ++ parameters.  The scaling of the graph in the x and y component
      ++ directions is set to be \spad{sX} and \spad{sY}; the window
      ++ translation in the x and y component directions is set to be
      ++ \spad{dX} and \spad{dY}; The graph points, lines, bounding box,
      ++ axes, or units will be shown in the viewport if their given
      ++ parameters \spad{pts}, \spad{lns}, \spad{box}, \spad{axes} or
      ++ \spad{un} are set to be \spad{1}, but will not be shown if they
      ++ are set to \spad{0}.  The color of the axes and the color of the
      ++ units are indicated by the palette colors \spad{axesC} and
      ++ \spad{unC} respectively.  To display the control panel when
      ++ the viewport window is displayed, set \spad{cP} to \spad{1},
      ++ otherwise set it to \spad{0}.
    graphStates    : %                                      -> V GS
      ++ graphStates(v) returns and shows a listing of a record containing
      ++ the current state of the characteristics of each of the ten graph
      ++ records in the given two-dimensional viewport, v, which is of
      ++ domain \spadtype{TwoDimensionalViewport}.
    graphs         : %                                      -> V GU
      ++ graphs(v) returns a vector, or list, which is a union of all
      ++ the graphs, of the domain \spadtype{GraphImage}, which are
      ++ allocated for the two-dimensional viewport, v, of domain
      ++ \spadtype{TwoDimensionalViewport}.  Those graphs which have
      ++ no data are labeled "undefined", otherwise their contents
      ++ are shown.
    title          : (%,STR)                                -> Void
      ++ title(v,s) changes the title which is shown in the two-dimensional
      ++ viewport window, v of domain \spadtype{TwoDimensionalViewport}.
    putGraph       : (%,G,PI)                               -> Void
      ++ putGraph(v,gi,n) sets the graph field indicated by n, of the
      ++ indicated two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, to be the graph, \spad{gi}
      ++ of domain \spadtype{GraphImage}.  The contents of viewport, v,
      ++ will contain \spad{gi} when the function \spadfun{makeViewport2D}
      ++ is called to create the an updated viewport v.
    getGraph       : (%,PI)                                 -> G
      ++ getGraph(v,n) returns the graph which is of the domain
      ++ \spadtype{GraphImage} which is located in graph field n
      ++ of the given two-dimensional viewport, v, which is of the
      ++ domain \spadtype{TwoDimensionalViewport}.
    axes           : (%,PI,STR)                             -> Void
      ++ axes(v,n,s) displays the axes of the graph in field n of
      ++ the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, if s is "on", or does
      ++ not display the axes if s is "off".
    axes           : (%,PI,PAL)                             -> Void
      ++ axes(v,n,c) displays the axes of the graph in field n of
      ++ the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, with the axes color set to
      ++ the given palette color c.
    units          : (%,PI,STR)                             -> Void
      ++ units(v,n,s) displays the units of the graph in field n of
      ++ the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, if s is "on", or does
      ++ not display the units if s is "off".
    units          : (%,PI,PAL)                             -> Void
      ++ units(v,n,c) displays the units of the graph in field n of
      ++ the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, with the units color set to
      ++ the given palette color c.
    points         : (%,PI,STR)                             -> Void
      ++ points(v,n,s) displays the points of the graph in field n of
      ++ the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, if s is "on", or does
      ++ not display the points if s is "off".
    region         : (%,PI,STR)                             -> Void
      ++ region(v,n,s) displays the bounding box of the graph in
      ++ field n of the given two-dimensional viewport, v, which is
      ++ of domain \spadtype{TwoDimensionalViewport}, if s is "on",
      ++ or does not display the bounding box if s is "off".
    connect        : (%,PI,STR)                             -> Void
      ++ connect(v,n,s) displays the lines connecting the graph
      ++ points in field n of the given two-dimensional viewport, v,
      ++ which is of domain \spadtype{TwoDimensionalViewport}, if s
      ++ is "on", or does not display the lines if s is "off".
    controlPanel   : (%,STR)                                -> Void
      ++ controlPanel(v,s) displays the control panel of the given
      ++ two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, if s is "on", or hides
      ++ the control panel if s is "off".
    close          : %                                      -> Void
      ++ close(v) closes the viewport window of the given
      ++ two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, and terminates the
      ++ corresponding process ID.
    dimensions     : (%,NNI,NNI,PI,PI)                      -> Void
      ++ dimensions(v,x,y,width,height) sets the position of the
      ++ upper left-hand corner of the two-dimensional viewport, v,
      ++ which is of domain \spadtype{TwoDimensionalViewport}, to
      ++ the window coordinate x, y, and sets the dimensions of the
      ++ window to that of \spad{width}, \spad{height}.  The new
      ++ dimensions are not displayed until the function
      ++ \spadfun{makeViewport2D} is executed again for v.
    scale          : (%,PI,F,F)                             -> Void
      ++ scale(v,n,sx,sy) displays the graph in field n of the given
      ++ two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, scaled by the factor \spad{sx}
      ++ in the x-coordinate direction and by the factor \spad{sy} in
      ++ the y-coordinate direction.
    translate      : (%,PI,F,F)                             -> Void
      ++ translate(v,n,dx,dy) displays the graph in field n of the given
      ++ two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, translated by \spad{dx} in
      ++ the x-coordinate direction from the center of the viewport, and
      ++ by \spad{dy} in the y-coordinate direction from the center.
      ++ Setting \spad{dx} and \spad{dy} to \spad{0} places the center
      ++ of the graph at the center of the viewport.
    show           : (%,PI,STR)                             -> Void
      ++ show(v,n,s) displays the graph in field n of the given
      ++ two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, if s is "on", or does not
      ++ display the graph if s is "off".
    move           : (%,NNI,NNI)                            -> Void
      ++ move(v,x,y) displays the two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport}, with the upper
      ++ left-hand corner of the viewport window at the screen
      ++ coordinate position x, y.
    update         :(%,G,PI)                               -> Void
      ++ update(v,gr,n) drops the graph \spad{gr} in slot \spad{n}
      ++ of viewport \spad{v}. The graph gr must have been
      ++ transmitted already and acquired an integer key.
    resize         : (%,PI,PI)                              -> Void
      ++ resize(v,w,h) displays the two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport}, with a width
      ++ of w and a height of h, keeping the upper left-hand corner
      ++ position unchanged.
    write          : (%,STR)                                -> STR
      ++ write(v,s) takes the given two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ files for v.
    write          : (%,STR,STR)                            -> STR
      ++ write(v,s,f) takes the given two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ files for v and an optional file type f.
    write          : (%,STR,L STR)                          -> STR
      ++ write(v,s,lf) takes the given two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ files for v and the optional file types indicated by the list lf.
    reset          :  %                                     -> Void
      ++ reset(v) sets the current state of the graph characteristics
      ++ of the given two-dimensional viewport, v, which is of domain
      ++ \spadtype{TwoDimensionalViewport}, back to their initial settings.
    key            :  %                                     -> I
      ++ key(v) returns the process ID number of the given two-dimensional
      ++ viewport, v, which is of domain \spadtype{TwoDimensionalViewport}.
    coerce         :  %                                     -> E
      ++ coerce(v) returns the given two-dimensional viewport, v, which
      ++ is of domain \spadtype{TwoDimensionalViewport} as output of
      ++ the domain \spadtype{OutputForm}.

  Implementation ==> add

    import GraphImage()
    import Color()
    import Palette()
    import ViewDefaultsPackage()
    import DrawOptionFunctions0
    import POINT

    Rep := Record (key:I, graphsField:V GU, graphStatesField:V GS, _
                   title:STR, moveTo:XYNN, size:XYP, flags:FLAG, optionsField:L DROP)

    defaultGS : GS := [convert(0.9)@SF, convert(0.9)@SF, 0$SF, 0$SF, _
                      yes, yes, no, _
                      yes, axesColorDefault(), no, unitsColorDefault(), _
                      yes]


     --% Local Functions
    checkViewport (viewport:%):B ==
        -- checks to see if this viewport still exists
        -- by sending the key to the viewport manager and
        -- waiting for its reply after it checks it against
        -- the viewports in its list. a -1 means it doesn't
        -- exist.
      sendI(VIEW,viewport.key)$Lisp
      i := getI(VIEW)$Lisp
      (i < 0$I) =>
        viewport.key := 0$I
        error "This viewport has already been closed!"
      true

    doOptions(v:Rep):Void ==
      v.title := title(v.optionsField,"FriCAS2D")
      -- etc - 2D specific stuff...

     --% Exported Functions

    options viewport ==
      viewport.optionsField

    options(viewport,opts) ==
      viewport.optionsField := opts
      viewport

    putGraph (viewport,aGraph,which) ==
      if ((which > maxGRAPHS) or (which < 1)) then
        error "Trying to put a graph with a negative index or too big an index"
      viewport.graphsField.which := aGraph

    getGraph (viewport,which) ==
      if ((which > maxGRAPHS) or (which < 1)) then
        error "Trying to get a graph with a negative index or too big an index"
      viewport.graphsField.which case "undefined" =>
        error "Graph is undefined!"
      viewport.graphsField.which::GraphImage


    graphStates viewport  == viewport.graphStatesField
    graphs viewport       == viewport.graphsField
    key viewport          == viewport.key

    dimensions(viewport,ViewX,ViewY,ViewWidth,ViewHeight) ==
      viewport.moveTo := [ViewX,ViewY]
      viewport.size   := [ViewWidth,ViewHeight]

    move(viewport,xLoc,yLoc) ==
      viewport.moveTo := [xLoc,yLoc]
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,MOVE)$Lisp
        checkViewport viewport =>
          sendI(VIEW,xLoc)$Lisp
          sendI(VIEW,yLoc)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    update(viewport,graph,slot) ==
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,putGraph2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,key graph)$Lisp
          sendI(VIEW,slot)$Lisp
          getI(VIEW)$Lisp -- acknowledge
      void()

    resize(viewport,xSize,ySize) ==
      viewport.size := [xSize,ySize]
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,RESIZE)$Lisp
        checkViewport viewport =>
          sendI(VIEW,xSize)$Lisp
          sendI(VIEW,ySize)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    translate(viewport,graphIndex,xTranslateF,yTranslateF) ==
      xTranslate := convert(xTranslateF)@SF
      yTranslate := convert(yTranslateF)@SF
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      viewport.graphStatesField.graphIndex.deltaX := xTranslate
      viewport.graphStatesField.graphIndex.deltaY := yTranslate
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,TRANSLATE2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendSF(VIEW,xTranslate)$Lisp
          sendSF(VIEW,yTranslate)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    scale(viewport,graphIndex,xScaleF,yScaleF) ==
      xScale := convert(xScaleF)@SF
      yScale := convert(yScaleF)@SF
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      viewport.graphStatesField.graphIndex.scaleX := xScale  -- check union (undefined?)
      viewport.graphStatesField.graphIndex.scaleY := yScale  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,SCALE2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendSF(VIEW,xScale)$Lisp
          sendSF(VIEW,yScale)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    viewport2D ==
      [0,new(maxGRAPHS,"undefined"), _
       new(maxGRAPHS,copy defaultGS),"FriCAS2D", _
        [viewPosDefault().1,viewPosDefault().2],[viewSizeDefault().1,viewSizeDefault().2], _
         [noControl], [] ]

    makeViewport2D0: % -> %

    makeViewport2D(g:G,opts:L DROP) ==
      viewport               := viewport2D()
      viewport.graphsField.1 := g
      viewport.optionsField := opts
      makeViewport2D0 viewport

    makeViewport2D viewport == makeViewport2D0 copy(viewport::Rep)

    makeViewport2D0 viewportDollar ==
      viewport := viewportDollar::Rep
      doOptions viewport --local function to extract and assign optional arguments for 2D viewports
      sayBrightly(["   FriCAS2D data being transmitted to the viewport manager..."::E]$List(E))$Lisp
      sendI(VIEW,typeVIEW2D)$Lisp
      sendI(VIEW,makeVIEW2D)$Lisp
      sendSTR(VIEW,viewport.title)$Lisp
      sendI(VIEW,viewport.moveTo.X)$Lisp
      sendI(VIEW,viewport.moveTo.Y)$Lisp
      sendI(VIEW,viewport.size.X)$Lisp
      sendI(VIEW,viewport.size.Y)$Lisp
      sendI(VIEW,viewport.flags.showCP)$Lisp
      for i in 1..maxGRAPHS repeat
        g := (graphs viewport).i
        if g case "undefined" then
          sendI(VIEW,0$I)$Lisp
        else
          sendI(VIEW,key(g::G))$Lisp
          gs := (graphStates viewport).i
          sendSF(VIEW,gs.scaleX)$Lisp
          sendSF(VIEW,gs.scaleY)$Lisp
          sendSF(VIEW,gs.deltaX)$Lisp
          sendSF(VIEW,gs.deltaY)$Lisp
          sendI(VIEW,gs.points)$Lisp
          sendI(VIEW,gs.connect)$Lisp
          sendI(VIEW,gs.spline)$Lisp
          sendI(VIEW,gs.axes)$Lisp
          hueShade := hue hue gs.axesColor + shade gs.axesColor * numberOfHues()
          sendI(VIEW,hueShade)$Lisp
          sendI(VIEW,gs.units)$Lisp
          hueShade := hue hue gs.unitsColor + shade gs.unitsColor * numberOfHues()
          sendI(VIEW,hueShade)$Lisp
          sendI(VIEW,gs.showing)$Lisp
      viewport.key := getI(VIEW)$Lisp
      viewport

    graphState(viewport,num,sX,sY,dX,dY,Points,Lines,Spline, _
               Axes,AxesColor,Units,UnitsColor,Showing) ==
      viewport.graphStatesField.num := [sX,sY,dX,dY,Points,Lines,Spline, _
                                        Axes,AxesColor,Units,UnitsColor,Showing]

    title(viewport,Title) ==
      viewport.title := Title
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,TITLE)$Lisp
        checkViewport viewport =>
          sendSTR(VIEW,Title)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    reset viewport ==
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,SPADBUTTONPRESS)$Lisp
        checkViewport viewport =>
          sendI(VIEW,reset2D)$Lisp
          getI(VIEW)$Lisp          -- acknowledge
      void()

    axes (viewport:%,graphIndex:PI,onOff:STR) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := yes
      else
        status := no
      viewport.graphStatesField.graphIndex.axes := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,axesOnOff2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    axes (viewport:%,graphIndex:PI,color:PAL) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      viewport.graphStatesField.graphIndex.axesColor := color
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,axesColor2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          hueShade := hue hue color + shade color * numberOfHues()
          sendI(VIEW,hueShade)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    units (viewport:%,graphIndex:PI,onOff:STR) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := yes
      else
        status := no
      viewport.graphStatesField.graphIndex.units := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,unitsOnOff2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    units (viewport:%,graphIndex:PI,color:PAL) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      viewport.graphStatesField.graphIndex.unitsColor := color
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,unitsColor2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          hueShade := hue hue color + shade color * numberOfHues()
          sendI(VIEW,hueShade)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    connect (viewport:%,graphIndex:PI,onOff:STR) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := 1$I
      else
        status := 0$I
      viewport.graphStatesField.graphIndex.connect := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,connectOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    points (viewport:%,graphIndex:PI,onOff:STR) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := 1$I
      else
        status := 0$I
      viewport.graphStatesField.graphIndex.points := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,pointsOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    region (viewport:%,graphIndex:PI,onOff:STR) : Void ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := 1$I
      else
        status := 0$I
      viewport.graphStatesField.graphIndex.spline := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,spline2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    show (viewport,graphIndex,onOff) ==
      if (graphIndex > maxGRAPHS) then
        error "Referring to a graph with too big an index"
      if onOff = "on" then
        status := 1$I
      else
        status := 0$I
      viewport.graphStatesField.graphIndex.showing := status  -- check union (undefined?)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,showing2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,graphIndex)$Lisp
          sendI(VIEW,status)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    controlPanel (viewport,onOff) ==
      if onOff = "on" then viewport.flags.showCP := yes
      else viewport.flags.showCP := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,hideControl2D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.showCP)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    close viewport ==
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,closeAll2D)$Lisp
        checkViewport viewport =>
          getI(VIEW)$Lisp          -- acknowledge
          viewport.key := 0$I
      void()

    coerce viewport ==
      (key(viewport) = 0$I) =>
        hconcat ["Closed or Undefined TwoDimensionalViewport: "::E,
                  (viewport.title)::E]
      hconcat ["TwoDimensionalViewport: "::E, (viewport.title)::E]

    write(viewport:%,Filename:STR,aThingToWrite:STR) ==
      write(viewport,Filename,[aThingToWrite])

    write(viewport,Filename) ==
      write(viewport,Filename,viewWriteDefault())

    write(viewport:%,Filename:STR,thingsToWrite:L STR) ==
      stringToSend : STR := ""
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW2D)$Lisp
        sendI(VIEW,writeView)$Lisp
        checkViewport viewport =>
          sendSTR(VIEW,Filename)$Lisp
          m := minIndex(avail := viewWriteAvailable())
          for aTypeOfFile in thingsToWrite repeat
            if (writeTypeInt:= position(upperCase aTypeOfFile,avail)-m) < 0 then
              sayBrightly(["  > "::E,(concat(aTypeOfFile, _
                " is not a valid file type for writing a 2D viewport"))::E]$List(E))$Lisp
            else
              sendI(VIEW,writeTypeInt+(1$I))$Lisp
                  --              stringToSend := concat [stringToSend,"%",aTypeOfFile]
                  --              sendSTR(VIEW,stringToSend)$Lisp
          sendI(VIEW,0$I)$Lisp     -- no more types of things to write
          getI(VIEW)$Lisp          -- acknowledge
          Filename

@
\subsection{TEST VIEW2D}
<<TEST VIEW2D>>=
<<multigraph.input>>
@
\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>>

<<domain GRIMAGE GraphImage>>
<<domain VIEW2D TwoDimensionalViewport>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}
