[alt.sources] graph3d part 1/3

michel@es.ele.tue.nl (& Berkelaar) (10/13/89)

Here is the graph3d graphics package I promised to send to interested people
in comp.sources.wanted. Because of the large number of requests (this was my
last such offer ever), I post the sources here. I am not the original author,
you can find his name and email address in the README file. Please send all
bug reports and questions to him. (He knows about me posting this).

Don't forget to cut my signature away before unsharring!

-------------------------
#! /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
# If this archive is complete, you will see the following message at the end:
#		"End of archive 1 (of 3)."
#
# Contents:
#   README graph3d.c
#
# Wrapped by tap@cs.utoronto.ca on Wed Oct 11 23:48:16 1989
#
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2601 characters\)
sed "s/^X//" >README <<'END_OF_README'
XGraph3d - a 3d plotting package composed of 4 programs + 2
Xtest-data generating programs.
X
XCOMPILATION
X-----------
XCompile the programs by typing "make".
X
XView the manual pages by typing "nroff -man graph3d.man | more", etc.
XThere is a manual page for each of the 6 program.
X
XCONTENTS
X--------
XProcessing programs:
X* graph3d
X* graph3d-tek
X* surface
X* pswrap
X
XTest data generating programs:
X* hills
X* hat
X
X* The main program `graph3d' is a 3d version of the standard
Xunix utility `graph'.  It takes input of 3d points and does
Xa projection onto 2d.
X
X* It can produce output in 3 formats: postscript, input for
X`graph', and plot(5) format.  Graph3d can be compiled with
Xany of the plot(3) libraries to directly produce graphic
Xoutput for particular devices.  E.g., compiled with the
X-l4014 library the program produces output for a tektronics
X4014 terminal.  This is useful since the output can be sent
Xto an Xterm in tektronics mode for plotting.  The Makefile
Xknows how to build `graph3d-tek'.  Graph3d contains various
Xfeatures designed to make it work very simply withing the X
Xenvironment.
X
X* Graph3d does hidden line removal by z-sorting and drawing
Xfilled polygons.  Thus it can produce plots with hidden
Xlines removed for postscript output format.  (But not for
Xplot(5) format since that does not support drawing filled
Xpolygons).
X
X* Graph3d can put up axis, and enclosing boxes, and can
Xprint labels in places specified by 3d world points or 2d
Xview points.  It does NOT do axis with tick marks.
X
X* A very common thing to want to do is to plot a surface in
X3d.  The `surface' program takes a 2d matrix and interprets
Xit as the description of a 3d surface, producing output for
X`graph3d'.  For efficiency the default output of surface is
Xbinary format so that graph3d does not have to spend alot of
Xtime reading real numbers.
X
X* The fourth program, `pswrap', puts a prologue and trailer
Xaround the postscript output from `graph3d'.
X
X* One test program, `hills', produces random pyramids, and the
Xother `hat', produces a hat like surface.  The output from
Xthese programs must be piped through `surface' before
Xgiving it to `graph3d'.
X
XThese programs have been successfully compiled and run on
Xsun3s, sun4s, and mips machines.
X
XThese programs are copyrighted, but only to prevent others
Xfrom copyrighting and restricting access.  Feel free to use
Xit, change it, delete it, or sell it, but retain the
Xcopyright notices.
X
XSend bugs and/or enhancements to tap@ai.toronto.edu
X
XTony Plate
XDepartment of Computer Science, University of Toronto, 
X10 Kings College Road, Toronto, 
XOntario, CANADA M5S 1A4
END_OF_README
if test 2601 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f graph3d.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"graph3d.c\"
else
echo shar: Extracting \"graph3d.c\" \(49102 characters\)
sed "s/^X//" >graph3d.c <<'END_OF_graph3d.c'
X/*******************************************************\
X* 							*
X*              @(#)graph3d.c	1/2/89			*
X*	Author:       Tony Plate			*
X*	Copyright (C) 1989 Tony Plate			*
X*	This program may be freely distributed and	*
X*	used, provided that this copyright notice is	*
X*	retained intact.  There is no warranty with	*
X*	this software.					*
X* 							*
X\*******************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include <ctype.h>
X
Xchar *options_description[] = {
X"Options: (an unambiguous substring is sufficient)",
X"-2d		: just work in 2 dimensions, like graph(1)",
X"-3d		: work in 3 dimensions (default)",
X"-axis		: draw an axis on the graph",
X"-back		: place the origin at the back",
X"-border		: put a square border around the graph",
X"-bounds		: print the bounds in the top left corner",
X"-box		: put a cubic box around the graph",
X"-focus	D	: put the focus at distance D from the centre of the graph",
X"-forcetty	: write to the tty even if we don't own it",
X"-front		: place the origin at the front",
X"-graph		: produce output for graph(1)",
X"-help		: print this list",
X"-hide		: do hidden line removal by Z-sorting polygons",
X"-label	X Y string	: put a label at offsets X and Y",
X"-left		: place the origin at the left",
X"-noerase	: don't erase the previous drawing, only applies when",
X"		  the -plot option is selected",
X"-noinvisibleborder	: don't delimit the graph with an invisible border",
X"-orient		: draw a small labelled axis in the right hand corner",
X"-plane	D	: put the projection plane at distance D from the center",
X"		  of the graph",
X"-plot		: produce output in plot(5) format",
X"-plot-scale S	: make the scale for plot output equal to S",
X"-ps		: produce POSTSCRIPT output",
X"-ps-scale S	: make the scale for POSTSCRIPT output equal to S",
X"-q1		: put the graph in the first quadrant",
X"-q2		: put the graph in the second quadrant",
X"-q3		: put the graph in the third quadrant",
X"-q4		: put the graph in the fourth quadrant",
X"-right		: place the origin at the right",
X"-show-rotations	: show the rotations that would be used and",
X"		  exit without drawing any graph",
X"-stdout		: send output to stdout",
X"-tek		: same as -plot",
X"-tty <hostname>:X	: send tektronics output directly to <hostname>:/dev/ttyX",
X"-xfraction F	: use fraction 0 <= F <=1 of the X dimension of the viewport",
X"-xlow X		: start using the X viewport at 0 <= X <= 1",
X"-xrotation R	: rotate the graph in the X plane by R degrees",
X"-xscale S	: scale the graph in the X direction by S",
X"-yfraction F	: use fraction 0 <= F <=1 of the Y dimension of the viewport",
X"-ylow Y		: start using the Y viewport at 0 <= Y <= 1",
X"-yrotation R	: rotate the graph in the Y plane by R degrees",
X"-yscale S	: scale the graph in the Y direction by S",
X"-zrotation R	: rotate the graph in the Z plane by R degrees",
X"-zscale S	: scale the graph in the Z direction by S",
X  NULL
X};
X
X#define DB(X)
X#define DBDATA(X)
X/*
X * This program works as follows:
X * (1) Read command line options
X * (2) Read data - one point per line, & knows format from first line
X * (3) Calculate size of image & the translation needed to put the centre
X *     of it at the origin.
X * (4) Add axis or a box to the list of polygons if they were requested.
X * (5) Create a cube & transform it into the viewing coordinates, in
X *     order to calculate the x & y scale factors neccessary to put
X *     the image in the viewing rectangle.
X * (6) Make the transformations on the list of polygons, perspective is done
X *     by translating the object so that its centre is at the origin, and
X *     so that its longest dimension is one.
X *     Then it is rotated so that the angle of view is parallel with
X *     the z-axis, and the points are scaled by their position on the z-axis.
X * (7) Convert the list of polygons to a vector of polygons (for sorting)
X * (8) If hidden line removal is desired, Qsort the vector by z-position
X * (9) Print out the polygons in the desired format
X */
X
Xtypedef float real;
X
Xtypedef struct SINGLE_POINT {
X  real		x;
X  real		y;
X  real		z;
X} SINGLE_POINT;
X
Xtypedef struct POINT_LIST {
X  SINGLE_POINT	p;
X  struct POINT_LIST	*next;
X} POINT_LIST;
X
Xtypedef struct POINT {
X  SINGLE_POINT	world;
X  SINGLE_POINT	view;
X} POINT;
X
Xtypedef struct POLYGON {
X  enum		{LINE,POLY}	type;
X  int		n_points;
X  POINT		*points;
X  real		z_pos;		/* for sorting to do hidden line removal */
X  char		*text;
X  struct POLYGON	*next;
X} POLYGON;
X
Xtypedef struct MIN_MAX {
X  SINGLE_POINT	min;
X  SINGLE_POINT	max;
X  SINGLE_POINT	edge;
X} MIN_MAX;
X
Xtypedef struct TRANSFORM {
X  real		proj_focus;	/* distance from the view origin	*/
X  real		proj_plane;	/* distance in from the focus		*/
X  real		x_low;		/* in view co-ordinates, [0-1]		*/
X  real		x_frac;		/* in view co-ordinates, [0-1]		*/
X  real		x_view_scale;	/* put the tranformed image in the viewport*/
X  real		x_view_move;
X  real		x_scale;	/* supplied scale factor (default 1)	*/
X  real		x_move;
X  real		x_rot;
X  real		sin_x_rot;
X  real		cos_x_rot;
X  real		y_low;
X  real		y_frac;
X  real		y_view_scale;
X  real		y_view_move;
X  real		y_scale;
X  real		y_move;
X  real		y_rot;
X  real		sin_y_rot;
X  real		cos_y_rot;
X  real		z_scale;
X  real		z_move;
X  real		z_rot;
X  real		z_view_scale;
X  real		z_view_move;
X  real		sin_z_rot;
X  real		cos_z_rot;
X} TRANSFORM;
X
Xtypedef struct STYLE {
X  enum		{NONE,BOX,AXIS} axis_style;
X  enum		{POST_SCRIPT,PLOT,GRAPH} output_style;
X  enum		{FIRM,SOFT} scale_style;
X  enum		{D2,D3} dimension;
X  int		remove_hidden;
X  int		border;
X  int		bounds;
X  int		invisible_border;
X  int		orient;	/* show a little labelled axis set in the corner */
X  long		ps_scale;
X  long		plot_scale;
X  int		erase;
X  real		x_char_size;
X  real		y_char_size;
X} STYLE;
X
Xchar *my_name;
Xint dont_change_out=0;
Xchar *use_tty=NULL;
XFILE *out;
Xint compare_poly();
XPOLYGON **list_to_vec();
Xchar *getenv();
XPOINT_LIST *new_point();
Xchar *strip_quotes();
Xint force_tty = 0;
X
X#define DEG_TO_RAD(x) ((x) * 3.141592 / 180)
X#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
X#define set_min_max(x,min,max) {real internal_temp=(x); if (min>max) min=max=internal_temp; else if (internal_temp<min) min=internal_temp; else if (internal_temp>max) max=internal_temp;}
X
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X  POLYGON *poly_list,**poly_vec,*label_list,*axis_list;
X  int n_polys;
X  TRANSFORM t;
X  STYLE s;
X  MIN_MAX min_max;
X  my_name = argv[0];
X  out = stdout;
X  poly_list = label_list = axis_list = NULL;
X  read_options(argv,&t,&s,&label_list);
X  if (s.output_style==PLOT) CheckTekTerminal();
X  output_prologue(&t,&s);
X  n_polys = read_polys(&s,&poly_list,&label_list,stdin);	/* read the input */
X  find_min_max_world(poly_list,&min_max);		/* find the min & max on all dimensions */
X  if (s.bounds) add_bounds_label(&min_max,&label_list);
X  add_axis(&axis_list,&min_max,&t,&s);	/* add axis or a box to the list of polygons */
X  DB( show_poly_list_world(poly_list); )
X  DB( show_min_max(&min_max); )
X  calc_view_scale(&t,&min_max,&s);
X  DB( show_poly_list_world(poly_list); )
X  transform_poly_list(poly_list,&t,&s);
X  transform_poly_list(axis_list,&t,&s);
X  poly_vec = list_to_vec(poly_list,n_polys);
X  DB( printf("Label list:\n");  show_poly_list_world(label_list); )
X  DB( show_poly_vec_world(n_polys,poly_vec); )
X  if (s.remove_hidden) qsort(poly_vec,n_polys,sizeof(POLYGON*),compare_poly);
X  DB( show_poly_vec_world(n_polys,poly_vec); )
X  DB( show_poly_vec_view(n_polys,poly_vec); )
X  /* output the axis list before the polygons */
X  output_back_axis(axis_list,&s);
X  output_poly_vec(n_polys,poly_vec,&s);
X  /* and now output the axis that should be in front */
X  output_front_axis(axis_list,&s);
X  output_label_list(label_list,&t,&s);
X  if (s.orient) output_orient(&t,&s);
X  output_epilogue(&t,&s);
X}
X
Xread_options(argv,t,s,label_list)
Xchar *argv[];
XTRANSFORM *t;
XSTYLE *s;
XPOLYGON **label_list;
X{
X  char *p;
X  int show_rotations=0;
X  /* set the rotations to put the origin in the left hand corner */
X  t->proj_plane = 1.0;
X  t->proj_focus = 1.0;
X  t->x_low	= 0.0;
X  t->x_frac	= 1.0;
X  t->x_rot	= -65;
X  t->x_scale	= 1.0;
X  t->x_view_scale= 1.0;
X  t->x_view_move= 0.0;
X  t->y_low	= 0.0;
X  t->y_frac	= 1.0;
X  t->y_rot	= 0;
X  t->y_scale	= 1.0;
X  t->y_view_scale= 1.0;
X  t->y_view_move= 0.0;
X  t->z_rot	= 30;
X  t->z_scale	= 1.0;
X  t->z_view_scale= 1.0;
X  t->z_view_move= 0.0;
X  s->axis_style = NONE;
X  s->output_style = PLOT;
X  s->scale_style = FIRM;
X  s->dimension	= D3;
X  s->remove_hidden = 0;
X  s->ps_scale	= 10000;
X  s->plot_scale	= 3120; /* just right for tektronics 4014 */
X  s->erase	= 1;
X  s->border	= 0;
X  s->bounds	= 0;
X  s->invisible_border	= 1;
X  s->orient	= 0;
X  while (p = *(++argv)) {
X    if (*p == '-') {
X      p++;
X      if (prefix(p,"2d")) {
X	s->dimension = D2;
X	t->x_rot = 0;
X	t->y_rot = 0;
X	t->z_rot = 0;
X      } else if (prefix(p,"3d")) {
X	s->dimension = D3;
X      } else if (prefix(p,"axis")) {
X	s->axis_style = AXIS;
X      } else if (prefix(p,"back")) {
X	t->x_rot = -65;
X	t->y_rot = 0;
X	t->z_rot = 150;
X	p += 3;
X      } else if (prefix(p,"border")) {
X	s->border = 1;
X      } else if (prefix(p,"bounds")) {
X	s->bounds = 1;
X      } else if (prefix(p,"box")) {
X	s->axis_style = BOX;
X      } else if (prefix(p,"forcetty")) {
X	force_tty = 1;
X      } else if (prefix(p,"focus")) {
X	if (!*(++argv)) {
X	  fprintf(stderr,"%s: Expected distance after '-focus'\n",my_name);
X	  exit(1);
X	}
X	t->proj_focus = atof(*argv);
X	p += 4;
X      } else if (prefix(p,"front")) {
X	t->x_rot = -65;
X	t->y_rot = 0;
X	t->z_rot = -30;
X	p += 4;
X      } else if (prefix(p,"graph")) {
X	s->output_style = GRAPH;
X      } else if (prefix(p,"help")) {
X	print_options();
X	exit(0);
X      } else if (prefix(p,"hide")) {
X	s->remove_hidden = 1;
X      } else if (prefix(p,"label")) {
X	double x,y;
X	if (!argv[1] || !argv[2] || !argv[3])
X	  error("expected 3 more arguments with '-%s'",p);
X	x = atof(argv[1]);
X	y = atof(argv[2]);
X	add_poly(label_list,new_point(NULL,x,y,0.0),NULL,argv[3],0);
X	argv += 3;
X      } else if (prefix(p,"left")) {
X	t->x_rot = -65;
X	t->y_rot = 0;
X	t->z_rot = 30;
X      } else if (prefix(p,"noerase")) {
X	s->erase = 0;
X      } else if (prefix(p,"noinvisibleborder")) {
X	s->invisible_border = 0;
X      } else if (prefix(p,"orient")) {
X	s->orient = 1;
X      } else if (prefix(p,"plane")) {
X	if (!*(++argv)) error("Expected distance after '-%s'",p);
X	t->proj_plane = atof(*argv);
X      } else if (prefix(p,"plot")) {
X	s->output_style = PLOT;
X      } else if (prefix(p,"plot-scale")) {
X	s->output_style = PLOT;
X	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
X	s->plot_scale = atoi(*argv);
X      } else if (prefix(p,"ps")) {
X	s->output_style = POST_SCRIPT;
X      } else if (prefix(p,"ps-scale")) {
X	s->output_style = POST_SCRIPT;
X	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
X	s->ps_scale = atoi(*argv);
X      } else if (prefix(p,"q1")) {
X	t->x_frac = 0.5;
X	t->y_frac = 0.5;
X	t->x_low = 0.0;
X	t->y_low = 0.5;
X      } else if (prefix(p,"q2")) {
X	t->x_frac = 0.5;
X	t->y_frac = 0.5;
X	t->x_low = 0.5;
X	t->y_low = 0.5;
X      } else if (prefix(p,"q3")) {
X	t->x_frac = 0.5;
X	t->y_frac = 0.5;
X	t->x_low = 0.0;
X	t->y_low = 0.0;
X      } else if (prefix(p,"q4")) {
X	t->x_frac = 0.5;
X	t->y_frac = 0.5;
X	t->x_low = 0.5;
X	t->y_low = 0.0;
X      } else if (prefix(p,"right")) {
X	t->x_rot = -65;
X	t->y_rot = 0;
X	t->z_rot = -150;
X      } else if (prefix(p,"show-rotations")) {
X	show_rotations = 1;
X      } else if (prefix(p,"stdout")) {
X	dont_change_out=1;
X      } else if (prefix(p,"tty")) {
X	if (!*(++argv)) error("Expected tty name after \"%s\"",p);
X	use_tty = *argv;
X      } else if (prefix(p,"tek")) {
X	s->output_style = PLOT;
X      } else if (prefix(p,"xfraction")) {
X	if (!*(++argv)) error("Expected value after '-%s'",p);
X	t->x_frac = atof(*argv);
X      } else if (prefix(p,"xlow")) {
X	if (!*(++argv)) error("Expected value after '-%s'",p);
X	t->x_low = atof(*argv);
X      } else if (prefix(p,"xrotation")) {
X	if (!*(++argv)) error("Expected angle after '-%s'",p);
X	t->x_rot = atof(*argv);
X      } else if (prefix(p,"xscale")) {
X	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
X	t->x_scale = atof(*argv);
X      } else if (prefix(p,"yfraction")) {
X	if (!*(++argv)) error("Expected value after '-%s'",p);
X	t->y_frac = atof(*argv);
X      } else if (prefix(p,"ylow")) {
X	if (!*(++argv)) error("Expected value after '-%s'",p);
X	t->y_low = atof(*argv);
X      } else if (prefix(p,"yrotation")) {
X	if (!*(++argv)) error("Expected angle after '-%s'",p);
X	t->y_rot = atof(*argv);
X      } else if (prefix(p,"yscale")) {
X	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
X	t->y_scale = atof(*argv);
X      } else if (prefix(p,"zrotation")) {
X	if (!*(++argv)) error("Expected angle after '-%s'",p);
X	t->z_rot = atof(*argv);
X      } else if (prefix(p,"zscale")) {
X	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
X	t->z_scale = atof(*argv);
X      } else {
X	goto bad_arg;
X      }
X    } else {
X      bad_arg:
X        error("Bad argument: '%s'",p);
X    }
X  }
X  t->sin_x_rot = sin(DEG_TO_RAD(t->x_rot));
X  t->sin_y_rot = sin(DEG_TO_RAD(t->y_rot));
X  t->sin_z_rot = sin(DEG_TO_RAD(t->z_rot));
X  t->cos_x_rot = cos(DEG_TO_RAD(t->x_rot));
X  t->cos_y_rot = cos(DEG_TO_RAD(t->y_rot));
X  t->cos_z_rot = cos(DEG_TO_RAD(t->z_rot));
X  switch (s->output_style) {
X  case POST_SCRIPT:
X    s->x_char_size = 0.01;
X    s->y_char_size = 1.0;
X    break;
X  case PLOT:
X    s->x_char_size = 0.014;
X    s->y_char_size = 0.025;
X    break;
X  case GRAPH:
X    s->x_char_size = 0.01;
X    s->y_char_size = 0.013;
X    break;
X  default:
X    fprintf(stderr,"%s: bad output_style %d\n",my_name,s->output_style);
X    exit(1);
X  }
X
X/* means no perspective
X  if (t->proj_plane == 0) {
X    fprintf(stderr,"%s: cannot have projection plane and focus in the same position\n",my_name);
X    exit(1);
X  }
X*/
X  if ((t->x_frac + t->x_low > 1) || (t->y_frac + t->y_low > 1)) {
X    fprintf(stderr,
X	    "%s: bad combination of -h & -u or -w & -r values\n",my_name);
X    exit(1);
X  }
X  if (t->y_frac<0 || t->y_frac>1) {
X    fprintf(stderr,"stderr,%s: bad -h value (Y_FRAC)\n",my_name);
X    exit(1);
X  }
X  if (t->x_frac<0 || t->x_frac>1) {
X    fprintf(stderr,"%s: bad -w value (X_FRAC)\n",my_name);
X    exit(1);
X  }
X  if (t->y_low<0 || t->y_low>1) {
X    fprintf(stderr,"%s: bad -u value (Y_LOW)\n",my_name);
X    exit(1);
X  }
X  if (t->x_low<0 || t->x_low>1) {
X    fprintf(stderr,"%s: bad -r value (X_LOW)\n",my_name);
X    exit(1);
X  }
X  if (show_rotations) {
X    /*
X    printf("-focus	%g  	distance of focus from view origin\n",t->proj_focus);
X    printf("-plane	%g	distance of the projection plan in from the focus\n",t->proj_plane);
X    printf("-sx		%g	x scale factor\n",t->x_scale);
X    printf("-sy		%g	y scale factor\n",t->y_scale);
X    printf("-sz		%g	z scale factor\n",t->z_scale);
X    */
X    printf("-rx		%g	x rotation (degrees)\n",t->x_rot);
X    printf("-ry		%g	y rotation (degrees)\n",t->y_rot);
X    printf("-rz		%g	z rotation (degrees)\n",t->z_rot);
X    exit(0);
X  }
X}
X
Xextern char *malloc(),*calloc();
X
Xchar *malloc_fail(s)
Xint s;
X{
X  char *p;
X  p = malloc(s);
X  if (p==NULL) {
X    fprintf(stderr,"%s: out of memory (requested %d)\n",my_name,s);
X    exit(1);
X  }
X  return p;
X}
X
Xchar *calloc_fail(s,n)
Xint s,n;
X{
X  char *p;
X  p = calloc(s,n);
X  if (p==NULL) {
X    fprintf(stderr,"%s: out of memory (requested %d x %d)\n",my_name,s,n);
X    exit(1);
X  }
X  return p;
X}
X
XPOINT_LIST *new_point(spare_points,x,y,z)
XPOINT_LIST **spare_points;
Xreal x,y,z;
X{
X  POINT_LIST *point;
X  if (spare_points == NULL || *spare_points == NULL)
X    point = (POINT_LIST*)malloc_fail(sizeof(POINT_LIST));
X  else {
X    point = *spare_points;
X    *spare_points = (*spare_points)->next;
X  }
X  point->next = NULL;
X  point->p.x = x;
X  point->p.y = y;
X  point->p.z = z;
X  return point;
X}
X
Xchar *strip_quotes(str)
Xchar *str;
X{
X  char *p;
X  while (*str==' ' || *str=='\t') str++;
X  if (*str=='"' || *str=='\'' || *str=='`') str++;
X  p = str;
X  while (p[0] && p[1]) p++;
X  while ((*p==' ' || *p=='\t' || *p=='\n') && p>str) p--;
X  if (*p!='"' && *p!='\'' && *p!='`') p++;
X  *p=0;
X  return str;
X}
X
XPOLYGON *list_to_poly(points,text,last_point,is_poly)
XPOINT_LIST *points;
Xchar *text;
XPOINT_LIST **last_point;
Xint is_poly;
X{
X  int n;
X  POINT_LIST *p,*lp;
X  POLYGON *poly;
X  real z_max;
X  /*
X   * count the points
X   */
X  *last_point = NULL;
X  if (points==NULL) return NULL;
X  poly = (POLYGON*)malloc_fail(sizeof(POLYGON));
X  if (is_poly)
X    poly->type=POLY;
X  else
X    poly->type=LINE;
X  n = 1;
X  for (p=points;p->next!=NULL;p = p->next) n++;
X  if (n>1 && p->p.x==points->p.x && p->p.y==points->p.y && p->p.z==points->p.z)
X    { poly->type=POLY; n--; }
X
X  poly->n_points = n;
X  poly->next = NULL;
X  poly->text = NULL;
X  if (has_content(text)) {
X    poly->text = malloc_fail(strlen(text)+1);
X    strcpy(poly->text,text);
X  }
X  poly->points = (POINT*)calloc_fail(sizeof(POINT),n);
X  z_max = -1e100;
X  /*
X   * transfer the points
X   */
X  p=points;
X  for (n=0;n<poly->n_points;n++) {
X    poly->points[n].world = p->p;
X    if (p->p.z > z_max) z_max = p->p.z;
X    lp = p;
X    p = p->next;
X  }
X  poly->z_pos = z_max; /* z_sum / poly->n_points; */
X  *last_point = lp;
X  return poly;
X}
X
Xhas_content(p)
Xchar *p;
X{
X  if (p==NULL) return 0;
X  for (;*p!=0;p++) if (!isspace(*p) && isprint(*p)) return 1;
X  return 0;
X}
X
X/*
X * add_poly()
X * convert the point list to a vector, make a polygon record, and
X * add it to the list of polygons
X */
Xint add_poly(poly_list,point_list,spare_points,text,is_poly)
XPOLYGON **poly_list;
XPOINT_LIST *point_list;
XPOINT_LIST **spare_points;
Xchar *text;
Xint is_poly;
X{
X  POLYGON *poly;
X  POINT_LIST *last_point;
X  if (!point_list) return 0;
X  poly = list_to_poly(point_list,text,&last_point,is_poly);
X  if (last_point!=NULL && spare_points != NULL) {
X    last_point->next = *spare_points;
X    *spare_points = point_list;
X  }
X  if (poly!=NULL) {
X    poly->next = *poly_list;
X    *poly_list = poly;
X    return 1;
X  } else {
X    return 0;
X  }
X}
X
Xchar *find_binary_format_text(str,len,in,record)
Xchar *str;
XFILE *in;
Xint len,record;
X{
X  char c;
X  char *t = NULL;
X  if ((c=getc(in))!='t') {
X    ungetc(c,in);
X    return NULL;
X  } else {
X    t = str;
X    while ((*t=getc(in))!=0 && *t!=EOF && *t!='\n') {
X      t++;
X      if (t >= str+len) {
X	fprintf(stderr,"%s: string too long!, point %d\n",my_name,record);
X	exit(1);
X      }
X    }
X    *t = 0;
X    return str;
X  }
X}
X
Xint read_polys(s,poly_list,label_list,in)
XSTYLE *s;
XPOLYGON **poly_list;
XPOLYGON **label_list;
XFILE *in;
X{
X  POINT_LIST *point_list,*point_cur,*spare_points;
X  float x,y,z;
X  char str[500],*t,label[500];
X  int c;
X  int n_polys;
X  int done,n,record;
X  point_list = point_cur = spare_points = 0;
X  /*
X   * The first line tells us the format of the file, it will
X   * be an ascii line.  If it is not recognised, we just read text.
X   */
X  fgets(str,500,in);
X  n_polys = 0;
X  record = 0;
X  if (!strcmp(str,"binary format float4\n")) {
X    /*
X     * read a binary format input file
X     */
X    done = 0;
X    point_list = point_cur = NULL;
X    while (!done && !feof(in)) {
X      c = getc(in);
X      while (c==' ') c = getc(in);
X      if (c==EOF) break;
X      str[0] = 0;
X      record++;
X      if (c == 'm' || c == 'n') {
X	if (fread(&x,sizeof(x),1,in)!=1 || fread(&y,sizeof(y),1,in)!=1 || fread(&z,sizeof(z),1,in)!=1)
X	  done = 1;
X	DB( else printf("%c %g %g %g\n",c,x,y,z); )
X      } DB( else printf("%c\n",c); )
X      if (!done) {
X	switch (c) {
X	case '0':
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X	case '.': /* read a regular point in ascii */
X	  ungetc(c,in);
X	  t = fgets(str,500,in);
X	  if (s->dimension == D3)
X	    n = sscanf(str," %e %e %e %[^\n]",&x,&y,&z,label);
X	  else {
X	    n = sscanf(str," %e %e %[^\n]",&x,&y,label);
X	    if (n) n++;
X	    z = 0.0;
X	  }
X	  if (n==3) label[0]=0;
X	  DBDATA(fprintf(stderr,"Ascii point, %g %g %g %s\n",x,y,z,label););
X	  if (n<3) {
X	    fprintf(stderr,"%s: couldn't find 3 numbers on input, point %d\n",my_name,record);
X	    exit(1);
X	  }
X	  /* add another point to the list of points */
X	  if (point_cur == NULL)
X	    point_list = point_cur = new_point(&spare_points,x,y,z);
X	  else
X	    point_cur = point_cur->next = new_point(&spare_points,x,y,z);
X	  if (n==4) {
X	    n_polys += add_poly(poly_list,point_list,&spare_points,strip_quotes(label),0);
X	    point_list = point_cur = NULL;
X	  }
X	  break;
X	  
X	case '"': /* read an ascii label */
X	  ungetc(c,in);
X	  t = fgets(str,500,in);
X	  DBDATA(fprintf(stderr,"Ascii label %s\n",t););
X	  n_polys += add_poly(poly_list,point_list,&spare_points,strip_quotes(t),0);
X	  point_list = point_cur = NULL;
X	  break;
X
X	case 'j': /* end a polygon and join it back to the first point */
X  	  t = find_binary_format_text(str,500,in,record);
X	  DBDATA(fprintf(stderr,"j record %s\n",t););
X	  n_polys += add_poly(poly_list,point_list,&spare_points,t,1);
X	  point_list = point_cur = NULL;
X	  break;
X
X	case 'm': /* begin a new point, line or polygon */
X	  DBDATA(fprintf(stderr,"m record, %g %g %g\n",x,y,z););
X	  n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X	  point_cur = point_list = new_point(&spare_points,x,y,z);
X	  if (t = find_binary_format_text(str,500,in,record)) {
X	    n_polys += add_poly(poly_list,point_list,&spare_points,t,0);
X	    point_list = point_cur = NULL;
X	  }
X	  break;
X
X	case 'n': /* continue a line */
X	  DBDATA(fprintf(stderr,"n record, %g %g %g\n",x,y,z););
X	  if (point_cur == NULL)
X	    point_list = point_cur = new_point(&spare_points,x,y,z);
X	  else
X	    point_cur = point_cur->next = new_point(&spare_points,x,y,z);
X	  break;
X
X	case 'J': /* end a polygon and join it back to the first point - ascii format */
X  	  t = find_binary_format_text(str,500,in,record);
X	  DBDATA(fprintf(stderr,"J record %s\n",t););
X	  n_polys += add_poly(poly_list,point_list,&spare_points,t,1);
X	  point_list = point_cur = NULL;
X	  break;
X
X	case 'M': /* begin a new point, line or polygon - ascii format */
X	  t = fgets(str,500,in);
X	  if (t==NULL || sscanf(t," %e %e %e",&x,&y,&z)!=3) {
X	    fprintf(stderr,"%s: bad format on M input, point %d\n",my_name,c,record);
X	    exit(1);
X	  }
X	  DBDATA(fprintf(stderr,"M record, %g %g %g\n",x,y,z););
X	  n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X	  point_cur = point_list = new_point(&spare_points,x,y,z);
X	  if (t = find_binary_format_text(str,500,in,record)) {
X	    n_polys += add_poly(poly_list,point_list,&spare_points,t,0);
X	    point_list = point_cur = NULL;
X	  }
X	  break;
X
X	case 'N': /* continue a line - ascii format */
X	  t = fgets(str,500,in);
X	  if (t==NULL || sscanf(t," %e %e %e",&x,&y,&z)!=3) {
X	    fprintf(stderr,"%s: bad format on N input, point %d\n",my_name,c,record);
X	    exit(1);
X	  }
X	  DBDATA(fprintf(stderr,"N record, %g %g %g\n",x,y,z););
X	  if (point_cur == NULL)
X	    point_list = point_cur = new_point(&spare_points,x,y,z);
X	  else
X	    point_cur = point_cur->next = new_point(&spare_points,x,y,z);
X	  break;
X
X	case 't': /* some text to place at the last point
X		     also causes then end of a line */
X	case 'L': /* label in view co-ordinates */
X
X	  ungetc('t',in);
X	  if (t = find_binary_format_text(str,500,in,record)) {
X	    if (sscanf(t,"ABEL: %e %e %[^\n]",&x,&y,label)==3) {
X	      DBDATA(fprintf(stderr,"LABEL record, %g %g %s\n",x,y,label););
X	      n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X	      z = 0.0;
X	      point_list = new_point(&spare_points,x,y,z);
X	      add_poly(label_list,point_list,&spare_points,
X		       strip_quotes(label),0);
X	      point_list = point_cur = NULL;
X	    } else {
X	      DBDATA(fprintf(stderr,"t record %s\n",t););
X	      n_polys += add_poly(poly_list,point_list,&spare_points,t,0);
X	      point_list = point_cur = NULL;
X	    }
X	  } else {
X	    fprintf(stderr,"%s: internal error: binary text\n",my_name);
X	    exit(1);
X	  }
X	  break;
X	default:
X	  fprintf(stderr,"%s: bad format on input, char %d, point %d\n",my_name,c,record);
X	  exit(1);
X	}
X      }
X    }
X    n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X  } else {
X    /*
X     * read an ascii format input file
X     */
X    do {
X      record++;
X      n = sscanf(str,"LABEL: %e %e %[^\n]",&x,&y,label);
X      if (n>0 && n<3) {
X	fprintf(stderr,"%s: bad format on label, point %d\n",my_name,record);
X	exit(1);
X      } else if (n==3) {
X	n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X	z = 0.0;
X	point_list = new_point(&spare_points,x,y,z);
X	add_poly(label_list,point_list,&spare_points,strip_quotes(label),0);
X	point_list = point_cur = NULL;
X      } else { /* n==0 */
X	if (s->dimension == D3)
X	  n = sscanf(str," %e %e %e %[^\n]",&x,&y,&z,label);
X	else {
X	  n = sscanf(str," %e %e %[^\n]",&x,&y,label);
X	  if (n) n++;
X	  z = 0.0;
X	}
X	if (n==0) {
X	  /*
X	   * just a label
X	   */
X	  n_polys += add_poly(poly_list,point_list,&spare_points,strip_quotes(str),0);
X	  point_list = point_cur = NULL;
X	} else if (n>=3) { /* add another point to the list of points */
X	  if (point_cur == NULL)
X	    point_list = point_cur = new_point(&spare_points,x,y,z);
X	  else
X	    point_cur = point_cur->next = new_point(&spare_points,x,y,z);
X	} else if (n>0) {
X	  fprintf(stderr,"%s: couldn't find 3 numbers on input, line %d\n",my_name,record);
X	  exit(1);
X	}
X	if (n==4) {
X	  n_polys += add_poly(poly_list,point_list,&spare_points,strip_quotes(label),0);
X	  point_list = point_cur = NULL;
X	}
X      }
X    } while (fgets(str,500,in)!=NULL);
X    n_polys += add_poly(poly_list,point_list,&spare_points,NULL,0);
X  }
X  return n_polys;
X}
X
Xint compare_poly(poly1,poly2)
XPOLYGON **poly1,**poly2;
X{
X  if ((*poly1)->z_pos < (*poly2)->z_pos) return -1;
X  if ((*poly1)->z_pos > (*poly2)->z_pos) return 1;
X  if ((*poly1)->z_pos == (*poly2)->z_pos) return 0;
X}
X
Xshow_poly_vec_world(n_polys,poly_vec)
Xint n_polys;
XPOLYGON **poly_vec;
X{
X  int i;
X  printf("WORLD POLYGON VECTOR:\n");
X  for (i=0;i<n_polys;i++)
X    show_poly_world(poly_vec[i]);
X  printf("\n");
X}
X
Xshow_poly_list_world(poly_list)
XPOLYGON *poly_list;
X{
X  POLYGON *poly;
X  printf("WORLD POLYGON LIST:\n");
X  for (poly = poly_list ; poly!=NULL ; poly = poly->next)
X    show_poly_world(poly);
X  printf("\n");
X}
X
Xshow_poly_world(poly)
XPOLYGON *poly;
X{
X  int i;
X  if (poly==NULL) {
X    printf("!!! NULL pointer to polygon !!!\n");
X    return;
X  }
X  printf("World %s, n=%d z=%10g text=\"%s\" (",(poly->type==LINE?"LINE":"POLY"),poly->n_points,poly->z_pos,poly->text);
X  for (i=0;i<poly->n_points;i++) {
X    show_single_point(&(poly->points[i].world));
X    /* printf("(%g %g %g)",poly->points[i].world.x,poly->points[i].world.y,poly->points[i].world.z); */
X    if (i<poly->n_points-1) putchar(' ');
X  }
X  printf(")\n");
X}
X
Xshow_poly_vec_view(n_polys,poly_vec)
Xint n_polys;
XPOLYGON **poly_vec;
X{
X  int i;
X  printf("VIEW POLYGON VECTOR:\n");
X  for (i=0;i<n_polys;i++)
X    show_poly_view(poly_vec[i]);
X  printf("\n");
X}
X
Xshow_poly_list_view(poly_list)
XPOLYGON *poly_list;
X{
X  POLYGON *poly;
X  printf("VIEW POLYGON LIST:\n");
X  for (poly = poly_list ; poly!=NULL ; poly = poly->next)
X    show_poly_view(poly);
X  printf("\n");
X}
X
Xshow_poly_view(poly)
XPOLYGON *poly;
X{
X  int i;
X  if (poly==NULL) {
X    printf("!!! NULL pointer to polygon !!!\n");
X    return;
X  }
X  printf("View %s, n=%d z=%6g text=\"%s\" (",(poly->type==LINE?"LINE":"POLY"),poly->n_points,poly->z_pos,poly->text);
X  for (i=0;i<poly->n_points;i++) {
X    show_single_point(&(poly->points[i].view));
X    /* printf("(%g %g %g)",poly->points[i].view.x,poly->points[i].view.y,poly->points[i].view.z); */
X    if (i<poly->n_points-1) putchar(' ');
X  }
X  printf(")\n");
X}
X
Xshow_single_point(p)
XSINGLE_POINT *p;
X{
X  printf("(%g %g %g)",p->x,p->y,p->z);
X}
X
XPOLYGON **list_to_vec(poly_list,n_polys)
XPOLYGON *poly_list;
Xint n_polys;
X{
X  int i;
X  POLYGON **vec;
X  POLYGON *poly;
X  vec = (POLYGON**)calloc_fail(sizeof(POLYGON*),n_polys);
X  for ((poly = poly_list),i=0; poly!=NULL; (poly = poly->next),i++) {
X    vec[i] = poly;
X  }
X  return vec;
X}
X
Xshow_min_max(m)
XMIN_MAX *m;
X{
X  printf("MIN:  ");
X  show_single_point(&(m->min));
X  printf("\nMAX:  ");
X  show_single_point(&(m->max));
X  printf("\nEDGE: ");
X  show_single_point(&(m->edge));
X  printf("\n");
X}
X
Xfind_min_max_world(poly_list,m)
XPOLYGON *poly_list;
XMIN_MAX *m;
X{
X  POLYGON *poly;
X  int i;
X  m->min.x = m->min.y = m->min.z = 1.0;
X  m->max.x = m->max.y = m->max.z = 0.0;
X  for (poly = poly_list; poly!=NULL; poly = poly->next)
X    for (i=0;i<poly->n_points;i++) {
X      set_min_max(poly->points[i].world.x,m->min.x,m->max.x);
X      set_min_max(poly->points[i].world.y,m->min.y,m->max.y);
X      set_min_max(poly->points[i].world.z,m->min.z,m->max.z);
X    }
X  m->edge.x = m->max.x - m->min.x;
X  m->edge.y = m->max.y - m->min.y;
X  m->edge.z = m->max.z - m->min.z;
X}
X
Xadd_bounds_label(m,label_list)
XMIN_MAX *m;
XPOLYGON **label_list;
X{
X  char s[100];
X  sprintf(s,"%g -x- %g  %g -y- %g  %g -z- %g",
X	  m->min.x,m->max.x,m->min.y,m->max.y,m->min.z,m->max.z);
X  add_poly(label_list,new_point(NULL,1.0,-1.0,0.0),NULL,s,0);
X}
X
Xfind_min_max_view(poly_list,m)
XPOLYGON *poly_list;
XMIN_MAX *m;
X{
X  POLYGON *poly;
X  int i;
X  m->min.x = m->min.y = m->min.z = 1.0;
X  m->max.x = m->max.y = m->max.z = 0.0;
X  for (poly = poly_list; poly!=NULL; poly = poly->next)
X    for (i=0;i<poly->n_points;i++) {
X      set_min_max(poly->points[i].view.x,m->min.x,m->max.x);
X      set_min_max(poly->points[i].view.y,m->min.y,m->max.y);
X      set_min_max(poly->points[i].view.z,m->min.z,m->max.z);
X    }
X  m->edge.x = m->max.x - m->min.x;
X  m->edge.y = m->max.y - m->min.y;
X  m->edge.z = m->max.z - m->min.z;
X}
X
Xint add_axis(poly_list,m,t,s)
XPOLYGON **poly_list;
XMIN_MAX *m;
XTRANSFORM *t;
XSTYLE *s;
X{
X  POINT_LIST *point_list,*spare_points;
X  int n=0;
X  point_list = spare_points = NULL;
X  switch (s->axis_style) {
X  case NONE:
X    break;
X  case AXIS:
X    if (m->max.x > m->min.x) {
X      point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X      point_list->next = new_point(&spare_points,m->max.x,m->min.y,m->min.z);
X      n++;
X      add_poly(poly_list,point_list,&spare_points,getenv("3D_X_AXIS_LABEL"),0);
X    }
X    if (m->max.y > m->min.y) {
X      point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X      point_list->next = new_point(&spare_points,m->min.x,m->max.y,m->min.z);
X      n++;
X      add_poly(poly_list,point_list,&spare_points,getenv("3D_Y_AXIS_LABEL"),0);
X    }
X    if (s->dimension==D3 && m->max.z > m->min.z) {
X      point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X      point_list->next = new_point(&spare_points,m->min.x,m->min.y,m->max.z);
X      n++;
X      add_poly(poly_list,point_list,&spare_points,getenv("3D_Z_AXIS_LABEL"),0);
X    }
X    break;
X  case BOX:
X    point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->min.y,m->min.z);
X    add_poly(poly_list,point_list,&spare_points,getenv("3D_X_AXIS_LABEL"),0);
X
X    point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->min.x,m->max.y,m->min.z);
X    add_poly(poly_list,point_list,&spare_points,getenv("3D_Y_AXIS_LABEL"),0);
X
X    point_list = new_point(&spare_points,m->max.x,m->min.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->max.y,m->min.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->min.x,m->max.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->max.y,m->min.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    n = 4;
X    if (s->dimension==D2) break;
X    
X    point_list = new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->min.x,m->min.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,getenv("3D_Z_AXIS_LABEL"),0);
X
X    point_list = new_point(&spare_points,m->max.x,m->min.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->min.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->min.x,m->max.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->min.x,m->max.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->max.x,m->max.y,m->min.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->max.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->min.x,m->min.y,m->max.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->min.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->min.x,m->max.y,m->max.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->max.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->min.x,m->min.y,m->max.z);
X    point_list->next = new_point(&spare_points,m->min.x,m->max.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X
X    point_list = new_point(&spare_points,m->max.x,m->min.y,m->max.z);
X    point_list->next = new_point(&spare_points,m->max.x,m->max.y,m->max.z);
X    add_poly(poly_list,point_list,&spare_points,NULL,0);
X    
X    n=12;
X    break;
X  default:
X    fprintf(stderr,"%s: bad axis style (%d) in add_axis()\n",s->axis_style);
X    exit(1);
X  }
X  return n;
X}
X
Xcalc_view_scale(t,m,s)
XTRANSFORM *t;
XMIN_MAX *m;
XSTYLE *s;
X{
X  POLYGON *poly;
X  POINT_LIST *point_list,*point_cur,*spare_points;
X  MIN_MAX mv;
X  real edge;
X  /*
X   * calculate the translation to put the centre of the object at the origin
X   */
X  t->x_move = -(m->max.x + m->min.x)/2;
X  t->y_move = -(m->max.y + m->min.y)/2;
X  t->z_move = -(m->max.z + m->min.z)/2;
X  edge = sqrt(m->edge.x*m->edge.x + m->edge.y*m->edge.y + m->edge.z*m->edge.z);
X  t->proj_focus *= 3 * edge;
X  t->proj_plane *= edge;
X  poly = NULL;
X  point_list = point_cur = spare_points = NULL;
X  point_cur = point_list	= new_point(&spare_points,m->min.x,m->min.y,m->min.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->max.x,m->min.y,m->min.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->max.x,m->max.y,m->min.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->max.x,m->max.y,m->max.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->max.x,m->min.y,m->max.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->min.x,m->min.y,m->max.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->min.x,m->max.y,m->max.z);
X  point_cur = point_cur->next	= new_point(&spare_points,m->min.x,m->max.y,m->min.z);
X  add_poly(&poly,point_list,&spare_points,NULL,0);
X  transform_poly_list(poly,t,s);
X  find_min_max_view(poly,&mv);
X  DB( printf("WORLD CORNER POLY:\n"); show_poly_world(poly); )
X  DB( printf("VIEW CORNER POLY:\n"); show_poly_view(poly); )
X  DB( printf("VIEW MIN MAX:\n"); show_min_max(&mv); )
X  t->x_view_scale = t->x_frac/mv.edge.x;
X  t->y_view_scale = t->y_frac/mv.edge.y;
X  if (s->scale_style==FIRM)
X    t->x_view_scale = t->y_view_scale = MIN(t->x_view_scale,t->y_view_scale);
X  t->x_view_move = t->x_low;
X  t->y_view_move = t->y_low;
X  t->x_view_move -= mv.min.x * t->x_view_scale;
X  t->y_view_move -= mv.min.y * t->y_view_scale;
X  /* t->z_view_move -= mv.min.z; */
X  /* delete - we just toss away the memory allocated for the points above */
X  /* for debugging: */
X  DB( transform_poly_list(poly,t,s); )
X  DB( printf("RETRANSFORMED VIEW CORNER POLY:\n"); show_poly_view(poly); )
X}
X
Xtransform_poly_list(p,t,s)
XPOLYGON *p;
XTRANSFORM *t;
XSTYLE *s;
X{
X  for (;p!=NULL;p = p->next) transform_poly(p,t,s);
X}
X
Xtransform_poly(p,t,s)
XPOLYGON *p;
XTRANSFORM *t;
XSTYLE *s;
X{
X  real z_sum=0.0;
X  int i;
X  for (i=0;i<p->n_points;i++) {
X    transform_point(p->points+i,t);
X    z_sum += p->points[i].view.z;
X  }
X  p->z_pos = z_sum/p->n_points;
X}
X
Xtransform_point(p,t)
XPOINT *p;
XTRANSFORM *t;
X{
X  register real x1,y1,z1,x2,y2,z2;
X  /* translate & scale to bring object centre to origin */
X  x1 = t->x_scale*p->world.x + t->x_move;
X  y1 = t->y_scale*p->world.y + t->y_move;
X  z1 = t->z_scale*p->world.z + t->z_move;
X  /* rotate around y axis */
X  z2 = z1*t->cos_y_rot + x1*t->sin_y_rot;
X  x2 = -z1*t->sin_y_rot + x1*t->cos_y_rot;
X  y2 = y1;
X  /* rotate around z axis */
X  x1 = x2*t->cos_z_rot + y2*t->sin_z_rot;
X  y1 = -x2*t->sin_z_rot + y2*t->cos_z_rot;
X  z1 = z2;
X  /* rotate around x axis */
X  y2 = y1*t->cos_x_rot - z1*t->sin_x_rot;
X  z2 = y1*t->sin_x_rot + z1*t->cos_x_rot;
X  x2 = x1;
X  /* scale according to distance from the projection focus */
X  if (t->proj_plane != 0.0) {
X    p->view.x = (x2 * t->x_view_scale * t->proj_plane/(t->proj_focus-z2)) + t->x_view_move;
X    p->view.y = (y2 * t->y_view_scale * t->proj_plane/(t->proj_focus-z2)) + t->y_view_move;
X  } else {
X    p->view.x = (x2 * t->x_view_scale) + t->x_view_move;
X    p->view.y = (y2 * t->y_view_scale) + t->y_view_move;
X  }
X  p->view.z = z2;
X}
X
Xoutput_prologue(t,s)
XTRANSFORM *t;
XSTYLE *s;
X{
X  /*
X   * prologue
X   */
X  switch (s->output_style) {
X  case GRAPH:
X    if (s->border)
X      fprintf(out,"%.5f %.5f\n%.5f %.5f\n%.5f %.5f\n%.5f %.5f\n%.5f %.5f \" \n",
X	     t->x_low,t->y_low,
X	     t->x_low+t->x_frac,t->y_low,
X	     t->x_low+t->x_frac,t->y_low+t->y_frac,
X	     t->x_low,t->y_low+t->y_frac,
X	     t->x_low,t->y_low);
X    else if (s->invisible_border)
X      fprintf(out,"%.5f %.5f \" \n%.5f %.5f \" \n%.5f %.5f \" \n%.5f %.5f \" \n",
X	     t->x_low,t->y_low,
X	     t->x_low+t->x_frac,t->y_low,
X	     t->x_low+t->x_frac,t->y_low+t->y_frac,
X	     t->x_low,t->y_low+t->y_frac);
X    break;
X  case POST_SCRIPT:
X    if (s->border)
X      fprintf(out,"save %.0f %.0f moveto %.0f %.0f lineto %.0f %.0f lineto %.0f %.0f lineto closepath stroke restore\n",
X	     t->x_low*s->ps_scale,t->y_low*s->ps_scale,
X	     (t->x_low+t->x_frac)*s->ps_scale,t->y_low*s->ps_scale,
X	     (t->x_low+t->x_frac)*s->ps_scale,(t->y_low+t->y_frac)*s->ps_scale,
X	     t->x_low*s->ps_scale,(t->y_low+t->y_frac)*s->ps_scale);
X    else if (s->invisible_border)
X      fprintf(out,"save %.0f %.0f moveto %.0f %.0f moveto %.0f %.0f moveto %.0f %.0f moveto restore\n",
X	     t->x_low*s->ps_scale,t->y_low*s->ps_scale,
X	     (t->x_low+t->x_frac)*s->ps_scale,t->y_low*s->ps_scale,
X	     (t->x_low+t->x_frac)*s->ps_scale,(t->y_low+t->y_frac)*s->ps_scale,
X	     t->x_low*s->ps_scale,(t->y_low+t->y_frac)*s->ps_scale);
X    break;
X  case PLOT:
X    openpl();
X    pl_space(s);
X    if (s->erase) erase();
X    linemod("solid");
X    if (s->border) {
X      pl_move(s,t->x_low,t->y_low);
X      pl_cont(s,t->x_low+t->x_frac,t->y_low);
X      pl_cont(s,t->x_low+t->x_frac,t->y_low+t->y_frac);
X      pl_cont(s,t->x_low,t->y_low+t->y_frac);
X      pl_cont(s,t->x_low,t->y_low);
X    } else if (s->invisible_border) {
X      pl_move(s,t->x_low,t->y_low);
X      pl_move(s,t->x_low+t->x_frac,t->y_low);
X      pl_move(s,t->x_low+t->x_frac,t->y_low+t->y_frac);
X      pl_move(s,t->x_low,t->y_low+t->y_frac);
X    }
X    break;
X  default:
X    fprintf(stderr,"%s: bad output style %d\n",s->output_style);
X    exit(1);
X  }
X}
Xoutput_epilogue(t,s)
XTRANSFORM *t;
XSTYLE *s;
X{
X  /*
X   * epilogue
X   */
X  switch (s->output_style) {
X  case GRAPH:
X    break;
X  case POST_SCRIPT:
X    break;
X  case PLOT:
X    pl_move(s,1.0,1.0); /* to put the cursor in the top right */
X    closepl();
X    break;
X  default:
X    fprintf(stderr,"%s: bad output style %d\n",s->output_style);
X    exit(1);
X  }
X}
X
Xoutput_poly_vec(n_polys,poly_vec,s)
Xint n_polys;
XPOLYGON **poly_vec;
XSTYLE *s;
X{
X  int i;
X  /*
X   * polygons
X   */
X  for (i=0;i<n_polys;i++)
X    output_poly(poly_vec[i],s);
X}
X
Xoutput_poly_list(poly,s)
XPOLYGON *poly;
XSTYLE *s;
X{
X  for (;poly!=NULL;poly=poly->next)
X    output_poly(poly,s);
X}
X
Xoutput_poly(poly,s)
XPOLYGON *poly;
XSTYLE *s;
X{
X  int j;
X  switch (s->output_style) {
X  case GRAPH:
X    for (j=0;j<poly->n_points;j++)
X      fprintf(out,"%.5f %.5f%c",poly->points[j].view.x,poly->points[j].view.y,
X	     (poly->type==POLY || j<poly->n_points-1?  '\n' : ' '));
X    if (poly->type==POLY)
X      fprintf(out,"%.5f %.5f \"%s\n",poly->points[0].view.x,poly->points[0].view.y,(poly->text==NULL ? " " : poly->text));
X    else
X      fprintf(out,"\"%s\n",(poly->text==NULL ? " " : poly->text));
X    break;
X  case PLOT:
X    if (poly->n_points>0) {
X      pl_move(s,poly->points[0].view.x,poly->points[0].view.y);
X      for (j=1;j<poly->n_points;j++)
X	pl_cont(s,poly->points[j].view.x,poly->points[j].view.y);
X      if (poly->type==POLY)
X	pl_cont(s,poly->points[0].view.x,poly->points[0].view.y);
X      if (poly->text!=NULL) pl_label(s,poly->text);
X    }
X    break;
X  case POST_SCRIPT:
X    if (poly->type==POLY) {
X      if (poly->n_points==3) {
X	fprintf(out,"%.0f %.0f %.0f %.0f %.0f %.0f %s\n",
X	       poly->points[0].view.x * s->ps_scale,poly->points[0].view.y * s->ps_scale,
X	       poly->points[1].view.x * s->ps_scale,poly->points[1].view.y * s->ps_scale,
X	       poly->points[2].view.x * s->ps_scale,poly->points[2].view.y * s->ps_scale,
X	       (s->remove_hidden ? "trfill" : "tr"));
X      } else if (poly->n_points==4) {
X	fprintf(out,"%.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f %s\n",
X	       poly->points[0].view.x * s->ps_scale,poly->points[0].view.y * s->ps_scale,
X	       poly->points[1].view.x * s->ps_scale,poly->points[1].view.y * s->ps_scale,
X	       poly->points[2].view.x * s->ps_scale,poly->points[2].view.y * s->ps_scale,
X	       poly->points[3].view.x * s->ps_scale,poly->points[3].view.y * s->ps_scale,
X	       (s->remove_hidden ? "sqfill" : "sq"));
X      } else {
X	fprintf(out,"save newpath ");
X	for (j=0;j<poly->n_points;j++)
X	  fprintf(out,"%.0f %.0f %s ",
X		 poly->points[j].view.x * s->ps_scale,poly->points[j].view.y * s->ps_scale,
X		 (j==0 ? "moveto" : "lineto"));
X	if (s->remove_hidden)
X	  fprintf(out,"closepath gsave 0 setgray stroke grestore gsave 1 setgray fill grestore restore\n");
X	else
X	  fprintf(out,"closepath gsave 0 setgray stroke grestore restore\n");
X      }
X    } else { /* LINE */
X      fprintf(out,"save newpath ");
X      for (j=0;j<poly->n_points;j++)
X	fprintf(out,"%.0f %.0f %s ",
X	       poly->points[j].view.x * s->ps_scale,poly->points[j].view.y * s->ps_scale,
X	       (j==0 ? "moveto" : "lineto"));
X      fprintf(out,"stroke restore\n");
X    }
X    if (poly->text!=0) {
X      if (print_ps_string(poly->text))
X	fprintf(out," %.0f %.0f text\n",
X	       poly->points[poly->n_points>0 ? poly->n_points-1 : 0].view.x * s->ps_scale,
X	       poly->points[poly->n_points>0 ? poly->n_points-1 : 0].view.y * s->ps_scale);
X    }
X    break;
X  default:
X    fprintf(stderr,"%s: bad output style %d\n",my_name,s->output_style);
X    exit(1);
X  }
X}
X
X
Xoutput_label_list(label_list,t,s)
XPOLYGON *label_list;
XTRANSFORM *t;
XSTYLE *s;
X{
X  POLYGON *poly;
X  real x,y;
X  for (poly=label_list;poly!=NULL;poly=poly->next) {
X    if (poly->n_points==0) {
X      fprintf(stderr,"%s: label poly has no points!\n",my_name);
X      exit(1);
X    }
X    x = s->x_char_size * poly->points[0].world.x;
X    y = s->y_char_size * poly->points[0].world.y;
X    if (x > 0) x += t->x_low; else x = t->x_low + t->x_frac + x;
X    if (y > 0) y += t->y_low; else y = t->y_low + t->y_frac + y;
X    switch (s->output_style) {
X    case GRAPH:
X      fprintf(out,"%.5f %.5f \"%s\n",x,y,(poly->text==NULL ? " " : poly->text));
X      break;
X    case POST_SCRIPT:
X      if (print_ps_string(poly->text))
X	fprintf(out," %.0f %.0f label\n",poly->points[0].world.x,poly->points[0].world.y);
X      break;
X    case PLOT:
X      pl_move(s,x,y);
X      pl_label(s,poly->text);
X      break;
X    default:
X      fprintf(stderr,"%s: bad output style %d\n",my_name,s->output_style);
X      exit(1);
X    }
X  }
X}
X
Xint print_ps_string(str)
Xchar *str;
X{
X  if (str!=NULL && has_content(str)) {
X    putchar('(');
X    for (;*str;str++) {
X      if (isprint(*str)) {
X	if (*str=='(' || *str==')' || (*str=='\\' && str[1]==0)) putchar('\\');
X	putchar(*str);
X      }
X    }
X    putchar(')');
X    return 1;
X  }
X  return 0;
X}
X
X/*
X * output_orient - a little-bitty labelled axis in the bottom-right-hand corner
X */
Xoutput_orient(t,s)
XTRANSFORM *t;
XSTYLE *s;
X{
X  POLYGON *poly_list=NULL;
X  POINT_LIST *point_list,*point_cur;
X  POINT_LIST *spare_points=NULL;
X  MIN_MAX m;
X  TRANSFORM newt;
X  point_cur = point_list      = new_point(&spare_points,-0.05,-0.05,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,0.05,-0.05,-0.05);
X  add_poly(&poly_list,point_list,&spare_points,"X",0);
X  point_cur = point_list      = new_point(&spare_points,0.04,-0.04,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,0.05,-0.05,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,0.04,-0.06,-0.05);
X  add_poly(&poly_list,point_list,&spare_points,NULL,0);
X  point_cur = point_list      = new_point(&spare_points,-0.05,-0.05,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,-0.05,-0.05,0.05);
X  add_poly(&poly_list,point_list,&spare_points,"Z",0);
X  point_cur = point_list      = new_point(&spare_points,-0.04,-0.05,0.04);
X  point_cur = point_cur->next = new_point(&spare_points,-0.05,-0.05,0.05);
X  point_cur = point_cur->next = new_point(&spare_points,-0.06,-0.05,0.04);
X  add_poly(&poly_list,point_list,&spare_points,NULL,0);
X  point_cur = point_list      = new_point(&spare_points,-0.05,-0.05,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,-0.05,0.05,-0.05);
X  add_poly(&poly_list,point_list,&spare_points,"Y",0);
X  point_cur = point_list      = new_point(&spare_points,-0.04,0.04,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,-0.05,0.05,-0.05);
X  point_cur = point_cur->next = new_point(&spare_points,-0.06,0.04,-0.05);
X  add_poly(&poly_list,point_list,&spare_points,NULL,0);
X
X  /*
X   * set up a transform record for doing the axis
X   */
X  newt.proj_focus	= 0; /* no perspective for this */
X  newt.proj_plane	= 0;
X  newt.x_low		= t->x_low;
X  newt.x_frac		= t->x_frac;
X  newt.x_view_scale	= 1;
X  newt.x_view_move	= 0;
X  newt.x_scale		= t->x_scale/fabs(t->x_scale);
X  newt.x_move		= 0;
X  newt.x_rot		= t->x_rot;
X  newt.sin_x_rot	= t->sin_x_rot;
X  newt.cos_x_rot	= t->cos_x_rot;
X  newt.y_low		= t->y_low;
X  newt.y_frac		= t->y_frac;
X  newt.y_view_scale	= 1;
X  newt.y_view_move	= 0;
X  newt.y_scale		= t->y_scale/fabs(t->y_scale);
X  newt.y_move		= 0;
X  newt.y_rot		= t->y_rot;
X  newt.sin_y_rot	= t->sin_y_rot;
X  newt.cos_y_rot	= t->cos_y_rot;
X  newt.z_scale		= t->z_scale/fabs(t->z_scale);
X  newt.z_move		= 0;
X  newt.z_rot		= t->z_rot;
X  newt.z_view_scale	= 1;
X  newt.z_view_move	= 0;
X  newt.sin_z_rot	= t->sin_z_rot;
X  newt.cos_z_rot	= t->cos_z_rot;
X
X  transform_poly_list(poly_list,&newt,s);
X  find_min_max_view(poly_list,&m);
X  newt.x_view_move = t->x_low+t->x_frac - m.max.x -.02;
X  newt.y_view_move = t->y_low - m.min.y +.02;
X  transform_poly_list(poly_list,&newt,s);
X  output_poly_list(poly_list,s);
X}
X
Xoutput_back_axis(poly_list,s)
XPOLYGON *poly_list;
XSTYLE *s;
X{
X  MIN_MAX m;
X  POLYGON *poly;
X  int front_is_corner; /* the front z point is a corner rather than the end of an axis */
X  find_min_max_view(poly_list,&m);
X  front_is_corner = 0;
X  for (poly=poly_list;poly!=NULL;poly=poly->next)
X    if (poly->n_points>1
X	&& (poly->points[0].view.z==m.max.z
X	    || poly->points[1].view.z==m.max.z))
X      front_is_corner++;
X  front_is_corner = (front_is_corner > 1);
X  for (poly=poly_list;poly!=NULL;poly=poly->next)
X    if (!front_is_corner
X	|| poly->n_points<2
X	|| (poly->points[0].view.z!=m.max.z && poly->points[1].view.z!=m.max.z))
X    output_poly(poly,s);
X}
X
X
Xoutput_front_axis(poly_list,s)
XPOLYGON *poly_list;
XSTYLE *s;
X{
X  MIN_MAX m;
X  POLYGON *poly;
X  int front_is_corner; /* the front z point is a corner rather than the end of an axis */
X  find_min_max_view(poly_list,&m);
X  front_is_corner = 0;
X  for (poly=poly_list;poly!=NULL;poly=poly->next)
X    if (poly->n_points>1
X	&& (poly->points[0].view.z==m.max.z || poly->points[1].view.z==m.max.z)) front_is_corner++;
X  front_is_corner = (front_is_corner > 1);
X  for (poly=poly_list;poly!=NULL;poly=poly->next)
X    if (poly->n_points<2
X	|| (front_is_corner
X	    && (poly->points[0].view.z==m.max.z || poly->points[1].view.z==m.max.z)))
X    output_poly(poly,s);
X}
X
Xpl_space(s)
XSTYLE *s;
X{
X  int x0,y0,x1,y1;
X  x0 = y0 = 0;
X  x1 = y1 = s->plot_scale;
X  space(x0,y0,x1,y1);
X}
X
Xpl_move(s,x,y)
XSTYLE *s;
Xreal x,y;
X{
X  int x0,y0;
X  x0 = x * s->plot_scale;
X  y0 = y * s->plot_scale;
X  move(x0,y0);
X}
X
Xpl_cont(s,x,y)
XSTYLE *s;
Xreal x,y;
X{
X  int x0,y0;
X  x0 = x * s->plot_scale;
X  y0 = y * s->plot_scale;
X  cont(x0,y0);
X}
X
Xpl_point(s,x,y)
XSTYLE *s;
Xreal x,y;
X{
X  int x0,y0;
X  x0 = x * s->plot_scale;
X  y0 = y * s->plot_scale;
X  point(x0,y0);
X}
X
Xpl_label(s,t)
XSTYLE *s;
Xchar *t;
X{
X  if (t!=NULL && *t) label(t);
X}
X
X/*
X * return 1 if prefix is an unambigous prefix of the option 'word'
X */
X
Xprefix(prefix,word)
Xchar *prefix,*word;
X{
X  int matches,len;
X  char **option;
X  len = strlen(prefix);
X  if (strncmp(prefix,word,len)) return 0;
X  if (strlen(word) == len) return 1;
X  /* we've got a prefix match, check for ambiguity */
X  matches = 0;
X  option = options_description;
X  while (*option) {
X    if (option[0][0]=='-' && !strncmp(prefix,option[0]+1,len))
X      matches++;
X    option++;
X  }
X  if (matches==1) return 1;
X  else return 0;
X}
X
Xprint_options()
X{
X  char **p = options_description;
X  while (*p) printf("%s\n",*p++);
X}
X
Xerror(s,p)
X{
X  char str[200];
X  fprintf(stderr,sprintf(str,"%s: %s\n",my_name,s),p);
X  exit(1);
X}
END_OF_graph3d.c
if test 49102 -ne `wc -c <graph3d.c`; then
    echo shar: \"graph3d.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

--
-------------------------------------------------------------------------------
Michel Berkelaar                   | Email: michel@ele.tue.nl      (prefered)
Eindhoven University of Technology |        ..!mcvax!euteal!michel (old)
Dept. of Electrical Engineering    |
Design Automation Section          |
P.O. Box 513                       | Phone: ... - 31 - 40 - 473345
NL-5600 MB Eindhoven               | Fax:   ... - 31 - 40 - 448375
The Netherlands                    |
-------------------------------------------------------------------------------