##########################
##
##    Title   :  writeoogl,  a package for converting maple PLOT3D
##				objects to Geomview data objects.
##		 gvplot,     interactive pipe to Geomview from Maple
##
##    Created :  Dec 5 1993
##
##    Authors :  Frederick Wicklin  and 
##		 Stuart Levy
##               The Geometry Center
##

##    Documentation :   currently ?gvplot or ?writeoogl or ?geomview
##
##    History
##          	fjw    9/21/93	initial maple->geomview for Maple VR2
## 		slevy 11/27/93	interactive geomview pipe; 
##				backwards compatable to Maple V
##	   	fjw   11/29/93	debugging; added color options
##
##
##    Usage:   	readlib(gvplot);
##		  (optional) gvcommand := `geomview  initial-options ...`;
##		  (optional) gvdirectories := `/some/dir/ectory:/other/dir...`;
##		3dplot_struct := plot3d( ... ):
## 		writeoogl(`filename`, 3dplot_struct);
##		gvplot(3dplot_struct);

# To search for "geomview" and "togeomview" in directories which might not
# be on the default UNIX search path, list those director(ies) here, as in
#    default_gvdirectories := `/u/geom/bin:/usr/local/bin:`
# or, set the "gvdirectories" variable before invoking gvplot().

default_gvdirectories := ``:

# To start geomview with non-default options, or to start another program
# via gvplot, put its name and initial arguments here in place of `geomview`,
# or set the variable "gvcommand" before invoking gvplot().
# Changing default_gvcommand, then resaving gvplot.m, alters the default for
# all users; setting the gvcommand variable changes it for just your session.

default_gvcommand := `geomview`:


### Upon invoking the geomview package, maple creates a global
### variable UsEr_ID__ which is assigned a "random" number.
### This variable is used to create user-specific files in /tmp.
##################################################################
# There doesn't seem to be any explicit test for Maple V1 vs. V2,
# but all V1 plot objects seem to begin with FUNCTION, so use that fact
# to detect that we must be careful not to print invalid float constants.
##################################################################
`oogl/lprn` := `oogl/lprnV2`:

writeoogl := proc()
   global  `oogl/lprn`;
   local header, item, ps, zlist, plist, llist, ppoint, pcolor, appear,
		i, j, totl, xrange, yrange, nx, ny, oldgc,
		coloron,colorlist,ccnt, totalverts;
   options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`;

   if nargs > 2 or nargs = 0 then
     ERROR(`Usage:writeoogl(``filename``,3dplot_struct); OR writeoogl(3dplot_struct);`)
   fi;
   ps := args[nargs];
   if not type(ps, PLOT3D) then ERROR(`Invalid plot structure`,ps,
	`; must be of type PLOT3D, as from plot3d(), tubeplot(), spacecurve(), etc.`)
   fi;
   if nargs = 2 and not type(args[1], string) then
	ERROR(`Invalid file name (not string)`, args[1])
   fi;
   if nops(ps) < 1 then ERROR(`Empty 3D plot structure!`) fi;

   ##################################################################
   # When run in command-line mode, Garbage Collection (GC)         #
   # messages printed to terminal can interfere with the data flow. #
   # Therefore suppress GC during writing of GeomView data          #
   ##################################################################
   if nargs = 2 then
       oldgc := status[5];      # words increment for automatic garbage collection
       gc(0);			# suppress garbage collection		
       print(`Saving Maple 3D structs to Geomview file`, args[1]);
       writeto(args[1]);
   fi;
   xrange := 'xrange';		# nullify this local variable
   appear := find_appearance(1, ps);
   lprint( appear, `{LIST` );

   ##################################################################
   ### BEGIN main loop over all 3D plots (may be a list of plots) ###
   ##################################################################
   for item in ps do
     coloron := FALSE;		# default is no color info
     header := op(0,item);

     if header = FUNCTION then
	# Maple V1 only:  FUNCTION( f(x,y),  xrange, yrange )
	# or	FUNCTION( x(u,v), y(u,v), z(u,v),  u = u0..u1, v = v0..v1 )
	xrange := op(nops(item)-1, item);
	if type(xrange, `=`) then xrange := op(2, xrange) fi;
	yrange := op(nops(item), item);
	if type(yrange, `=`) then yrange := op(2, yrange) fi;
	# Maple V1 -- don't trust lprint()
	`oogl/lprn` := `oogl/lprnV1`;

     ###########################  GRID   ############################
     # EX: plot3d( f(x,y), x=xmin..xmax, y=ymin..ymax] 
     # Saving Maple GRID struct to geomview ZMESH struct
     # Maple V1:  FUNCTION( f(x,y), xrange,yrange ) followed by GRID( zlist )
     #  In Maple V1, we might see either ZMESH-style data (only Z per vertex)
     #	or a full 3-D mesh (x,y,z per vertex).  Just check the first
     #	vertex to see.
     # Maple V2:  GRID( xrange, yrange, zlist )
     #	Maple V2 uses GRID only for ZMESH-style data,
     #	and uses a MESH header for meshes with general 3-D verts.
     ###############################################################
     elif header = GRID then
	if type(xrange, `..`) then
	    zlist := item
	else				# this is typical VR2 route
	    xrange := op(1, item);
	    yrange := op(2, item);
	    zlist := op(3, item);
	    #######################################################
	    # if color, then there are 4 possibilities:
	    # colorlist = COLOR(HUE, h[1],...,h[nops[colorlist])
	    # colorlist = COLOR(HUE, h)
	    # colorlist = COLOR(RGB, r[1],g[1],b[1],...)
	    # colorlist = COLOR(RGB, r,g,b)
	    # Convert HUES to an RGB value using HSV2RGB and
	    # (assume that Maple uses s=v=1).  Add a 1 at the end of
	    # the list for geomview's "alpha": 0<=>transparent, 1<=>opaque
	    #######################################################
	    if( nops(item)>3 ) then 
		colorlist := find_colorlist(4, item);
		coloron := op(1,colorlist); # either RGB, HUE, or FALSE
	    fi;
	fi;
	nx := nops(zlist);
	ny := nops(op(1,zlist));
	if type(op(1, op(1,zlist)), list) then
	    lprint(`{ { MESH`, ny, nx)
	else   # scale this data by wrapping it in transformation matrix
	    lprint(`{ INST transform { `);	
	    `oogl/lprn`( [0, (op(2,yrange)-op(1,yrange)) / (ny-1), 0, 0] );
	    `oogl/lprn`( [(op(2,xrange)-op(1,xrange)) / (nx-1), 0, 0, 0] );
	    lprint(0, 0, 1, 0);
	    `oogl/lprn`( [op(1,xrange), op(1,yrange), 0, 1] );
	    if(coloron = FALSE) then
		lprint(`  } geom { ZMESH`, ny, nx);  	# gv type
	    else
		lprint(`  } geom { CZMESH`, ny, nx);  	# color gv type
	    fi;
	fi;
	ccnt := 2;			# set color counter to 2
	for plist in zlist do
	    for ppoint in plist do     
	       `oogl/lprn`(ppoint);
	       if (coloron = HUE) and nops(colorlist)>2 then 
	         lprint(HSV2RGB(op(ccnt,colorlist), 1,1), 1);
	         ccnt := ccnt + 1;
	       elif (coloron = HUE) and nops(colorlist)=2 then
		 lprint(HSV2RGB(op(2,colorlist), 1,1), 1);
	       elif (coloron = RGB) and nops(colorlist)>4 then 
	         lprint(op(ccnt,colorlist),op(ccnt+1,colorlist),op(ccnt+2,colorlist),1);
	         ccnt := ccnt + 3;
	       elif (coloron = RGB) and nops(colorlist)=4 then
		 lprint(op(2,colorlist),op(3,colorlist),op(4,colorlist), 1);
	       fi;
	    od;
	od;
	lprint( `} }`);

     ###########################  MESH   ###########################
     # EX: plot3d( [x(s,t), y(s,t), z(s,t)], s=smin..smax, t=tmin..tmax] 
     # Saving Maple MESH struct to geomview MESH struct
     ###############################################################
     elif header = MESH  then
	llist := op(1, item):
        if( nops(item)>1 ) then
          colorlist := find_colorlist(2, item);
          coloron := op(1,colorlist); # either RGB, HUE, or FALSE
        fi;
	if(coloron=FALSE) then 
	   lprint(`{ MESH ` );  		# gv type
	else 
	   lprint(`{ CMESH ` );  		# color gv type
	fi;
	lprint( nops(llist)); 		# num x elements
	lprint( nops(op(1,llist)) );	# num y elements
	# Maple store points in row-dominant manner
        # But geomview want column-dominant, so need to 
	# print out the transpose of the matrix in the plot3d struct
	nx := nops(llist);		# maple rows
	ny := nops(op(1,llist));	# maple cols
	for j from 1 to ny do
	  for i from 1 to nx do 
	    ppoint := op(j, op(i,llist));
	    `oogl/lprn`(ppoint);     
             if (coloron = HUE) and nops(colorlist)>2 then
               lprint(HSV2RGB(op((i-1)*ny+j +1,colorlist), 1,1), 1);
             elif (coloron = HUE) and nops(colorlist)=2 then
               lprint(HSV2RGB(op(2,colorlist), 1,1), 1);
             elif (coloron = RGB) and nops(colorlist)>4 then
               lprint(op(3*((i-1)*ny+j-1)+2,colorlist),op(3*((i-1)*ny+j-1)+3,colorlist),op(3*((i-1)*ny+j-1)+4,colorlist),1);
             elif (coloron = RGB) and nops(colorlist)=4 then
               lprint(op(2,colorlist),op(3,colorlist),op(4,colorlist), 1);
             fi;
	  od;
	od;
	lprint( `}`);

     ###########################  CURVES  ##########################
     # EX: spacecurve( [x(t), y(t), z(t)], t=tmin..tmax] 
     # Saving Maple CURVES struct to geomview VECT struct
     ###############################################################
     elif header = CURVES then
	llist := select(type, item, list);
        if( nops(item)>1 ) then
          colorlist := find_colorlist(2, item);
          coloron := op(1,colorlist); # either RGB, HUE, or FALSE
        fi;
        lprint(`{ VECT `);  		# gv type
			# Number of polylines, total vertices.
	totalverts := sum('nops(op(i,llist))', 'i'=1..nops(llist));
	lprint(nops(llist), totalverts);
	if coloron=FALSE then
	  lprint(1);			# One color in all
	  lprint(seq(nops(op(i,llist)), i=1..nops(llist))); # Vertex counts
	  lprint(1, 0 $ 'i'=2..nops(llist));		# Color counts.
	else
	  lprint(totalverts);		# Total number of colors, 1 per vert
	  lprint(seq(nops(op(i,llist)), i=1..nops(llist))); # Vertex counts
	  lprint(seq(nops(op(i,llist)), i=1..nops(llist))); # color per vert
	fi;
	for plist in llist do
	  for ppoint in plist do     	# print all vertices
	    `oogl/lprn`(ppoint);     
	  od
	od;
	if coloron=FALSE then
	  lprint(1,1,1,1);		# color RGBA = white and opaque
        elif (coloron = HUE) and nops(colorlist)>2 then
	  for ccnt from 2 to nops(colorlist) do
	    lprint(HSV2RGB(op(ccnt,colorlist), 1,1), 1);
          od;
        elif (coloron = HUE) and nops(colorlist)=2 then
          for ccnt from 1 to nops(llist) do
            lprint(HSV2RGB(op(2,colorlist), 1,1), 1);
	  od;
        elif (coloron = RGB) and nops(colorlist)>4 then
          for ccnt from 2 by 3 to nops(colorlist) do
	    lprint(op(ccnt,colorlist),op(ccnt+1,colorlist),op(ccnt+2,color\list),1);
	  od;
        elif (coloron = RGB) and nops(colorlist)=4 then
          for ccnt from 1 to nops(llist) do
	    lprint(op(2,colorlist),op(3,colorlist),op(4,colorlist),1);
	  od;
        fi;
	lprint( `}`);
 
     #########################  POLYGONS  ##########################
     #EX:polygonplot3d([seq([seq([x(s,t),y(s,t),z(s,t)],s=smin..smax],tmin..tmax])):
     # Polygons are handled differently than the other objects w/r/t
     # color.  Leave color alone and let user change color using geomview.
     ###############################################################
     elif header = POLYGONS then
	pcolor := i $ i=1..0;	# Empty sequence
	totl := 0: nx := 0: 	# use nx to count number of polygons
	for llist in item do		# sequence of lists POLY(),COLOR(),
	  if type(llist,list) then
	    nx := nx + 1;		# number of polygons
	    totl := totl + nops(llist);	# compute total number of vertices
	  fi
	od;

	lprint(find_appearance(1, item));

#	if coloron=FALSE then
	  lprint(`{ OFF `);  		# gv type
#	else 
#	  lprint(`{ COFF `);		# color
#	fi;
	lprint(totl, nx, 0);	# total verts,polygons,"edges"(not used!)
	for llist in item do 
	  if type(llist,list) then
            for ppoint in llist do    
	      `oogl/lprn`(ppoint);     	# List of vertices
	    od;
	  fi;
	od;
	lprint(``);
	totl := 0;
	for llist in item do
	  if type(llist,function) 
               and (op(0,llist)=COLOR or op(0,llist)=COLOUR) then
	    colorlist := llist;
	    if op(1,llist)=HUE and nops(colorlist)=2 then
	        pcolor := HSV2RGB(op(2,colorlist),1,1);  # use ppoint for RGB
	    elif op(1,llist)=RGB and nops(colorlist)=4 then
		pcolor := op(2..4,colorlist);
	    fi;
	  elif type(llist,list) then
	     ## There are only two possibilities for POLYGONS ##
	     ## In both cases, it means entire polygon is same color ##
	     lprint( nops(llist), i $ i=totl..totl+nops(llist)-1, ` `, pcolor);
	     totl := totl + nops(llist);
	   fi;
	od;
	lprint( `}`);

     #########################   POINTS   ##########################
     #EX:PLOT3D(POINTS([0,0,1],[1,0,0],[0,1,0]));
     ###############################################################
     elif header = POINTS then
	lprint(`{ VECT`, nops(item), nops(item), 0);
	for plist in item do lprint(`1`) od;
	lprint(``);
	for plist in item do lprint(`0`) od;
	lprint(``);
	for ppoint in item do
	    `oogl/lprn`(ppoint)
	od;
	lprint(`}`);

     ###########################  TEXT  ############################
     # 3D plots using the "plots" package may include TEXT
     # This is not supported
     ###############################################################
     elif header = TEXT then
	print(` `);
     fi;
   od;  # END main for loop

   lprint( `}`);
   if nargs = 2 then
	writeto(terminal);
	gc(oldgc);
   fi;
end:


gvplot := proc()
   global UsEr_ID__, gvcommand, default_gvcommand, gvdirectories, default_gvdirectories;
   local gvname, gvcmd, gvdirs, ps, oldgc, tmp_fname;
   options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`;
   ### Set up filename to use as temporary site for data. 	 ###
   ### Take file in /tmp and postfix number which is (hopefully) ###
   ### independent of users.  Eg, if user1 and user2 are both    ###
   ### using writeoogl, then they will be writing to different   ###
   ### files. This is UNIX specific (but so is Geomview).	 ### 
   if UsEr_ID__ = 'UsEr_ID__' then
	UsEr_ID__ := (round( rand() * (time()+1) ) mod 9999) + 1;
   fi;
   tmp_fname := `Maple`.(UsEr_ID__);

   ### Let user specify, via "gvcommand" and "gvdirectories" global vars,
   ### which program/args to run when invoking geomview,
   ### and how to set the search path to find it and togeomview.

   if gvcommand <> 'gvcommand'
	then gvcmd := gvcommand
	else gvcmd := default_gvcommand
   fi;
   if gvdirectories <> 'gvdirectories'
	then gvdirs := gvdirectories
	else gvdirs := default_gvdirectories
   fi;
	
   ps := args[nargs];
   gvname := `Maple`;

   if nargs < 1 or nargs > 2 then
	ERROR(`Usage: gvplot(3dplot_structure)  -or-  gvplot(``name``, 3dplot_structure)`);
   fi;
   if nargs > 1 then gvname := args[1] fi;
   if not type( ps, PLOT3D) then 
      ERROR(`Invalid plot structure`,ps,
	`; must be of type PLOT3D, as from plot3d(), tubeplot(), spacecurve(), etc.`)
   fi;
   # start geomview reading from stdin
   if system( `PATH=` . gvdirs . `:$PATH togeomview -Mcp `.tmp_fname.` `.gvcmd.`</dev/null` ) <> 0 then
	ERROR(`gvplot: togeomview: Can't start a copy of geomview.  `.
	    `If "togeomview" or "geomview" were not found `.
	    `try setting the variable "gvdirectories" to the name of the directory where `.
	    `they're installed (or to a colon-separated list of directories).`);
   fi;
   oldgc := status[5];  # words increment for automatic garbage collection
   gc(0);               # suppress garbage collection messages
   writeto(`/tmp/geomview/`.tmp_fname);
   lprint(`(geometry`, gvname);
   writeoogl( ps );
   lprint(`)`);
   writeto(terminal);
   gc(oldgc);   	# return to previous garbage collection state

end:

gvcommand := proc()
   global UsEr_ID__, gvcommand, default_gvcommand, gvdirectories, default_gvdirectories;
   local gvname, gvcmd, gvdirs, ps, oldgc, tmp_fname;
   options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`;
   ### Set up filename to use as temporary site for data. 	 ###
   ### Take file in /tmp and postfix number which is (hopefully) ###
   ### independent of users.  Eg, if user1 and user2 are both    ###
   ### using writeoogl, then they will be writing to different   ###
   ### files. This is UNIX specific (but so is Geomview).	 ### 
   if UsEr_ID__ = 'UsEr_ID__' then
	UsEr_ID__ := (round( rand() * (time()+1) ) mod 9999) + 1;
   fi;
   tmp_fname := `Maple`.(UsEr_ID__);

   ### Let user specify, via "gvcommand" and "gvdirectories" global vars,
   ### which program/args to run when invoking geomview,
   ### and how to set the search path to find it and togeomview.

   if gvcommand <> 'gvcommand'
	then gvcmd := gvcommand
	else gvcmd := default_gvcommand
   fi;
   if gvdirectories <> 'gvdirectories'
	then gvdirs := gvdirectories
	else gvdirs := default_gvdirectories
   fi;

   # start geomview reading from stdin
   if system( `PATH=` . gvdirs . `:$PATH togeomview -Mcp `.tmp_fname.` `.gvcmd.`</dev/null` ) <> 0 then
	ERROR(`gvplot: togeomview: Can't start a copy of geomview.  `.
	    `If "togeomview" or "geomview" were not found `.
	    `try setting the variable "gvdirectories" to the name of the directory where `.
	    `they're installed (or to a colon-separated list of directories).`);
   fi;
   oldgc := status[5];  # words increment for automatic garbage collection
   gc(0);               # suppress garbage collection messages
   writeto(`/tmp/geomview/`.tmp_fname);
   lprint(args);
   writeto(terminal);
   gc(oldgc);   	# return to previous garbage collection state

end:

# possible gvplot enhancements:
#  allow remote display?
#  Maybe use a two-step Rube Goldberg hookup with an external converter
#  that directly reads lprint() format.  Likely to be faster for large objects.
#  Then gvplot would read
#  gvplot := proc()
#    ...
#    if system(`togeomview -Mcp Maple.raw  maple2oogl -togeomview -Mcp Maple`)<>0
#	then ERROR(...) fi;
#    writeto(`/tmp/geomview/Maple.raw`);
#    lprint(`(geometry`, gvname, `<<`);
#    lprint(3dplot_struct);
#    lprint(`>>)`);
#    writeto(terminal);
#  end:
# and writeoogl would read
# writeoogl := proc()
#    ...
#    if system(cat(`togeomview -Mcp Maple.rawdata  maple2oogl -o `, fname)) <> 0
#	then ERROR(...) fi;
#    writeto(`/tmp/geomview/Maple.rawdata`);
#    lprint(`<<', 3dplot_string, `>>');
#    writeto(terminal);
#  end:
#
# Here 'togeomview' is actually being used to start 'maple2oogl' rather
# than geomview itself.  In the first case, maple2oogl -togeomview would
# invoke code to start a copy of geomview.

# Help information for writeoogl
`help/text/writeoogl` := TEXT(
` `,
`HELP FOR: writeoogl, gvplot						`,
` `,
`CALLING SEQUENCE:							`,
`	readlib(gvplot):						`,
`	writeoogl( ``filename``, 3dplot_struct );			`,
`	writeoogl( 3dplot_struct );					`,
`	gvplot( 3dplot_struct );					`,
`	gvplot( ``geomview_name``, 3dplot_struct )			`,
` `,
`PARAMETERS:								`,
`	filename        the file which will contain the Geomview data	`,
`	3dplot_struct	a Maple PLOT3D data structure			`,
`	geomview_name	name of the object in the Geomview browser	`,
` `,
`SYNOPSIS: 								`,
`	writeoogl() accepts Maple PLOT3D structures and writes files	`,
`	readable by Geomview.  gvplot() converts Maple PLOT3D structures`,
`	and displays them immediately using Geomview, starting a copy of`,
`	Geomview if necessary.`,
``,
`	Supported data types include the Maple structures MESH, GRID,	`,
`	CURVES, POINTS, and POLYGONS.	`,
`	See ?plot3d[structure] for more information on Maple PLOT3D types.`,
` `,
`	The Maple MESH and GRID structures are translated into Geomview's`,
`	MESH and ZMESH objects, respectively, Maple CURVES and POINTS`,
`	become VECT objects, and Maple POLYGONS becomes an OFF object.`,
` `,
`	The Maple TEXT structure is not supported. Color information is`,
`	supported for all objects.`,
``,
`	The form writeoogl(filename, plot_struct) writes data in OOGL`,
`	(Geomview) form to the given file; writeoogl(plot) writes to the`,
`	current output stream as selected by writeto().`,
``,
`	gvplot() normally starts the program "geomview", with no options;`,
`	to specify something else, set the variable "gvcommand", as in:`,
`	   gvcommand := ``/usr/local/bin/gv -wpos 200x200 -c startup.gv``;`,
`	before invoking gvplot().  Also, if the programs "geomview" or`,
`	"togeomview" are not on your UNIX search path, set the variable`,
`	   gvdirectories := ``/some/dir/ectory:/some/other/directory``;`,
`	to the appropriate directory (or directories separated by colons).`,
` `,
`EXAMPLES:								`,
`	readlib(gvplot):						`,
`	my_plot := plot3d(sin(x+y), x=-Pi..Pi, y=-Pi..Pi):		`,
`	writeoogl( ``sinxy.mesh``, my_plot );				`,
`                  Saving Maple 3D structs to Geomview file, sinxy.mesh	`,
`	steiner := plot3d([ sin(2*x)*(cos(y))^2, sin(x)*sin(2*y),	`,
`	      cos(x)*sin(2*y)], x=-Pi..Pi, y=-Pi..Pi):			`,
`	writeoogl( ``steiner.mesh``, steiner);				`,
`                  Saving Maple 3D structs to Geomview file, steiner.mesh`,
`	# Display it in geomview directly				`,
`	gvplot( steiner );						`,
`	# load in the plots package					`,
`	with(plots):							`,
`	trefoil := spacecurve([ -2*cos(t)- 1/2*cos(5*t)+ 3*sin(2*t),	`,
`              -3*cos(2*t)+ 2*sin(t)- 1/2*sin(5*t), 2*cos(3*t), t=0..2*Pi]):`,
`	writeoogl( ``trefoil.vect``, trefoil);				`,
`                  Saving Maple 3D structs to Geomview file, trefoil.vect`,
`	tetrahedra := [[1,0,0],[-1,0,0],[0,0,1]], [[1,0,0],[0,0,1],[0,1,0]], `,
`	              [[0,1,0],[-1,0,0],[0,0,1]], [[1,0,0],[0,1,0],[-1,0,0]]:`,
`	Tplot :=polygonplot3d([tetrahedra]):				`,
`	writeoogl( ``tetrahedra.off``, Tplot);				`,
`                  Saving Maple 3D structs to Geomview file, tetrahedra.off`,
`	# you can even create a single file with multiple objects	`,
`	all_objs := display3d( {my_plot, steiner, trefoil, Tplot} ):	`,
`	writeoogl( ``all.list``, all_objs );				`,
`                  Saving Maple 3D structs to Geomview file, all.list	`,
` `,
`SEE ALSO: plot3d[structure]						`

):

`help/text/gvplot`   := `help/text/writeoogl`:
`help/text/geomview` := `help/text/writeoogl`:


# Convert number to string, avoiding excess digits and avoiding Maple V1's
# propensity to emit Float(mantissa,exponent) rather than ordinary exponential
# notation!

`oogl/cvs` := proc(v)
	local sign, absmant;
	options `Copyright 1993 by Stuart Levy, Geometry Center`;
	if type(v, float) then
	    absmant := cat(abs(op(1,v)));
	    sign := substring(`-`, 1..1-signum(v));
	    if abs(v) >= 1 then
		if(op(2,v) >= 0) then
		    cat(op(1,v), '0' $ op(2,v))
		else
		    cat(
			sign,
			substring(absmant, 1..length(absmant)+op(2,v)),
			`.`,
			substring(absmant, length(absmant)+op(2,v)+1..8)
		    )
		fi
	    elif abs(v) > .000001  then
		cat( sign,
		    substring( `.0000000`, 1 .. 1-length(absmant)-op(2,v) ),
		    substring(absmant, 1..7)
		)
	    else
		cat( sign,
		    `.`, substring( absmant, 1..7),
		    `e`, op(2,v) + length(absmant)
		)
	    fi
	elif type(v, realcons) then
	    cat(v)
	fi;
end:

#
# lprint a number, or a list of numbers.
#
`oogl/lprnV1` := proc (v)
	local i;
	options `Copyright 1993 by Stuart Levy, Geometry Center`;
	if type(v, list) then
	    lprint( ' `oogl/cvs`(v[i]) ' $ i=1..nops(v) );
	elif type(v,float) and abs(v) <= .1 then
	    lprint(`oogl/cvs`(v));
	elif type(v, realcons) then
	    lprint(v);
	else
	    lprint(`0 #`);
	fi;
end:


# Ditto, but assume we're Maple V2, which prints floating constants
# in acceptable form.  Don't bother to reformat them.

`oogl/lprnV2` := proc(v)
	local i;
	options `Copyright 1993 by Stuart Levy, Geometry Center`;
	if type(v, list) then
	    lprint( 'v[i]' $ i = 1..nops(v) );	# Print on one line
	elif type(v, realcons) then
	    lprint(v);
	else
	    lprint(`0 #`);
	fi
end:

###############################################################
## HSV2RGB converts Maple Hues to RGB colors.
## The HUEs used are in [0,1] so assume that S=V=1 (this is close)
## The following algorithm is from Computer Graphics
## By Foley, vanDam, Feiner, Hughes, 2nd Ed. Addison-Wesley
## p 593
##
## Adapted by fjw 11/29/93
## Input: (h,s,v) in [0,1]^3
## Output: sequence r,b,g  each in [0,1]
###############################################################
HSV2RGB := proc( h,s,v )
  local hh,ip,fp,p,q,t;
  options `Copyright 1990 by Foley, vanDam, Feiner, Hughes`;
  if (s = 0) then     # color on B/W center line
    if (h<0) then     # There is no hue,ie, hue undefined
      RETURN( v,v,v );
    else
      ERROR(`Undefined color`);
    fi;
  else
    if (h>1) then hh:=1 fi;
    hh := 6*h;         # hh now in [0,6]
    ip := floor(hh);   # ip is integer part of h
    fp := hh - ip;     # fp is fractional part of h
    p  := v*(1-s); 
    q  := v*(1-(s*fp));
    t  := v*(1-(s*(1-fp)));
    if (ip=0) then 
	RETURN( v,t,p );
    elif (ip=1) then
        RETURN( q,v,p );
    elif (ip=2) then
	RETURN( p,v,t );
    elif (ip=3) then
	RETURN( p,q,v );
    elif (ip=4) then
	RETURN( t,p,v );
    else 
	RETURN( v,p,q );
    fi;
  fi;
end:


########################################################
# find_colorlist
# input: n       where to start looking for color data
#        item    what list to search
# output: list of color information or NULL list
########################################################
find_colorlist := proc(n,item)
  local i;	
  options `Copyright 1993 by Frederick Wicklin, Geometry Center`;
  for i from n to nops(item) do
     if type(op(i,item),function) and (op(0,op(i,item))=COLOR or op(0,op(i,item))=COLOUR) then
	   RETURN(op(i,item))
	fi;
  od;
  RETURN([FALSE]);  # no color info found
end:

########################################################
# find_appearance
# input: n	index to start seeking color data
#	 list	list to search
# output: argument of STYLE option (e.g. `PATCH`) or [] list.
########################################################
find_appearance := proc(n, list)
  local i, part, ap, color, colortype;
  ap := ``; color := ``;
  for i from n to nops(list) do
    part := op(i,list);
    if type(part,function) and (op(0,part)=COLOR or op(0,part)=COLOUR) then
	colortype := op(1,part);
	if colortype = HUE and nops(part) = 2 then
	  color := [HSV2RGB(op(2,part), 1, 1)]
	elif colortype = RGB and nops(part) = 4 then
	  color := [op(2..4,part)]
	fi
	# Otherwise, this "color" tag isn't for us
    elif type(part,function) and op(0,part) = STYLE then
	if op(1,part) = PATCH then
	   ap := cat(ap, ` +face -edge`)
	elif op(1,part) = LINE or op(1,part) = WIREFRAME then
	   ap := cat(ap, ` -face +edge`)
	fi
    elif type(part,function) and op(0,part) = THICKNESS and type(op(1,part),integer) then
	ap := cat(ap, ` linewidth `, op(1,part));
    fi
  od;
  if color <> `` then
    color := cat( op(1..3, map(v -> cat(convert(v,string),` `), color) ) );
    ap := cat(ap, `\n material { edgecolor `, color, `\n  diffuse `, color, `}\n`);
  fi;
  if ap <> `` then
    ap := cat(` appearance { `, ap, `}`)
  fi;
  RETURN(ap);
end:

[`writeoogl`, `gvplot`];
