|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 13006 (0x32ce)
Types: TextFile
Names: »graphics.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z«
└─⟦036c765ac⟧
└─⟦this⟧ »TeX3.0/TeXcontrib/gnutex/graphics.c«
/*
*
* 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);
}