)abbrev category SPACEC ThreeSpaceCategory
++ Author:
++ 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:
++ 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 from POINT
    import from SUBSPACE
    import from ListFunctions2(List(R), POINT)
    import from 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 := empty()$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 _
          (#children first rest kid ~= 1) =>
             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([message("3-Space with "), _
               (sizo := #(s.rep3DField.llliPt))::O, _
               message(sizo = 1=>" component";" components")])

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

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