tplot.c

Go to the documentation of this file.
00001 /*                         T P L O T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2012 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * version 2.1 as published by the Free Software Foundation.
00010  *
00011  * This library is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this file; see the file named COPYING for more
00018  * information.
00019  */
00020 /** @addtogroup plot */
00021 /** @{ */
00022 /** @file libbn/tplot.c
00023  *
00024  * @brief
00025  *      This routine is designed to simplify the creation of
00026  *  X, Y plots for user.
00027  *
00028  *                      George W. Hartwig, Jr.
00029  *                              16 March 1979
00030  *
00031  *      This routine is designed to simplify the creation of
00032  * X, Y plots for user. The user need only furnish this program
00033  * the data arrays to be plotted, the lengths of the respective
00034  * axis, titles for the axis, and the point on the page corresponding
00035  * to data point (0, 0).
00036  *      The program will then do everything else required to make
00037  * the plot appear on the user's terminal including scaling of the
00038  * data, centering of the titles and positioning on the page.
00039  *
00040  * where
00041  * -    int xp, yp      page point corresponding to (0, 0) of the data
00042  * -    int xl, yl      lengths of the x and y axis, respectively
00043  * -    char xtitle[], ytitle[] titles for the axis
00044  * -    float x[], y[]  the floating point data arrays
00045  * -    int n           the number of points in the data arrays
00046  *
00047  *              R E V I S I O N  H I S T O R Y
00048  *
00049  *      WHO     WHEN            WHAT
00050  *      GWH     5/21/79         Modified ftoa so that nos. < e-15
00051  *                              map to zero.
00052  *      GWH     6/29/79         Changed the axis drawing loops to
00053  *                              prevent a one tic mark overrun.
00054  *      GWH     7/10/79         Subtracted one from n to allow for the
00055  *                              fact that fortran arrays start at one
00056  *                              and not zero as with c.
00057  */
00058 
00059 #include "common.h"
00060 
00061 /* system headers */
00062 #include <stdio.h>
00063 #include <string.h>
00064 #include <math.h>
00065 
00066 /* interface headers */
00067 #include "vmath.h"
00068 #include "plot3.h"
00069 
00070 
00071 #define TIC             100
00072 #define REF_WIDTH       0.857143
00073 #define NUM_DISTANCE    250
00074 #define LAB_LNGTH       860
00075 
00076 
00077 /**                     T P _ S E P
00078  *@brief
00079  *  tp_sep() divides a floating point number into a coefficient
00080  *  and an exponent. works in base ten.
00081  */
00082 void
00083 tp_sep(float x, float *coef, int *ex)
00084 {
00085     int i, isv;
00086     float xx;
00087 
00088     isv = 1;
00089     if (x < 0.0 ) {
00090         isv = -1;
00091         x = -x;
00092     }
00093 
00094     if ( x > 1.0 ) {
00095         xx = x;
00096         *ex = 0;
00097         *coef = 0.0;
00098 
00099         if ( xx < 10.0) {
00100             *coef = xx*isv;
00101             return;
00102         }
00103 
00104         for ( i=1; i < 39; ++i) {
00105             *ex += 1;
00106             xx = xx/10.0;
00107             if ( xx < 10.0 )
00108                 break;
00109         }
00110         *coef = xx*isv;
00111         return;
00112     } else {
00113         xx = x;
00114         *ex = 0;
00115         *coef = 0.0;
00116         for ( i=1; i<39; ++i) {
00117             *ex -= 1;
00118             xx *= 10.0;
00119             if ( xx >= 1.0 )
00120                 break;
00121         }
00122         *coef = xx*isv;
00123         return;
00124     }
00125 }
00126 
00127 
00128 /**                     T P _ I P O W
00129  *@brief
00130  *  tp_ipow() raises a floating point number to a positve integer
00131  *  power.
00132  *  XXX Horribly inefficient!
00133  */
00134 double tp_ipow (double x, int n)
00135 {
00136     return n>0?x*tp_ipow(x, n-1):1;
00137 }
00138 
00139 
00140 /**                     T P _ F I X S C
00141  *
00142  *   tp_fixsc is a scaling routine intended to be used in conjunction
00143  *   with plotting routines. What tp_fixsc does is scale the user supplied
00144  *   data so that it fits on a specified axis and has 'nice' numbers
00145  *   for labels.
00146  *
00147  *   Calling sequence
00148  *
00149  *   tp_fixsc(x, npts, size, xs, xmin, xmax, dx)
00150  *   where
00151  *
00152  * @param       x[]     the data array to be scaled
00153  * @param       npts    the number of elements in x[]
00154  * @param       size    the length into which x[] is supposed to be fitted
00155  *                      (in inches)
00156  * @param       xs      the returned scale facter to integer space
00157  * @param       xmin    the new minimum value for the data array (a returned
00158  *                      value)
00159  * @param       xmax    the new maximum value for the data array (a returned
00160  *                      value)
00161  * @param       dx      the value in data units between tic marks (a returned
00162  *                      value)
00163  *
00164  */
00165 void
00166 tp_fixsc(float *x,
00167          int npts,
00168          float size,
00169          float *xs,
00170          float *xmin,
00171          float *xmax,
00172          float *dx)
00173 {
00174     float txmi, txma, coef, delta, diff;
00175     int i, ex;
00176 
00177     txmi=txma=x[0];
00178     i = 0;
00179     while ( i <= npts ) {
00180         if ( x[i] < txmi)
00181             txmi = x[i];
00182         if ( x[i] > txma)
00183             txma = x[i];
00184         i++;
00185     }
00186 
00187     diff = txma - txmi;
00188     if ( diff < .000001f )
00189         diff = .000001f;
00190 
00191     tp_sep (diff, &coef, &ex);
00192     if ( coef < 2.0f )
00193         delta = .1f;
00194     else if ( coef < 4.0f )
00195         delta = .2f;
00196     else
00197         delta = .5f;
00198 
00199     i = 0;
00200     if (ex < 0 ) {
00201         ex = -ex;
00202         i=12;
00203     }
00204 
00205     delta *= tp_ipow(10.0, ex);
00206     if (i == 12)
00207         delta = 1.0/delta;
00208     *dx = delta;
00209 
00210     i = (fabs(txmi)/delta);
00211     *xmin = i*delta;
00212     if ( txmi < 0.0f )
00213         *xmin = -(*xmin+delta);
00214 
00215     i = (fabs(txma)/delta);
00216     *xmax = i*delta;
00217     if ( txma < 0.0f)
00218         *xmax = - *xmax;
00219     else
00220         *xmax = *xmax+delta;
00221     *xs = 1000.0f*size/(*xmax - *xmin);
00222 }
00223 
00224 
00225 /**
00226  * @param fp file pointer
00227  * @param xtitle title for the x axis
00228  * @param ytitle title for the y axis
00229  * @param xp is the x page point desired to be (0, 0) for plot
00230  * @param yp is the y page point desired to be (0, 0) for plot
00231  * @param xl is the length of the x axis
00232  * @param yl is the length of the y axis
00233  * @param n is the number of points
00234  * @param cscale is the character scale factor
00235  * @param x the x data
00236  * @param y the y data
00237  */
00238 void
00239 tp_plot(FILE *fp,
00240         int xp,
00241         int yp,
00242         int xl,
00243         int yl,
00244         char *xtitle,
00245         char *ytitle,
00246         float *x,
00247         float *y,
00248         int n,
00249         double cscale)
00250 {
00251     int  ddx = 0, ddy = 0, xend = 0, yend = 0, xpen = 0, ypen = 0;
00252     float fxl = 0.0, fyl = 0.0, xs = 0.0, ys = 0.0, xmin = 0.0, xmax = 0.0, ymin = 0.0, ymax = 0.0, dx = 0.0, dy = 0.0;
00253     float lab = 0.0;
00254     int xtics = 0, ytics = 0, i = 0, xtl = 0, ytl = 0, j = 0;
00255     int ix[101] = {0}, iy[101] = {0}, isave = 0;
00256     char str[32] = {0};
00257 
00258     if ( xl == 0 ) {
00259         j = 0;
00260         goto loop;
00261     }
00262     fxl = xl/1000.0;
00263     fyl = yl/1000.0;
00264     n -= 1; /* allow for the fact that fortran starts arrays at 1 */
00265     tp_fixsc (x, n, fxl, &xs, &xmin, &xmax, &dx);
00266     tp_fixsc (y, n, fyl, &ys, &ymin, &ymax, &dy);
00267     ddx = dx*xs;
00268     ddy = dy*ys;
00269     xtics = LAB_LNGTH / ddx + 1.0;
00270     ytics = 500/ddy + 1.0;
00271     xend = xl+xp;
00272     xpen = xp;
00273 
00274     pl_move(fp, xpen, yp-TIC);
00275     pl_cont(fp, xpen, yp);
00276 
00277     /* label first tic */
00278     lab = xmin;
00279     snprintf( str, 32, "%3.3g", xmin );
00280     tp_2symbol( fp, str, (double)(xpen-171), (double)(yp-TIC-NUM_DISTANCE), cscale, 0.0);
00281 
00282     i = 0;
00283     while ((xpen+ddx)<=xend) {
00284         i++;
00285         xpen += ddx;
00286         pl_line( fp, xpen, yp, xpen, yp-TIC );
00287         /* while here label this tic mark if no overlapping will occur */
00288         lab += dx;
00289         /* need if test here to check for overlap */
00290         if ( (i%xtics) == 0) {
00291             snprintf( str, 32, "%3.3g", lab );
00292             tp_2symbol( fp, str, (double)(xpen-171), (double)(yp-TIC-NUM_DISTANCE), cscale, 0.0);
00293         }
00294     }
00295 
00296     /* insert axis label here */
00297     xtl = xp+(xl - strlen(xtitle)*cscale)/2;
00298     ytl = yp - 8 * cscale;
00299     tp_2symbol( fp, xtitle, (double)xtl, (double)ytl, 100.0, 0.0);
00300     yend = yl+yp;
00301     ypen= yp;
00302     pl_line( fp, xp-TIC, ypen, xp, ypen );
00303 
00304     /* draw first y label */
00305     lab = ymin;
00306     snprintf( str, 32, "%3.3g", lab );
00307     tp_2symbol( fp, str, (double)(xp-TIC-LAB_LNGTH-NUM_DISTANCE), (double)ypen, cscale, 0.0);
00308 
00309     i=0;
00310     while ((ypen+ddy)<=yend) {
00311         i++;
00312         ypen += ddy;
00313         pl_line( fp, xp, ypen, xp-TIC, ypen );
00314         /* label the y-axis now, nicely */
00315         lab += dy;
00316         if (( i%ytics) ==0) {
00317             snprintf( str, 32, "%3.3g", lab );
00318             tp_2symbol( fp, str, (double)(xp-TIC-LAB_LNGTH-NUM_DISTANCE), (double)ypen, cscale, 0.0);
00319         }
00320     }
00321 
00322     /* insert y-axis title here */
00323     xtl= xp-1500;
00324     ytl= yp + (yl - strlen(ytitle)*cscale)/2;
00325     tp_2symbol( fp, ytitle, (double)xtl, (double)ytl, 100.0, 90.0);
00326 
00327     /* now at long last plot the data */
00328     j = 0;
00329 
00330 loop:
00331     if ( n <= 100 ) {
00332         isave = n-1;
00333     } else {
00334         isave = 100;
00335         n -= 101;
00336     }
00337 
00338     if (j == 0) {
00339         ix[0] = (x[j] - xmin)*xs + xp;
00340         iy[0] = (y[j] - ymin)*ys + yp;
00341         j++;
00342     } else {
00343         ix[0] = (x[j-1] - xmin)*xs + xp;
00344         iy[0] = (y[j-1] - ymin)*ys + yp;
00345     }
00346 
00347     i = 1;
00348     while ( i <= isave ) {
00349         ix[i] = (x[j] - xmin)*xs + xp;
00350         iy[i] = (y[j] - ymin)*ys + yp;
00351         i++;
00352         j++;
00353     }
00354     tp_i2list( fp, ix, iy, isave+1 );
00355     if ( isave == 100 ) {
00356         goto loop;
00357     }
00358 }
00359 
00360 
00361 /**                     T P _ F T O A
00362  * @brief
00363  * This routine converts a floating point number into a string
00364  * of ascii characters of the form "sX.XXXesXX". The string is
00365  * null terminated.
00366  */
00367 void
00368 tp_ftoa(float x, char *s)
00369 {
00370     int ex, tmp;
00371     float coef;
00372     char esgn, nsgn;
00373     char i;
00374 
00375     tp_sep(x, &coef, &ex);
00376     if ( ex < -15 ) {
00377         ex = 0;
00378         *s++ = '0';
00379         *s++ = '.';
00380         *s++ = '0';
00381         *s++ = '0';
00382         *s++ = '0';
00383         *s++ = 'e';
00384         *s++ = '+';
00385         *s++ = '0';
00386         *s++ = '0';
00387         *s   =  0;
00388         return;
00389     }
00390 
00391     if (ex < 0) {
00392         esgn = '-';
00393         ex = -ex;
00394     } else {
00395         esgn = '+';
00396     }
00397 
00398     if ( coef < 0.0) {
00399         nsgn = '-';
00400         coef = -coef;
00401     } else {
00402         nsgn = ' ';
00403     }
00404     *s++ = nsgn;
00405 
00406     /* load the first numeral and the decimal point */
00407     tmp = coef;
00408     *s++ = tmp + '0';
00409     coef = (coef - tmp)*10.0;
00410     *s++ = '.';
00411 
00412     /* now do the three after the decimal */
00413     for ( i=1; i<=3; ++i) {
00414         tmp = coef;
00415         coef = (coef - tmp)*10.0;
00416         *s++ = tmp + '0';
00417     }
00418 
00419     /* put the e in */
00420     *s++ = 'e';
00421 
00422     /* the sign for the exponent */
00423     *s++ = esgn;
00424 
00425     /* and the exponent */
00426     if ( ex < 0)
00427         ex = -ex;
00428 
00429     if ( ex < 10 ) {
00430         *s++ = '0';
00431         *s++ = ex + '0';
00432     } else {
00433         tmp = ex/10;
00434         *s++ = tmp + '0';
00435         ex = ex - tmp*10;
00436         *s++ = ex +'0';
00437     }
00438     /* add a null byte terminator */
00439     *s = 0;
00440 }
00441 
00442 
00443 /**
00444  *      FORTRAN Interface Entry
00445  */
00446 void
00447 PL_FORTRAN(fplot, FPLOT)(FILE **fp, int *xp, int *yp, int *xl, int *yl, char *xtitle, char *ytitle, float *x, float *y, int *n, float *cscale)
00448 {
00449     tp_plot(*fp, *xp, *yp, *xl, *yl, xtitle, ytitle, x, y, *n, *cscale);
00450 }
00451 
00452 /** @} */
00453 /*
00454  * Local Variables:
00455  * mode: C
00456  * tab-width: 8
00457  * indent-tabs-mode: t
00458  * c-file-style: "stroustrup"
00459  * End:
00460  * ex: shiftwidth=4 tabstop=8
00461  */
Generated on Tue Dec 11 13:14:28 2012 for LIBBN by  doxygen 1.6.3