|
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); }