DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦3ab54cdb3⟧ TextFile

    Length: 13006 (0x32ce)
    Types: TextFile
    Names: »graphics.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z« 
        └─⟦036c765ac⟧ 
            └─⟦this⟧ »TeX3.0/TeXcontrib/gnutex/graphics.c« 

TextFile

/*
 *
 *    G N U P L O T  --  graphics.c
 *
 *  Copyright (C) 1986 Thomas Williams, Colin Kelley
 *
 *  You may use this code as you wish if credit is given and this message
 *  is retained.
 *
 *  Please e-mail any useful additions to vu-vlsi!plot so they may be
 *  included in later releases.
 *
 *  This file should be edited with 4-column tabs!  (:set ts=4 sw=4 in vi)
 */
/*
 * Modifications for LaTeX and other support by David Kotz, 1988.
 * Department of Computer Science, Duke University, Durham, NC 27706.
 * Mail to dfk@cs.duke.edu.
 */

#include <stdio.h>
#include <math.h>
#include "plot.h"

char *strcpy(),*strncpy(),*strcat();

extern FILE *outfile;
extern BOOLEAN log_x, log_y;
extern int term;

extern BOOLEAN printer;		/* DFK 6/8/87 */

extern BOOLEAN screen_ok;
extern BOOLEAN term_init;

extern struct termentry term_tbl[];

extern int put_label;

extern char title_string[];
extern char xlabel_string[];
extern char ylabel_string[];
extern char xformat[];
extern char yformat[];
extern int y_skip_factor;
extern double plot_width;
extern double plot_height;
extern struct st_entry st[];
extern BOOLEAN xtics;
extern BOOLEAN ytics;

extern BOOLEAN autoscale_lx;
extern BOOLEAN autoscale_ly;

#ifndef max		/* Lattice C has max() in math.h, but shouldn't! */
#define max(a,b) ((a > b) ? a : b)
#endif

#define map_x(x) (int)((x-xmin)*xscale) /* maps floating point x to screen */ 
#define map_y(y) (int)((y-ymin)*yscale)	/* same for y */

/* (DFK) Watch for cancellation error near zero on axes labels */
#define SIGNIF (0.01)		/* less than one hundredth of a tic mark */
#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))

/* (DFK) Use 10^x if logscale is in effect, else x */
#define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))

/* Remember these from the last do_plot  */
static double last_xmin, last_ymin;
static double last_xscale, last_yscale;

double raise(x,y)
double x;
int y;
{
register int i;
double val;

	val = 1.0;
	for (i=0; i < abs(y); i++)
		val *= x;
	if (y < 0 ) return (1.0/val);
	return(val);
}


double make_tics(tmin,tmax,logscale)
double tmin,tmax;
BOOLEAN logscale;
{
double xr,xnorm,tics,tic,l10;

	xr = fabs(tmin-tmax);
	
	l10 = log10(xr);
	if (logscale) {
		tic = raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
		if (tic < 1.0)
			tic = 1.0;
	} else {
		xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
		if (xnorm <= 2)
			tics = 0.2;
		else if (xnorm <= 5)
			tics = 0.5;
		else tics = 1.0;	
		tic = tics * raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
	}
	return(tic);
}

char *idx(a,b)
register char *a,b;
{
	do {
		if (*a == b)
			return(a);
	} while (*a++);
	return(0);
}

 
num2str(num,str)
double num;
char str[];
{
char temp[80];
char *a,*b;

 	if (fabs(num) > 9999.0 || fabs(num) < 0.001 && fabs(num) != 0.0) 
		(void) sprintf(temp,"%-.3e",num);	
	else
		(void) sprintf(temp,"%-.3g",num);
	if (b = idx(temp,'e')) {
		a = b-1;     /* b points to 'e'.  a points before 'e' */
		while ( *a == '0') /* trailing zeros */
			a--;	
		if ( *a == '.') 
			a--;
		(void) strncpy(str,temp,(int)(a-temp)+1);
		str[(int)(a-temp)+1] = '\0';
		a = b+1;	/* point to 1 after 'e' */
		if ( *a == '-') 
			(void) strcat(str,"e-");
		else	
			(void) strcat(str,"e");
		a++; /* advance a past '+' or '-' */
		while ( *a == '0' && *(a+1) != '\0') /* leading blanks */
			a++;
		(void) strcat(str,a); /* copy rest of string */
	}
	else
		(void) strcpy(str,temp);	
}


do_plot(plots, p_count, xmin, xmax, ymin, ymax)
struct curve_points plots[MAX_PLOTS];
int p_count;			/* count of plots to do */
double xmin, xmax;
double ymin, ymax;
{
register int curve, i, x, xaxis_y, yaxis_x,dp_count;
register BOOLEAN prev_undef;
register double xscale, yscale;
register double ytic, xtic, least, most, ticplace;
register struct termentry *t = &term_tbl[term];
register int mms,mts;
static char xns[20],xms[20],yns[20],yms[20],xts[20],yts[20];
static char label[80];
char *special;
int lines;
struct st_entry *stp;
int title_line = 0;

	if (ymin == HUGE || ymax == -HUGE)
		int_error("all points undefined!", NO_CARET);

	ytic = make_tics(ymin,ymax,log_y);
	xtic = make_tics(xmin,xmax,log_x);
	dp_count = 0;
	
     if (autoscale_ly) {
	    if (ymin < ymax ) {
		   ymin = ytic * floor(ymin/ytic);	
		   ymax = ytic * ceil(ymax/ytic);
	    }
	    else {
		   ymin = ytic * ceil(ymin/ytic);
		   ymax = ytic * floor(ymax/ytic);
	    }
	}

     if (autoscale_lx) {
	    if (xmin < xmax ) {
		   xmin = xtic * floor(xmin/xtic);	
		   xmax = xtic * ceil(xmax/xtic);
	    }
	    else {
		   xmin = xtic * ceil(xmin/xtic);
		   xmax = xtic * floor(xmax/xtic);
	    }
	}

	if (xmin == xmax)
		int_error("xmin should not equal xmax!",NO_CARET);
	if (ymin == ymax)
		int_error("ymin should not equal ymax!",NO_CARET);
	
	if (!term_init) {
		(*t->init)();
		term_init = TRUE;
	}
	screen_ok = FALSE;
     if (!printer) {			/* DFK 6/8/87 */
	    (*t->graphics)(plot_width, plot_height, t,
				    xlabel_string, ylabel_string, y_skip_factor,
				    title_string);
	} else {
	    printer = FALSE;
	}

     /* NOW we can figure the scale from the terminal's resolution */
	yscale = (t->ymax - 2)/(ymax - ymin);
	xscale = (t->xmax - 2)/(xmax - xmin);
	
     /* And remember them all for later use in do_label */
    last_xmin = xmin;
    last_ymin = ymin;
    last_xscale = xscale;
    last_yscale = yscale;

	/* draw plot border */
	(*t->linetype)(-2); /* border linetype */
	(*t->move)(0,0);	
	(*t->vector)(t->xmax-1,0);	
	(*t->vector)(t->xmax-1,t->ymax-1);	
	(*t->vector)(0,t->ymax-1);	
	(*t->vector)(0,0);

     if (ytics) {
	    if (ymin < ymax) {
		   least = ytic * floor(ymin/ytic);	
		   most = ytic * ceil(ymax/ytic);
		   if (least >= ymin)
			(*t->ytick_text)(map_y(least),
						  CheckLog(log_y, CheckZero(least,ytic)),
						  yformat);
		   if (most <= ymax)
			(*t->ytick_text)(map_y(most), 
						  CheckLog(log_y, CheckZero(most,ytic)), 
						  yformat);
	    } else {
		   least = ytic * floor(ymax/ytic);
		   most = ytic * ceil(ymin/ytic);
		   if (least >= ymax)
			(*t->ytick_text)(map_y(least), 
						  CheckLog(log_y, CheckZero(least,ytic)),
						  yformat);
		   if (most <= ymin)
			(*t->ytick_text)(map_y(most), 
						  CheckLog(log_y, CheckZero(most,ytic)),
						  yformat);
	    }

	    for (ticplace = ytic + least; ticplace < most ; ticplace += ytic) { 
		   (*t->move)(0,map_y(ticplace));
		   (*t->vector)(t->h_tic,map_y(ticplace));
		   (*t->move)(t->xmax-1,map_y(ticplace));
		   (*t->vector)(t->xmax-1-t->h_tic,map_y(ticplace));
		   (*t->ytick_text)(map_y(ticplace), 
						CheckLog(log_y, CheckZero(ticplace,ytic)),
						yformat);
	    }
	}

     if (xtics) {
	    if (xmin < xmax) {
		   least = xtic * floor(xmin/xtic);	
		   most = xtic * ceil(xmax/xtic);
		   if (least >= xmin)
			(*t->xtick_text)(map_x(least), 
						  CheckLog(log_x, CheckZero(least,xtic)),
						  xformat);
		   if (most <= xmax)
			(*t->xtick_text)(map_x(most), 
						  CheckLog(log_x, CheckZero(most,xtic)),
						  xformat);
	    } else {
		   least = xtic * floor(xmax/xtic);
		   most = xtic * ceil(xmin/xtic);
		   if (least >= xmax)
			(*t->xtick_text)(map_x(least), 
						  CheckLog(log_x, CheckZero(least,xtic)),
						  xformat);
		   if (most <= xmin)
			(*t->xtick_text)(map_x(most),
						  CheckLog(log_x, CheckZero(most,xtic)),
						  xformat);
	    }

	    for (ticplace = xtic + least; ticplace < most ; ticplace += xtic) { 
		   (*t->move)(map_x(ticplace),0);
		   (*t->vector)(map_x(ticplace),t->v_tic);
		   (*t->move)(map_x(ticplace),t->ymax-1);
		   (*t->vector)(map_x(ticplace),t->ymax-1-t->v_tic);
		   (*t->xtick_text)(map_x(ticplace), 
						CheckLog(log_x, CheckZero(ticplace,xtic)),
						xformat);
	    }
	}

	if (log_x) {
		num2str(pow(10.0,xmin),xns);
		num2str(pow(10.0,xmax),xms);
		num2str(pow(10.0,xtic),xts);
	}
	else {
		num2str(xmin,xns);
		num2str(xmax,xms);
		num2str(xtic,xts);
	}
	if (log_y) {
		num2str(pow(10.0,ymin),yns);
		num2str(pow(10.0,ymax),yms);
		num2str(pow(10.0,ytic),yts);
	} else {
		num2str(ymin,yns);
		num2str(ymax,yms);
		num2str(ytic,yts);
	}
	mms = max(strlen(xms),strlen(yms));
	mts = max(strlen(xts),strlen(yts));

	if (put_label) {
	  (void) sprintf(label,"%s < y < %-*s  inc = %-*s",yns,mms,yms,mts,yts);
	  (*t->lrput_text)(0, label);
	  (void) sprintf(label,"%s < x < %-*s  inc = %-*s",xns,mms,xms,mts,xts);
	  (*t->lrput_text)(1, label);

	  if (*title_string != '\0') {
		 (*t->ulput_text)(0, title_string);
		 title_line = 1;
	  } else {
		 title_line = 0;
	  }
	}


/* DRAW AXES */
	(*t->linetype)(-1);	/* axis line type */
	xaxis_y = map_y(0.0);
	yaxis_x = map_x(0.0); 

	if (xaxis_y < 0)
		xaxis_y = 0;				/* save for impulse plotting */
	else if (xaxis_y >= t->ymax)
		xaxis_y = t->ymax - 1;
	else if (!log_y) {
		(*t->move)(0,xaxis_y);
		(*t->vector)((t->xmax-1),xaxis_y);
	}

	if (!log_x && yaxis_x >= 0 && yaxis_x < t->xmax) {
		(*t->move)(yaxis_x,0);
		(*t->vector)(yaxis_x,(t->ymax-1));
	}

/* DRAW CURVES */
	for (curve = 0; curve < p_count; curve++) {
		(*t->linetype)(curve);
		if (put_label)
			(*t->ulput_text)(curve + title_line, plots[curve].title);
		(*t->linetype)(curve);

		lines = TRUE;
		special = NULL;

		switch(plots[curve].plot_style) {
			case IMPULSES:
		    	 	(*t->linetype)(-1);	/* get straight lines */
				for (i = 0; i < plots[curve].count; i++) {
					if (!plots[curve].points[i].undefined) {
					    x = map_x(plots[curve].points[i].x);
						(*t->move)(x,xaxis_y);
						(*t->vector)(x,map_y(plots[curve].points[i].y));
					}
				}
				break;
			case LINES:
				prev_undef = TRUE;
				for (i = 0; i < plots[curve].count; i++) {
					if (!plots[curve].points[i].undefined) {
					    if (prev_undef)
						 (*t->move)(map_x(plots[curve].points[i].x),
								  map_y(plots[curve].points[i].y));
					    else
						 (*t->vector)(map_x(plots[curve].points[i].x),
								    map_y(plots[curve].points[i].y));
					}
					prev_undef = plots[curve].points[i].undefined;
				}
				break;
			case POINTS:
				for (i = 0; i < plots[curve].count; i++) {
					if (!plots[curve].points[i].undefined) {
					    (*t->point)(map_x(plots[curve].points[i].x),
								 map_y(plots[curve].points[i].y),
								 dp_count, NULL);
					}
				}
				dp_count++;
				break;
			case DOTS:
				for (i = 0; i < plots[curve].count; i++) {
					if (!plots[curve].points[i].undefined) {
					    (*t->point)(map_x(plots[curve].points[i].x),
								 map_y(plots[curve].points[i].y),
								 -1, NULL);
					}
				}
				break;
    	   	     default:		/* user-defined styles */
				stp = &st[plots[curve].plot_style];
				(*t->plotstyle)(stp);
				lines = stp->st_length > 0;
				special = stp->st_point;
				/* FALL THROUGH */
			case LINESPOINTS:
				prev_undef = TRUE;
				for (i = 0; i < plots[curve].count; i++) {
				    if (!plots[curve].points[i].undefined) {
					   x = map_x(plots[curve].points[i].x);
					   
					   if (prev_undef)
						(*t->move)(x,
								 map_y(plots[curve].points[i].y));
					   if (lines)
						(*t->vector)(x, 
								   map_y(plots[curve].points[i].y));
					   if (special != NULL)
						if (*special != '\0')
						  /* plot user-specified point */
						  (*t->point)(x,
								    map_y(plots[curve].points[i].y),
								    0, special);
						else
						  ; /* plot no point at all */
					   else	/* plot the normal type of point */
						(*t->point)(x,map_y(plots[curve].points[i].y),
								  dp_count, NULL);
				    }
				    prev_undef = plots[curve].points[i].undefined;
				}
				if (special == NULL)
				  dp_count++;
				break;

		}
	}
	(*t->text)();
	(void) fflush(outfile);
}

/* Put an arbitrary label at some point on the graph (DFK 1/28/88) */
/* Currently supported only by LaTeX terminal type */
do_label(x, y, string, pos, length, dx, dy)
	double x,y;
	char *string;			/* the text */
	char *pos;			/* optional [pos] in \makebox */
	double length;			/* optional length of the arrow */
	int dx, dy;			/* optional arrow slope */
{
    double xmin = last_xmin;
    double ymin = last_ymin;
    double xscale = last_xscale;
    double yscale = last_yscale;
    struct termentry *t = &term_tbl[term];

    if (strcmp(pos,"b")==0 || strcmp(pos,"t")==0 || (dx == 0 && dy != 0)) {
	   /* vertical line, interpret length as vertical extent */
	   (*t->xyput_text)(map_x(x), map_y(y), string, pos, 
					map_y(length) - map_y(0), dx, dy);
    } else {
	   /* non-vertical line, use length as horizontal extent */
	   (*t->xyput_text)(map_x(x), map_y(y), string, pos, 
					map_x(length) - map_x(0), dx, dy);
    }
}

/* Plot a key somewhere on the last plot. */
do_key (x,y, style, text)
	double x,y;			/* location of key */
	int style[];			/* which style does it use? */
	char *text[];			/* description for key */
{
    double xmin = last_xmin;
    double ymin = last_ymin;
    double xscale = last_xscale;
    double yscale = last_yscale;

    /* Hack: call LATEX routine directly. Yuck. */
    LATEX_key((unsigned long) map_x(x), (unsigned long) map_y(y), style, text);
}