6.3. A CwGraph Rotating Cube

This code creates two graphs, one of which is a two-dimensional representation of a cube that appears to rotate in three-dimensional space. The graphs are created using the CwGraph widget, a contributed widget created at Cogent Real-Time Systems, Inc. This program uses a dynamic library, which requires that Gamma be called from it's own directory. For example, if Gamma is in your /usr/cogent/bin/ directory, you would start this program with the following command:

$ /usr/cogent/bin/phgamma graph.g 3d

The code starts here:

#!/usr/cogent/bin/phgamma

/*
 * This example shows two graphs made using CwGraph.
 * One graph is a 3-dimensional rotating cube.  You can
 * display this graph using the argument "3d" on the
 * command line.  The other graph shows 6 randomly-
 * generated traces of various colors.  No argument is
 * necessary on the command line to display this graph.
 */

/*
 * Load the required files, which include two dynamic
 * libraries that are not generally needed for Photon
 * widgets.
 */

require_lisp ("PhotonWidgets");
require_lisp("PhabTemplate.lsp");

use3d = nil;

/*
 * Used with the 3D cube example.
 */
xrot = 0;
yrot = 0;
zrot = 0;
pi = 3.141592653589;

/*
 * Used with the 2D graph example.
 */
DataSetSize = 100;
count = 0;
xlist1 = nil;

function main ()
{
	PtInit (nil);

	if (length(argv) > 1 && cadr(argv) == "3d")
		use3d = t;

	/* Set the redraw frequency. */
	
	if (use3d)
		every (0.1, #redraw());
	else
		every (0.1, #redraw2());

	MakeWindow ();

	PtRealizeWidget (w);
	PtMainLoop();
}

function MakeWindow ()
{
	w = new (PtWindow);
	gr = new (PtGroup);
	gr.SetDim (325,300);

	/* Anchor the group to the window.*/
	
	gr.group_flags = Pt_GROUP_STRETCH_HORIZONTAL |
	                 Pt_GROUP_STRETCH_VERTICAL;
	gr.anchor_flags = Pt_LEFT_ANCHORED_LEFT |
	                  Pt_RIGHT_ANCHORED_RIGHT |
			  Pt_TOP_ANCHORED_TOP |
			  Pt_BOTTOM_ANCHORED_BOTTOM;

	/* Assign graph variables.*/
	
	g = new (CwGraph);
	g.SetDim (325, 300);
	g.fill_color = 0x7777bb;
	g.graph_x_axis_color = 0x00ff00;
	g.graph_y_axis_color_left = 0x00ff00;
	g.graph_y_axis_color_right = 0x00ff00;
	g.graph_x_label_color = 0xffff00;
	g.graph_y_label_color_left = 0xffff00;
	g.graph_y_label_color_right = 0xffff00;

	if (!use3d)
	{
		g.graph_traces = 4;
		g.graph_xmin = 0;
		g.graph_xmax = DataSetSize;
		g.graph_x_label = "Test Trace";
		g.graph_y_label_left = "Y Axis";
		g.graph_y_label_right = "Alternate Axis";
		g.graph_x_font = "helv14bi";
		g.graph_y_font_left = "helv14b";
		g.graph_y_font_right = "helv14i";
		g.graph_flags = cons (Cw_GRAPH_Y_AXIS_LEFT |
				      Cw_GRAPH_X_AXIS, -1);

		CwGraphSetYLimits (g, 0, 0, 1000);
		CwGraphSetYLimits (g, 1, 0, 1000);
		CwGraphSetYLimits (g, 2, 0, 1000);
		CwGraphSetYLimits (g, 3, 0, 1000);
		CwGraphSetTraceColor (g, 0, 0xff0000);
		CwGraphSetTraceColor (g, 1, 0x0000ff);
		CwGraphSetTraceColor (g, 2, 0x00ffff);
		CwGraphSetTraceColor (g, 3, 0x00ff00);
	}
	else
	{
		g.graph_traces = 6;
		g.graph_xmin = -2;
		g.graph_xmax = 2;
		g.graph_flags = cons (Cw_GRAPH_Y_AXIS_RIGHT |
				      Cw_GRAPH_Y_MAJOR_TICK_RIGHT |
				      Cw_GRAPH_Y_MINOR_TICK_RIGHT |
				      Cw_GRAPH_Y_AXIS_TITLE_RIGHT |
				      Cw_GRAPH_Y_AXIS_LABEL_RIGHT
				      , nil);
		g.margin_width = 10;

		CwGraphSetYLimits (g, 0, -2, 2);
		CwGraphSetYLimits (g, 1, -2, 2);
		CwGraphSetYLimits (g, 2, -2, 2);
		CwGraphSetYLimits (g, 3, -2, 2);
		CwGraphSetYLimits (g, 4, -2, 2);
		CwGraphSetYLimits (g, 5, -2, 2);
		CwGraphSetTraceColor (g, 0, 0xff0000);
		CwGraphSetTraceColor (g, 1, 0xffff00);
		CwGraphSetTraceColor (g, 2, 0x00ff00);
		CwGraphSetTraceColor (g, 3, 0x00ff00);
		CwGraphSetTraceColor (g, 4, 0x00ff00);
		CwGraphSetTraceColor (g, 5, 0x00ff00);
	}
}

/*
 * Functions for the 3D example.
 */

function data (n, range, adder)
{
	local		i, l;

	for (i=0; i<n; i++)
	{
		l = cons (random() * range + adder, l);
	}
	l;
}

function xlist (start, n)
{
	local		i, l;
	for (i=start+n - 1; i>=start; i --)
		l = cons (i,l);
	l;
}

function newdata ()
{
	if (count > DataSetSize)
	{
		count = 0;
		CwGraphClearTrace (g,0);
		CwGraphClearTrace (g,1);
	}
	CwGraphAddXYPoints (g, 0, xlist(count,10), data(10,500,500));
	CwGraphAddXYPoints (g, 1, xlist(count,10), data(10,500,0));
	count += 10;
}

function mk3dpt (x, y, z)
{
	array (x, y, z);
}

function cube3d ()
{
	array (array (mk3dpt(-1,1,1), mk3dpt(-1,-1,1),
		      mk3dpt(1,-1,1), mk3dpt(1,1,1),
		      mk3dpt(-1,1,1)),
		   array (mk3dpt(-1,1,-1), mk3dpt(1,1,-1),
			  mk3dpt(1,-1,-1), mk3dpt(-1,-1,-1),
			  mk3dpt(-1,1,-1)),
		   array (mk3dpt(-1,1,1), mk3dpt(-1,1,-1)),
		   array (mk3dpt(1,1,1), mk3dpt(1,1,-1)),
		   array (mk3dpt(1,-1,1), mk3dpt(1,-1,-1)),
		   array (mk3dpt(-1,-1,1), mk3dpt(-1,-1,-1))
		   );
}

function identmatrix ()
{
	array (array (1,0,0,0),
	       array(0,1,0,0),
	       array (0,0,1,0),
	       array (0,0,0,1));
}

function matxmat (mat1, mat2)
{
	local		i,j,res=array(array(0,0,0,0),
				      array(0,0,0,0),
				      array(0,0,0,0),
				      array(0,0,0,0));

	for (i=0; i<4; i++)
	{
		for (j=0; j<4; j++)
		{
			res[i][j] = mat1[i][0] * mat2[0][j] +
				    mat1[i][1] * mat2[1][j] +
				    mat1[i][2] * mat2[2][j] +
				    mat1[i][3] * mat2[3][j];
		}
	}
	res;
}

function vecxmat (vec, mat)
{
	local	res = array (0,0,0,0);
	local	i;

	for (i=0; i<4; i++)
	{
		res[i] = vec[0] * mat[0][i] +
		         vec[1] * mat[1][i] +
			 vec[2] * mat[2][i];
	}
	res;
}

function xrotmat (degrees)
{
	local		rad = degrees / 180 * pi, ret = identmatrix();
	ret[1][1] = ret[2][2] = cos (rad);
	ret[1][2] = sin (rad);
	ret[2][1] = -sin (rad);
	ret;
}

function yrotmat (degrees)
{
	local		rad = degrees / 180 * pi, ret = identmatrix();
	ret[0][0] = ret[2][2] = cos (rad);
	ret[0][2] = sin (rad);
	ret[2][0] = -sin (rad);
	ret;
}

function zrotmat (degrees)
{
	local		rad = degrees / 180 * pi, ret = identmatrix();
	ret[0][0] = ret[1][1] = cos (rad);
	ret[0][1] = sin (rad);
	ret[1][0] = -sin (rad);
	ret;
}

function redraw ()
{
	local		c = cube3d();
	local		mat = identmatrix();
	local		xr = xrotmat(xrot);
	local		yr = yrotmat(yrot);
	local		zr = zrotmat(zrot);
	local		traces = array();
	local		i=0, xpts, ypts, vec;

	xrot += 1;
	yrot += 1;
	zrot += 1;

	mat = matxmat (mat, xr);
	mat = matxmat (mat, yr);
	mat = matxmat (mat, zr);

	i=0;
	with trace in c do
	{
		xpts = nil;
		ypts = nil;
		with pt in trace do
		{
			vec = vecxmat (pt, mat);
			xpts = cons (vec[0], xpts);
			ypts = cons (vec[1], ypts);
		}
		traces[i] = cons (xpts,ypts);
		i++;
	}

	PtHold();
	for (i=0; i<6; i++)
	{
		CwGraphClearTrace (g,i);
		CwGraphAddXYPoints (g, i, car(traces[i]),
				    cdr(traces[i]));
	}
	PtRelease();
}


/*
 * Function for the 2D example.
 */

function redraw2 ()
{
	local	nanosleep = list;
	
	PtHold();
	{
		ylist1 = data (DataSetSize, 400, 600);
		ylist2 = data (DataSetSize, 400, 400);
		ylist3 = data (DataSetSize, 400, 200);
		ylist4 = data (DataSetSize, 400, 0);
		xlist1 = xlist (0, DataSetSize);
	}
	CwGraphClearTrace (g,0);
	CwGraphClearTrace (g,1);
	CwGraphClearTrace (g,2);
	CwGraphClearTrace (g,3);
	CwGraphAddXYPoints (g, 0, xlist1, ylist1);
	CwGraphAddXYPoints (g, 1, xlist1, ylist2);
	CwGraphAddXYPoints (g, 2, xlist1, ylist3);
	CwGraphAddXYPoints (g, 3, xlist1, ylist4);
	PtRelease();
}