)abbrev package EXP3D Export3D
++ Author: Martin Baker
++ Date: June, 2010
++ Description:
++ This package provides support for exporting SubSpace and
++ ThreeSpace structures to files.

EF ==> Expression Float
SBF ==> SegmentBinding Float
DF ==> DoubleFloat
I    ==> Integer
PI   ==> PositiveInteger
NNI  ==> NonNegativeInteger
STR ==> String

Export3D() : with

  writeObj : (SubSpace(3, DoubleFloat), String) -> Void
    ++ writes 3D SubSpace to a file in Wavefront (.OBJ) format

 == add

  -- return list of indexes
  -- assumes subnodes are leaves containing index
  faceIndex(subSp : SubSpace(3, DoubleFloat)) : List NNI ==
    faceIndexList : List NNI := []
    for poly in children(subSp) repeat
      faceIndexList := cons(extractIndex(poly), faceIndexList)
    reverse faceIndexList

  -- called if this component contains a single polygon
  -- write out face information for Wavefront (.OBJ) 3D file format
  -- one face per line, represented by list of vertex indexes
  writePolygon(f1 : TextFile, curves : List SubSpace(3, DoubleFloat)) : Void ==
    faceIndexList : List NNI := []
    for curve in curves repeat
      faceIndexList := append(faceIndexList, faceIndex(curve))
    -- write out face information for Wavefront (.OBJ) 3D file format
    -- one face per line, represented by list of vertex indexes
    s:String := "f "
    for i in faceIndexList repeat
      s := concat(s, string(i))$String
      s := concat(s," ")$String
    writeLine!(f1, s)

  -- called if this component contains a mesh, the mesh will be rendered
  -- as quad polygons.
  -- write out face information for Wavefront (.OBJ) 3D file format
  -- one face per line, represented by list of vertex indexes
  writeMesh(f1 : TextFile, curves : List SubSpace(3, DoubleFloat)) : Void ==
    meshIndexArray : List List NNI := []
    for curve in curves repeat
      -- write out face information for Wavefront (.OBJ) 3D file format
      -- one face per line, represented by list of vertex indexes
      meshIndexArray := cons(faceIndex(curve), meshIndexArray)
    meshIndexArray := reverse meshIndexArray
    rowLength := #meshIndexArray
    colLength := #(meshIndexArray.1)
    for i in 1..(rowLength-1) repeat
      for j in 1..(colLength-1) repeat
        --s1:String := concat["row ",string(i)," col ",string(j)]
        --writeLine!(f1, s1)
        s:String := concat["f ",string((meshIndexArray.i).j)," ",_
          string((meshIndexArray.(i+1)).j)," ",_
            string((meshIndexArray.(i+1)).(j+1))," ",_
              string((meshIndexArray.i).(j+1))]
        writeLine!(f1, s)

  toString(d : DoubleFloat) : String ==
      unparse(convert(d)@InputForm)

  -- this writes SubSpace geometry to Wavefront (.OBJ) 3D file format
  -- reqires SubSpace to contain 3 or 4 dimensional points over DoubleFloat
  -- to export a function plot try:
  -- writeObj(subspace(makeObject(x*x-y*y,x=-1..1,y=-1..1)),"myfile.obj")
  -- colour dimension is ignored
  -- no normals or texture data is generated
  writeObj(subSp : SubSpace(3, DoubleFloat), filename : String) : Void ==
    f1:TextFile := open(filename::FileName,"output")
    writeLine!(f1,"# mesh generated by axiom")
    -- write vertex data
    verts := pointData(subSp)
    for v in verts repeat
      #v < 3  => error "Can't write OBJ file from 2D points"
      writeLine!(f1,concat(["v ", toString(v.1), " ",_
                 toString(v.2), " ", toString(v.3)])$String)
    for component in children(subSp) repeat
      curves := children(component)
      if #curves < 2 then
          say("Can't write point or curve to OBJ file")$DisplayPackage
      --writeLine!(f1,"new component")
      if #curves > 1 then
        if numberOfChildren(curves.1) = 1 then writePolygon(f1, curves)
        if numberOfChildren(curves.1) > 1 then writeMesh(f1, curves)
    close! f1
