This is hplot.c in view mode; [Download] [Up]
/*
* hippoplot.c - Routines for displaying hippo ntuples.
*
* Copyright (C) 1991 The Board of Trustees of The Leland Stanford
* Junior University. All Rights Reserved.
*
* $Id: hplot.c,v 5.0 1993/08/17 21:55:27 rensing Exp $
*
* by jonas karlsson, at SLAC, August 1990
* split up by Paul Rensing, Feb 28,1991
* modified by M. Gravina, March 28, 1991
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <float.h>
#include <ctype.h>
#include "hippo.h"
#include "hutil.h"
#include "h3D.h"
#include "hdata.h"
GLOB_QUAL const char hippoplot_c_rcsid[] =
"$Id: hplot.c,v 5.0 1993/08/17 21:55:27 rensing Exp $";
#ifdef _NEXT_PLOT_
#include "hplotNxt.h"
/*
* copied from appkit/View.h; hopefully it does not change
*/
extern short NXDrawingStatus;
#define NX_DRAWING 1 /* we're drawing */
#define NX_PRINTING 2 /* we're printing */
#define NX_COPYING 3 /* we're copying to the scrap */
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR NEXT
#endif
#endif
#ifdef _UNIXPLOT_PLOT_
#include "hplotUP.h"
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR UNIXPLOT
#endif
#endif
#ifdef _XIV_PLOT_
#include "hplotXIV.h"
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR XIVPLOT
#endif
#endif
#ifdef _X11_PLOT_
#include "hplotX11.h"
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR X11PLOT
#endif
#endif
#ifdef THINK_C
#include "hplotMAC.h"
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR MAC
#endif
#endif
#include "hplotPS.h"
#ifndef DEF_PLOT_DRVR
#define DEF_PLOT_DRVR PSPLOT
#endif
#define NUM_FUZZ FLT_EPSILON*4
#define MIN(x, y) (((x) > (y)) ? (y) : (x))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define XPADDING(disp) ((disp)->drawRect.size.width*0.01)
#define YPADDING(disp) ((disp)->drawRect.size.height*0.01)
#if defined(VMS) || defined(ultrix)
#define Concat3(x,y,z) x/**/y/**/z
#else
#define Concat3(x,y,z) x##y##z
#endif
#ifdef _NEXT_PLOT_
#define NeXTFunc(name,parm) \
case NEXT: \
rc = Concat3(name,_NeXT,parm); \
break;
#else
#define NeXTFunc(name,parm)
#endif
#ifdef _UNIXPLOT_PLOT_
#define UPFunc(name,parm) \
case UNIXPLOT: \
rc = Concat3(name,_UP,parm); \
break;
#else
#define UPFunc(name,parm)
#endif
#ifdef _XIV_PLOT_
#define XIVFunc(name,parm) \
case XIVPLOT: \
Concat3(name,_XIV,parm); \
rc = 0; \
break;
#else
#define XIVFunc(name,parm)
#endif
#ifdef _X11_PLOT_
#define X11Func(name,parm) \
case X11PLOT: \
Concat3(name,_X11,parm); \
rc = 0; \
break;
#else
#define X11Func(name,parm)
#endif
#ifdef THINK_C
#define MACFunc(name,parm) \
case MAC: \
Concat3(name,_MAC,parm); \
rc = 0; \
break;
#else
#define MACFunc(name,parm)
#endif
/*
* always make PS driver available
*/
#define PSFunc(name,parm) \
case PSPLOT: \
case EPSPLOT: \
Concat3(name,_PS,parm); \
rc = 0; \
break;
#define PlotSwitch(drvr,name, parm) \
switch (drvr) \
{ \
NeXTFunc(name,parm) \
UPFunc(name,parm) \
XIVFunc(name,parm) \
X11Func(name,parm) \
MACFunc(name,parm) \
PSFunc(name,parm) \
default: \
rc = -1; \
}
/*
* private functions
*/
static int drawData( display disp );
static int drawData1D( display disp );
static int drawAxis( display disp );
static int drawLabels( display disp );
static int drawLego1D(display disp, float *lego, int *over, int npts,
linestyle_t ls);
static int drawPoint1D(display disp, float *xy, int *over, int npts);
static int drawError1D(display disp, float *xy, float *err,
int *over, int npts, int err_type);
static int drawLine1D(display disp, float *xy, int *over,
int npts, int xmin_pt, linestyle_t ls);
static void box_cross(float *p1, float *p2, display disp);
int intcmp(const void *i1, const void *i2);
static int drawColor2D(display disp);
static int drawScatter2D(display disp);
static int drawLego2D(display disp);
static int drawScatter3D(display disp);
static int initPlot(display disp);
static int endPlot(display disp);
static int drawAxisBox(display disp);
static int drawTicks(display disp, binding_t axis);
#define N__TICKS 20
static int drawXTicks(display disp, int nticks, float *ticks,
char labels[N__TICKS][10], float pmag,
float fontSize );
static int drawYTicks(display disp, int nticks, float *ticks,
char labels[N__TICKS][10], float pmag,
float fontSize );
static int drawMag( float x, float y, int mag, float fontSize );
int drawText(char *s, float x, float y, float fontsize, float angle,
char xp, char yp );
static int plotFunc(display disp, func_id fun );
static double funcSum(double x, double width, double *parm );
/*
* global variables.
*/
static int init_done;
static plotdrvr_t plot_drvr = DEF_PLOT_DRVR;
#ifdef _XIV_PLOT_
/* For passing to the X Interviews driver... */
static void* canvas;
static void* painter;
#endif
#ifdef _X11_PLOT_
/* for passing to X11 driver ... */
static Display* dpy;
static Screen* screen;
static Drawable drawable;
static GC gc;
#endif
int h_setPlotDrvr( plotdrvr_t drvr, ...)
{
int rc;
va_list argPtr;
void *parm;
switch (drvr)
{
#ifdef _NEXT_PLOT_
case NEXT:
#endif
#ifdef _XIV_PLOT_
case XIVPLOT:
#endif
#ifdef _X11_PLOT_
case X11PLOT:
#endif
#ifdef THINK_C
case MAC:
#endif
case LPR:
rc = 0;
break;
case PSPLOT:
case EPSPLOT:
va_start( argPtr, drvr );
parm = va_arg(argPtr, FILE *);
rc = initDrvr_PS( parm );
va_end(argPtr);
break;
#ifdef _UNIXPLOT_PLOT_
case UNIXPLOT:
va_start( argPtr, drvr );
parm = va_arg(argPtr, FILE *); /* this shit does not work yet */
rc = initDrvr_UP( parm );
va_end(argPtr);
break;
#endif
default:
h_error("h_setPlotDrvr - invalid plot driver. Driver may not be compiled in this version.\n");
rc = -1;
}
if (rc == 0)
plot_drvr = drvr;
else
h_error("h_setPlotDrvr - error in driver init. Driver not changed.\n");
return rc;
}
int h_endPlotDrvr( void )
{
int rc;
switch (plot_drvr)
{
case PSPLOT:
case EPSPLOT:
rc = endDrvr_PS( );
break;
default:
rc = 0;
}
return rc;
}
int h_endPage( void )
{
int rc;
switch (plot_drvr)
{
case PSPLOT:
case EPSPLOT:
rc = endPage_PS( );
break;
default:
rc = 0;
}
return rc;
}
int h_plot(display disp,...)
{
int rc = 0;
int xLogFlag, yLogFlag;
#if defined(_XIV_PLOT_) || defined(_X11_PLOT_)
va_list argPtr;
#endif
if (disp == NULL || disp->tuple == NULL) return -1;
/*
* be nice. If driver is lineprinter, call h_print.
*/
if (plot_drvr == LPR)
{
h_print( disp );
return 0;
}
#ifdef _XIV_PLOT_
if (plot_drvr == XIVPLOT)
{
va_start( argPtr, disp );
painter = va_arg(argPtr, void *);
canvas = va_arg(argPtr, void *);
va_end(argPtr);
}
#endif
#ifdef _X11_PLOT_
if (plot_drvr == X11PLOT)
{
va_start( argPtr, disp );
dpy = va_arg(argPtr, Display *);
screen = va_arg(argPtr, Screen *);
drawable = va_arg(argPtr, Drawable);
gc = va_arg(argPtr, GC);
va_end(argPtr);
}
#endif
/*
* make sure min/max of ntuple columns is up-to-date
*/
if (disp->tuple->extremeBad) h_findExtreme(disp->tuple);
/*
* bin the data. Function will decide if it is needed.
*/
if (h_bin(disp) != 0) return -1;
init_done = 0;
/*
* We want to ignore the log flags if not appropriate (binned axes)
* Save the flag value and reset afterwards. (bit of a hack)
*/
xLogFlag = disp->xAxis.flags.log;
yLogFlag = disp->yAxis.flags.log;
if (disp->graphtype == HISTOGRAM || disp->graphtype == LEGOPLOT
|| disp->graphtype == COLORPLOT)
disp->xAxis.flags.log = 0;
if (disp->graphtype == LEGOPLOT || disp->graphtype == COLORPLOT)
disp->yAxis.flags.log = 0;
drawData(disp);
/*
* Plot the functions
*/
if (disp->flags.plotFuncs)
{
func_id fun;
for (fun = disp->plot_func; fun != NULL && rc == 0; fun = fun->next ) {
if ( fun->funcPtr != NULL ) {
rc = plotFunc( disp, fun );
} else {
rc = 0;
}
}
}
if (disp->flags.plotFuncSum)
{
func_id fun;
fun = disp->plot_func;
if (fun == NULL) { /* cannot have a sum without a function */
disp->flags.plotFuncSum = 0;
} else {
/* build a "fake" function block and call plotFunc */
func_id_t fun;
fun.funcPtr = (int (*)())funcSum;
fun.paramBlk = (double *)disp;
fun.lineStyle = disp->fSumLineStyle;
plotFunc( disp, &fun );
}
}
if (disp->graphtype != LEGOPLOT && disp->graphtype != THREEDSCATTER) {
if (disp->flags.drawAxes) drawAxis(disp);
if (disp->flags.drawTitles) drawLabels( disp );
}
endPlot( disp );
disp->xAxis.flags.log = xLogFlag;
disp->yAxis.flags.log = yLogFlag;
return 0;
}
static int drawAxis(display disp)
{
if (disp == NULL) return -1;
if (!init_done)
{
initPlot(disp);
init_done = 1;
}
drawAxisBox( disp );
if (drawTicks(disp,YAXIS))
h_error("drawAxis: error drawing y ticks");
if (drawTicks(disp,XAXIS))
h_error("drawAxis: error drawing x ticks");
return 0;
}
static int drawData(display disp)
{
float fontHeight;
if (disp->tuple == NULL) return 0;
if (disp->tuple->ndata == 0)
{
fontHeight= MIN(disp->drawRect.size.width*0.05,24.0);
drawText("No Data in Tuple",
disp->marginRect.origin.x+disp->marginRect.size.width/2.0,
disp->marginRect.origin.y+disp->marginRect.size.height/2.0,
fontHeight, 0, 'c', 'c');
return 0;
}
switch (disp->graphtype)
{
case HISTOGRAM:
case XYPLOT:
case STRIPCHART:
drawData1D( disp );
break;
case COLORPLOT: /* 2D COLOR */
drawColor2D(disp);
break;
case SCATTERPLOT: /* 2D SCATTER */
drawScatter2D(disp);
break;
case LEGOPLOT: /* 3D LEGO */
drawLego2D(disp);
break;
case THREEDSCATTER: /* 3D SCATTER */
drawScatter3D(disp);
break;
}
return 0;
}
static int drawData1D(display disp)
{
float *xy = NULL, *lego = NULL, *xerr = NULL, *yerr = NULL;
int *over = NULL, xmin_pt = 0, npts;
struct maxs limits;
/*
* first get the appropriate data, depending on the graphtype.
*/
switch (disp->graphtype)
{
case HISTOGRAM: /* Histogra */
npts = getHistoData(disp,&xy,&lego,&xerr,&yerr,&over,&limits);
if (npts == 0) return 0;
if (npts < 0)
{
h_error("h_plot - error getting bin data");
return -1;
}
if (disp->yAxis.flags.autoScale)
{
if (limits.yh < limits.yl)
{
/* must be no points in range. */
return 0;
}
else if (limits.yh == limits.yl)
{
/* must be only on point in range. */
disp->yAxis.low = limits.yh - 0.5;
disp->yAxis.high = limits.yh + 0.5;
}
else
{
if (limits.yh > 0.0)
disp->yAxis.high = limits.yh;
else
{
if (disp->yAxis.flags.log)
{
h_error("All data < 0 on log axis");
return -1;
}
disp->yAxis.high = 0.0;
}
if (limits.yl < 0.0 || disp->yAxis.flags.log)
disp->yAxis.low = limits.yl;
else
disp->yAxis.low = 0.0;
}
}
else if (disp->yAxis.flags.log && disp->yAxis.low <= 0.0)
{
if (limits.yl > 0.0)
disp->yAxis.low = limits.yl;
else
disp->yAxis.low = pow(10.0, FLT_MIN);
if (disp->yAxis.high <= disp->yAxis.low)
disp->yAxis.high =
disp->yAxis.low*(1.0+NUM_FUZZ) + FLT_MIN;
}
break;
case XYPLOT:
case STRIPCHART:
npts = getXYData(disp,&xy,&xerr,&yerr,&over,&limits,&xmin_pt);
if (npts == 0) return 0;
if (npts < 0)
{
h_error("h_plot - error getting data for x-y plot");
return -1;
}
if (disp->graphtype == XYPLOT) xmin_pt = 0;
/*
* autoscale axes
*/
if (disp->xAxis.flags.autoScale)
{
if (limits.xh > limits.xl)
{
disp->xAxis.low = limits.xl;
disp->xAxis.high = limits.xh;
}
else if (limits.xh == limits.xl)
{
/* must be only on point in range. */
disp->xAxis.low = limits.xl - 0.5;
disp->xAxis.high = limits.xh + 0.5;
}
else
{
/* must be no points in range. */
return 0;
}
h_adjustAxis(&(disp->xAxis.low), &(disp->xAxis.high),
0, disp->xAxis.flags.log);
}
else if (disp->xAxis.flags.log && disp->xAxis.low <= 0.0)
{
if (limits.xl > 0.0)
disp->xAxis.low = limits.xl;
else
disp->xAxis.low = pow(10.0, FLT_MIN);
if (disp->xAxis.high <= disp->xAxis.low)
disp->xAxis.high =
disp->xAxis.low*(1.0+NUM_FUZZ) + FLT_MIN;
}
if (disp->yAxis.flags.autoScale)
{
if (limits.yh > limits.yl)
{
disp->yAxis.low = limits.yl;
disp->yAxis.high = limits.yh;
}
else if (limits.yh == limits.yl)
{
/* must be only on point in range. */
disp->yAxis.low = limits.yl - 0.5;
disp->yAxis.high = limits.yh + 0.5;
}
else
{
/* must be no points in range. */
return 0;
}
}
else if (disp->yAxis.flags.log && disp->yAxis.low <= 0.0)
{
if (limits.yl > 0.0)
disp->yAxis.low = limits.yl;
else
disp->yAxis.low = pow(10.0, FLT_MIN);
if (disp->yAxis.high <= disp->yAxis.low)
disp->yAxis.high =
disp->yAxis.low*(1.0+NUM_FUZZ) + FLT_MIN;
}
break;
default:
h_error("hippo error: invalid disp->graphtype\n");
return -1;
break;
}
if (disp->yAxis.flags.autoScale)
h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
0, disp->yAxis.flags.log );
/*
* init the plot device
*/
if (!init_done)
{
initPlot( disp );
init_done = 1;
}
/*
* draw the points, lines etc.
*/
/* draw points */
if ( disp->drawtype & POINT )
drawPoint1D(disp, xy, over, npts);
/* draw error bars */
if ( disp->drawtype & ERRBAR )
{
if (yerr != NULL) drawError1D(disp,xy,yerr,over,npts,YERROR);
if (xerr != NULL) drawError1D(disp,xy,xerr,over,npts,XERROR);
}
/* join points */
if ( disp->drawtype & LINE )
drawLine1D(disp,xy,over,npts,xmin_pt,disp->lineStyle);
/* draw bars */
if ( (disp->drawtype & BOX) && disp->graphtype==HISTOGRAM )
drawLego1D(disp, lego, over, npts,disp->lineStyle);
free(lego);
free(xy);
free(xerr);
free(yerr);
free(over);
return 0;
}
static int initPlot(display disp)
{
int rc;
rectangle userRect;
if (disp->xAxis.flags.log)
{
userRect.origin.x = log10(disp->xAxis.low);
userRect.size.width = log10(disp->xAxis.high / disp->xAxis.low);
}
else
{
userRect.origin.x = disp->xAxis.low;
userRect.size.width = disp->xAxis.high - disp->xAxis.low;
}
if (disp->yAxis.flags.log)
{
userRect.origin.y = log10(disp->yAxis.low);
userRect.size.height = log10(disp->yAxis.high / disp->yAxis.low);
}
else
{
userRect.origin.y = disp->yAxis.low;
userRect.size.height = disp->yAxis.high - disp->yAxis.low;
}
switch (plot_drvr)
{
NeXTFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
UPFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
MACFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
PSFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
#ifdef _XIV_PLOT_
case XIVPLOT:
initPlot_XIV(painter,canvas);
setHistoCoords_XIV(&disp->marginRect, &userRect);
rc = 0;
break;
#endif
#ifdef _X11_PLOT_
case X11PLOT:
initPlot_X11(dpy,screen,drawable,gc);
setHistoCoords_X11(&disp->drawRect, &disp->marginRect, &userRect);
rc = 0;
break;
#endif
default:
rc = -1;
}
return rc;
}
static int endPlot(display disp)
{
int rc;
switch (plot_drvr)
{
UPFunc(endPlot,());
default:
rc = 0;
}
return rc;
}
static int drawLabels( display disp )
{
float x, y;
float fontSize;
char string[80];
/*
* title
*/
fontSize = disp->drawRect.size.width*0.05;
fontSize = MIN(fontSize,
(disp->drawRect.size.height -
disp->marginRect.size.height - 2*YPADDING(disp) -
(disp->marginRect.origin.y-disp->drawRect.origin.y)));
x = disp->marginRect.origin.x + 0.5 * disp->marginRect.size.width;
y = disp->drawRect.origin.y + disp->drawRect.size.height
- YPADDING(disp);
h_expandLabel(string,disp->title,80,disp);
if (fontSize > disp->marginRect.size.width/strlen(string)*2)
{
fontSize = disp->drawRect.size.width/strlen(string)*2;
x = disp->drawRect.origin.x + 0.5 * disp->drawRect.size.width;
}
if (drawText(string, x, y, fontSize, 0.0, 'c', 't') != 0)
{
h_error("Error drawing plot title");
return -1;
}
/*
* x axis label
*/
y -= fontSize;
x = disp->marginRect.origin.x + 0.5 * disp->marginRect.size.width;
fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
fontSize = MIN(disp->drawRect.size.height*0.04,14.0);
fontSize = MIN(fontSize,
disp->drawRect.size.width/strlen(disp->xAxis.label)*2);
h_expandLabel(string,disp->xAxis.label,80,disp);
if (disp->xAxis.flags.labelLocation & PLOTBOTTOM)
{
y = disp->drawRect.origin.y + YPADDING(disp);
if (drawText(string, x, y, fontSize,0.0,'c','b') != 0)
{
h_error("Error drawing x axis label");
return -1;
}
}
else if (disp->xAxis.flags.labelLocation & PLOTTOP)
{
y -= YPADDING(disp);
if (drawText(string, x, y, fontSize,0.0,'c','t') != 0)
{
h_error("Error drawing x axis label");
return -1;
}
}
/*
* y axis label
*/
fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
fontSize = MIN(fontSize,
disp->drawRect.size.height/strlen(disp->yAxis.label)*2);
y = disp->marginRect.origin.y + disp->marginRect.size.height/2.0;
h_expandLabel(string,disp->yAxis.label,80,disp);
if (disp->yAxis.flags.labelLocation & PLOTLEFT)
{
x = disp->drawRect.origin.x + XPADDING(disp);
if (drawText(string, x, y, fontSize,90.0,'c','t') != 0)
{
h_error("Error drawing y axis label");
return -1;
}
}
else if (disp->yAxis.flags.labelLocation & PLOTRIGHT)
{
x = disp->drawRect.origin.x + disp->drawRect.size.width
- XPADDING(disp);
if (drawText(string, x, y, fontSize,-90.0,'c','t') != 0)
{
h_error("Error drawing y axis label");
return -1;
}
}
return 0;
}
int drawText(char *s, float x, float y, float fontsize, float angle,
char xp, char yp )
{
int rc;
PlotSwitch(plot_drvr,drawText,(s, x, y, fontsize, angle, xp, yp));
return rc;
}
static int drawAxisBox( display disp )
{
int rc = 0;
float xy[10];
if (disp->xAxis.flags.log)
{
xy[0] = xy[2] = xy[8] = log10(disp->xAxis.low);
xy[4] = xy[6] = log10(disp->xAxis.high);
}
else
{
xy[0] = xy[2] = xy[8] = disp->xAxis.low;
xy[4] = xy[6] = disp->xAxis.high;
}
if (disp->yAxis.flags.log)
{
xy[1] = xy[7] = xy[9] = log10(disp->yAxis.low);
xy[3] = xy[5] = log10(disp->yAxis.high);
}
else
{
xy[1] = xy[7] = xy[9] = disp->yAxis.low;
xy[3] = xy[5] = disp->yAxis.high;
}
PlotSwitch(plot_drvr,drawLine,(xy,5, SOLID));
return rc;
}
static int drawTicks(display disp, binding_t axis)
{
int nticks = 0;
float ticks[N__TICKS];
char labels[N__TICKS][10];
float fontSize;
float pmag;
axis_t *thisAxis;
if (axis == XAXIS)
thisAxis = &disp->xAxis;
else if (axis == YAXIS)
thisAxis = &disp->yAxis;
else
return -1;
genTicks(thisAxis, N__TICKS, &nticks, ticks, labels, &pmag);
/*
* determine the font size. We want the x and y axes to be labeled in
* the same font size, so make the same calculation, independent of
* which axis we are dealing with.
*/
if (thisAxis->scaleFontSize > 0.0)
fontSize = thisAxis->scaleFontSize;
else
{
fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
if (disp->xAxis.flags.scaleLocation & PLOTBOTTOM)
{
fontSize = MIN(fontSize, (disp->marginRect.origin.y -
disp->drawRect.origin.y)/2.0);
}
else if (disp->xAxis.flags.scaleLocation & PLOTTOP)
{
fontSize = MIN(fontSize, (disp->drawRect.size.height -
disp->marginRect.size.height -
(disp->marginRect.origin.y -
disp->drawRect.origin.y))/2.0
);
}
if (disp->yAxis.flags.scaleLocation & PLOTLEFT)
{
/* estimate the space needed for the y axis label */
float yr;
if (disp->flags.drawTitles &&
disp->yAxis.flags.labelLocation & PLOTLEFT)
yr = 14;
else
yr = 0;
fontSize = MIN(fontSize,
(disp->marginRect.origin.x -
disp->drawRect.origin.x - yr)
/strlen(labels[nticks-1]));
}
else if (disp->yAxis.flags.scaleLocation & PLOTRIGHT)
{
/* estimate the space needed for the y axis label */
float yr;
if (disp->flags.drawTitles &&
disp->yAxis.flags.labelLocation & PLOTRIGHT)
yr = 14;
else
yr = 0;
fontSize = MIN(fontSize,
(disp->drawRect.size.width -
disp->marginRect.size.width -
(disp->marginRect.origin.x -
disp->drawRect.origin.x) - yr)
/strlen(labels[nticks-1]));
}
}
/*
* Plot the tick marks and labels
*/
switch (axis)
{
case XAXIS:
return drawXTicks(disp, nticks, ticks, labels, pmag, fontSize );
break;
case YAXIS:
return drawYTicks(disp, nticks, ticks, labels, pmag, fontSize );
break;
default:
return -1;
}
return 0;
}
static int drawXTicks(display disp, int nticks, float *ticks,
char labels[N__TICKS][10], float pmag,
float fontSize )
{
int rc = 0;
int i;
float pOrigin, aOrigin, scale;
char yalign;
float x, y;
if (disp->xAxis.flags.tickLocation & PLOTBOTTOM)
{
PlotSwitch(plot_drvr,drawXTicks,
(ticks,nticks,disp->xAxis.tickLength,0));
}
if (disp->xAxis.flags.tickLocation & PLOTTOP)
{
PlotSwitch(plot_drvr,drawXTicks,
(ticks,nticks,disp->xAxis.tickLength,1));
}
if (rc != 0 || disp->xAxis.flags.scaleLocation == 0) return rc;
pOrigin = disp->marginRect.origin.x;
if (! disp->xAxis.flags.log)
{
scale = disp->marginRect.size.width /
(disp->xAxis.high - disp->xAxis.low);
aOrigin = disp->xAxis.low;
}
else
{
scale = disp->marginRect.size.width /
log10(disp->xAxis.high / disp->xAxis.low);
aOrigin = log10(disp->xAxis.low);
}
if (disp->xAxis.flags.scaleLocation & PLOTBOTTOM)
{
y = disp->marginRect.origin.y - YPADDING(disp);
yalign = 't';
}
else
{
y = disp->marginRect.origin.y + disp->marginRect.size.height +
YPADDING(disp);
yalign = 'b';
}
for (i=0; i<nticks; i++ )
{
x = pOrigin + (ticks[i] - aOrigin) * scale;
if (drawText(labels[i], x, y, fontSize, 0.0, 'c', yalign ) != 0)
{
h_error("Error draw label on axis.");
return -1;
}
}
if (pmag != 0.0)
{
x = pOrigin + (ticks[nticks-1] - aOrigin) * scale +
strlen(labels[nticks-1]) * fontSize / 2.0;
x = MIN( x, disp->marginRect.origin.x +
disp->marginRect.size.width + XPADDING(disp));
if (yalign == 't') {
y -= fontSize*0.8;
} else {
y += fontSize*0.2;
}
drawMag(x, y, (int)pmag, fontSize*0.75 );
}
return rc;
}
static int drawYTicks(display disp, int nticks, float *ticks,
char labels[N__TICKS][10], float pmag,
float fontSize )
{
int rc = 0;
int i;
float pOrigin, aOrigin, scale;
char xalign;
float x, y;
if (disp->yAxis.flags.tickLocation & PLOTLEFT)
{
PlotSwitch(plot_drvr,drawYTicks,
(ticks,nticks,disp->yAxis.tickLength,0));
}
if (disp->yAxis.flags.tickLocation & PLOTRIGHT)
{
PlotSwitch(plot_drvr,drawYTicks,
(ticks,nticks,disp->yAxis.tickLength,1));
}
if (rc != 0 || disp->yAxis.flags.scaleLocation == 0) return rc;
pOrigin = disp->marginRect.origin.y;
if (! disp->yAxis.flags.log)
{
scale = disp->marginRect.size.height /
(disp->yAxis.high - disp->yAxis.low);
aOrigin = disp->yAxis.low;
}
else
{
scale = disp->marginRect.size.height /
log10(disp->yAxis.high / disp->yAxis.low);
aOrigin = log10(disp->yAxis.low);
}
if (disp->yAxis.flags.scaleLocation & PLOTLEFT)
{
x = disp->marginRect.origin.x - XPADDING(disp);
xalign = 'r';
}
else
{
x = disp->marginRect.origin.x + disp->marginRect.size.width
+ XPADDING(disp);
xalign = 'l';
}
for (i=0; i<nticks; i++ )
{
y = pOrigin + (ticks[i] - aOrigin) * scale;
if (drawText(labels[i], x, y, fontSize, 0.0, xalign, 'c' ) != 0)
{
h_error("Error draw label on axis.");
return -1;
}
}
if (pmag != 0.0)
{
if (disp->yAxis.flags.scaleLocation & PLOTLEFT)
x = disp->marginRect.origin.x - XPADDING(disp) -
fontSize*(strlen(labels[nticks-1])+2);
else
x = disp->marginRect.origin.x + disp->marginRect.size.width
+ XPADDING(disp) +
fontSize*(strlen(labels[nticks-1]));
y = pOrigin + (ticks[nticks-1] - aOrigin)*scale - fontSize*0.4;
/***** y = disp->marginRect.origin.y + disp->marginRect.size.height
+ fontSize/2.0 + YPADDING(disp); *****/
drawMag(x, y, (int)pmag, fontSize*0.75 );
}
return rc;
}
static int drawMag( float x, float y, int mag, float fontSize )
{
int rc;
PlotSwitch(plot_drvr,drawMag,( x, y, mag, fontSize ));
return rc;
}
static int drawLego1D(display disp, float *xylego, int *over,
int npts, linestyle_t ls)
{
int rc = 0;
int end;
int i_over;
float ylow, yhigh;
if (disp->yAxis.flags.log)
{
yhigh = log10(disp->yAxis.high);
ylow = log10(disp->yAxis.low);
}
else
{
yhigh = disp->yAxis.high;
ylow = disp->yAxis.low;
}
/*
* first, check the first group of points, since
* it is not associated with a bin. (last group is check
* by last element in over)
*/
if (xylego[1] > yhigh) xylego[1] = yhigh;
if (xylego[1] < ylow) xylego[1] = ylow;
if (xylego[3] > yhigh) xylego[3] = yhigh;
if (xylego[3] < ylow) xylego[3] = ylow;
i_over = 0;
do
{
end = over[i_over++];
if (xylego[4*(end+1)+1] > yhigh) xylego[4*(end+1)+1] = yhigh;
if (xylego[4*(end+1)+1] < ylow) xylego[4*(end+1)+1] = ylow;
if (xylego[4*(end+1)+3] > yhigh) xylego[4*(end+1)+3] = yhigh;
if (xylego[4*(end+1)+3] < ylow) xylego[4*(end+1)+3] = ylow;
}
while (end < npts);
PlotSwitch(plot_drvr,drawLine,( xylego, 2*(npts+2), ls ));
return rc;
}
static int drawPoint1D(display disp, float *xy, int *over, int npts)
{
int rc=0;
int start = -1, end;
int i_over=0;
float xlow, ylow;
float xhigh, yhigh;
if (disp->xAxis.flags.log)
{
xhigh = log10(disp->xAxis.high);
xlow = log10(disp->xAxis.low);
}
else
{
xhigh = disp->xAxis.high;
xlow = disp->xAxis.low;
}
if (disp->yAxis.flags.log)
{
yhigh = log10(disp->yAxis.high);
ylow = log10(disp->yAxis.low);
}
else
{
yhigh = disp->yAxis.high;
ylow = disp->yAxis.low;
}
do
{
/*
* Check that points marked as over are really over (it may be
* that error bar is over).
*/
do
{
if (start == -1)
start = 0;
else
start = over[i_over++]+1;
end = over[i_over];
while (end<npts)
{
/* include some fuzz in comparisons */
if (xy[2*end+1]<(ylow*(1.0-NUM_FUZZ)) ||
xy[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
if (xy[2*end]<(xlow*(1.0-NUM_FUZZ)) ||
xy[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
end = over[++i_over];
}
}
while ( (end-start) <= 0 && start<npts );
if (start >= npts) continue;
PlotSwitch(plot_drvr,drawPoints,(&(xy[2*start]),end-start,
disp->plotSymbol,disp->symbolSize));
}
while (rc == 0 && end < npts && start < npts);
return rc;
}
static int drawLine1D(display disp, float *xy, int *over,
int npts, int xmin_pt, linestyle_t ls)
{
int rc = 0;
int start, end;
int s_saved, e_saved;
int i_over = 0;
float *xy_alt;
int *over_alt;
float xlow, ylow;
float xhigh, yhigh;
float start_save[2],end_save[2];
if (npts < 2) return 0;
if (ls == LS_INVISIBLE) return 0;
if (xmin_pt > 0)
{
if ( (xy_alt = (float *)malloc( 2*npts*sizeof(float) ))
== NULL)
{
h_error("drawLine1D - ran out of memory");
return -1;
}
if ( (over_alt = (int *)malloc( (npts+1)*sizeof(int) ))
== NULL)
{
h_error("drawLine1D - ran out of memory");
return -1;
}
memcpy((char *)xy_alt, (char *)&xy[2*xmin_pt],
2*(npts-xmin_pt)*sizeof(float) );
memcpy((char *)&xy_alt[2*(npts-xmin_pt)], (char *)xy,
2*xmin_pt*sizeof(float) );
for (i_over=0; over[i_over]<npts; i_over++ )
{
if (over[i_over] >= xmin_pt)
over_alt[i_over] = over[i_over] - xmin_pt;
else
over_alt[i_over] = over[i_over] + npts - xmin_pt;
}
over_alt[i_over++] = npts;
if (i_over > 1)
qsort( over_alt, (size_t)i_over, sizeof(int), intcmp );
}
else
{
over_alt = over;
xy_alt = xy;
}
if (disp->xAxis.flags.log)
{
xhigh = log10(disp->xAxis.high);
xlow = log10(disp->xAxis.low);
}
else
{
xhigh = disp->xAxis.high;
xlow = disp->xAxis.low;
}
if (disp->yAxis.flags.log)
{
yhigh = log10(disp->yAxis.high);
ylow = log10(disp->yAxis.low);
}
else
{
yhigh = disp->yAxis.high;
ylow = disp->yAxis.low;
}
i_over = 0;
start = -1;
do
{
/*
* Check that points marked as over are really over (it may be
* that error bar is over). Interpolate to find point where
* line crosses axes.
*/
s_saved = 0;
e_saved = 0;
do
{
if (start == -1)
start = 0;
else
start = over_alt[i_over++]+1;
end = over_alt[i_over];
while (end<npts)
{
/* include some fuzz in comparisons */
if (xy_alt[2*end+1]<(ylow*(1.0-NUM_FUZZ)) ||
xy_alt[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
if (xy_alt[2*end]<(xlow*(1.0-NUM_FUZZ)) ||
xy_alt[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
end = over_alt[++i_over];
}
}
while ( (end-start) <= 0 && start<npts );
if (start >= npts) continue;
if (start > 0)
{
memcpy(start_save,&(xy_alt[2*(start-1)]),2*sizeof(float) );
s_saved = 1;
box_cross( &xy_alt[2*(start-1)], &xy_alt[2*start], disp);
start--;
}
if (end < npts)
{
memcpy(end_save,&(xy_alt[2*end]),2*sizeof(float) );
e_saved = 1;
box_cross( &xy_alt[2*end], &xy_alt[2*(end-1)], disp);
end++;
}
PlotSwitch(plot_drvr,drawLine,
(&(xy_alt[2*start]),end-start,ls));
if (s_saved)
memcpy(&(xy_alt[2*start]),start_save,2*sizeof(float) );
if (e_saved)
memcpy(&(xy_alt[2*(end-1)]),end_save,2*sizeof(float) );
}
while (rc == 0 && end < npts && start < npts);
if (xmin_pt != 0)
{
free(xy_alt);
free(over_alt);
}
return rc;
}
/*
* integer comparison for qsort.
*/
int intcmp(const void *i1, const void *i2)
{
if ((int *)i1 > (int *)i2)
return 1;
else if ((int *)i1 == (int *)i2)
return 0;
else
return -1;
}
/*
* find point where interpolation between p1 and p2 cross the
* axes box.
*/
static void box_cross( float *p1, float *p2, display disp )
{
float xlow,ylow, xhigh, yhigh;
float x_int1,x_int2,y_int1,y_int2;
if (disp->xAxis.flags.log)
{
xlow = log10(disp->xAxis.low);
xhigh = log10(disp->xAxis.high);
}
else
{
xlow = disp->xAxis.low;
xhigh = disp->xAxis.high;
}
if (disp->yAxis.flags.log)
{
ylow = log10(disp->yAxis.low);
yhigh = log10(disp->yAxis.high);
}
else
{
ylow = disp->yAxis.low;
yhigh = disp->yAxis.high;
}
x_int1 = p1[0] + (ylow-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]);
if (x_int1 >= xlow && x_int1 <= xhigh &&
ylow >= p1[1] && ylow <= p2[1])
{
p1[0] = x_int1;
p1[1] = ylow;
return;
}
x_int2 = p1[0] + (yhigh-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]);
if (x_int2 >= xlow && x_int2 <= xhigh &&
yhigh <= p1[1] && yhigh >= p2[1])
{
p1[0] = x_int2;
p1[1] = yhigh;
return;
}
y_int1 = p1[1] + (xlow-p1[0])*(p2[1]-p1[1])/(p2[0]-p1[0]);
if (y_int1 >= ylow && y_int1 <= yhigh &&
xlow >= p1[0] && xlow <= p2[0])
{
p1[0] = xlow;
p1[1] = y_int1;
return;
}
y_int2 = p1[1] + (xhigh-p1[0])*(p2[1]-p1[1])/(p2[0]-p1[0]);
if (y_int2 >= ylow && y_int1 <= yhigh &&
xhigh <= p1[0] && xhigh >= p2[0])
{
p1[0] = xhigh;
p1[1] = y_int2;
return;
}
}
/*
* draw errors - err_type specifies whether they are x or y errors.
*/
static int drawError1D(display disp, float *xy, float *err,
int *over, int npts, int err_type)
{
int rc = 0;
int start = -1;
int end;
int i_over = 0;
float xlow, ylow;
float xhigh, yhigh;
if (disp->xAxis.flags.log)
{
xhigh = log10(disp->xAxis.high);
xlow = log10(disp->xAxis.low);
}
else
{
xhigh = disp->xAxis.high;
xlow = disp->xAxis.low;
}
if (disp->yAxis.flags.log)
{
yhigh = log10(disp->yAxis.high);
ylow = log10(disp->yAxis.low);
}
else
{
yhigh = disp->yAxis.high;
ylow = disp->yAxis.low;
}
do
{
/*
* Plot any x/y error bar where the y/x coordinate is in range
* because of bars which reach into plot, even when point
* is outside.
*/
do
{
if (start == -1)
start = 0;
else
start = over[i_over++]+1;
end = over[i_over];
while (end<npts)
{
if (err_type==XERROR)
{
/* include some fuzz in comparisons */
if ( xy[2*end+1]<(ylow*(1.0-NUM_FUZZ)) ||
xy[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
if ( err[2*end]<(xlow*(1.0-NUM_FUZZ)) ||
err[2*end+1]>(xhigh*(1.0+NUM_FUZZ))) break;
if ( err[2*end] > xhigh)
err[2*end] = xhigh;
if ( err[2*end+1] < xlow)
err[2*end+1] = xlow;
}
else
{
if ( xy[2*end]<(xlow*(1.0-NUM_FUZZ)) ||
xy[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
if ( err[2*end]<(ylow*(1.0-NUM_FUZZ)) ||
err[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
if ( err[2*end] > yhigh)
err[2*end] = yhigh;
if ( err[2*end+1] < ylow)
err[2*end+1] = ylow;
}
end = over[++i_over];
}
}
while ( (end-start) <= 0 && start<npts );
if (start >= npts) continue;
if (err_type == YERROR)
{
PlotSwitch(plot_drvr,drawYError,(&(xy[2*start]),
&(err[2*start]),
end-start));
}
else
{
PlotSwitch(plot_drvr,drawXError,(&(xy[2*start]),
&(err[2*start]),
end-start));
}
}
while (rc == 0 && end < npts && start < npts);
return rc;
}
static int drawColor2D(display disp)
{
int rc=0;
if (!init_done)
{
initPlot( disp );
init_done = 1;
}
if (disp->zAxis.flags.autoScale) {
disp->zAxis.low = disp->bins.binMin*(1.0-2.0*FLT_EPSILON)-2.0*FLT_MIN;
disp->zAxis.high = disp->bins.binMax*(1.0+2.0*FLT_EPSILON)+2.0*FLT_MIN;
}
PlotSwitch(plot_drvr,drawColor2D,(disp->bins.xAxis.nBins,
disp->bins.yAxis.nBins,
disp->zAxis.low,
disp->zAxis.high,
disp->bins.data,
disp->drawtype & COLOR));
return rc;
}
static int drawScatter2D(display disp)
{
int rc;
int npts;
float *xylist;
struct maxs max;
npts = getScatData( disp, &xylist, &max );
if (npts == 0) return 0;
if (npts < 0)
{
h_error("h_plot - error getting scatter plot data");
return -1;
}
if (disp->xAxis.flags.autoScale)
{
disp->xAxis.low = max.xl;
disp->xAxis.high = max.xh;
h_adjustAxis(&(disp->xAxis.low),&(disp->xAxis.high),
0, disp->xAxis.flags.log);
}
if (disp->yAxis.flags.autoScale)
{
disp->yAxis.low = max.yl;
disp->yAxis.high = max.yh;
h_adjustAxis(&(disp->yAxis.low),&(disp->yAxis.high),
0, disp->yAxis.flags.log);
}
if (!init_done)
{
initPlot( disp );
init_done = 1;
}
switch (plot_drvr)
{
NeXTFunc(drawPointsScat,(xylist,npts,disp->plotSymbol,
disp->symbolSize));
PSFunc(drawPoints,(xylist,npts,disp->plotSymbol,
disp->symbolSize));
UPFunc(drawPoints,(xylist,npts,disp->plotSymbol,
disp->symbolSize));
XIVFunc(drawPoints,(xylist,npts,disp->plotSymbol,
disp->symbolSize));
X11Func(drawPoints,(xylist,npts,disp->plotSymbol,
disp->symbolSize));
default:
rc = -1;
}
free( xylist );
return rc;
}
static int drawLego2D(display disp)
{
int rc;
if (!init_done)
{
initPlot( disp );
init_done = 1;
}
PlotSwitch(plot_drvr,drawLego2D,(disp));
return rc;
}
static int drawScatter3D(display disp)
{
int rc;
int npts;
float *xyzlist;
struct maxs max;
npts = getScatData3D( disp, &xyzlist, &max );
if (npts == 0) return 0;
if (npts < 0)
{
h_error("h_plot - error getting scatter plot data");
return -1;
}
if (disp->xAxis.flags.autoScale)
{
disp->xAxis.low = max.xl;
disp->xAxis.high = max.xh;
h_adjustAxis(&(disp->xAxis.low),&(disp->xAxis.high),
0, disp->xAxis.flags.log);
}
if (disp->yAxis.flags.autoScale)
{
disp->yAxis.low = max.yl;
disp->yAxis.high = max.yh;
h_adjustAxis(&(disp->yAxis.low),&(disp->yAxis.high),
0, disp->yAxis.flags.log);
}
if (disp->zAxis.flags.autoScale)
{
disp->zAxis.low = max.zl;
disp->zAxis.high = max.zh;
h_adjustAxis(&(disp->zAxis.low),&(disp->zAxis.high),
0, disp->zAxis.flags.log);
}
if (!init_done)
{
initPlot( disp );
init_done = 1;
}
PlotSwitch(plot_drvr, drawScatter3D,(disp, xyzlist,npts));
free( xyzlist );
return rc;
}
int h_shade(display disp, float var1, float var2)
/*
* Shade an area of a plot to indicate area. Make sure not
* to outside the bounds of the plot.
*/
{
int rc;
float low, high;
if (disp == NULL) return -1;
low = (var1 - disp->xAxis.low)/(disp->xAxis.high - disp->xAxis.low);
if (low < 0.0) low = 0.0;
low = low * disp->marginRect.size.width + disp->marginRect.origin.x;
high = (var2 - disp->xAxis.low)/(disp->xAxis.high - disp->xAxis.low);
if (high > 1.0) high = 1.0;
high = high * disp->marginRect.size.width + disp->marginRect.origin.x;
switch (plot_drvr)
{
NeXTFunc(shade,(low,high,disp->marginRect.origin.y,
disp->marginRect.origin.y+
disp->marginRect.size.height));
PSFunc(shade,(low,high,disp->marginRect.origin.y,
disp->marginRect.origin.y+
disp->marginRect.size.height));
MACFunc(shade,(low,high,disp->marginRect.origin.y,
disp->marginRect.origin.y+
disp->marginRect.size.height));
XIVFunc(shade,(low,high,disp->marginRect.origin.y,
disp->marginRect.origin.y+
disp->marginRect.size.height));
X11Func(shade,(low,high,disp->marginRect.origin.y,
disp->marginRect.origin.y+
disp->marginRect.size.height));
default:
rc = -1;
}
return rc;
}
typedef struct fp
{
float x,f;
struct fp *n;
} fp;
static fp *pCache(int n );
typedef double (*pfun)( double, double, double *);
static int plotFunc( display disp, func_id func )
{
int yClip = 0;
int i, nCacheUsed;
float ylow, yhigh;
float maxKink, minDelta; /* set limits on how many points to plot */
float delta1;
float delta2, kink;
float ydelta1, ydelta2;
int isover;
double binWidth;
float kinkScale;
float xrange, yrange;
fp *p=NULL, *t;
int *over, *overp;
float *xy, *xyp;
#define NSEG_START 10
if (disp == NULL || func == NULL) return 0;
if (disp->xAxis.high <= disp->xAxis.low)
{
h_error("Plotfunc - xAxis.high <= xAxis.low");
return 0;
}
if (func->lineStyle == LS_INVISIBLE) return 0;
if (disp->graphtype == HISTOGRAM)
binWidth = h_getBinWidth( disp, XAXIS );
else
binWidth = 1.0;
/*
* start from the beginning of the cache of point structures.
*/
nCacheUsed = 0;
/*
* axis ranges including log
*/
if (disp->xAxis.flags.log)
xrange = log10(disp->xAxis.high) - log10(disp->xAxis.low);
else
xrange = disp->xAxis.high - disp->xAxis.low;
if (disp->yAxis.flags.log)
yrange = log10(disp->yAxis.high) - log10(disp->yAxis.low);
else
yrange = disp->yAxis.high - disp->yAxis.low;
/*
* set the resolution depending on whether printing or drawing to screen
*/
if (plot_drvr == PSPLOT
#ifdef _NEXT_PLOT_
|| (plot_drvr == NEXT && NXDrawingStatus != NX_DRAWING)
#endif
)
{
minDelta = xrange / disp->marginRect.size.width;
maxKink = 3.141593/180.0;
}
else
{
minDelta = 7.0 * xrange / disp->marginRect.size.width;
maxKink = 5.0 * 3.141593 / 180.0;
}
kinkScale = disp->marginRect.size.height / yrange
* xrange / disp->marginRect.size.width;
if (init_done || !disp->yAxis.flags.autoScale) yClip = 1;
ylow = FLT_MAX;
yhigh = -FLT_MAX;
delta1 = (disp->xAxis.high - disp->xAxis.low)/((float)NSEG_START);
for (i=0; i<=NSEG_START; i++)
{
if (p == NULL)
p = pCache(nCacheUsed++);
else
{
p->n = pCache(nCacheUsed++);
p = p->n;
}
p->x = disp->xAxis.low + ((float) i) * delta1;
p->f = (*(pfun)(func->funcPtr))((double)p->x, binWidth,
(double *)func->paramBlk);
p->n = NULL;
}
for (p=pCache(0); (p->n)->n != NULL; p = p->n )
{
/*
* This loop is written as an infinite loop with an internal
* break because we always want to calculate delta[12] and kink
* before testing whether to continue, including at the first
* iteration. This seemed like the most compact coding.
*/
while (1)
{
if (disp->xAxis.flags.log)
{
delta2 = log10(((p->n)->n)->x) - log10((p->n)->x);
delta1 = log10((p->n)->x) - log10(p->x);
}
else
{
delta2 = ((p->n)->n)->x - (p->n)->x;
delta1 = (p->n)->x - p->x;
}
if (disp->yAxis.flags.log)
{
ydelta2 = log10(((p->n)->n)->f) - log10((p->n)->f);
ydelta1 = log10((p->n)->f) - log10(p->f);
}
else
{
ydelta2 = ((p->n)->n)->f - (p->n)->f;
ydelta1 = (p->n)->f - p->f;
}
kink = atan(ydelta2 / delta2 * kinkScale) -
atan(ydelta1 / delta1 * kinkScale);
/*
* check the exit condition
*/
if ( fabs(kink) <= maxKink ||
(delta1 <= minDelta && delta2 <= minDelta) )
break;
if (delta1 <= delta2)
{
t = pCache(nCacheUsed++);
t->x = (((p->n)->n)->x + (p->n)->x)/2.0;
t->f = (float)
(*(pfun)(func->funcPtr))((double)t->x, binWidth,
(double *)func->paramBlk);
t->n = (p->n)->n;
(p->n)->n = t;
}
if (delta1 >= delta2)
{
t = pCache(nCacheUsed++);
t->x = ((p->n)->x + p->x)/2.0;
t->f = (float)
(*(pfun)(func->funcPtr))((double)t->x, binWidth,
(double *)func->paramBlk);
t->n = p->n;
p->n = t;
}
}
}
/*
* We now have the complete list of points to plot. Create the
* list of x-y points and overflow flags.
*/
xy = (float *) malloc( 2 * nCacheUsed * sizeof(float) );
over = (int *) malloc( (nCacheUsed+1) * sizeof(int) );
xyp = xy;
overp = over;
for (p=pCache(0), i=0; p != NULL; p = p->n, i++ )
{
isover = 0;
if (disp->xAxis.flags.log)
if (p->x > 0.0)
*xyp++ = log10(p->x);
else
{
isover = 1;
*xyp++ = -FLT_MAX;
}
else
*xyp++ = p->x;
if (disp->yAxis.flags.log)
if (p->f > 0.0)
*xyp++ = log10(p->f);
else
{
isover = 1;
*xyp++ = -FLT_MAX;
}
else
*xyp++ = p->f;
if (isover ||
(yClip && (p->f > disp->yAxis.high || p->f < disp->yAxis.low)))
*overp++ = i;
else
{
if (p->f > yhigh) yhigh = p->f;
if (p->f < ylow && (!disp->yAxis.flags.log || p->f > 0.0))
ylow = p->f;
}
}
*overp++ = i;
/*
* Set scales if it has not been done already.
*/
if (! init_done)
{
if (disp->yAxis.flags.autoScale)
{
disp->yAxis.low = ylow;
disp->yAxis.high = yhigh;
h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
0, disp->yAxis.flags.log );
}
initPlot( disp );
init_done = 1;
}
/*
* plot the line, clean up and we're done!
*/
drawLine1D( disp, xy, over, nCacheUsed, 0, func->lineStyle );
free(xy);
free(over);
return 0;
}
static fp *pCache(int n )
{
static nBlks = 0;
#define FP_BLK 100
static fp **list = NULL;
if (n >= nBlks*FP_BLK)
{
if ( list )
list = (fp **)realloc( list, (nBlks+1) * sizeof(fp *) );
else
list = (fp **)malloc( (nBlks+1) * sizeof(fp *) );
if ( list == NULL)
{
h_error("Plotfunc is out of memory");
return NULL;
}
nBlks++;
if ( (list[nBlks-1] = (fp *)malloc(FP_BLK * sizeof(fp))) == NULL)
{
h_error("Plotfunc is out of memory");
return NULL;
}
}
return &list[n / FP_BLK][n % FP_BLK];
}
/*
* This is the externally callable function.
*/
double h_funcSum( display disp, double x )
{
double sum = 0.0;
func_id fun;
double binWidth;
if (disp->graphtype == HISTOGRAM)
binWidth = h_getBinWidth( disp, XAXIS );
else
binWidth = 1.0;
for (fun = disp->plot_func; fun != NULL; fun = fun->next )
sum += (*(pfun)(fun->funcPtr))(x, binWidth,
(double *)fun->paramBlk);
return sum;
}
/*
* This is the internally callable function for the plotFunc routine.
*/
static double funcSum(double x, double width, double *parm )
{
return h_funcSum( (display)parm, x );
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.