--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.

)abbrev category SPACEC ThreeSpaceCategory
++ Author: 
++ Date Created: 
++ Date Last Updated:
++ Basic Operations: create3Space, numberOfComponents, numberOfComposites,
++ merge, composite, components, copy, enterPointData, modifyPointData, point,
++ point?, curve, curve?, closedCurve, closedCurve?, polygon, polygon? mesh,
++ mesh?, lp, lllip, lllp, llprop, lprop, objects, check, subspace, coerce
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords: 
++ References:
++ Description: The category ThreeSpaceCategory is used for creating 
++ three dimensional objects using functions for defining points, curves, 
++ polygons, constructs and the subspaces containing them.

ThreeSpaceCategory(R:Ring): Exports == Implementation where
 I    ==> Integer
 PI   ==> PositiveInteger
 NNI  ==> NonNegativeInteger
 L    ==> List
 B    ==> Boolean
 O    ==> OutputForm
 SUBSPACE ==> SubSpace(3,R)
 POINT   ==> Point(R)
 PROP    ==> SubSpaceComponentProperty()
 REP3D   ==> Record(lp:L POINT,llliPt:L L L NNI, llProp:L L PROP, lProp:L PROP)
 OBJ3D   ==> Record(points:NNI, curves:NNI, polygons:NNI, constructs:NNI)

 Exports ==> Category
 Implementation ==>
  SetCategory with
    create3Space : () -> %
      ++ create3Space() creates a \spadtype{ThreeSpace} object capable of 
      ++ holding point, curve, mesh components and any combination.
    create3Space : SUBSPACE -> %
      ++ create3Space(s) creates a \spadtype{ThreeSpace} object containing
      ++ objects pre-defined within some \spadtype{SubSpace} s.
    numberOfComponents : % -> NNI
      ++ numberOfComponents(s) returns the number of distinct
      ++ object components in the indicated \spadtype{ThreeSpace}, s, such
      ++ as points, curves, polygons, and constructs.
    numberOfComposites : % -> NNI
      ++ numberOfComposites(s) returns the number of supercomponents,
      ++ or composites, in the \spadtype{ThreeSpace}, s; Composites are 
      ++ arbitrary groupings of otherwise distinct and unrelated components;
      ++ A \spadtype{ThreeSpace} need not have any composites defined at all
      ++ and, outside of the requirement that no component can belong
      ++ to more than one composite at a time, the definition and
      ++ interpretation of composites are unrestricted.
    merge : L % -> %
      ++ merge([s1,s2,...,sn]) will create a new \spadtype{ThreeSpace} that has 
      ++ the components of all the ones in the list; Groupings of components
      ++ into composites are maintained.
    merge : (%,%) -> %
      ++ merge(s1,s2) will create a new \spadtype{ThreeSpace} that has the
      ++ components of \spad{s1} and \spad{s2}; Groupings of components
      ++ into composites are maintained.
    composite : L % -> %
      ++ composite([s1,s2,...,sn]) will create a new \spadtype{ThreeSpace} that 
      ++ is a union of all the components from each \spadtype{ThreeSpace} in 
      ++ the parameter list, grouped as a composite.
    components : % -> L %
      ++ components(s) takes the \spadtype{ThreeSpace} s, and creates a list 
      ++ containing a unique \spadtype{ThreeSpace} for each single component 
      ++ of s. If s has no components defined, the list returned is empty.
    composites : % -> L %
      ++ composites(s) takes the \spadtype{ThreeSpace} s, and creates a list 
      ++ containing a unique \spadtype{ThreeSpace} for each single composite 
      ++ of s. If s has no composites defined (composites need to be explicitly 
      ++ created), the list returned is empty. Note that not all the components
      ++ need to be part of a composite.
    copy : % -> %
      ++ copy(s) returns a new \spadtype{ThreeSpace} that is an exact copy of s.
    enterPointData  : (%,L POINT) -> NNI
      ++ enterPointData(s,[p0,p1,...,pn]) adds a list of points from p0 through
      ++ pn to the \spadtype{ThreeSpace}, s, and returns the index, to the 
      ++ starting point of the list;
    modifyPointData : (%,NNI,POINT) -> %
      ++ modifyPointData(s,i,p) changes the point at the indexed 
      ++ location i in the \spadtype{ThreeSpace}, s, to that of point p.
      ++ This is useful for making changes to a point which has been 
      ++ transformed.

    -- 3D primitives
    point        : (%,POINT) -> %
      ++ point(s,p) adds a point component defined by the point, p, specified as
      ++ a list from \spad{List(R)}, to the \spadtype{ThreeSpace}, s,
      ++ where R is the \spadtype{Ring} over which the point is defined.
    point        : (%,L R) -> %
      ++ point(s,[x,y,z]) adds a point component defined by a list of elements 
      ++ which are from the \spad{PointDomain(R)} to the \spadtype{ThreeSpace},
      ++ s, where R is the \spadtype{Ring} over which the point elements are 
      ++ defined.
    point        : (%,NNI) -> %
      ++ point(s,i) adds a point component which is placed into a component
      ++ list of the \spadtype{ThreeSpace}, s, at the index given by i.
    point        : POINT -> %  
      ++ point(p) returns a \spadtype{ThreeSpace} object which is composed of 
      ++ one component, the point p.
    point        : % -> POINT
      ++ point(s) checks to see if the \spadtype{ThreeSpace}, s, is composed of
      ++ only a single point and if so, returns the point. An error
      ++ is signaled otherwise.
    point?       : % -> B
      ++ point?(s) queries whether the \spadtype{ThreeSpace}, s, is composed of
      ++ a single component which is a point and returns the boolean result.
    curve        : (%,L POINT) -> %
      ++ curve(s,[p0,p1,...,pn]) adds a space curve component defined by a 
      ++ list of points \spad{p0} through \spad{pn}, to the \spadtype{ThreeSpace} s.
    curve        : (%,L L R) -> %
      ++ curve(s,[[p0],[p1],...,[pn]]) adds a space curve which is a list of 
      ++ points p0 through pn defined by lists of elements from the domain 
      ++ \spad{PointDomain(m,R)}, where R is the \spadtype{Ring} over which the
      ++ point elements are defined and m is the dimension of the points, to 
      ++ the \spadtype{ThreeSpace} s.
    curve         : L POINT -> %
      ++ curve([p0,p1,p2,...,pn]) creates a space curve defined
      ++ by the list of points \spad{p0} through \spad{pn}, and returns the 
      ++ \spadtype{ThreeSpace} whose component is the curve.
    curve         : % -> L POINT
      ++ curve(s) checks to see if the \spadtype{ThreeSpace}, s, is composed of
      ++ a single curve defined by a list of points and if so, returns the 
      ++ curve, i.e., list of points. An error is signaled otherwise.
    curve?        : % -> B
      ++ curve?(s) queries whether the \spadtype{ThreeSpace}, s, is a curve, 
      ++ i.e., has one component, a list of list of points, and returns true if
      ++ it is, or false otherwise.
    closedCurve  : (%,L POINT) -> %
      ++ closedCurve(s,[p0,p1,...,pn,p0]) adds a closed curve component which is
      ++ a list of points defined by the first element p0 through the last 
      ++ element pn and back to the first element p0 again, to the 
      ++ \spadtype{ThreeSpace} s.
    closedCurve  : (%,L L R) -> %
      ++ closedCurve(s,[[lr0],[lr1],...,[lrn],[lr0]]) adds a closed curve 
      ++ component defined by a list of points \spad{lr0} through \spad{lrn}, 
      ++ which are lists of elements from the domain \spad{PointDomain(m,R)}, 
      ++ where R is the \spadtype{Ring} over which the point elements are 
      ++ defined and m is the dimension of the points, in which the last element
      ++ of the list of points contains a copy of the first element list, lr0.
      ++ The closed curve is added to the \spadtype{ThreeSpace}, s.
    closedCurve         : L POINT -> %
      ++ closedCurve(lp) sets a list of points defined by the first element
      ++ of lp through the last element of lp and back to the first elelment
      ++ again and returns a \spadtype{ThreeSpace} whose component is the
      ++ closed curve defined by lp.
    closedCurve         : % -> L POINT
      ++ closedCurve(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a single closed curve component defined by a list of 
      ++ points in which the first point is also the last point, all of which 
      ++ are from the domain \spad{PointDomain(m,R)} and if so, returns the 
      ++ list of points.  An error is signaled otherwise.
    closedCurve?        : % -> B
      ++ closedCurve?(s) returns true if the \spadtype{ThreeSpace} s contains 
      ++ a single closed curve component, i.e., the first element of the curve 
      ++ is also the last element, or false otherwise.
    polygon      : (%,L POINT) -> %
      ++ polygon(s,[p0,p1,...,pn]) adds a polygon component defined by a list of 
      ++ points, p0 throught pn, to the \spadtype{ThreeSpace} s.
    polygon      : (%,L L R) -> %
      ++ polygon(s,[[r0],[r1],...,[rn]]) adds a polygon component defined
      ++ by a list of points \spad{r0} through \spad{rn}, which are lists of
      ++ elements from the domain \spad{PointDomain(m,R)} to the 
      ++ \spadtype{ThreeSpace} s, where m is the dimension of the points
      ++ and R is the \spadtype{Ring} over which the points are defined.
    polygon         : L POINT -> %
      ++ polygon([p0,p1,...,pn]) creates a polygon defined by a list of points,
      ++ p0 through pn, and returns a \spadtype{ThreeSpace} whose component
      ++ is the polygon.
    polygon         : % -> L POINT
      ++ polygon(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a single polygon component defined by a list of 
      ++ points, and if so, returns the list of points;  An error is signaled 
      ++ otherwise.
    polygon?        : % -> B
      ++ polygon?(s) returns true if the \spadtype{ThreeSpace} s contains 
      ++ a single polygon component, or false otherwise.
    mesh         : (%,L L POINT,L PROP,PROP) -> %
      ++ mesh(s,[[p0],[p1],...,[pn]],[props],prop) adds a surface component, 
      ++ defined over a list curves which contains lists of points, to the 
      ++ \spadtype{ThreeSpace} s; props is a list which contains the subspace 
      ++ component properties for each surface parameter, and prop is the 
      ++ subspace component property by which the points are defined.
    mesh         : (%,L L L R,L PROP,PROP) -> %
      ++ mesh(s,[ [[r10]...,[r1m]], [[r20]...,[r2m]],..., [[rn0]...,[rnm]] ], [props], prop)
      ++ adds a surface component to the \spadtype{ThreeSpace} s, which is 
      ++ defined over a rectangular domain of size WxH where W is the number 
      ++ of lists of points from the domain \spad{PointDomain(R)} and H is the 
      ++ number of elements in each of those lists; lprops is the list of the 
      ++ subspace component properties for each curve list, and prop is 
      ++ the subspace component property by which the points are defined.
    mesh         : (%,L L POINT,B,B) -> %
      ++ mesh(s,[[p0],[p1],...,[pn]], close1, close2) adds a surface component to
      ++ the \spadtype{ThreeSpace}, which is defined over a list of curves,
      ++ in which each of these curves is a list of points. 
      ++ The boolean arguments close1 and close2 indicate how the surface 
      ++ is to be closed. Argument close1 equal true
      ++ means that each individual list (a curve) is to be closed, i.e. the 
      ++ last point of the list is to be connected to the first point.
      ++ Argument close2 equal true 
      ++ means that the boundary at one end of the surface is to be
      ++ connected to the boundary at the other end, i.e. the boundaries 
      ++ are defined as the first list of points (curve) and 
      ++ the last list of points (curve).
    mesh         : (%,L L L R,B,B) -> %
      ++ mesh(s,[ [[r10]...,[r1m]], [[r20]...,[r2m]],..., [[rn0]...,[rnm]] ], close1, close2)
      ++ adds a surface component to the \spadtype{ThreeSpace} s, which is 
      ++ defined over a rectangular domain of size WxH where W is the number 
      ++ of lists of points from the domain \spad{PointDomain(R)} and H is the 
      ++ number of elements in each of those lists; the booleans close1 and 
      ++ close2 indicate how the surface is to be closed: if close1 is true 
      ++ this means that each individual list (a curve) is to be closed (i.e., 
      ++ the last point of the list is to be connected to the first point);
      ++ if close2 is true, this means that the boundary at one end of the
      ++ surface is to be connected to the boundary at the other end
      ++ (the boundaries are defined as the first list of points (curve)
      ++ and the last list of points (curve)).
    mesh         : L L POINT -> %
      ++ mesh([[p0],[p1],...,[pn]]) creates a surface defined by a list of 
      ++ curves which are lists, p0 through pn, of points, and returns a 
      ++ \spadtype{ThreeSpace} whose component is the surface.
    mesh         : (L L POINT,B,B) -> %
      ++ mesh([[p0],[p1],...,[pn]], close1, close2) creates a surface defined 
      ++ over a list of curves, p0 through pn, which are lists of points;
      ++ the booleans close1 and close2 indicate how the surface is to be 
      ++ closed: close1 set to true means that each individual list (a curve) 
      ++ is to be closed (that is, the last point of the list is to be 
      ++ connected to the first point); close2 set to true means that the 
      ++ boundary at one end of the surface is to be connected to the boundary
      ++ at the other end (the boundaries are defined as the first list of 
      ++ points (curve) and the last list of points (curve)); the
      ++ \spadtype{ThreeSpace} containing this surface is returned.
    mesh         : % -> L L POINT
      ++ mesh(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a single surface component defined by a list curves which
      ++ contain lists of points, and if so, returns the list of lists of 
      ++ points;  An error is signaled otherwise.
    mesh?        : % -> B
      ++ mesh?(s) returns true if the \spadtype{ThreeSpace} s is composed of one
      ++ component, a mesh comprising a list of curves which are lists
      ++ of points, or returns false if otherwise
    lp           : % -> L POINT
      ++ lp(s) returns the list of points component which the 
      ++ \spadtype{ThreeSpace}, s, contains; these points are used by reference,
      ++ i.e., the component holds indices referring to the points rather
      ++ than the points themselves. This allows for sharing of the points.
    lllip        : % -> L L L NNI
      ++ lllip(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a list of components, which are lists of curves, 
      ++ which are lists of indices to points, and if so, returns the list of 
      ++ lists of lists;  An error is signaled otherwise.
    lllp         : % -> L L L POINT   -- used by view3D
      ++ lllp(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a list of components, which are lists of curves, 
      ++ which are lists of points, and if so, returns the list of 
      ++ lists of lists;  An error is signaled otherwise.
    llprop       : % -> L L PROP      -- used by view3D
      ++ llprop(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a list of curves which are lists of the
      ++ subspace component properties of the curves, and if so, returns the 
      ++ list of lists;  An error is signaled otherwise.
    lprop        : % -> L PROP        -- used by view3D
      ++ lprop(s) checks to see if the \spadtype{ThreeSpace}, s, is 
      ++ composed of a list of subspace component properties, and if so, 
      ++ returns the list;  An error is signaled otherwise.
    objects      : % -> OBJ3D
      ++ objects(s) returns the \spadtype{ThreeSpace}, s, in the form of a 
      ++ 3D object record containing information on the number of points, 
      ++ curves, polygons and constructs comprising the \spadtype{ThreeSpace}..
    check        : % -> %             -- used by mesh
      ++ check(s) returns lllpt, list of lists of lists of point information 
      ++ about the \spadtype{ThreeSpace} s.
    subspace     : % -> SUBSPACE
      ++ subspace(s) returns the \spadtype{SubSpace} which holds all the point
      ++ information in the \spadtype{ThreeSpace}, s.
    coerce       : % -> O
      ++ coerce(s) returns the \spadtype{ThreeSpace} s to Output format.

)abbrev domain SPACE3 ThreeSpace
++ Author: 
++ Date Created: 
++ Date Last Updated:
++ Basic Operations: create3Space, numberOfComponents, numberOfComposites,
++ merge, composite, components, copy, enterPointData, modifyPointData, point,
++ point?, curve, curve?, closedCurve, closedCurve?, polygon, polygon? mesh,
++ mesh?, lp, lllip, lllp, llprop, lprop, objects, check, subspace, coerce
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords: 
++ References:
++ Description: The domain ThreeSpace is used for creating three dimensional 
++ objects using functions for defining points, curves, polygons, constructs 
++ and the subspaces containing them.

ThreeSpace(R:Ring):Exports == Implementation where
  -- m is the dimension of the point
 
  I    ==> Integer
  PI   ==> PositiveInteger
  NNI  ==> NonNegativeInteger
  L    ==> List
  B    ==> Boolean
  O    ==> OutputForm
  SUBSPACE ==> SubSpace(3,R)
  POINT  ==> Point(R)
  PROP   ==> SubSpaceComponentProperty()
  REP3D  ==> Record(lp:L POINT,llliPt:L L L NNI, llProp:L L PROP, lProp:L PROP)
  OBJ3D  ==> Record(points:NNI, curves:NNI, polygons:NNI, constructs:NNI)

  Exports ==> ThreeSpaceCategory(R)
  Implementation ==> add
    import COMPPROP
    import POINT
    import SUBSPACE
    import ListFunctions2(List(R),POINT)
    import Set(NNI)

    Rep := Record( subspaceField:SUBSPACE, compositesField:L SUBSPACE, _
                   rep3DField:REP3D, objectsField:OBJ3D, _
                   converted:B)
 
--% Local Functions
    convertSpace : % -> %
    convertSpace space ==
      space.converted => space
      space.converted := true
      lllipt : L L L NNI := [] 
      llprop : L L PROP := []
      lprop : L PROP := []
      for component in children space.subspaceField repeat
        lprop := cons(extractProperty component,lprop)  
        tmpllipt : L L NNI := []
        tmplprop : L PROP := []
        for curve in children component repeat
          tmplprop := cons(extractProperty curve,tmplprop)
          tmplipt : L NNI := []
          for point in children curve repeat
            tmplipt := cons(extractIndex point,tmplipt)
          tmpllipt := cons(reverse! tmplipt,tmpllipt)
        llprop := cons(reverse! tmplprop, llprop)
        lllipt := cons(reverse! tmpllipt, lllipt)
      space.rep3DField := [pointData space.subspaceField, 
                           reverse! lllipt,reverse! llprop,reverse! lprop]
      space
      

--% Exported Functions
    polygon(space:%,points:L POINT) ==
      #points < 3 =>
        error "You need at least 3 points to define a polygon"
      pt := addPoint2(space.subspaceField,first points)
      points := rest points
      addPointLast(space.subspaceField, pt, first points, 1)
      for p in rest points repeat
        addPointLast(space.subspaceField, pt, p, 2)
      space.converted := false
      space
    create3Space() == [ new()$SUBSPACE, [], [ [], [], [], [] ], [0,0,0,0], false ]
    create3Space(s) == [ s, [], [ [], [], [], [] ], [0,0,0,0], false ]
    numberOfComponents(space) == #(children((space::Rep).subspaceField))
    numberOfComposites(space) == #((space::Rep).compositesField)
    merge(listOfThreeSpaces) ==
          -- * -- we may want to remove duplicate components when that functionality exists in List
      newspace := create3Space(merge([ts.subspaceField for ts in listOfThreeSpaces]))
--      newspace.compositesField := [for cs in ts.compositesField for ts in listOfThreeSpaces]
      for ts in listOfThreeSpaces repeat 
        newspace.compositesField := append(ts.compositesField,newspace.compositesField)
      newspace
    merge(s1,s2) == merge([s1,s2])
    composite(listOfThreeSpaces) ==
      space := create3Space()
      space.subspaceField := merge [s.subspaceField for s in listOfThreeSpaces]
      space.compositesField := [deepCopy space.subspaceField]
--      for aSpace in listOfThreeSpaces repeat
          -- create a composite (which are supercomponents that group
          -- separate components together) out of all possible components
--        space.compositesField := append(children aSpace.subspaceField,space.compositesField)
      space
    components(space) == [create3Space(s) for s in separate space.subspaceField]
    composites(space) == [create3Space(s) for s in space.compositesField]
    copy(space) ==
      spc := create3Space(deepCopy(space.subspaceField))
      spc.compositesField := [deepCopy s for s in space.compositesField]
      spc

    enterPointData(space,listOfPoints) ==
      for p in listOfPoints repeat
        addPoint(space.subspaceField,p)
      #(pointData space.subspaceField)
    modifyPointData(space,i,p) ==
      modifyPoint(space.subspaceField,i,p)
      space

      -- 3D primitives, each grouped in the following order
      --     xxx?(s)  : query whether the threespace, s, holds an xxx
      --     xxx(s)   : extract xxx from threespace, s
      --     xxx(p)   : create a new three space with xxx, p
      --     xxx(s,p) : add xxx, p, to a three space, s
      --     xxx(s,q) : add an xxx, convertable from q, to a three space, s
      --     xxx(s,i) : add an xxx, the data for xxx being indexed by reference  *** complete this
    point?(space:%) ==
      #(c:=children space.subspaceField) > 1$NNI => 
        error "This ThreeSpace has more than one component"
        -- our 3-space has one component, a list of list of points
      #(kid:=children first c) = 1$NNI => -- the component has one subcomponent (a list of points)
        #(children first kid) = 1$NNI  -- this list of points only has one entry, so it's a point
      false
    point(space:%) ==
      point? space => extractPoint(traverse(space.subspaceField,[1,1,1]::L NNI))
      error "This ThreeSpace holds something other than a single point - try the objects() command"
    point(aPoint:POINT) == point(create3Space(),aPoint)
    point(space:%,aPoint:POINT) ==
      addPoint(space.subspaceField,[],aPoint)
      space.converted := false
      space
    point(space:%,l:L R) ==
      pt := point(l)
      point(space,pt)
    point(space:%,i:NNI) ==
      addPoint(space.subspaceField,[],i)
      space.converted := false
      space

    curve?(space:%) ==
      #(c:=children space.subspaceField) > 1$NNI => 
        error "This ThreeSpace has more than one component"
        -- our 3-space has one component, a list of list of points
      #(children first c) = 1$NNI -- there is only one subcomponent, so it's a list of points
    curve(space:%) ==
      curve? space => 
        spc := first children first children space.subspaceField
        [extractPoint(s) for s in children spc]
      error "This ThreeSpace holds something other than a curve - try the objects() command"
    curve(points:L POINT) == curve(create3Space(),points)
    curve(space:%,points:L POINT) ==
      addPoint(space.subspaceField,[],first points)
      path : L NNI := [#(children space.subspaceField),1]
      for p in rest points repeat
        addPoint(space.subspaceField,path,p)
      space.converted := false
      space
    curve(space:%,points:L L R) ==
      pts := map(point,points)
      curve(space,pts)
      
    closedCurve?(space:%) ==
      #(c:=children space.subspaceField) > 1$NNI => 
        error "This ThreeSpace has more than one component"
        -- our 3-space has one component, a list of list of points
      #(kid := children first c) = 1$NNI => -- there is one subcomponent => it's a list of points
        extractClosed first kid   -- is it a closed curve?
      false
    closedCurve(space:%) ==
      closedCurve? space => 
        spc := first children first children space.subspaceField 
          -- get the list of points
        [extractPoint(s) for s in children spc]  
          -- for now, we are not repeating points...
      error "This ThreeSpace holds something other than a curve - try the objects() command"
    closedCurve(points:L POINT) == closedCurve(create3Space(),points)
    closedCurve(space:%,points:L POINT) ==
      addPoint(space.subspaceField,[],first points)
      path : L NNI := [#(children space.subspaceField),1]
      closeComponent(space.subspaceField,path,true)
      for p in rest points repeat
        addPoint(space.subspaceField,path,p)
      space.converted := false
      space
    closedCurve(space:%,points:L L R) ==
      pts := map(point,points)
      closedCurve(space,pts)

    polygon?(space:%) ==
      #(c:=children space.subspaceField) > 1$NNI => 
        error "This ThreeSpace has more than one component"
        -- our 3-space has one component, a list of list of points
      #(kid:=children first c) = 2::NNI => 
          -- there are two subcomponents
          -- the convention is to have one point in the first child and to put 
          -- the remaining points (2 or more) in the second, and last, child
        #(children first kid) = 1$NNI and #(children second kid) > 2::NNI
      false  -- => returns Void...?
    polygon(space:%) ==
      polygon? space =>
        listOfPoints : L POINT := 
          [extractPoint(first children first (cs := children first children space.subspaceField))]
        [extractPoint(s) for s in children second cs]
      error "This ThreeSpace holds something other than a polygon - try the objects() command"
    polygon(points:L POINT) == polygon(create3Space(),points)
    polygon(space:%,points:L L R) ==
      pts := map(point,points)
      polygon(space,pts) 

    mesh?(space:%) ==
      #(c:=children space.subspaceField) > 1$NNI => 
        error "This ThreeSpace has more than one component"
        -- our 3-space has one component, a list of list of points
      #(kid:=children first c) > 1$NNI => 
          -- there are two or more subcomponents (list of points)
          -- so this may be a definition of a mesh; if the size
          -- of each list of points is the same and they are all
          -- greater than 1(?) then we have an acceptable mesh
          -- use a set to hold the curve size info: if heterogenous
          -- curve sizes exist, then the set would hold all the sizes;
          -- otherwise it would just have the one element indicating
          -- the sizes for all the curves
          whatSizes := brace()$Set(NNI)
          for eachCurve in kid repeat
            insert!(#children eachCurve,whatSizes)
          #whatSizes > 1 => error "Mesh defined with curves of different sizes"
          first parts whatSizes < 2 => 
            error "Mesh defined with single point curves (use curve())"
          true
      false
    mesh(space:%) ==
      mesh? space =>
        llp : L L POINT := []
        for lpSpace in children first children space.subspaceField repeat
          llp := cons([extractPoint(s) for s in children lpSpace],llp)
        llp
      error "This ThreeSpace holds something other than a mesh - try the objects() command"
    mesh(points:L L POINT) == mesh(create3Space(),points,false,false)
    mesh(points:L L POINT,prop1:B,prop2:B) == mesh(create3Space(),points,prop1,prop2)
--+ old ones \/
    mesh(space:%,llpoints:L L L R,lprops:L PROP,prop:PROP) ==
      pts := [map(point,points) for points in llpoints]
      mesh(space,pts,lprops,prop)
    mesh(space:%,llp:L L POINT,lprops:L PROP,prop:PROP) ==
      addPoint(space.subspaceField,[],first first llp)
      defineProperty(space.subspaceField,path:L NNI:=[#children space.subspaceField],prop)
      path := append(path,[1])
      defineProperty(space.subspaceField,path,first lprops)
      for p in rest (first llp) repeat
        addPoint(space.subspaceField,path,p)
      for lp in rest llp for aProp in rest lprops for count in 2.. repeat
        addPoint(space.subspaceField,path := [first path],first lp)
        path := append(path,[count])
        defineProperty(space.subspaceField,path,aProp)
        for p in rest lp repeat
          addPoint(space.subspaceField,path,p)
      space.converted := false
      space
--+ old ones /\
    mesh(space:%,llpoints:L L L R,prop1:B,prop2:B) ==
      pts := [map(point,points) for points in llpoints]
      mesh(space,pts,prop1,prop2)
    mesh(space:%,llp:L L POINT,prop1:B,prop2:B) ==
        -- prop2 refers to property of the ends of a surface (list of lists of points)
        -- while prop1 refers to the individual curves (list of points)
        -- ** note we currently use Booleans for closed (rather than a pair
        -- ** of booleans for closed and solid)
      propA : PROP := new()
      close(propA,prop1)
      propB : PROP := new()
      close(propB,prop2)
      addPoint(space.subspaceField,[],first first llp)
      defineProperty(space.subspaceField,path:L NNI:=[#children space.subspaceField],propB)
      path := append(path,[1])
      defineProperty(space.subspaceField,path,propA)
      for p in rest (first llp) repeat
        addPoint(space.subspaceField,path,p)
      for lp in rest llp for count in 2.. repeat
        addPoint(space.subspaceField,path := [first path],first lp)
        path := append(path,[count])
        defineProperty(space.subspaceField,path,propA)
        for p in rest lp repeat
          addPoint(space.subspaceField,path,p)
      space.converted := false
      space

    lp space ==
      if not space.converted then space := convertSpace space 
      space.rep3DField.lp
    lllip space   == 
      if not space.converted then space := convertSpace space 
      space.rep3DField.llliPt
--    lllp space   == 
--      if not space.converted then space := convertSpace space 
--      space.rep3DField.lllPt
    llprop space == 
      if not space.converted then space := convertSpace space 
      space.rep3DField.llProp
    lprop space  == 
      if not space.converted then space := convertSpace space 
      space.rep3DField.lProp

      -- this function is just to see how this representation really
      -- does work
    objects space ==
      if not space.converted then space := convertSpace space 
      numPts        := 0$NNI
      numCurves     := 0$NNI
      numPolys      := 0$NNI
      numConstructs := 0$NNI
      for component in children space.subspaceField repeat
        #(kid:=children component) = 1 =>
          #(children first kid) = 1 => numPts := numPts + 1
          numCurves := numCurves + 1
        (#kid = 2) and _
          (#children first kid = 1) and _
          not one?(#children first rest kid) =>
             numPolys := numPolys + 1
        numConstructs := numConstructs + 1
        -- otherwise, a mathematical surface is assumed
        -- there could also be garbage representation
        -- since there are always more permutations that
        -- we could ever want, so the user should not
        -- fumble around too much with the structure
        -- as other applications need to interpret it
      [numPts,numCurves,numPolys,numConstructs]

    check(s) ==
      not s.converted => convertSpace s
      s

    subspace(s) == s.subspaceField

    coerce(s) == 
      if not s.converted then s := convertSpace s
      hconcat(["3-Space with "::O, _
               (sizo:=#(s.rep3DField.llliPt))::O, _
               (sizo=1=>" component"::O;" components"::O)])

)abbrev package TOPSP TopLevelThreeSpace
++ Description:
++ This package exports a function for making a \spadtype{ThreeSpace}
TopLevelThreeSpace(): with
    createThreeSpace: () -> ThreeSpace DoubleFloat
      ++ createThreeSpace() creates a \spadtype{ThreeSpace(DoubleFloat)} object 
      ++ capable of holding point, curve, mesh components and any combination.
  == add
    createThreeSpace() == create3Space()$ThreeSpace(DoubleFloat)

