########################### Hey, Emacs, we're -*-maplev-*- mode! ## ## 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 ## ## Revised : 2003 ## Claus-Justus Heine, Abteilung fuer Angewandte Mathematik, ## Universitaet Freiburg. ## ## ## 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 ## ## lr (renggli@math.fsu.edu) 03/28/97 ## modifications for Maple VR4 (replaced gc() calls) ## ## ## 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); geomview := module() option `Copyright (C) 2003 by Claus-Justus Heine, Department for Applied Mathematics, Freiburg University. Heavily based on gvplot, Copyright (C) 1993 by Frederick Wicklin and Stuart Levy, Geometry Center.`; description `Geomview interface for MapleV8`; export gvdirectories, gvcommand, fwriteoogl, writeoogl, gvplot, gvsendcmd; local default_gvdirectories, default_gvcommand, `oogl/lprn`, HSV2RGB, find_colorlist, find_appearance, make_tmpname, print_colorlist, find_view, make_localtmpname; global `gvplot/User_ID`; # 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`: ### 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). ### make_tmpname := proc() local tmp_fname; if `gvplot/User_ID` = '`gvplot/User_ID`' then `gvplot/User_ID` := (round( rand() * (time()+1) ) mod 9999) + 1; fi; tmp_fname := `Maple`||(`gvplot/User_ID`); return(tmp_fname); end; make_localtmpname := proc() local tmp_fname, id; id := (round( rand() * (time()+1) ) mod 9999) + 1; tmp_fname := `/tmp/`||`Maple`||`id`; return(tmp_fname); end; ### Upon invoking the geomview package, maple creates a global ### variable `gvplot/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. ################################################################## writeoogl := proc() option `Copyright (C) 2003 by Claus-Justus Heine, Department for Applied Mathematics, Freiburg University. All rights reserved.`; description `convert a MapleV8 PLOT3d() structure to OOGL`; local outfd, ps; if nargs > 2 or nargs = 0 then ERROR(`Usage:writeoogl(``filename``,3dplot_struct); OR writeoogl(3dplot_struct);`) fi; if nargs = 2 and not type(args[1], string) then ERROR(`Invalid file name (not string)`, args[1]) fi; if nargs = 2 then print(`Saving Maple 3D structs to Geomview file`, args[1]); outfd:=fopen(args[1],`WRITE`,`BINARY`); else outfd:=`default`; fi; ps := args[nargs]; try fwriteoogl(outfd, ps); finally if outfd <> `default` then fclose(outfd); fi; end try; end; # writeoogl fwriteoogl := proc() local header, item, zlist, plist, llist, ppoint, pcolor, appear, i, j, totl, xrange, yrange, nx, ny, savedprintbytes, coloron, colorlist, totalverts, tlist, npoints, view, haveview, clipcmd, clipfd, clipfname, ccnt, outfd, ps; options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`; if nargs <> 2 then ERROR(`Usage:fwriteoogl(file_descriptor,3dplot_struct);`) fi; outfd := args[1]; ps := args[2]; if not op(0, ps) = PLOT3D then ERROR(`Invalid plot structure`,ps, `; must be of type PLOT3D, as from plot3d(), tubeplot(), spacecurve(), etc.`) fi; if nops(ps) < 1 then ERROR(`Empty 3D plot structure!`) fi; xrange := 'xrange'; # nullify this local variable # # Some things we need to know beforehand. # appear := find_appearance(1, ps); colorlist := find_colorlist(1, ps); coloron := op(1,colorlist); view := find_view(1, ps); haveview := op(1,view); # # possibly pipe the stuff to clip(1) # if haveview <> FALSE then clipfname:=make_localtmpname(); clipfd :=outfd; outfd :=fopen(clipfname,WRITE,BINARY); fi; fprintf(outfd, "{ %s", appear); fprintf(outfd, "LIST"); ################################################################## ### BEGIN main loop over all 3D plots (may be a list of plots) ### ################################################################## for item in ps do header := op(0,item); if 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( nops(item)>3 ) then colorlist := find_colorlist(4, item); coloron := op(1,colorlist); # either RGB, HUE, or FALSE fi; fi; nx := op(2,[ArrayDims(zlist)][1]); # num x elements ny := op(2,[ArrayDims(zlist)][1]);# num y elements fprintf(outfd, "{ INST transform { \n"); `oogl/lprn`(outfd, [0, (op(2,yrange)-op(1,yrange)) / (ny-1), 0, 0], "\n" ); `oogl/lprn`(outfd, [(op(2,xrange)-op(1,xrange)) / (nx-1), 0, 0, 0], "\n" ); fprintf(outfd, "0 0 1 0\n"); `oogl/lprn`(outfd, [op(1,xrange), op(1,yrange), 0, 1],"\n" ); if(coloron = FALSE) then fprintf(outfd, " } geom { ZMESH %d %d\n", ny, nx); # gv type else fprintf(outfd, " } geom { CZMESH %d %d\n", ny, nx); # color gv type fi; for j from 1 to ny do for i from 1 to nx do ppoint := zlist[j][i]; `oogl/lprn`(outfd, ppoint,"\n"); print_colorlist(outfd, coloron, colorlist); od; od; fprintf(outfd, "} }\n"); ########################### 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 fprintf(outfd, "{ MESH \n" ); # gv type else fprintf(outfd, "{ CMESH \n" ); # color gv type fi; if op(0,llist) = Array then nx := op(2,[ArrayDims(llist)][1]); # num x elements ny := op(2,[ArrayDims(llist)][1]);# num y elements else nx := nops(llist); # maple rows ny := nops(op(1,llist)); # maple cols fi; fprintf(outfd, "%d\n", nx ); # num x elements fprintf(outfd, "%d\n", ny ); # 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 for j from 1 to ny do for i from 1 to nx do ppoint := llist[j][i]; `oogl/lprn`(outfd,ppoint,"\n"); print_colorlist(outfd, coloron, colorlist); od; od; fprintf(outfd, " }\n"); ########################### 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; fprintf(outfd, "{ VECT \n"); # gv type # Number of polylines, total vertices. totalverts := sum('nops(op(i,llist))', 'i'=1..nops(llist)); fprintf(outfd, "%d %d ", nops(llist), totalverts); if coloron=FALSE then fprintf(outfd, "1\n"); # One color in all `oogl/lprn`(outfd,[seq(nops(op(i,llist)), i=1..nops(llist))],"\n"); # Vertex counts `oogl/lprn`(outfd,[1, seq(0, i=2..nops(llist))],"\n"); # Color counts. else fprintf(outfd, "%d\n", nops(llist));# Total number of colors, 1 per polyline `oogl/lprn`(outfd,[seq(nops(op(i,llist)), i=1..nops(llist))],"\n"); # Vertex counts `oogl/lprn`(outfd,[seq(1, i=1..nops(llist))],"\n"); # Color counts. fi; for plist in llist do for ppoint in plist do # print all vertices `oogl/lprn`(outfd,ppoint,"\n"); od od; if coloron=FALSE then fprintf(outfd, "1 1 1 1\n"); # color RGBA = white and opaque else for ccnt from 1 to nops(llist) do print_colorlist(outfd, coloron, colorlist); od; fi; fprintf(outfd, " }\n"); ######################### 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 # coloron:=FALSE; pcolor := i $ i=1..0; # Empty sequence totl := 0: nx := 0: # use nx to count number of polygons if( nops(item)>1 ) then colorlist := find_colorlist(2, item); coloron := op(1,colorlist); # either RGB, HUE, or FALSE fi; 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; fprintf(outfd, "%s\n", find_appearance(1, item)); fprintf(outfd, "{ OFF \n"); # gv type fprintf(outfd, "%d %d %d\n", 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`(outfd,ppoint,"\n"); # List of vertices od; fi; od; fprintf(outfd, "\n"); totl := 0; for llist in item do if type(llist,list) then ## There are only two possibilities for POLYGONS ## ## In both cases, it means entire polygon is same color ## tlist:=[nops(llist), i $ i=totl..totl+nops(llist)-1]; `oogl/lprn`(outfd,tlist,""); print_colorlist(outfd, coloron, colorlist); if coloron=FALSE then fprintf(outfd, "\n"); fi; totl := totl + nops(llist); fi; od; fprintf(outfd, "}\n"); ######################### POINTS ########################## #EX:PLOT3D(POINTS([0,0,1],[1,0,0],[0,1,0])); ############################################################### elif header = POINTS then colorlist := find_colorlist(2, item); coloron := op(1,colorlist); # either RGB, HUE, or FALSE fprintf(outfd, "%s\n", find_appearance(2,item)); if coloron=FALSE then npoints := nops(item); fprintf(outfd, "{ VECT %d %d %d\n", npoints, npoints, 0); else npoints := nops(item) - 1; fprintf(outfd, "{ VECT %d %d %d\n", npoints, npoints, npoints); fi; fprintf(outfd, cat(seq("1\n", i=1..npoints))); fprintf(outfd, "\n"); if coloron=FALSE then fprintf(outfd, cat(seq("0\n", i=1..npoints))); else fprintf(outfd, cat(seq("1\n", i=1..npoints))); fi; fprintf(outfd, "\n"); for i from 1 to npoints do ppoint := op(i, item); `oogl/lprn`(outfd,ppoint,"\n"); od; if coloron<>FALSE then for i from 1 to npoints do print_colorlist(outfd, coloon, colorlist); od; fi; fprintf(outfd, "}\n"); ########################### TEXT ############################ # 3D plots using the "plots" package may include TEXT # This is not supported ############################################################### elif header = TEXT then fprintf(outfd, " "); fi; od; # END main for loop fprintf(outfd, "}\n"); if haveview <> FALSE then if nops(view) = 1 then clipcmd:=sprintf("clip -v 0,0,1 -g %e -l %e %s", view[1][1], view[1][2], clipfname); else clipcmd:=sprintf(cat("clip -v 1,0,0 -g %e -l %e %s |", "clip -v 0,1,0 -g %e -l %e |", "clip -v 0,0,1 -g %e -l %e"), view[1][1], view[1][2], clipfname, view[2][1], view[2][2], view[3][1], view[3][2]); fi; fclose(outfd); outfd:=clipfd; fprintf(outfd, op(2,ssystem(clipcmd))); fremove(clipfname); fi; NULL; end; gvplot := proc() local gvname, gvcmd, gvdirs, ps, tmp_fname, outfd; options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`; tmp_fname := make_tmpname(); ### 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 op(0, 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 -cp `||tmp_fname||` `||gvcmd||` 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; outfd:=fopen(`/tmp/geomview/`||tmp_fname,WRITE,BINARY); try fprintf(outfd, "(geometry %s\n", gvname); fwriteoogl( outfd, ps ); fprintf(outfd, ")\n"); finally fclose(outfd); end try; NULL; end; gvsendcmd := proc() local gvname, gvcmd, gvdirs, ps, savedprintbytes, tmp_fname; options `Copyright 1993 by Frederick Wicklin and Stuart Levy, Geometry Center`; tmp_fname := make_tmpname(); ### 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||` 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; savedprintbytes:=kernelopts( printbytes): kernelopts( printbytes=false): writeto(`/tmp/geomview/`||tmp_fname); lprint(args); writeto(terminal); kernelopts( printbytes=savedprintbytes): NULL; 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. `oogl/lprn` := proc(outfd, v, terminator) local i, fmt, n; options `Copyright 2003 by Claus-Justus Heine`; if type(v, list) then fmt:=""; for i from 1 to nops(v) do if type(v[i],integer) then fmt:=cat(fmt, "%d "); elif type(v[i],realcons) then fmt:=cat(fmt, "%e "); fi; od; fprintf(outfd, cat(fmt, terminator), seq(v[i], i = 1..nops(v)) ); elif type(v, hfarray) then n := op(2, ArrayDims(v)); fmt:=cat(seq("%e ", i = 1 .. n)); fprintf(outfd, cat(fmt, terminator), seq(v[i], i = 1..n) ); elif type(v, realcons) then fprintf(outfd, cat("%e", terminator), v); else fprintf(outfd, "0 #\n"); 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_view # input: n where to start looking for clipping data # item what list to search # output: clipping information in the form [[xmin,xmax],[...]] ######################################################## find_view := proc(n, item) option `Copyright (C) 2003 by Claus-Justus Heine, Department for Applied Mathematics, Freiburg University. All rights reserved.`; description `Find the viewport definition`; local i, j, clipping, view; for i from n to nops(item) do if type(op(i,item),function) and (op(0,op(i,item))=VIEW) then view:=op(i,item); clipping:=[seq([op(1,op(j,view)),op(2,op(j,view))],j = 1..nops(view))]; return clipping; fi; od; return([FALSE]); # no view info found end; # find_view find_view := proc(n,item) ######################################################## # 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 then color := [HSV2RGB(op(2,part), 0.9, 1)] elif colortype = RGB then color := [op(2..4,part)] elif colortype = HSV then color := [HSV2RGB(op(2,colorlist), op(3,colorlist), op(4,colorlist))]; 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)); elif type(part,function) and op(0,part) = SYMBOL then ap := cat(ap, ` linewidth `, op(2,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`); # leave everything except the edge color to the handlers # for the specific plot-types. Otherwise there are # problems with Geomview and transparency # ap := cat(ap, `\n material { edgecolor `, color, `}\n`); fi; if ap <> `` then # # "transparent" is here because it cannot be changed # inside Geomview otherwise # ap := cat(` appearance { `, ap, `}`) fi; return(ap); end; ######################################################## # # COLOR # Color may be specified in three different ways. RGB color # specification requires three floating-point values for each # color. The three values must each be between 0 and 1 and specify the # amount of red, green, and blue light in the final color. For # example, COLOR(RGB, 1.0, 0.0, 0.0) is red while COLOR(RGB, 1.0, 1.0, # 0.0) is yellow. The HSV color specification also requires three # numbers for each color. The fractional portion of the first value # indicates the color and the remaining two values give the purity # (saturation) and the brightness of the color. The latter two values # must be between zero and one. The HUE color specification only # requires a single floating-point value and cycles through the colors # of the spectrum based on the fractional part of the value. For # example COLOR(HUE, 0.9) is violet while COLOR(HUE, 0.1) is # red. COLOR(HUE, x) is equivalent to COLOR(HSV, x, 0.9, 1.0). # # Color can take several extra keyword options for 3-D # plotting. XYZSHADING, XYSHADING and ZSHADING specify that an objects # color is to be based on its coordinates. ZHUE and ZGREYSCALE are # modified forms of ZSHADING. # ######################################################## print_colorlist := proc(outfd, coloron, colorlist) option `Copyright (C) 2003 by Claus-Justus Heine, Department for Applied Mathematics, Freiburg University. All rights reserved.`; description `Print colorlist in OOGL RGB format.`; if coloron = RGB then fprintf(outfd, "%e %e %e %e\n", op(2,colorlist),op(3,colorlist),op(4,colorlist), 1); elif coloron = HUE then fprintf(outfd, "%s %d\n", HSV2RGB(op(2,colorlist), 0.9, 1.0), 1); elif coloron = HSV then fprintf(outfd, "%s %d\n", HSV2RGB(op(2,colorlist), op(3,colorlist), op(4,colorlist)), 1); elif coloron != FALSE then fprintf(outfd, "0.666 0.666 0.666 1\n"); fi; end; # print_colorlist print_colorlist := proc(outfd, coloron, colorlist) end module: # geomviewgeomview:=module()