\documentclass{article}
\usepackage{open-axiom}
\begin{document}
\title{\$SPAD/src/algebra view3D.spad}
\author{James Wen}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{domain VIEW3D ThreeDimensionalViewport}
<<domain VIEW3D ThreeDimensionalViewport>>=
)abbrev domain VIEW3D ThreeDimensionalViewport
++ Author: Jim Wen
++ Date Created: 28 April 1989
++ Date Last Updated: 2 November 1991, Jim Wen
++ Basic Operations:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords: 
++ References:
++ Description: ThreeDimensionalViewport creates viewports to display graphs
VIEW    ==> _$ViewportServer$Lisp
sendI   ==> sockSendInt
sendSF  ==> sockSendFloat
sendSTR ==> sockSendString
getI    ==> sockGetInt
getSF   ==> sockGetFloat

typeVIEW3D   ==> 1$I
typeVIEWTube ==> 4

makeVIEW3D ==> (-1)$SingleInteger

ThreeDimensionalViewport(): Exports == Implementation where
  I   ==> Integer
  PI  ==> PositiveInteger
  NNI ==> NonNegativeInteger
  XY  ==> Record( X:I, Y:I )
  XYP ==> Record( X:PI, Y:PI )
  XYNN ==> Record( X:NNI, Y:NNI )
  SF  ==> DoubleFloat
  F   ==> Float
  L   ==> List
  Pt ==> ColoredThreeDimensionalPoint
  SEG ==> Segment
  S   ==> String
  E   ==> OutputForm
  PLOT3D ==> Plot3D
  V   ==> Record( theta:SF, phi:SF, scale:SF, scaleX:SF, scaleY:SF, scaleZ:SF, deltaX:SF, deltaY:SF )
  H   ==> Record( hueOffset:I, hueNumber:I)
  FLAG   ==> Record( showCP:I, style:I, axesOn:I, diagonalsOn:I, outlineRenderOn:I, showRegionField:I )
  FR  ==> Record( fn:Fn2, fc: FnU, xmin:SF, xmax:SF, ymin:SF, ymax:SF, xnum:I, ynum:I )
  LR  ==> Record( lightX:SF, lightY:SF, lightZ:SF, lightTheta:SF, lightPhi:SF , translucence:SF)
  PR  ==> Record( perspectiveField:I, eyeDistance:SF, hitherPlane:SF)
  VR  ==> Record( clipXMin:SF, clipXMax:SF, clipYMin:SF, clipYMax:SF, clipZMin:SF, clipZMax:SF, clipRegionField:I, clipSurfaceField:I)
  C   ==> Color()
  B   ==> Boolean
  POINT ==> Point(SF)
  SUBSPACE ==> SubSpace(3,SF)
  SPACE3 ==> ThreeSpace(SF)
  DROP ==> DrawOption
  COORDSYS ==> CoordinateSystems(SF)

    -- the below macros correspond to the ones in include/actions.h
  ROTATE       ==> 0$I  -- rotate      in actions.h
  ZOOM         ==> 1$I  -- zoom        in actions.h
  TRANSLATE    ==> 2    -- translate   in actions.h
  rendered     ==> 3    -- render      in actions.h
  hideControl  ==> 4
  closeAll     ==> 5
  axesOnOff    ==> 6
  opaque       ==> 7    -- opaqueMesh  in action.h
  contour      ==> 24
  RESET        ==> 8
  wireMesh     ==> 9    -- transparent in actions.h
  region3D     ==> 12
  smooth       ==> 22
  diagOnOff    ==> 26      
  outlineOnOff ==> 13      
  zoomx        ==> 14
  zoomy        ==> 15
  zoomz        ==> 16
  perspectiveOnOff ==> 27  
  clipRegionOnOff ==> 66   
  clipSurfaceOnOff ==> 67  

  SPADBUTTONPRESS ==> 100
  COLORDEF        ==> 101
  MOVE            ==> 102
  RESIZE          ==> 103
  TITLE           ==> 104
  lightDef        ==> 108
  translucenceDef ==> 109
  writeView       ==> 110
  eyeDistanceData ==> 111
  modifyPOINT     ==> 114
--  printViewport   ==> 115
  hitherPlaneData ==> 116
  queryVIEWPOINT  ==> 117
  changeVIEWPOINT ==> 118

  noControl ==> 0$I

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

  EYED      ==> 500::SF  -- see draw.h, should be the same(?) as clipOffset
  HITHER    ==> (-250)::SF   -- see process.h in view3D/ (not yet passed to viewman)

  openTube  ==> 1$I
  closedTube ==> 0$I

  fun2Var3D  ==> "   Three Dimensional Viewport: Function of Two Variables"
  para1Var3D ==> "   Three Dimensional Viewport: Parametric Curve of One Variable"
  undef3D    ==> "   Three Dimensional Viewport: No function defined for this viewport yet"

  Exports ==> SetCategory with  
    viewThetaDefault      : ()                                       -> F
      ++ viewThetaDefault() returns the current default longitudinal
      ++ view angle in radians.
    viewThetaDefault      : F                                        -> F
      ++ viewThetaDefault(t) sets the current default longitudinal
      ++ view angle in radians to the value t and returns t.
    viewPhiDefault        : ()                                       -> F
      ++ viewPhiDefault() returns the current default latitudinal
      ++ view angle in radians.
    viewPhiDefault        : F                                        -> F
      ++ viewPhiDefault(p) sets the current default latitudinal
      ++ view angle in radians to the value p and returns p.
    viewZoomDefault       : ()                                       -> F
      ++ viewZoomDefault() returns the current default graph scaling
      ++ value.
    viewZoomDefault       : F                                        -> F
      ++ viewZoomDefault(s) sets the current default graph scaling
      ++ value to s and returns s.
    viewDeltaXDefault     : ()                                       -> F
      ++ viewDeltaXDefault() returns the current default horizontal
      ++ offset from the center of the viewport window.
    viewDeltaXDefault     : F                                        -> F
      ++ viewDeltaXDefault(dx) sets the current default horizontal
      ++ offset from the center of the viewport window to be \spad{dx}
      ++ and returns \spad{dx}.
    viewDeltaYDefault     : ()                                       -> F
      ++ viewDeltaYDefault() returns the current default vertical
      ++ offset from the center of the viewport window.
    viewDeltaYDefault     : F                                        -> F
      ++ viewDeltaYDefault(dy) sets the current default vertical
      ++ offset from the center of the viewport window to be \spad{dy}
      ++ and returns \spad{dy}.
    viewport3D            : ()                                       -> %
      ++ viewport3D() returns an undefined three-dimensional viewport
      ++ of the domain \spadtype{ThreeDimensionalViewport} whose
      ++ contents are empty.
    makeViewport3D        : %                                        -> %
      ++ makeViewport3D(v) takes the given three-dimensional viewport,
      ++ v, of the domain \spadtype{ThreeDimensionalViewport} and
      ++ displays a viewport window on the screen which contains 
      ++ the contents of v.
    makeViewport3D        : (SPACE3,S)                               -> %
      ++ makeViewport3D(sp,s) takes the given space, \spad{sp} which is
      ++ of the domain \spadtype{ThreeSpace} and displays a viewport
      ++ window on the screen which contains the contents of \spad{sp},
      ++ and whose title is given by s.
    makeViewport3D        : (SPACE3,L DROP)                          -> %
      ++ makeViewport3D(sp,lopt) takes the given space, \spad{sp} which is
      ++ of the domain \spadtype{ThreeSpace} and displays a viewport
      ++ window on the screen which contains the contents of \spad{sp},
      ++ and whose draw options are indicated by the list \spad{lopt}, which
      ++ is a list of options from the domain \spad{DrawOption}.
    subspace              : %                                        -> SPACE3
      ++ subspace(v) returns the contents of the viewport v, which is
      ++ of the domain \spadtype{ThreeDimensionalViewport}, as a subspace
      ++ of the domain \spad{ThreeSpace}.
    subspace              : (%,SPACE3)                               -> %
      ++ subspace(v,sp) places the contents of the viewport v, which is
      ++ of the domain \spadtype{ThreeDimensionalViewport}, in the subspace
      ++ \spad{sp}, which is of the domain \spad{ThreeSpace}.
    modifyPointData       : (%,NNI,POINT)                            -> Void
      ++ modifyPointData(v,ind,pt) takes the viewport, v, which is of the
      ++ domain \spadtype{ThreeDimensionalViewport}, and places the data
      ++ point, \spad{pt} into the list of points database of v at the index
      ++ location given by \spad{ind}.
    options               : %                                        -> L DROP
      ++ options(v) takes the viewport, v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport} and returns a list of all
      ++ the draw options from the domain \spad{DrawOption} which are
      ++ being used by v.
    options               : (%,L DROP)                               -> %
      ++ options(v,lopt) takes the viewport, v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport} and sets the draw options
      ++ being used by v to those indicated in the list, \spad{lopt},
      ++ which is a list of options from the domain \spad{DrawOption}.
    move                  : (%,NNI,NNI)                              -> Void
      ++ move(v,x,y) displays the three-dimensional viewport, v, which
      ++ is of domain \spadtype{ThreeDimensionalViewport}, with the upper
      ++ left-hand corner of the viewport window at the screen 
      ++ coordinate position x, y.
    resize                : (%,PI,PI)                                -> Void
      ++ resize(v,w,h) displays the three-dimensional viewport, v, which
      ++ is of domain \spadtype{ThreeDimensionalViewport}, with a width
      ++ of w and a height of h, keeping the upper left-hand corner
      ++ position unchanged.
    title                 : (%,S)                                    -> Void
      ++ title(v,s) changes the title which is shown in the three-dimensional 
      ++ viewport window, v of domain \spadtype{ThreeDimensionalViewport}.
    dimensions            : (%,NNI,NNI,PI,PI)                        -> Void
      ++ dimensions(v,x,y,width,height) sets the position of the
      ++ upper left-hand corner of the three-dimensional viewport, v,
      ++ which is of domain \spadtype{ThreeDimensionalViewport}, 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{makeViewport3D} is executed again for v.
    viewpoint             : (%,F,F,F,F,F)                            -> Void
      ++ viewpoint(v,th,phi,s,dx,dy) sets the longitudinal view angle
      ++ to \spad{th} radians, the latitudinal view angle to \spad{phi}
      ++ radians, the scale factor to \spad{s}, the horizontal viewport 
      ++ offset to \spad{dx}, and the vertical viewport offset to \spad{dy}
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.  The new viewpoint position
      ++ is not displayed until the function \spadfun{makeViewport3D} is
      ++ executed again for v.
    viewpoint             : (%)					    -> V
      ++ viewpoint(v) returns the current viewpoint setting of the given
      ++ viewport, v.  This function is useful in the situation where the
      ++ user has created a viewport, proceeded to interact with it via
      ++ the control panel and desires to save the values of the viewpoint
      ++ as the default settings for another viewport to be created using
      ++ the system.
    viewpoint		  : (%,V)				     -> Void
      ++ viewpoint(v,viewpt) sets the viewpoint for the viewport.  The
      ++ viewport record consists of the latitudal and longitudal angles,
      ++ the zoom factor, the X, Y, and Z scales, and the X and Y displacements.
    viewpoint             : (%,I,I,F,F,F)                            -> Void
      ++ viewpoint(v,th,phi,s,dx,dy) sets the longitudinal view angle
      ++ to \spad{th} degrees, the latitudinal view angle to \spad{phi}
      ++ degrees, the scale factor to \spad{s}, the horizontal viewport 
      ++ offset to \spad{dx}, and the vertical viewport offset to \spad{dy}
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.  The new viewpoint position
      ++ is not displayed until the function \spadfun{makeViewport3D} is
      ++ executed again for v.
    viewpoint             : (%,F,F)                                  -> Void
      ++ viewpoint(v,th,phi) sets the longitudinal view angle to \spad{th}
      ++ radians and the latitudinal view angle to \spad{phi} radians
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.  The new viewpoint position
      ++ is not displayed until the function \spadfun{makeViewport3D} is
      ++ executed again for v.
    viewpoint             : (%,F,F,F)                                -> Void
      ++ viewpoint(v,rotx,roty,rotz) sets the rotation about the x-axis
      ++ to be \spad{rotx} radians, sets the rotation about the y-axis
      ++ to be \spad{roty} radians, and sets the rotation about the z-axis
      ++ to be \spad{rotz} radians, for the viewport v, which is of the
      ++ domain \spadtype{ThreeDimensionalViewport} and displays v with
      ++ the new view position.
    controlPanel          : (%,S)                                    -> Void
      ++ controlPanel(v,s) displays the control panel of the given
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, if s is "on", or hides
      ++ the control panel if s is "off".
    axes                  : (%,S)                                    -> Void
      ++ axes(v,s) displays the axes of the given three-dimensional
      ++ viewport, v, which is of domain \spadtype{ThreeDimensionalViewport},
      ++ if s is "on", or does not display the axes if s is "off".
    diagonals             : (%,S)                                    -> Void
      ++ diagonals(v,s) displays the diagonals of the polygon outline
      ++ showing a triangularized surface instead of a quadrilateral
      ++ surface outline, for the given three-dimensional viewport v
      ++ which is of domain \spadtype{ThreeDimensionalViewport}, if s is 
      ++ "on", or does not display the diagonals if s is "off".
    outlineRender         : (%,S)                                    -> Void
      ++ outlineRender(v,s) displays the polygon outline showing either
      ++ triangularized surface or a quadrilateral surface outline depending
      ++ on the whether the \spadfun{diagonals} function has been set, for
      ++ the given three-dimensional viewport v which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, if s is "on", or does not
      ++ display the polygon outline if s is "off".
    drawStyle             : (%,S)                                    -> Void
      ++ drawStyle(v,s) displays the surface for the given three-dimensional
      ++ viewport v which is of domain \spadtype{ThreeDimensionalViewport}
      ++ in the style of drawing indicated by s.  If s is not a valid
      ++ drawing style the style is wireframe by default.  Possible
      ++ styles are \spad{"shade"}, \spad{"solid"} or \spad{"opaque"},
      ++ \spad{"smooth"}, and \spad{"wireMesh"}.
    rotate                : (%,F,F)                                  -> Void
      ++ rotate(v,th,phi) rotates the graph to the longitudinal view angle
      ++ \spad{th} radians and the latitudinal view angle \spad{phi} radians
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.
    rotate                : (%,I,I)                                  -> Void
      ++ rotate(v,th,phi) rotates the graph to the longitudinal view angle
      ++ \spad{th} degrees and the latitudinal view angle \spad{phi} degrees
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.  The new rotation position
      ++ is not displayed until the function \spadfun{makeViewport3D} is
      ++ executed again for v.
    zoom                  : (%,F)                                    -> Void
      ++ zoom(v,s) sets the graph scaling factor to s, for the viewport v,
      ++ which is of the domain \spadtype{ThreeDimensionalViewport}.
    zoom                  : (%,F,F,F)                                -> Void
      ++ zoom(v,sx,sy,sz) sets the graph scaling factors for the x-coordinate
      ++ axis to \spad{sx}, the y-coordinate axis to \spad{sy} and the
      ++ z-coordinate axis to \spad{sz} for the viewport v, which is of
      ++ the domain \spadtype{ThreeDimensionalViewport}.
    translate             : (%,F,F)                                  -> Void
      ++ translate(v,dx,dy) sets the horizontal viewport offset to \spad{dx}
      ++ and the vertical viewport offset to \spad{dy}, for the viewport v,
      ++ which is of the domain \spadtype{ThreeDimensionalViewport}.
    perspective           : (%,S)                                    -> Void
      ++ perspective(v,s) displays the graph in perspective if s is "on",
      ++ or does not display perspective if s is "off" for the given
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}.
    eyeDistance           : (%,F)                                    -> Void
      ++ eyeDistance(v,d) sets the distance of the observer from the center
      ++ of the graph to d, for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.
    hitherPlane           : (%,F)                                    -> Void
      ++ hitherPlane(v,h) sets the hither clipping plane of the graph to h,
      ++ for the viewport v, which is of the domain
      ++ \spadtype{ThreeDimensionalViewport}.
    showRegion            : (%,S)                                    -> Void
      ++ showRegion(v,s) displays the bounding box of the given 
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, if s is "on", or does not
      ++ display the box if s is "off".
    showClipRegion        : (%,S)                                    -> Void
      ++ showClipRegion(v,s) displays the clipping region of the given 
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, if s is "on", or does not
      ++ display the region if s is "off".
    clipSurface           : (%,S)                                    -> Void
      ++ clipSurface(v,s) displays the graph with the specified
      ++ clipping region removed if s is "on", or displays the graph
      ++ without clipping implemented if s is "off", for the given 
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}.
    lighting              : (%,F,F,F)                                -> Void
      ++ lighting(v,x,y,z) sets the position of the light source to
      ++ the coordinates x, y, and z and displays the graph for the given 
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}.
    intensity             : (%,F)                                    -> Void
      ++ intensity(v,i) sets the intensity of the light source to i, for
      ++ the given three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}.
    reset                 :  %                                       -> Void
      ++ reset(v) sets the current state of the graph characteristics
      ++ of the given three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, back to their initial settings.
    colorDef              : (%,C,C)                                  -> Void
      ++ colorDef(v,c1,c2) sets the range of colors along the colormap so
      ++ that the lower end of the colormap is defined by \spad{c1} and the
      ++ top end of the colormap is defined by \spad{c2}, for the given
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}.
    write                 : (%,S)                                    -> S
      ++ write(v,s) takes the given three-dimensional viewport, v, which
      ++ is of domain \spadtype{ThreeDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ file for v.
    write                 : (%,S,S)                                  -> S
      ++ write(v,s,f) takes the given three-dimensional viewport, v, which
      ++ is of domain \spadtype{ThreeDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ file for v and an optional file type f.
    write                 : (%,S,L S)                                -> S
      ++ write(v,s,lf) takes the given three-dimensional viewport, v, which
      ++ is of domain \spadtype{ThreeDimensionalViewport}, and creates
      ++ a directory indicated by s, which contains the graph data
      ++ file for v and the optional file types indicated by the list lf.
    close                 :  %                                       -> Void
      ++ close(v) closes the viewport window of the given
      ++ three-dimensional viewport, v, which is of domain
      ++ \spadtype{ThreeDimensionalViewport}, and terminates the
      ++ corresponding process ID.
    key                   :  %                                       -> I
      ++ key(v) returns the process ID number of the given three-dimensional
      ++ viewport, v, which is of domain \spadtype{ThreeDimensionalViewport}.
--    print                 :  %                                       -> Void

  Implementation ==> add
    import Color()
    import ViewDefaultsPackage()
    import Plot3D()
    import POINT
    import PointPackage(SF)
    import SubSpaceComponentProperty()
    import SPACE3
    import MeshCreationRoutinesForThreeDimensions()
    import DrawOptionFunctions0
    import COORDSYS
    import Set(PositiveInteger)

    Rep := Record (key:I, fun:I, _
                   title:S, moveTo:XYNN, size:XYP, viewpoint:V, colors:H, flags:FLAG, _
                   lighting:LR, perspective:PR, volume:VR, _
                   space3D:SPACE3, _
                   optionsField:L DROP)

    degrees := pi()$F / 180.0
    degreesSF := pi()$SF / 180
    defaultTheta  : Reference(SF) := ref(convert(pi()$F/4.0)@SF)
    defaultPhi    : Reference(SF) := ref(convert(-pi()$F/4.0)@SF)
    defaultZoom   : Reference(SF) := ref(convert(1.2)@SF)
    defaultDeltaX : Reference(SF) := ref 0
    defaultDeltaY : Reference(SF) := ref 0


--%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
      negative? i => 
        viewport.key := 0$I
        error "This viewport has already been closed!"
      true
    
    arcsinTemp(x:SF):SF ==
      -- the asin function doesn't exist in the SF domain currently
      x >= 1  => (pi()$SF / 2)  -- to avoid floating point error from SF (ie 1.0 -> 1.00001)
      x <= -1 => 3 * pi()$SF / 2
      convert(asin(convert(x)@Float)$Float)@SF

    arctanTemp(x:SF):SF == convert(atan(convert(x)@Float)$Float)@SF

    doOptions(v:Rep):Void ==    
      v.title := title(v.optionsField,"AXIOM3D")
      st:S := style(v.optionsField,"wireMesh")
      if (st = "shade" or st = "render") then
        v.flags.style := rendered
      else if (st = "solid" or st = "opaque") then
        v.flags.style := opaque
      else if (st = "contour") then
        v.flags.style := contour      
      else if (st = "smooth") then
        v.flags.style := smooth
      else v.flags.style := wireMesh
      v.viewpoint := viewpoint(v.optionsField,
        [deref defaultTheta,deref defaultPhi,deref defaultZoom, _
          1$SF,1$SF,1$SF,deref defaultDeltaX, deref defaultDeltaY])
        -- etc - 3D specific stuff...

--%Exported Functions : Default Settings
    viewport3D() ==
      [0,typeVIEW3D,"AXIOM3D",[viewPosDefault().1,viewPosDefault().2], _
       [viewSizeDefault().1,viewSizeDefault().2], _
        [deref defaultTheta,deref defaultPhi,deref defaultZoom, _
          1$SF,1$SF,1$SF,deref defaultDeltaX, deref defaultDeltaY], [0,27], _
            [noControl,wireMesh,yes,no,no,no], [0$SF,0$SF,1$SF,0$SF,0$SF,1$SF], _
              [yes, EYED, HITHER], [0$SF,1$SF,0$SF,1$SF,0$SF,1$SF,no,yes], _
                create3Space()$SPACE3, [] ]

    subspace viewport ==
      viewport.space3D

    subspace(viewport,space) ==
      viewport.space3D := space
      viewport

    options viewport ==
      viewport.optionsField

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

    makeViewport3D(space:SPACE3,Title:S):% ==
      v := viewport3D()
      v.space3D := space
      v.optionsField := [title(Title)]
      makeViewport3D v

    makeViewport3D(space:SPACE3,opts:L DROP):% ==
      v := viewport3D()
      v.space3D := space
      v.optionsField := opts
      makeViewport3D v

    makeViewport3D viewport ==
      doOptions viewport --local function to extract and assign optional arguments for 3D viewports
      sayBrightly(["   Transmitting data..."::E]$List(E))$Lisp
      transform := coord(viewport.optionsField,cartesian$COORDSYS)$DrawOptionFunctions0
      check(viewport.space3D)
      lpts := lp(viewport.space3D) 
      lllipts  := lllip(viewport.space3D)
      llprops := llprop(viewport.space3D)
      lprops  := lprop(viewport.space3D)
        -- check for dimensionality of points
        -- if they are all 4D points, then everything is okay
        -- if they are all 3D points, then pad an extra constant
        -- coordinate for color
        -- if they have varying dimensionalities, give an error
      s := brace()$Set(PI)
      for pt in lpts repeat
        insert!(dimension pt,s)
      #s > 1 => error "All points should have the same dimension"
      (n := first parts s) < 3 => error "Dimension of points should be greater than 2"
      sendI(VIEW,viewport.fun)$Lisp
      sendI(VIEW,makeVIEW3D)$Lisp
      sendSTR(VIEW,viewport.title)$Lisp
      sendSF(VIEW,viewport.viewpoint.deltaX)$Lisp
      sendSF(VIEW,viewport.viewpoint.deltaY)$Lisp
      sendSF(VIEW,viewport.viewpoint.scale)$Lisp
      sendSF(VIEW,viewport.viewpoint.scaleX)$Lisp
      sendSF(VIEW,viewport.viewpoint.scaleY)$Lisp
      sendSF(VIEW,viewport.viewpoint.scaleZ)$Lisp
      sendSF(VIEW,viewport.viewpoint.theta)$Lisp
      sendSF(VIEW,viewport.viewpoint.phi)$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
      sendI(VIEW,viewport.flags.style)$Lisp
      sendI(VIEW,viewport.flags.axesOn)$Lisp
      sendI(VIEW,viewport.flags.diagonalsOn)$Lisp
      sendI(VIEW,viewport.flags.outlineRenderOn)$Lisp
      sendI(VIEW,viewport.flags.showRegionField)$Lisp  -- add to make3D.c
      sendI(VIEW,viewport.volume.clipRegionField)$Lisp  -- add to make3D.c
      sendI(VIEW,viewport.volume.clipSurfaceField)$Lisp  -- add to make3D.c
      sendI(VIEW,viewport.colors.hueOffset)$Lisp
      sendI(VIEW,viewport.colors.hueNumber)$Lisp
      sendSF(VIEW,viewport.lighting.lightX)$Lisp
      sendSF(VIEW,viewport.lighting.lightY)$Lisp
      sendSF(VIEW,viewport.lighting.lightZ)$Lisp
      sendSF(VIEW,viewport.lighting.translucence)$Lisp
      sendI(VIEW,viewport.perspective.perspectiveField)$Lisp
      sendSF(VIEW,viewport.perspective.eyeDistance)$Lisp
        -- new, crazy points domain stuff
          -- first, send the point data list
      sendI(VIEW,#lpts)$Lisp
      for pt in lpts repeat
        aPoint := transform pt
        sendSF(VIEW,xCoord aPoint)$Lisp
        sendSF(VIEW,yCoord aPoint)$Lisp
        sendSF(VIEW,zCoord aPoint)$Lisp
        n = 3 => sendSF(VIEW,zCoord aPoint)$Lisp
        sendSF(VIEW,color aPoint)$Lisp  -- change to c
          -- now, send the 3d subspace structure
      sendI(VIEW,#lllipts)$Lisp
      for allipts in lllipts for oneprop in lprops for onelprops in llprops repeat
           -- the following is false for f(x,y) and user-defined for [x(t),y(t),z(t)]
           -- this is temporary - until the generalized points stuff gets put in
        sendI(VIEW,(closed? oneprop => yes; no))$Lisp
        sendI(VIEW,(solid? oneprop => yes; no))$Lisp
        sendI(VIEW,#allipts)$Lisp
        for alipts in allipts for tinyprop in onelprops repeat
           -- the following is false for f(x,y) and true for [x(t),y(t),z(t)]
           -- this is temporary -- until the generalized points stuff gets put in
          sendI(VIEW,(closed? tinyprop => yes;no))$Lisp
          sendI(VIEW,(solid? tinyprop => yes;no))$Lisp
          sendI(VIEW,#alipts)$Lisp
          for oneIndexedPoint in alipts repeat
            sendI(VIEW,oneIndexedPoint)$Lisp 
      viewport.key := getI(VIEW)$Lisp
      viewport
         -- the key (now set to 0) should be what the viewport returns

    viewThetaDefault    == convert(defaultTheta())@F
    viewThetaDefault  t == 
      defaultTheta() := convert(t)@SF
      t
    viewPhiDefault      == convert(defaultPhi())@F
    viewPhiDefault    t == 
      defaultPhi() := convert(t)@SF
      t
    viewZoomDefault     == convert(defaultZoom())@F
    viewZoomDefault   t == 
      defaultZoom() := convert(t)@SF
      t
    viewDeltaXDefault   == convert(defaultDeltaX())@F
    viewDeltaXDefault t == 
      defaultDeltaX() := convert(t)@SF
      t
    viewDeltaYDefault   == convert(defaultDeltaY())@F
    viewDeltaYDefault t == 
      defaultDeltaY() := convert(t)@SF
      t

--Exported Functions: Available features for 3D viewports
    lighting(viewport,Xlight,Ylight,Zlight) ==
      viewport.lighting.lightX := convert(Xlight)@SF
      viewport.lighting.lightY := convert(Ylight)@SF
      viewport.lighting.lightZ := convert(Zlight)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,lightDef)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.lighting.lightX)$Lisp
          sendSF(VIEW,viewport.lighting.lightY)$Lisp
          sendSF(VIEW,viewport.lighting.lightZ)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    axes (viewport,onOff) ==
      if onOff = "on" then viewport.flags.axesOn := yes
      else viewport.flags.axesOn := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,axesOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.axesOn)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    diagonals (viewport,onOff) ==
      if onOff = "on" then viewport.flags.diagonalsOn := yes
      else viewport.flags.diagonalsOn := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,diagOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.diagonalsOn)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    outlineRender (viewport,onOff) ==
      if onOff = "on" then viewport.flags.outlineRenderOn := yes
      else viewport.flags.outlineRenderOn := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,outlineOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.outlineRenderOn)$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,typeVIEW3D)$Lisp
        sendI(VIEW,hideControl)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.showCP)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    drawStyle (viewport,how) ==
      if (how = "shade") then                    -- render
        viewport.flags.style := rendered
      else if (how = "solid") then               -- opaque
        viewport.flags.style := opaque
      else if (how = "contour") then             -- contour
        viewport.flags.style := contour
      else if (how = "smooth") then              -- smooth
        viewport.flags.style := smooth
      else viewport.flags.style := wireMesh
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,viewport.flags.style)$Lisp
        checkViewport viewport =>
          getI(VIEW)$Lisp          -- acknowledge

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

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

    viewpoint (viewport:%):V ==
      (key(viewport) ~= 0$I) =>
	sendI(VIEW,typeVIEW3D)$Lisp
	sendI(VIEW,queryVIEWPOINT)$Lisp
	checkViewport viewport =>
	  deltaX_sf : SF := getSF(VIEW)$Lisp
	  deltaY_sf : SF := getSF(VIEW)$Lisp
	  scale_sf  : SF := getSF(VIEW)$Lisp
	  scaleX_sf : SF := getSF(VIEW)$Lisp
	  scaleY_sf : SF := getSF(VIEW)$Lisp
	  scaleZ_sf : SF := getSF(VIEW)$Lisp
	  theta_sf  : SF := getSF(VIEW)$Lisp
	  phi_sf    : SF := getSF(VIEW)$Lisp
          getI(VIEW)$Lisp          -- acknowledge
	  viewport.viewpoint := 
	    [ theta_sf, phi_sf, scale_sf, scaleX_sf, scaleY_sf, scaleZ_sf, 
	      deltaX_sf, deltaY_sf ]
        viewport.viewpoint
      viewport.viewpoint

    viewpoint (viewport:%, viewpt:V):Void ==
      viewport.viewpoint := viewpt
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,changeVIEWPOINT)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.viewpoint.deltaX)$Lisp
          sendSF(VIEW,viewport.viewpoint.deltaY)$Lisp
          sendSF(VIEW,viewport.viewpoint.scale)$Lisp
          sendSF(VIEW,viewport.viewpoint.scaleX)$Lisp
          sendSF(VIEW,viewport.viewpoint.scaleY)$Lisp
          sendSF(VIEW,viewport.viewpoint.scaleZ)$Lisp
          sendSF(VIEW,viewport.viewpoint.theta)$Lisp
          sendSF(VIEW,viewport.viewpoint.phi)$Lisp
          getI(VIEW)$Lisp          -- acknowledge


    viewpoint (viewport:%,Theta:F,Phi:F,Scale:F,DeltaX:F,DeltaY:F):Void ==
      viewport.viewpoint := 
        [convert(Theta)@SF,convert(Phi)@SF,convert(Scale)@SF,1$SF,1$SF,1$SF,convert(DeltaX)@SF,convert(DeltaY)@SF]

    viewpoint (viewport:%,Theta:I,Phi:I,Scale:F,DeltaX:F,DeltaY:F):Void ==
      viewport.viewpoint := [convert(Theta)@SF * degreesSF,convert(Phi)@SF * degreesSF,
        convert(Scale)@SF,1$SF,1$SF,1$SF,convert(DeltaX)@SF,convert(DeltaY)@SF]

    viewpoint (viewport:%,Theta:F,Phi:F):Void ==
      viewport.viewpoint.theta := convert(Theta)@SF * degreesSF
      viewport.viewpoint.phi   := convert(Phi)@SF * degreesSF

    viewpoint (viewport:%,X:F,Y:F,Z:F):Void ==
      Theta : F
      Phi : F
      if (X=0$F) and (Y=0$F) then
        Theta := 0$F
        if (Z>=0$F) then
          Phi := 0$F
        else 
          Phi := 180.0
      else
        Theta := asin(Y/(R := sqrt(X*X+Y*Y)))
        if (Z=0$F) then
          Phi := 90.0
        else
          Phi := atan(Z/R)
      rotate(viewport, Theta * degrees, Phi * degrees)
    
    title (viewport,Title) == 
      viewport.title := Title
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,TITLE)$Lisp
        checkViewport viewport =>
          sendSTR(VIEW,Title)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    colorDef (viewport,HueOffset,HueNumber) ==
      viewport.colors := [h := (hue HueOffset),(hue HueNumber) - h]
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,COLORDEF)$Lisp
        checkViewport viewport =>
          sendI(VIEW,hue HueOffset)$Lisp
          sendI(VIEW,hue HueNumber)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    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,typeVIEW3D)$Lisp
        sendI(VIEW,MOVE)$Lisp
        checkViewport viewport =>
          sendI(VIEW,xLoc)$Lisp
          sendI(VIEW,yLoc)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    resize(viewport,xSize,ySize) ==
      viewport.size := [xSize,ySize]
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,RESIZE)$Lisp
        checkViewport viewport =>
          sendI(VIEW,xSize)$Lisp
          sendI(VIEW,ySize)$Lisp
          getI(VIEW)$Lisp          -- acknowledge
 
    coerce viewport ==
      (key(viewport) = 0$I) =>
        hconcat
          ["Closed or Undefined ThreeDimensionalViewport: "::E,
           (viewport.title)::E]
      hconcat ["ThreeDimensionalViewport: "::E, (viewport.title)::E]

    key viewport == viewport.key

    rotate(viewport:%,Theta:I,Phi:I) ==
      rotate(viewport,Theta::F * degrees,Phi::F * degrees) 

    rotate(viewport:%,Theta:F,Phi:F) ==
      viewport.viewpoint.theta := convert(Theta)@SF
      viewport.viewpoint.phi   := convert(Phi)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,ROTATE)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.viewpoint.theta)$Lisp
          sendSF(VIEW,viewport.viewpoint.phi)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    zoom(viewport:%,Scale:F) ==
      viewport.viewpoint.scale := convert(Scale)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,ZOOM)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.viewpoint.scale)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    zoom(viewport:%,ScaleX:F,ScaleY:F,ScaleZ:F) ==
      viewport.viewpoint.scaleX := convert(ScaleX)@SF
      viewport.viewpoint.scaleY := convert(ScaleY)@SF
      viewport.viewpoint.scaleZ := convert(ScaleZ)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,zoomx)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.viewpoint.scaleX)$Lisp
          sendSF(VIEW,viewport.viewpoint.scaleY)$Lisp
          sendSF(VIEW,viewport.viewpoint.scaleZ)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    translate(viewport,DeltaX,DeltaY) ==
      viewport.viewpoint.deltaX := convert(DeltaX)@SF
      viewport.viewpoint.deltaY := convert(DeltaY)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,TRANSLATE)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.viewpoint.deltaX)$Lisp
          sendSF(VIEW,viewport.viewpoint.deltaY)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    intensity(viewport,Amount) ==
      if negative? Amount or (Amount > 1$F) then
        error "The intensity must be a value between 0 and 1, inclusively."
      viewport.lighting.translucence := convert(Amount)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,translucenceDef)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.lighting.translucence)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

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

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

    perspective (viewport,onOff) ==
      if onOff = "on" then viewport.perspective.perspectiveField := yes
      else viewport.perspective.perspectiveField := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,perspectiveOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.perspective.perspectiveField)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    showRegion (viewport,onOff) ==
      if onOff = "on" then viewport.flags.showRegionField := yes
      else viewport.flags.showRegionField := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,region3D)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.flags.showRegionField)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    showClipRegion (viewport,onOff) ==
      if onOff = "on" then viewport.volume.clipRegionField := yes
      else viewport.volume.clipRegionField := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,clipRegionOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.volume.clipRegionField)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    clipSurface (viewport,onOff) ==
      if onOff = "on" then viewport.volume.clipSurfaceField := yes
      else viewport.volume.clipSurfaceField := no
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,clipSurfaceOnOff)$Lisp
        checkViewport viewport =>
          sendI(VIEW,viewport.volume.clipSurfaceField)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    eyeDistance(viewport:%,EyeDistance:F) ==
      viewport.perspective.eyeDistance := convert(EyeDistance)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,eyeDistanceData)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.perspective.eyeDistance)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    hitherPlane(viewport:%,HitherPlane:F) ==
      viewport.perspective.hitherPlane := convert(HitherPlane)@SF
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,hitherPlaneData)$Lisp
        checkViewport viewport =>
          sendSF(VIEW,viewport.perspective.hitherPlane)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

    modifyPointData(viewport,anIndex,aPoint) ==
      (n := dimension aPoint) < 3 => error "The point should have dimension of at least 3"
      viewport.space3D := modifyPointData(viewport.space3D,anIndex,aPoint)
      (key(viewport) ~= 0$I) =>
        sendI(VIEW,typeVIEW3D)$Lisp
        sendI(VIEW,modifyPOINT)$Lisp
        checkViewport viewport =>
          sendI(VIEW,anIndex)$Lisp
          sendSF(VIEW,xCoord aPoint)$Lisp
          sendSF(VIEW,yCoord aPoint)$Lisp
          sendSF(VIEW,zCoord aPoint)$Lisp
          if (n = 3) then sendSF(VIEW,convert(0.5)@SF)$Lisp
          else sendSF(VIEW,color aPoint)$Lisp
          getI(VIEW)$Lisp          -- acknowledge

--    print viewport ==
--      (key(viewport) ~= 0$I) =>
--        sendI(VIEW,typeVIEW3D)$Lisp
--        sendI(VIEW,printViewport)$Lisp
--        checkViewport viewport =>
--          getI(VIEW)$Lisp          -- acknowledge

@
\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>>

-- this is a new graphics package and does not depend on any of the
-- current plotting stuff
-- so it is best to run it in a minimum system (like spadsys)

<<domain VIEW3D ThreeDimensionalViewport>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}