[comp.windows.x] enhanced ico with polygon fill

jimmc@sci.UUCP (Jim McBeath) (01/12/88)

I thought ico was a nice program, but I was disappointed that
it was just a wire-frame.  So I made a bunch of changes so that
it could do decent solid polyhedron images.  It's a bit slow on
my Sun 3/60 (which of course uses the cfb stuff); I would hope
that it's a lot faster on a server which has been better
optimized (if anyone has a fast server, let me know how well
it works!).

A co-worker of mine here has a nice little book called
"Exact Descriptions of Regular and Semi-Regular Polyhedra
and Their Duals", by Andrew Hume; AT&T Bell Labaratories
Computing Science Technical Report No. 13 0, November 1986.
This booklet has great descriptions of the five regualar
and thirteen semi-regular polyhedra with regular polygonal
faces, plus their duals.  If anyone is interested in adding
more polyhedra to ico, this would be a good source.  I just
decided I wasn't up to it....

Jim McBeath    {decwrl|oliveb|weitek|auspyr}!sci!jimmc
Silicon Compilers Systems Corporation   (408)371-2900
2045 Hamilton Avenue, San Jose CA 95125

------------------------------------------------------------
#! /bin/sh
##  This is a shell archive.  Remove anything before this line, then unpack
##  it by saving it into a file and typing "sh file".  To overwrite existing
##  files, type "sh file -c".  You can also feed this as standard input via
##  unshar, or by typing "sh <file".  If this archive is complete, you will
##  see the following message at the end:
#		"End of shell archive."
# Contents:  ico.c allobjs.h objcube.h objico.h objtetra.h polyinfo.h
#   Makefile Imakefile ico.man TODO
# Wrapped by jimmc@duff on Mon Jan 11 10:46:26 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f ico.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ico.c\"
else
echo shar: Extracting \"ico.c\" \(20249 characters\)
sed "s/^X//" >ico.c <<'END_OF_ico.c'
X/* $Header: ico.c,v 1.1 87/09/11 08:23:25 toddb Exp $ */
X/***********************************************************
XCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
Xand the Massachusetts Institute of Technology, Cambridge, Massachusetts.
X
X                        All Rights Reserved
X
XPermission to use, copy, modify, and distribute this software and its 
Xdocumentation for any purpose and without fee is hereby granted, 
Xprovided that the above copyright notice appear in all copies and that
Xboth that copyright notice and this permission notice appear in 
Xsupporting documentation, and that the names of Digital or MIT not be
Xused in advertising or publicity pertaining to distribution of the
Xsoftware without specific, written prior permission.  
X
XDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
XDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
XSOFTWARE.
X
X******************************************************************/
X/******************************************************************************
X * Description
X *	Display a wire-frame rotating icosahedron, with hidden lines removed
X *
X * Arguments:
X *	-r		display on root window instead of creating a new one
X *	=wxh+x+y	X geometry for new window (default 600x600 centered)
X *	host:display	X display on which to run
X * (plus a host of others, try -help)
X *****************************************************************************/
X/* Additions by jimmc@sci:
X *  faces and colors
X *  double buffering on the display
X *  additional polyhedra
X *  sleep switch
X */
X
X
X#include <X11/Xlib.h>
X#include <X11/Xatom.h>
X#include <X11/Xutil.h>
X#include <stdio.h>
X
Xtypedef double Transform3D[4][4];
X
X#include "polyinfo.h"	/* define format of one polyhedron */
X
X/* Now include all the files which define the actual polyhedra */
XPolyinfo polys[] = {
X#include "allobjs.h"
X};
Xint polysize = sizeof(polys)/sizeof(polys[0]);
X
Xtypedef struct {
X	int prevX, prevY;
X	unsigned long *plane_masks;	/* points into dbpair.plane_masks */
X	unsigned long enplanemask;	/* what we enable for drawing */
X	XColor *colors;		/* size = 2 ** totalplanes */
X	unsigned long *pixels;	/* size = 2 ** planesperbuf */
X} DBufInfo;
X
Xtypedef struct {
X	int planesperbuf;
X	int pixelsperbuf;	/* = 1<<planesperbuf */
X	int totalplanes;	/* = 2*planesperbuf */
X	int totalpixels;	/* = 1<<totalplanes */
X	unsigned long *plane_masks;	/* size = totalplanes */
X	unsigned long pixels[1];
X	int dbufnum;
X	DBufInfo bufs[2];
X	DBufInfo *drawbuf, *dpybuf;
X} DBufPair;
X
XDBufPair dbpair;
X
XXColor bgcolor,fgcolor;
X
Xextern GC XCreateGC();
Xextern long time();
Xextern long random();
X
XDisplay *dpy;
XWindow win;
Xint winWidth, winHeight;
XColormap cmap;
XGC gc;
X
Xint dsync = 0;
Xint dblbuf = 0;
Xint sleepcount = 0;
Xint isleepcount = 5;
Xint numcolors = 0;
Xchar **colornames;	/* points into argv */
Xint dofaces = 0;
Xint doedges = 1;
X
XPolyinfo *findpoly();
X
X/******************************************************************************
X * Description
X *	Main routine.  Process command-line arguments, then bounce a bounding
X *	box inside the window.  Call DrawIco() to redraw the icosahedron.
X *****************************************************************************/
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X	{
X	char *display = NULL;
X	char *geom = NULL;
X	int useRoot = 0;
X	int fg, bg;
X	int invert = 0;
X	int dash = 0;
X
X	int winX, winY, winW, winH;
X	XSetWindowAttributes xswa;
X	XWindowAttributes xwa;
X
X
X	Polyinfo *poly;		/* the poly to draw */
X	int icoX, icoY;
X	int icoDeltaX, icoDeltaY;
X	int icoW, icoH;
X
X	XEvent xev;
X	XGCValues xgcv;
X
X	/* Process arguments: */
X
X	poly = findpoly("icosahedron");	/* default */
X
X	while (*++argv)
X		{
X		if (**argv == '=') 
X			geom = *argv;
X		else if (index(*argv, ':'))
X			display = *argv;
X		else if (!strcmp(*argv, "-r"))
X			useRoot = 1;
X		else if (!strcmp (*argv, "-d"))
X			dash = atoi(*++argv);
X		else if (!strcmp(*argv, "-colors")) {
X			colornames = ++argv;
X			for ( ; *argv && *argv[0]!='-'; argv++) ;
X			numcolors = argv - colornames;
X			--argv;
X		}
X		else if (!strcmp (*argv, "-dbl"))
X			dblbuf = 1;
X		else if (!strcmp(*argv, "-noedges"))
X			doedges = 0;
X		else if (!strcmp(*argv, "-faces"))
X			dofaces = 1;
X		else if (!strcmp(*argv, "-i"))
X			invert = 1;
X		else if (!strcmp (*argv, "-sleep"))
X			sleepcount = atoi(*++argv);
X		else if (!strcmp (*argv, "-isleep"))
X			isleepcount = atoi(*++argv);
X		else if (!strcmp (*argv, "-obj"))
X			poly = findpoly(*++argv);
X		else if (!strcmp(*argv, "-dsync"))
X			dsync = 1;
X		else if (!strcmp(*argv, "-objhelp")) {
X			giveObjHelp();
X			exit(1);
X		}
X		else {	/* unknown arg */
Xprintf("usage: ico [host:display.screen] [=geom] \
X[-r] [-d pattern] [-i] [-dbl] [-faces] [-noedges] \
X[-sleep n] [-obj object] [-objhelp] [-colors color-list]\n");
Xprintf("-r   use root window\n");
Xprintf("-d   use dashed lines (supply a bit pattern)\n");
Xprintf("-i   inverted\n");
Xprintf("-dbl use double buffering on the display\n");
Xprintf("-faces  draw faces\n");
Xprintf("-noedges  don't draw edges\n");
Xprintf("-obj object   specify what object to draw\n");
Xprintf("-objhelp      give help on what objects are available\n");
Xprintf("-sleep n  sleep for n seconds between each frame\n");
Xprintf("-colors color-list  list of colors to use on faces\n");
Xexit(1);
X			}
X		}
X
X	if (!dofaces && !doedges) icoFatal("nothing to draw");
X
X	if (!(dpy= XOpenDisplay(display)))
X	        {
X		perror("Cannot open display\n");
X		exit(-1);
X	        }
X
X	if (invert)
X		{
X		fg = BlackPixel(dpy, DefaultScreen(dpy));
X		bg = WhitePixel(dpy, DefaultScreen(dpy));
X		}
X	else
X		{
X		fg = WhitePixel(dpy, DefaultScreen(dpy));
X		bg = BlackPixel(dpy, DefaultScreen(dpy));
X		}
X
X	/* Set up window parameters, create and map window if necessary: */
X
X	if (useRoot)
X		{
X		win = DefaultRootWindow(dpy);
X		winX = 0;
X		winY = 0;
X		winW = DisplayWidth(dpy, DefaultScreen(dpy));
X		winH = DisplayHeight(dpy, DefaultScreen(dpy));
X		}
X	else
X		{
X		winW = 600;
X		winH = 600;
X		winX = (DisplayWidth(dpy, DefaultScreen(dpy)) - winW) >> 1;
X		winY = (DisplayHeight(dpy, DefaultScreen(dpy)) - winH) >> 1;
X		if (geom) 
X			XParseGeometry(geom, &winX, &winY, &winW, &winH);
X
X		xswa.event_mask = 0;
X		xswa.background_pixel = bg;
X		xswa.border_pixel = fg;
X		win = XCreateWindow(dpy, DefaultRootWindow(dpy), 
X		    winX, winY, winW, winH, 0, 
X		    DefaultDepth(dpy, DefaultScreen(dpy)), 
X		    InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
X		    CWEventMask | CWBackPixel | CWBorderPixel, &xswa);
X		XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, 
X				PropModeReplace, "Ico", 3);
X		XMapWindow(dpy, win);
X		if (XGetWindowAttributes(dpy,win,&xwa)==0) {
X			icoFatal("cant get window attributes (size)");
X		}
X		winWidth = xwa.width;
X		winHeight = xwa.height;
X		}
X
X
X	/* Set up a graphics context: */
X
X	gc = XCreateGC(dpy, win, 0, NULL);
X	XSetForeground(dpy, gc, fg);
X	XSetBackground(dpy, gc, bg);
X
X	if (dash)
X		{
X		xgcv.line_style = LineDoubleDash;
X		xgcv.dashes = dash;
X		XChangeGC(dpy, gc, GCLineStyle | GCDashList, &xgcv);
X		}
X
X	if (dofaces && numcolors>=1) {
X	    int i,t,bits;
X		bits = 0;
X		for (t=numcolors; t; t=t>>1) bits++;
X		initDBufs(fg,bg,bits);
X		/* don't set the background color */
X		for (i=0; i<numcolors; i++) {
X			setBufColname(i+1,colornames[i]);
X		}
X		setDisplayBuf(dblbuf?1:0);	/* insert new colors */
X	}
X	else if (dblbuf || dofaces) {
X		initDBufs(fg,bg,1);
X	}
X	if (!numcolors) numcolors=1;
X
X	if (dsync)
X		XSync(dpy, 0);
X
X	/* Get the initial position, size, and speed of the bounding-box: */
X
X	icoW = icoH = 150;
X	srandom((int) time(0) % 231);
X	icoX = ((winW - icoW) * (random() & 0xFF)) >> 8;
X	icoY = ((winH - icoH) * (random() & 0xFF)) >> 8;
X	icoDeltaX = 13;
X	icoDeltaY = 9;
X
X
X	/* Bounce the box in the window: */
X
X	for (;;)
X		{
X		int prevX;
X		int prevY;
X
X		if (XPending(dpy))
X			XNextEvent(dpy, &xev);
X
X		prevX = icoX;
X		prevY = icoY;
X
X		icoX += icoDeltaX;
X		if (icoX < 0 || icoX + icoW > winW)
X			{
X			icoX -= (icoDeltaX << 1);
X			icoDeltaX = - icoDeltaX;
X			}
X		icoY += icoDeltaY;
X		if (icoY < 0 || icoY + icoH > winH)
X			{
X			icoY -= (icoDeltaY << 1);
X			icoDeltaY = - icoDeltaY;
X			}
X
X		drawPoly(poly, win, gc, icoX, icoY, icoW, icoH, prevX, prevY);
X		}
X	}
X
XgiveObjHelp()
X{
Xint i;
XPolyinfo *poly;
X	printf("%-16s%-12s  #Vert.  #Edges  #Faces  %-16s\n",
X		"Name", "ShortName", "Dual");
X	for (i=0; i<polysize; i++) {
X		poly = polys+i;
X		printf("%-16s%-12s%6d%8d%8d    %-16s\n",
X			poly->longname, poly->shortname,
X			poly->numverts, poly->numedges, poly->numfaces,
X			poly->dual);
X	}
X}
X
XPolyinfo *
Xfindpoly(name)
Xchar *name;
X{
Xint i;
XPolyinfo *poly;
X	for (i=0; i<polysize; i++) {
X		poly = polys+i;
X		if (strcmp(name,poly->longname)==0 ||
X		    strcmp(name,poly->shortname)==0) return poly;
X	}
X	icoFatal("can't find object %s", name);
X}
X
XicoClearArea(x,y,w,h)
Xint x,y,w,h;
X{
X	if (dblbuf || dofaces) {
X		XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
X			/* use background as foreground color for fill */
X		XFillRectangle(dpy,win,gc,x,y,w,h);
X	}
X	else {
X		XClearArea(dpy,win,x,y,w,h,0);
X	}
X}
X
X/******************************************************************************
X * Description
X *	Undraw previous polyhedron (by erasing its bounding box).
X *	Rotate and draw the new polyhedron.
X *
X * Input
X *	poly		the polyhedron to draw
X *	win		window on which to draw
X *	gc		X11 graphics context to be used for drawing
X *	icoX, icoY	position of upper left of bounding-box
X *	icoW, icoH	size of bounding-box
X *	prevX, prevY	position of previous bounding-box
X *****************************************************************************/
Xchar drawn[MAXNV][MAXNV];
X
XdrawPoly(poly, win, gc, icoX, icoY, icoW, icoH, prevX, prevY)
XPolyinfo *poly;
XWindow win;
XGC gc;
Xint icoX, icoY, icoW, icoH;
Xint prevX, prevY;
X	{
X	static int initialized = 0;
X
X	Point3D *v = poly->v;
X	int *f = poly->f;
X	int NV = poly->numverts;
X	int NF = poly->numfaces;
X
X	static Transform3D xform;
X	static Point3D xv[2][MAXNV];
X	static int buffer;
X	register int p0;
X	register int p1;
X	register XPoint *pv2;
X	XSegment *pe;
X	register Point3D *pxv;
X	static double wo2, ho2;
X	XPoint v2[MAXNV];
X	XSegment edges[MAXEDGES];
X	register int i;
X	int j,k;
X	register int *pf;
X	int facecolor;
X
X	int pcount;
X	double pxvz;
X	XPoint ppts[MAXEDGESPERPOLY];
X
X	/* Set up points, transforms, etc.:  */
X
X	if (!initialized)	
X		{
X		Transform3D r1;
X		Transform3D r2;
X
X		FormatRotateMat('x', 5 * 3.1416 / 180.0, r1);
X		FormatRotateMat('y', 5 * 3.1416 / 180.0, r2);
X		ConcatMat(r1, r2, xform);
X
X		bcopy((char *) v, (char *) xv[0], NV * sizeof(Point3D));
X		buffer = 0;
X
X		wo2 = icoW / 2.0;
X		ho2 = icoH / 2.0;
X
X		initialized = 1;
X		}
X
X
X	/* Switch double-buffer and rotate vertices: */
X
X	buffer = !buffer;
X	PartialNonHomTransform(NV, xform, xv[!buffer], xv[buffer]);
X
X
X	/* Convert 3D coordinates to 2D window coordinates: */
X
X	pxv = xv[buffer];
X	pv2 = v2;
X	for (i = NV - 1; i >= 0; --i)
X		{
X		pv2->x = (int) ((pxv->x + 1.0) * wo2) + icoX;
X		pv2->y = (int) ((pxv->y + 1.0) * ho2) + icoY;
X		++pxv;
X		++pv2;
X		}
X
X
X	/* Accumulate edges to be drawn, eliminating duplicates for speed: */
X
X	pxv = xv[buffer];
X	pv2 = v2;
X	pf = f;
X	pe = edges;
X	bzero(drawn, sizeof(drawn));
X
X	if (dblbuf)
X		setDrawBuf(dbpair.dbufnum);
X			/* switch drawing buffers if double buffered */
X	if (dofaces) {	/* for faces, need to clear before FillPoly */
X		if (dblbuf)
X			icoClearArea(
X				dbpair.drawbuf->prevX, dbpair.drawbuf->prevY,
X				icoW + 1, icoH + 1);
X		icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
X	}
X
X	if (dsync)
X		XSync(dpy, 0);
X
X	for (i = NF - 1; i >= 0; --i, pf += pcount)
X		{
X
X		pcount = *pf++;	/* number of edges for this face */
X		pxvz = 0.0;
X		for (j=0; j<pcount; j++) {
X			p0 = pf[j];
X			pxvz += pxv[p0].z;
X		}
X
X		/* If facet faces away from viewer, don't consider it: */
X		if (pxvz<0.0)
X			continue;
X
X		if (dofaces) {
X			if (numcolors)
X				facecolor = i%numcolors + 1;
X			else	facecolor = 1;
X			XSetForeground(dpy, gc,
X				dbpair.drawbuf->pixels[facecolor]);
X			for (j=0; j<pcount; j++) {
X				p0 = pf[j];
X				ppts[j].x = pv2[p0].x;
X				ppts[j].y = pv2[p0].y;
X			}
X			XFillPolygon(dpy, win, gc, ppts, pcount,
X				Convex, CoordModeOrigin);
X		}
X
X		if (doedges) {
X			for (j=0; j<pcount; j++) {
X				if (j<pcount-1) k=j+1;
X				else k=0;
X				p0 = pf[j];
X				p1 = pf[k];
X				if (!drawn[p0][p1]) {
X					drawn[p0][p1] = 1;
X					drawn[p1][p0] = 1;
X					pe->x1 = pv2[p0].x;
X					pe->y1 = pv2[p0].y;
X					pe->x2 = pv2[p1].x;
X					pe->y2 = pv2[p1].y;
X					++pe;
X				}
X			}
X		}
X		}
X
X	/* Erase previous, draw current icosahedrons; sync for smoothness. */
X
X	if (doedges) {
X		if (dofaces) {
X			XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
X				/* use background as foreground color */
X		}
X		else {
X			if (dblbuf)
X				icoClearArea(dbpair.drawbuf->prevX,
X					dbpair.drawbuf->prevY,
X					icoW + 1, icoH + 1);
X			icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
X			if (dblbuf || dofaces)
X				XSetForeground(dpy, gc, dbpair.drawbuf->pixels[
X					dbpair.pixelsperbuf-1]);
X		}
X		XDrawSegments(dpy, win, gc, edges, pe - edges);
X	}
X
X	if (dsync)
X		XSync(dpy, 0);
X
X	if (dblbuf) {
X		dbpair.drawbuf->prevX = icoX;
X		dbpair.drawbuf->prevY = icoY;
X		setDisplayBuf(dbpair.dbufnum);
X	}
X	XSync(dpy, 0);
X	if (dblbuf)
X		dbpair.dbufnum = 1 - dbpair.dbufnum;
X	if (sleepcount) sleep(sleepcount);
X	}
X
Xchar *xalloc(nbytes)
Xint nbytes;
X{
Xchar *p, *malloc();
X
X	p = malloc((unsigned int)nbytes);
X	if (p) return p;
X	fprintf(stderr,"ico: no more memory\n");
X	exit(1);
X}
X
XinitDBufs(fg,bg,planesperbuf)
Xint fg,bg;
Xint planesperbuf;
X{
Xint i,j,jj,j0,j1,k,m,t;
XDBufInfo *b, *otherb;
X
X	dbpair.planesperbuf = planesperbuf;
X	dbpair.pixelsperbuf = 1<<planesperbuf;
X	dbpair.totalplanes = (dblbuf?2:1)*planesperbuf;
X	dbpair.totalpixels = 1<<dbpair.totalplanes;
X	dbpair.plane_masks = (unsigned long *)
X		xalloc(dbpair.totalplanes * sizeof(unsigned long));
X	dbpair.dbufnum = 0;
X	for (i=0; i<(dblbuf?2:1); i++) {
X		b = dbpair.bufs+i;
X		b->plane_masks = dbpair.plane_masks + (i*planesperbuf);
X		b->colors = (XColor *)
X			xalloc(dbpair.totalpixels * sizeof(XColor));
X		b->pixels = (unsigned long *)
X			xalloc(dbpair.pixelsperbuf * sizeof(unsigned long));
X	}
X
X	cmap = XDefaultColormap(dpy,DefaultScreen(dpy));
X	if (!cmap) {
X		icoFatal("can't get default colormap");
X	}
X	t = XAllocColorCells(dpy,cmap,0,
X		dbpair.plane_masks,dbpair.totalplanes, dbpair.pixels,1);
X			/* allocate color planes */
X	if (t==0) {
X		icoFatal("can't allocate color planes");
X	}
X
X	fgcolor.pixel = fg;
X	bgcolor.pixel = bg;
X	XQueryColor(dpy,cmap,&fgcolor);
X	XQueryColor(dpy,cmap,&bgcolor);
X
X	setBufColor(0,&bgcolor);
X	setBufColor(1,&fgcolor);
X	for (i=0; i<(dblbuf?2:1); i++) {
X		b = dbpair.bufs+i;
X		if (dblbuf)
X			otherb = dbpair.bufs+(1-i);
X		for (j0=0; j0<(dblbuf?dbpair.pixelsperbuf:1); j0++) {
X		    for (j1=0; j1<dbpair.pixelsperbuf; j1++) {
X			j = (j0<<dbpair.planesperbuf)|j1;
X			if (i==0) jj=j;
X			else jj= (j1<<dbpair.planesperbuf)|j0;
X			b->colors[jj].pixel = dbpair.pixels[0];
X			for (k=0, m=j; m; k++, m=m>>1) {
X				if (m&1)
X				   b->colors[jj].pixel |= dbpair.plane_masks[k];
X			}
X			b->colors[jj].flags = DoRed | DoGreen | DoBlue;
X		    }
X		}
X		b->prevX = b->prevY = 0;
X		b->enplanemask = 0;
X		for (j=0; j<planesperbuf; j++) {
X			b->enplanemask |= b->plane_masks[j];
X		}
X		for (j=0; j<dbpair.pixelsperbuf; j++) {
X			b->pixels[j] = dbpair.pixels[0];
X			for (k=0, m=j; m; k++, m=m>>1) {
X				if (m&1)
X				   b->pixels[j] |= b->plane_masks[k];
X			}
X		}
X	}
X
X	setDrawBuf(0);
X
X	XSetBackground(dpy, gc, dbpair.bufs[0].pixels[0]);
X	XSetPlaneMask(dpy, gc, AllPlanes);
X	icoClearArea(0, 0, winWidth, winHeight); /* clear entire window */
X	sleep(isleepcount);	/*** doesn't work without this!!! */
X	XSync(dpy,0);
X
X	setDisplayBuf(dblbuf?1:0);
X}
X
XsetBufColname(n,colname)
Xint n;
Xchar *colname;
X{
Xint t;
XXColor dcolor, color;
X
X	t = XLookupColor(dpy,cmap,colname,&dcolor,&color);
X	if (t==0) {	/* no such color */
X		icoFatal("no such color %s",colname);
X	}
X	setBufColor(n,&color);
X}
X
XsetBufColor(n,color)
Xint n;		/* color index */
XXColor *color;	/* color to set */
X{
Xint i,j,cx;
XDBufInfo *b;
Xunsigned long pix;
X
X	for (i=0; i<(dblbuf?2:1); i++) {
X		b = dbpair.bufs+i;
X		for (j=0; j<(dblbuf?dbpair.pixelsperbuf:1); j++) {
X			cx = n + j*dbpair.pixelsperbuf;
X			pix = b->colors[cx].pixel;
X			b->colors[cx] = *color;
X			b->colors[cx].pixel = pix;
X			b->colors[cx].flags = DoRed | DoGreen | DoBlue;
X		}
X	}
X}
X
XsetDrawBuf(n)
Xint n;
X{
XXGCValues xgcv;
Xunsigned long mask;
X
X	dbpair.drawbuf = dbpair.bufs+n;
X	xgcv.plane_mask = dbpair.drawbuf->enplanemask;
X	xgcv.foreground = dbpair.drawbuf->pixels[dbpair.pixelsperbuf-1];
X	xgcv.background = dbpair.drawbuf->pixels[0];
X	mask = GCForeground | GCBackground;
X	if (dblbuf) mask |= GCPlaneMask;
X	XChangeGC(dpy, gc, mask, &xgcv);
X}
X
XsetDisplayBuf(n)
Xint n;
X{
X	dbpair.dpybuf= dbpair.bufs+n;
X	XStoreColors(dpy,cmap,dbpair.dpybuf->colors,dbpair.totalpixels);
X}
X
XicoFatal(fmt,a0)
Xchar *fmt;
X{
X	fprintf(stderr,"ico: ");
X	fprintf(stderr,fmt,a0);
X	fprintf(stderr,"\n");
X	exit(1);
X}
X
X/******************************************************************************
X * Description
X *	Concatenate two 4-by-4 transformation matrices.
X *
X * Input
X *	l		multiplicand (left operand)
X *	r		multiplier (right operand)
X *
X * Output
X *	*m		Result matrix
X *****************************************************************************/
X
XConcatMat(l, r, m)
Xregister Transform3D l;
Xregister Transform3D r;
Xregister Transform3D m;
X	{
X	register int i;
X	register int j;
X	register int k;
X
X	for (i = 0; i < 4; ++i)
X		for (j = 0; j < 4; ++j)
X			m[i][j] = l[i][0] * r[0][j]
X			    + l[i][1] * r[1][j]
X			    + l[i][2] * r[2][j]
X			    + l[i][3] * r[3][j];
X	}
X
X
X
X/******************************************************************************
X * Description
X *	Format a matrix that will perform a rotation transformation
X *	about the specified axis.  The rotation angle is measured
X *	counterclockwise about the specified axis when looking
X *	at the origin from the positive axis.
X *
X * Input
X *	axis		Axis ('x', 'y', 'z') about which to perform rotation
X *	angle		Angle (in radians) of rotation
X *	A		Pointer to rotation matrix
X *
X * Output
X *	*m		Formatted rotation matrix
X *****************************************************************************/
X
XFormatRotateMat(axis, angle, m)
Xchar axis;
Xdouble angle;
Xregister Transform3D m;
X	{
X	double s, c;
X	double sin(), cos();
X
X	IdentMat(m);
X
X	s = sin(angle);
X	c = cos(angle);
X
X	switch(axis)
X		{
X		case 'x':
X			m[1][1] = m[2][2] = c;
X			m[1][2] = s;
X			m[2][1] = -s;
X			break;
X		case 'y':
X			m[0][0] = m[2][2] = c;
X			m[2][0] = s;
X			m[0][2] = -s;
X			break;
X		case 'z':
X			m[0][0] = m[1][1] = c;
X			m[0][1] = s;
X			m[1][0] = -s;
X			break;
X		}
X	}
X
X
X
X/******************************************************************************
X * Description
X *	Format a 4x4 identity matrix.
X *
X * Output
X *	*m		Formatted identity matrix
X *****************************************************************************/
X
XIdentMat(m)
Xregister Transform3D m;
X	{
X	register int i;
X	register int j;
X
X	for (i = 3; i >= 0; --i)
X		{
X		for (j = 3; j >= 0; --j)
X			m[i][j] = 0.0;
X		m[i][i] = 1.0;
X		}
X	}
X
X
X
X/******************************************************************************
X * Description
X *	Perform a partial transform on non-homogeneous points.
X *	Given an array of non-homogeneous (3-coordinate) input points,
X *	this routine multiplies them by the 3-by-3 upper left submatrix
X *	of a standard 4-by-4 transform matrix.  The resulting non-homogeneous
X *	points are returned.
X *
X * Input
X *	n		number of points to transform
X *	m		4-by-4 transform matrix
X *	in		array of non-homogeneous input points
X *
X * Output
X *	*out		array of transformed non-homogeneous output points
X *****************************************************************************/
X
XPartialNonHomTransform(n, m, in, out)
Xint n;
Xregister Transform3D m;
Xregister Point3D *in;
Xregister Point3D *out;
X	{
X	for (; n > 0; --n, ++in, ++out)
X		{
X		out->x = in->x * m[0][0] + in->y * m[1][0] + in->z * m[2][0];
X		out->y = in->x * m[0][1] + in->y * m[1][1] + in->z * m[2][1];
X		out->z = in->x * m[0][2] + in->y * m[1][2] + in->z * m[2][2];
X		}
X	}
END_OF_ico.c
if test 20249 -ne `wc -c <ico.c`; then
    echo shar: \"ico.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f allobjs.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"allobjs.h\"
else
echo shar: Extracting \"allobjs.h\" \(63 characters\)
sed "s/^X//" >allobjs.h <<'END_OF_allobjs.h'
X#include "objcube.h"
X#include "objico.h"
X#include "objtetra.h"
END_OF_allobjs.h
if test 63 -ne `wc -c <allobjs.h`; then
    echo shar: \"allobjs.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f objcube.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"objcube.h\"
else
echo shar: Extracting \"objcube.h\" \(732 characters\)
sed "s/^X//" >objcube.h <<'END_OF_objcube.h'
X/* objcube.h - structure values for cube */
X
X{	"cube", "cube",	/* long and short names */
X	"tetrahedron",	/* long name of dual */
X	8, 12, 6,	/* number of vertices, edges, and faces */
X	{		/* vertices (x,y,z) */
X			/* all points must be within radius 1 of the origin */
X#define T 0.577
X		{  T,  T,  T },
X		{  T,  T, -T },
X		{  T, -T, -T },
X		{  T, -T,  T },
X		{ -T,  T,  T },
X		{ -T,  T, -T },
X		{ -T, -T, -T },
X		{ -T, -T,  T },
X#undef T
X	},
X	{	/* faces (numfaces + indexes into vertices) */
X		/*  faces must be specified clockwise from the outside */
X		4,	0, 1, 2, 3,
X		4, 	7, 6, 5, 4,
X		4, 	1, 0, 4, 5,
X		4,	3, 2, 6, 7,
X		4,	2, 1, 5, 6,
X		4,	0, 3, 7, 4,
X	}
X},		/* leave a comma to separate from the next include file */
X/* end */
END_OF_objcube.h
if test 732 -ne `wc -c <objcube.h`; then
    echo shar: \"objcube.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f objico.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"objico.h\"
else
echo shar: Extracting \"objico.h\" \(1330 characters\)
sed "s/^X//" >objico.h <<'END_OF_objico.h'
X/* objico.h - structure values for icosahedron */
X
X{	"icosahedron", "ico",	/* long and short names */
X	"dodecahedron",		/* long name of dual */
X	12, 30, 20,	/* number of vertices, edges, and faces */
X	{		/* vertices (x,y,z) */
X			/* all points must be within radius 1 of the origin */
X		{ 0.00000000,  0.00000000, -0.95105650},
X		{ 0.00000000,  0.85065080, -0.42532537},
X		{ 0.80901698,  0.26286556, -0.42532537},
X		{ 0.50000000, -0.68819095, -0.42532537},
X		{-0.50000000, -0.68819095, -0.42532537},
X		{-0.80901698,  0.26286556, -0.42532537},
X		{ 0.50000000,  0.68819095,  0.42532537},
X		{ 0.80901698, -0.26286556,  0.42532537},
X		{ 0.00000000, -0.85065080,  0.42532537},
X		{-0.80901698, -0.26286556,  0.42532537},
X		{-0.50000000,  0.68819095,  0.42532537},
X		{ 0.00000000,  0.00000000,  0.95105650}
X	},
X	{	/* faces (numfaces + indexes into vertices) */
X		/*  faces must be specified clockwise from the outside */
X		 3,	0,  2,  1,
X		 3,	0,  3,  2,
X		 3,	0,  4,  3,
X		 3,	0,  5,  4,
X		 3,	0,  1,  5,
X		 3,	1,  6, 10,
X		 3,	1,  2,  6,
X		 3,	2,  7,  6,
X		 3,	2,  3,  7,
X		 3,	3,  8,  7,
X		 3,	3,  4,  8,
X		 3,	4,  9,  8,
X		 3,	4,  5,  9,
X		 3,	5, 10,  9,
X		 3,	5,  1, 10,
X		 3,	10,  6, 11,
X		 3,	6,  7, 11,
X		 3,	7,  8, 11,
X		 3,	8,  9, 11,
X		 3,	9, 10, 11
X	}
X},		/* leave a comma to separate from the next include file */
X/* end */
END_OF_objico.h
if test 1330 -ne `wc -c <objico.h`; then
    echo shar: \"objico.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f objtetra.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"objtetra.h\"
else
echo shar: Extracting \"objtetra.h\" \(712 characters\)
sed "s/^X//" >objtetra.h <<'END_OF_objtetra.h'
X/* objtetra.h - structure values for tetrahedron */
X
X{	"tetrahedron", "tetra",	/* long and short names */
X	"cube",		/* long name of dual */
X	6, 12, 8,	/* number of vertices, edges, and faces */
X	{		/* vertices (x,y,z) */
X			/* all points must be within radius 1 of the origin */
X#define T 1.0
X		{  T,  0,  0 },
X		{ -T,  0,  0 },
X		{  0,  T,  0 },
X		{  0, -T,  0 },
X		{  0,  0,  T },
X		{  0,  0, -T },
X#undef T
X	},
X	{	/* faces (numfaces + indexes into vertices) */
X		/*  faces must be specified clockwise from the outside */
X		3,	0, 4, 2,
X		3,	0, 2, 5,
X		3,	0, 5, 3,
X		3,	0, 3, 4,
X		3,	1, 2, 4,
X		3,	1, 5, 2,
X		3,	1, 3, 5,
X		3,	1, 4, 3,
X	}
X},		/* leave a comma to separate from the next include file */
X/* end */
END_OF_objtetra.h
if test 712 -ne `wc -c <objtetra.h`; then
    echo shar: \"objtetra.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f polyinfo.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"polyinfo.h\"
else
echo shar: Extracting \"polyinfo.h\" \(808 characters\)
sed "s/^X//" >polyinfo.h <<'END_OF_polyinfo.h'
X/* polyinfo.h
X * This is the description of one polyhedron file
X */
X
X#define MAXVERTS 120
X	/* great rhombicosidodecahedron has 120 vertices */
X#define MAXNV MAXVERTS
X#define MAXFACES 30
X	/* (hexakis icosahedron has 120 faces) */
X#define MAXEDGES 180
X	/* great rhombicosidodecahedron has 180 edges */
X#define MAXEDGESPERPOLY 20
X
Xtypedef struct {
X	double x, y, z;
X} Point3D;
X
X/* structure of the include files which define the polyhedra */
Xtypedef struct {
X	char *longname;		/* long name of object */
X	char *shortname;	/* short name of object */
X	char *dual;		/* long name of dual */
X	int numverts;		/* number of vertices */
X	int numedges;		/* number of edges */
X	int numfaces;		/* number of faces */
X	Point3D v[MAXVERTS];	/* the vertices */
X	int f[MAXEDGES*2+MAXFACES];	/* the faces */
X} Polyinfo;
X
X/* end */
END_OF_polyinfo.h
if test 808 -ne `wc -c <polyinfo.h`; then
    echo shar: \"polyinfo.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(3495 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X#
X# Warning: the cpp used on this machine replaces
X# all newlines and multiple tabs/spaces in a macro
X# expansion with a single space.  Imake tries to
X# compensate for this, but is not always
X# successful.
X#
X
X#
X# This makefile is automatically generated by imake... do not modify
X# or you may lose your changes when imake generates makefiles again.
X# Ignore this message if you are not using imake.
X#
X
X            TOP = ./../..
X             AS = as
X             CC = cc
X            CPP = /lib/cpp
X             LD = ld
X           LINT = lint
X           MAKE = make
X    CDEBUGFLAGS = -O
X        DESTDIR = /u8/X/X11R1/`/u8/X/X11R1/machtype`
X
X        INSTALL = install
X           TAGS = ctags
X         DEPEND = $(DEPENDSRC)/makedepend
X          IMAKE = $(IMAKESRC)/imake
X            RGB = $(RGBSRC)/rgb
X         CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(DEFINES)
X        LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES)
X   INSTLIBFLAGS = -c -m 0664
X      USRLIBDIR = $(DESTDIR)/usr/lib
X         BINDIR = $(DESTDIR)/usr/bin/X11
X         LIBDIR = $(DESTDIR)/usr/lib/X11
X         INCDIR = $(DESTDIR)/usr/include/X11
X   FUTUREINCDIR = $(DESTDIR)/usr/include/X
X        FONTDIR = $(LIBDIR)/fonts
X         MANDIR = $(DESTDIR)/usr/man/mann
X      CLIENTSRC = $(TOP)/clients
X        DEMOSRC = $(TOP)/demos
X         LIBSRC = $(TOP)/lib
X        FONTSRC = $(TOP)/fonts
X     INCLUDESRC = $(TOP)/include
X      SERVERSRC = $(TOP)/server
X        UTILSRC = $(TOP)/util
X        HACKSRC = $(TOP)/hacks
X         DOCSRC = $(TOP)/doc
X      DEPENDSRC = $(UTILSRC)/makedepend
X       IMAKESRC = $(UTILSRC)/imake
X         RGBSRC = $(UTILSRC)/rgb
X        XLIBSRC = $(LIBSRC)/X
X         XRMSRC = $(LIBSRC)/Xrm
X     TOOLKITSRC = $(LIBSRC)/Xtk
X     OLDXLIBSRC = $(LIBSRC)/oldX
X    OLDXMENUSRC = $(LIBSRC)/oldXMenu
X      OLDXRMSRC = $(LIBSRC)/oldXrm
X  OLDTOOLKITSRC = $(LIBSRC)/oldXtk
X   EXTENSIONSRC = $(TOP)/extensions
X        XMANSRC = $(DOCSRC)/Xlib/Xman
X   EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a
X           XLIB = $(XLIBSRC)/libX.a
X        OLDXLIB = $(OLDXLIBSRC)/liboldX.a
X       XTOOLLIB = $(TOOLKITSRC)/libXtk.a
X    OLDXTOOLLIB = $(OLDTOOLKITSRC)/liboldXtk.a
X    OLDXMENULIB = $(OLDXMENUSRC)/libXMenu.a
X         XRMLIB = $(XRMSRC)/libXrm.a
X      OLDXRMLIB = $(OLDXRMSRC)/liboldXrm.a
X       INCLUDES = -I$(TOP)
X      MACROFILE = Sun.macros
X      IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl \
X			-I$(NEWTOP)$(UTILSRC)/imake.includes \
X			-s Makefile
X         RM_CMD = rm -f *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a \
X			tags TAGS make.log
X
XLOCAL_LIBRARIES = $(XLIB)
X  SYS_LIBRARIES = -lm
X
Xnewdefault: all
X
Xshar:;	shar $(SRCS) *.h Makefile Imakefile ico.man TODO > ico.shar
X
Xdepend::	allobjsh
X
Xallobjsh:
X	ls -1 obj*.h | sed -e 's/.*/#include "&"/' > allobjs.h
X
X OBJS = ico.o
X SRCS = ico.c
X
X PROGRAM = ico
X
Xall:: ico
X
Xico: $(OBJS) $(LOCAL_LIBRARIES)
X	rm -f $@
X	$(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS)
X
Xrelink:
X	rm -f $(PROGRAM)
X	$(MAKE) $(MFLAGS) $(PROGRAM)
X
Xinstall:: ico
X	$(INSTALL) -c $(INSTALLFLAGS) ico $(BINDIR)
X
Xinstall:: ico.man
X	$(INSTALL) -c -m 0664 ico.man $(MANDIR)/ico.n
X
Xdepend::
X	$(DEPEND) -s "# DO NOT DELETE" $(CFLAGS) $(SRCS)
Xclean::
X	rm -f $(PROGRAM)
X
Xclean::
X	$(RM_CMD) \#*
X
XMakefile:: Imakefile \
X	$(UTILSRC)/imake.includes/Imake.tmpl \
X	$(UTILSRC)/imake.includes/Imake.rules \
X	$(UTILSRC)/imake.includes/$(MACROFILE)
X	-rm -f Makefile.bak; mv Makefile Makefile.bak
X	$(IMAKE_CMD) -DTOPDIR=$(TOP)
X
Xtags::
X	$(TAGS) -w *.[ch]
X	$(TAGS) -xw *.[ch] > TAGS
X
Xinstall::
X	@echo "install done"
X
XMakefiles::
X
END_OF_Makefile
if test 3495 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Imakefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Imakefile\"
else
echo shar: Extracting \"Imakefile\" \(246 characters\)
sed "s/^X//" >Imakefile <<'END_OF_Imakefile'
XLOCAL_LIBRARIES = $(XLIB)
X  SYS_LIBRARIES = -lm
X
Xnewdefault: all
X
Xshar:;	shar $(SRCS) *.h Makefile Imakefile ico.man TODO > ico.shar
X
Xdepend::	allobjsh
X
Xallobjsh:
X	ls -1 obj*.h | sed -e 's/.*/#include "&"/' > allobjs.h
X
XSimpleProgramTarget(ico)
X
END_OF_Imakefile
if test 246 -ne `wc -c <Imakefile`; then
    echo shar: \"Imakefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ico.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ico.man\"
else
echo shar: Extracting \"ico.man\" \(2776 characters\)
sed "s/^X//" >ico.man <<'END_OF_ico.man'
X.\" $Header: ico.man,v 1.2 88/01/11 10:30:00 jimmc Exp $
X.TH ICO "11 January 1988" "X Version 11"
X.UC 4
X.SH NAME
Xico \- animate an icosahedron or other polyhedron
X.SH SYNOPSIS
X.B Ico
X[-r] [-d pattern] [-i] [-dbl] [-faces] [-noedges]
X[-sleep n] [-obj object] [-objhelp] [-colors color-list]
X.SH DESCRIPTION
X.I Ico
Xdisplays a wire-frame rotating polyhedron, with hidden lines removed,
Xor a solid-fill polyhedron with hidden faces removed.
XThere are a number of different polyhedra available;
Xadding a new polyhedron to the program is quite simple.
X.SH OPTIONS
X.TP
X.B -r
XDisplay on the root window instead of creating a new window.
X.TP
X.B -d pattern
XSpecify a bit pattern for drawing dashed lines for wire frames.
X.TP
X.B -i
XUse inverted colors for wire frames.
X.TP
X.B -dbl
XUse double buffering on the display.
XThis works for either wire frame or solid fill drawings.
XFor solid fill drawings, using this switch results in substantially
Xsmoother movement.
XNote that this requires twice as many bit planes as without double buffering.
XSince some colors are typically allocated by other programs,
Xmost eight-bit-plane displays will probably be limited to eight colors
Xwhen using double buffering.
X.TP
X.B -faces
XDraw filled faces instead of wire frames.
X.TP
X.B -noedges
XDon't draw the wire frames.
XTypically used only when -faces is used.
X.TP
X.B -sleep n
XSleep n seconds between each move of the object.
X.TP
X.B -obj object
XSpecify what object to draw.
XIf no object is specified, an icosahedron is drawn.
X.TP
X.B -objhelp
XPrint out a list of the available objects, along with information
Xabout each object.
X.TP
X.B -colors colorlist
XSpecify what colors should be used to draw the filled faces of the object.
XIf less colors than faces are given, the colors are reused.
X.SH ADDING POLYHEDRA
X.LP
XIf you have the source to ico, it is very easy to add more polyhedra.
XEach polyhedron is defined in an include file by the name of objXXX.h,
Xwhere XXX is something related to the name of the polyhedron.
XThe format of the include file is defined in the file polyinfo.h.
XLook at the file objcube.h to see what the exact format of an objXXX.h
Xfile should be, then create your objXXX.h file in that format.
X.LP
XAfter making the new objXXX.h file (or copying in a new one from elsewhere),
Xsimply do a 'make depend'.
XThis will recreate the file allobjs.h, which lists all of the objXXX.h
Xfiles.
XDoing a 'make' after this will rebuild ico with the new object information.
X.SH BUGS
X.LP
XIf -dbl or -colors is specified on a monochrome screen, or if the number
Xof bit planes needed is more than what is available, the server hangs
X(this is on a Sun 3/60, patches up to 80 applied).
X.LP
XA separate color cell is allocated for each name in the -colors list,
Xeven when the same name may be specified twice.
END_OF_ico.man
if test 2776 -ne `wc -c <ico.man`; then
    echo shar: \"ico.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f TODO -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"TODO\"
else
echo shar: Extracting \"TODO\" \(239 characters\)
sed "s/^X//" >TODO <<'END_OF_TODO'
X- Add a demo switch with some prepackaged neat demos
X- Add a verify switch which makes sure that all the counts in
X  the objects are less than the MAX values defined in the program
X- Add a switch to tell how to use the colors on the faces
END_OF_TODO
if test 239 -ne `wc -c <TODO`; then
    echo shar: \"TODO\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0

trainor@CS.UCLA.EDU (Vulture of Light) (01/12/88)

>If anyone is interested in adding more polyhedra to ico, this would be
>a good source.  I just decided I wasn't up to it....

Please don't duplicate the good work of others with polyhedra.  NETLIB
has a lot of stuff!  See "Communications of the ACM", May 1987, p.403-7.

Here's part of an old blurp:

    "netlib" is automated to respond to requests sent to it.  There are two
    nodes, one on the arpanet, the other on UUCP.  Write to either
    "netlib@anl-mcs.arpa" or ...!research!netlib.  To get general info on
    the library, type "send index" as a mail message to either site (the
    sites are about 95%+ identical in the programs carried).

    One nice library available is "polyhedra".  To access it, mail the
    message "send index from polyhedra".  In this library are some 142
    polyhedra descriptions (a few of which are slightly buggy - please
    report these problems to them).