/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
/* PROC AXIS - Draw an X or Y axis. astart parameter allows areadef xaxis.* or yaxis.* parameters */
/* Coded for Y axis.. axes are logically flipped when drawing an X axis */
#include "pl.h"
#define INCREMENTAL 1
#define HERE 2
#define FROMFILE 3
#define FROMDATA 4
#define FROMCATS 5
#define MONTHS 100
int
PLP_axis( xory, astart )
char xory; /* either 'x' or 'y' */
int astart;
{
int i;
char attr[NAMEMAXLEN], val[256];
char *line, *lineval;
int nt, lvp;
int first;
int stat;
int align;
double adjx, adjy;
char buf[256];
int j;
char opax;
double y;
double f;
double pos; /* distance of axis in absolute units from scale-0 */
double stubstart, stubstop; /* start and stop of stubs and tics in data units */
double inc;
char tics[256]; /* details of tic lines */
double ticin, ticout; /* length of tic into plot area and outward */
char mtics[256]; /* details of minor tic lines */
double minorticinc; /* inc for minor tics */
double mticin, mticout; /* length of minor tic into plot area and outward */
char axisline[256]; /* axis line details */
char stubdetails[256]; /* stub text details and on/off */
char txt[256]; /* general */
char stubformat[80];
int isrc;
FILE *stubfp;
double axlinestart, axlinestop;
double max, min;
char axislabel[300];
char axislabeldet[256];
double axislabelofs;
int stubreverse;
char grid[256];
int vertstub;
int irow;
double ofsx, ofsy;
char stubomit[256];
int mon, day, yr;
int stubdf1, stubdf2, nstubdf;
int selfloc;
char filename[256];
double incamount, ticincamount;
char incunits[50], ticincunits[50], minorticunits[50];
int ibb;
double overrun;
int bigbuflen;
int doingtics;
int stubrangegiven;
int stubreverse_given;
int specialunits;
int doinggrid;
double stubslide;
char scaleunits[30];
char gridskip[20];
char scalesubtype[20];
char autoyears[20];
int firsttime;
double ticslide;
int revsign;
char glemins[40], glemaxs[40];
double glemin, glemax;
char gbcolor1[COLORLEN], gbcolor2[COLORLEN];
double gbylast;
int gbstate;
double stubcull, prevstub;
int stubevery;
int forlen;
char clickmap;
double cmylast, cmemin, cmemax;
char cmemins[40], cmemaxs[40];
char cmvalfmt[80], cmtxt[100];
int logx, logy, stubexp;
int stublen;
char autodays[40], automonths[40];
char labelurl[256], labelinfo[MAXTT];
double stubmult;
double stubmininc;
char firststub[80], laststub[80];
char stubsubpat[80], stubsubnew[80];
int sanecount, stubhide;
int curyr, curday, curmon;
int circuit_breaker_disable;
int axis_arrow;
double arrowheadsize;
char nearest[30];
char stubround[30];
int prec;
TDH_errprog( "pl proc axis" );
if( xory == 'x' ) opax = 'y';
else if( xory == 'y' ) opax = 'x';
else { Eerr( 301, "axis: bad xory", "" ); xory = 'x'; opax = 'y'; }
/* initialize */
min = Elimit( xory, 'l', 's' );
max = Elimit( xory, 'h', 's' );
pos = Elimit( opax, 'l', 'a' ); /* location will be at minima of other axis */
stubstart = axlinestart = min;
stubstop = axlinestop = max;
ticin = 0;
ticout = 0.07;
strcpy( axisline, "" );
strcpy( tics, "" );
strcpy( mtics, "none" );
minorticinc = 0.0;
mticin = 0;
mticout = 0.03;
strcpy( stubformat, "" );
strcpy( PL_bigbuf, "" );
strcpy( stubdetails, "" );
strcpy( axislabel, "" );
strcpy( axislabeldet, "" );
axislabelofs = 0.4;
stubreverse = 0;
strcpy( grid, "none" );
/* isrc = INCREMENTAL; */
isrc = 0;
incamount = 0.0;
ticincamount = 0.0;
vertstub = 0;
nstubdf = 0;
strcpy( stubomit, "" );
doingtics = 1;
selfloc = 0;
stubrangegiven = 0;
stubreverse_given = 0;
doinggrid = 0;
stubslide = 0.0;
ticslide = 0.0;
strcpy( gridskip, "" );
strcpy( autoyears, "" );
revsign = 0;
strcpy( glemins, "min" ); strcpy( glemaxs, "max" );
strcpy( gbcolor1, "" );
strcpy( gbcolor2, "white" );
stubcull = 0.0;
stubevery = 1;
clickmap = 0;
strcpy( cmemins, "min" ); strcpy( cmemaxs, "max" );
strcpy( cmvalfmt, "" );
stubexp = 0; stublen = 0;
strcpy( autodays, "" ); strcpy( automonths, "" );
strcpy( labelurl, "" ); strcpy( labelinfo, "" );
stubmult = 1.0; stubmininc = 0.0;
strcpy( firststub, "" ); strcpy( laststub, "" );
strcpy( stubsubpat, "" ); strcpy( stubsubnew, "" );
stubhide = 0;
curyr = curmon = curday = 0;
circuit_breaker_disable = 0;
axis_arrow = 0;
arrowheadsize = 0.15;
strcpy( nearest, "" );
strcpy( stubround, "" );
Egetunits( xory, scaleunits ); /* moved from below - scg 1/27/05 */
/* get attributes.. */
first = 1;
while( 1 ) {
line = getnextattr( first, attr, val, &lvp, &nt );
if( line == NULL ) break;
first = 0;
lineval = &line[lvp];
/* screen out areadef attributes for the other axis.. */
if( GL_slmember( attr, "axisline tic* minortic*" )) ;
else if( astart > 0 && strnicmp( &attr[1], "axis.", 5 )!=0 ) continue;
else if( astart > 0 && tolower(attr[0]) != xory ) continue;
if( stricmp( &attr[astart], "label" )==0 ) {
strcpy( axislabel, lineval );
convertnl( axislabel );
}
else if( stricmp( &attr[astart], "labelurl" )==0 ) strcpy( labelurl, val );
else if( stricmp( &attr[astart], "labelinfo" )==0 ) strcpy( labelinfo, lineval );
else if( stricmp( attr, "labelinfotext" )==0 ) {
if( PLS.clickmap ) { getmultiline( "labelinfotext", lineval, MAXTT, labelinfo ); }
}
else if( stricmp( &attr[astart], "stubs" )==0 || stricmp( &attr[astart], "selflocatingstubs" )==0 ) {
if( stricmp( &attr[astart], "selflocatingstubs" )==0 ) selfloc = 1;
else selfloc = 0;
if( strnicmp( val, "inc", 3 )==0 || GL_slmember( val, "dat*matic" )) {
isrc = INCREMENTAL;
strcpy( incunits, "" );
nt = sscanf( lineval, "%*s %lf %s", &incamount, incunits );
if( nt < 1 || incamount == 0.0 ) {
if( strncmp( scaleunits, "date", 4 )== 0 || strcmp( scaleunits, "time" )==0 ) {
DT_reasonable( scaleunits, min, max, &incamount, incunits, stubformat, automonths,
autoyears, autodays, &minorticinc, minorticunits, nearest );
}
else incamount = 0.0;
}
}
else if( stricmp( val, "minmaxonly" )==0 ) {
isrc = INCREMENTAL;
incamount = max - min;
}
else if( stricmp( val, "minonly" )==0 ) {
isrc = INCREMENTAL;
incamount = (max - min) * 2.0;
}
else if( stricmp( val, "maxonly" )==0 ) {
isrc = INCREMENTAL;
stubstart = max;
incamount = (max - min) * 2.0;
}
else if( stricmp( val, "file" )==0 ) {
isrc = FROMFILE;
strcpy( filename, "" );
nt = sscanf( lineval, "%*s %s", filename );
if( nt < 1 ) {
Eerr( 2796, "usage: stub: file filename", "" );
isrc = INCREMENTAL;
}
}
else if( strnicmp( val, "datafield", 9 ) ==0 ) {
char fnames[2][50];
isrc = FROMDATA;
for( j = 0, forlen = strlen( lineval ); j < forlen; j++ ) /* allow = and , */
if( GL_member( lineval[j], "=," )) lineval[j] = ' ';
nstubdf = sscanf( lineval, "%*s %s %s", fnames[0], fnames[1] );
if( nstubdf < 1 ) {
Eerr( 2795, "usage: stub: datafields=a,[b] where a and b are dfields", "" );
isrc = INCREMENTAL;
}
if( nstubdf > 0 ) stubdf1 = fref( fnames[0] );
if( nstubdf == 2 ) stubdf2 = fref( fnames[1] );
}
else if( stricmp( val, "categories" )==0 || stricmp( val, "usecategories" )==0 ) isrc = FROMCATS;
else if( stricmp( val, "list" )==0 ) {
isrc = HERE;
i = 0;
GL_getchunk( buf, lineval, &i, " \t" );
while( GL_member( lineval[i], " \t" ) ) i++;
strcpy( PL_bigbuf, &lineval[i] );
convertnl( PL_bigbuf );
}
else if( stricmp( val, "none" )==0 ) isrc = 0;
else {
isrc = HERE;
if( stricmp( val, "text" ) == 0 ) {
getmultiline( "stubs", "", MAXBIGBUF, PL_bigbuf );
}
else {
fprintf( PLS.errfp,
"warning: proc axis assuming multiline stub text even though 'text' keyword not given\n" );
getmultiline( "stubs", lineval, MAXBIGBUF, PL_bigbuf );
}
}
}
else if( stricmp( &attr[astart], "stubformat" )==0 ) strcpy( stubformat, lineval );
else if( stricmp( &attr[astart], "stubdetails" )==0 ) strcpy( stubdetails, lineval );
else if( stricmp( &attr[astart], "stubrange" )==0 ) {
getrange( lineval, &stubstart, &stubstop, xory, min, max );
stubrangegiven = 1;
}
else if( stricmp( &attr[astart], "stubround" )==0 ) strcpy( stubround, val ); /* added 5/29/06 scg */
else if( stricmp( &attr[astart], "stubreverse" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 )stubreverse = 1;
else stubreverse = 0;
stubreverse_given = 1;
}
else if( stricmp( &attr[astart], "stubvert" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) vertstub = 1;
else vertstub = 0;
}
else if( stricmp( &attr[astart], "stubomit" )==0 ) strcpy( stubomit, lineval );
else if( stricmp( &attr[astart], "stubslide" )==0 ) Elenex( val, xory, &stubslide );
else if( stricmp( &attr[astart], "stubexp" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) stubexp = 1;
else if( stricmp( val, "exp-1" )==0 ) stubexp = 2;
else stubexp = 0;
}
else if( stricmp( &attr[astart], "stublen" )==0 ) stublen = atoi( val );
else if( stricmp( &attr[astart], "stubmult" )==0 ) stubmult = atof( val );
else if( stricmp( &attr[astart], "stubmininc" )==0 ) stubmininc = atof( val );
else if( stricmp( &attr[astart], "stubhide" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) stubhide = 1;
else stubhide = 0;
}
else if( stricmp( &attr[astart], "ticslide" )==0 ) Elenex( val, xory, &ticslide );
else if( stricmp( &attr[astart], "labeldetails" )==0 ) strcpy( axislabeldet, lineval );
else if( stricmp( &attr[astart], "labeldistance" )==0 ) {
axislabelofs = atof( val );
if( PLS.usingcm ) axislabelofs /= 2.54;
}
else if( stricmp( &attr[astart], "location" )==0 ) {
Eposex( val, opax, &f );
pos = f;
}
else if( stricmp( &attr[astart], "axisline" )==0 ) {
if( strnicmp( val, "no", 2 )==0 ) strcpy( axisline, "none" );
else strcpy( axisline, lineval );
}
else if( stricmp( &attr[astart], "axislinerange" )==0 ) {
getrange( lineval, &axlinestart, &axlinestop, xory, min, max );
}
else if( stricmp( &attr[astart], "tics" )==0 ) {
strcpy( tics, lineval );
if( strnicmp( tics, "no", 2 ) != 0 ) doingtics = 1;
else doingtics = 0;
}
else if( stricmp( &attr[astart], "ticincrement" )==0 ) {
strcpy( ticincunits, "" );
sscanf( lineval, "%lf %s", &ticincamount, ticincunits );
}
else if( stricmp( &attr[astart], "ticlen" )==0 ) {
sscanf( lineval, "%lf %lf", &ticout, &ticin );
if( PLS.usingcm ) { ticout /= 2.54; ticin /= 2.54; }
}
else if( stricmp( &attr[astart], "minortics" )==0 ) {
if( strnicmp( val, "no", 2 )==0 ) { strcpy( mtics, "none" ); minorticinc = 0.0; } /* set ticinc = 0 scg 1/28/05 */
else strcpy( mtics, lineval );
}
else if( stricmp( &attr[astart], "minorticinc" )==0 ) {
strcpy( minorticunits, "" );
nt = sscanf( lineval, "%lf %s", &minorticinc, minorticunits );
}
else if( stricmp( &attr[astart], "minorticlen" )==0 ||
stricmp( attr, "minorticlen" )==0 ) {
sscanf( lineval, "%lf %lf", &mticout, &mticin );
if( PLS.usingcm ) { mticout /= 2.54; mticin /= 2.54; }
}
else if( stricmp( &attr[astart], "grid" )==0 ) {
strcpy( grid, lineval );
if( strnicmp( grid, "no", 2 )!= 0 ) doinggrid = 1;
}
else if( stricmp( &attr[astart], "gridskip" )==0 ) strcpy( gridskip, val );
else if( stricmp( &attr[astart], "gridlineextent" )==0 ) {
nt = sscanf( lineval, "%s %s", glemins, glemaxs );
}
else if( stricmp( &attr[astart], "gridblocks" )==0 ) {
nt = sscanf( lineval, "%s %s", gbcolor1, gbcolor2 );
if( stricmp( gbcolor1, "no" )==0 || stricmp( gbcolor1, "none" )==0 ) strcpy( gbcolor1, "" );
else doinggrid = 1;
}
else if( stricmp( &attr[astart], "stubcull" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) stubcull = 0.1;
else if( atof( val ) > 0.0 ) stubcull = atof( val );
else stubcull = 0.0;
}
else if( stricmp( &attr[astart], "autoyears" )==0 ) {
strcpy( autoyears, val );
if( stricmp( autoyears, "yes" )==0 || stricmp( autoyears, "y" )==0 ) strcpy( autoyears, "'yy" );
else if( stricmp( autoyears, "no" )==0 ) strcpy( autoyears, "" );
}
else if( stricmp( &attr[astart], "autodays" )==0 ) {
strcpy( autodays, val );
if( stricmp( autodays, "yes" )==0 || stricmp( autodays, "y" )==0 ) strcpy( autodays, "Mmmdd" );
else if( stricmp( autodays, "no" )==0 ) strcpy( autodays, "" );
}
else if( stricmp( &attr[astart], "automonths" )==0 ) {
strcpy( automonths, val );
if( stricmp( automonths, "yes" )==0 || stricmp( automonths, "y" )==0 ) strcpy( automonths, "Mmm" );
else if( stricmp( automonths, "no" )==0 ) strcpy( automonths, "" );
}
else if( stricmp( &attr[astart], "signreverse" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 )revsign = 1;
else revsign = 0;
}
else if( stricmp( &attr[astart], "stubevery" )==0 ) stubevery = atoi( val );
else if( stricmp( &attr[astart], "firststub" )==0 ) {
strcpy( firststub, lineval );
if( strcmp( firststub, "\"\"" )==0 ) strcpy( firststub, " " );
}
else if( stricmp( &attr[astart], "laststub" )==0 ) {
strcpy( laststub, lineval );
if( strcmp( laststub, "\"\"" )==0 ) strcpy( laststub, " " );
}
else if( stricmp( &attr[astart], "stubsubpat" )==0 ) strcpy( stubsubpat, lineval );
else if( stricmp( &attr[astart], "stubsubnew" )==0 ) {
strcpy( stubsubnew, lineval );
if( strcmp( stubsubnew, "\"\"" )==0 ) strcpy( stubsubnew, " " );
}
else if( stricmp( &attr[astart], "clickmap" )==0 ) {
if( strnicmp( val, "xy", 2 )==0 ) {
if( xory == 'x' ) clickmap = 3;
else clickmap = 4;
}
else {
if( xory == 'x' ) clickmap = 1;
else clickmap = 2;
}
}
else if( stricmp( &attr[astart], "clickmapextent" )==0 ) nt = sscanf( lineval, "%s %s", cmemins, cmemaxs );
else if( stricmp( &attr[astart], "clickmapvalformat" )==0 ) strcpy( cmvalfmt, lineval );
else if( stricmp( &attr[astart], "nolimit" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) circuit_breaker_disable = 1;
}
else if( stricmp( &attr[astart], "arrow" )==0 ) {
if( strnicmp( val, YESANS, 1 )==0 ) axis_arrow = 1;
}
else if( stricmp( &attr[astart], "arrowheadsize" )==0 ) {
arrowheadsize = atof( val );
if( PLS.usingcm ) arrowheadsize /= 2.54;
}
else if( astart == 0 || strnicmp( attr, "xaxis.", 6 )==0 ||
strnicmp( attr, "yaxis.", 6 )==0 )
Eerr( 301, "axis attribute not recognized", attr );
}
/* check for degenerate cases and control overrides.. */
if( !scalebeenset() )
return( Eerr( 51, "No scaled plotting area has been defined yet w/ proc areadef", "" ) );
if( stubstart < min || stubstart > max ) stubstart = min;
if( stubstop > max || stubstop < min ) stubstop = max;
if( axlinestart < min || axlinestart > max ) axlinestart = min;
if( axlinestop > max || axlinestop < min ) axlinestop = max;
if( stubevery == 0 ) stubevery = 1;
/* -------------------------- */
/* now do the plotting work.. */
/* -------------------------- */
/* Egetunits( xory, scaleunits ); */ /* moved up - scg 1/27/05 */
/* do the label.. easier if we do it before the Eflip below.. */
if( axislabel[0] != '\0' ) {
double xpos, ypos, txtsize;
textdet( "labeldetails", axislabeldet, &align, &adjx, &adjy, 0, "R", 1.0 );
txtsize = (double)(strlen( axislabel )) * Ecurtextwidth;
if( xory == 'x' ) {
xpos = ( EXlo+ (( EXhi - EXlo ) / 2.0 )) + adjx;
ypos = (pos - axislabelofs) + adjy;
Emov( xpos, ypos );
Ecentext( axislabel );
if( PLS.clickmap && ( labelurl[0] != '\0' || labelinfo[0] != '\0' ) )
clickmap_entry( 'r', labelurl, 0, xpos - (txtsize/2.0), ypos,
xpos + (txtsize/2.0), ypos+Ecurtextheight, 1, 0, labelinfo );
}
else if( xory == 'y' ) {
xpos = (pos - axislabelofs) + adjx;
ypos = (EYlo + (( EYhi-EYlo ) / 2.0 )) + adjy;
Emov( xpos, ypos );
Etextdir( 90 );
Ecentext( axislabel );
Etextdir( 0 );
if( PLS.clickmap && ( labelurl[0] != '\0' || labelinfo[0] != '\0' ) )
clickmap_entry( 'r', labelurl, 0, xpos-Ecurtextheight, ypos - (txtsize*0.6),
xpos, ypos + (txtsize*0.6), 0, 0, labelinfo );
}
}
if( xory == 'x' ) Eflip = 1; /* reverse sense of x and y for draw operations */
/* avoid "circuit breaker" message when just doing label and/or line.. added scg 5/24/06 */
if( isrc == 0 && !doingtics && !doinggrid ) goto SKIPLOOP;
/* --------------------- */
/* tics and axis preliminaries.. */
/* --------------------- */
inc = 1.0;
overrun = inc / 10.0;
specialunits = 0;
/* ----------------- */
/* helpful overrides */
/* ----------------- */
/* if user didn't specify stub range, and
if isrc indicates text stubs, and not doing stubreverse, start at 1.0 */
if( !stubrangegiven && !stubreverse && !selfloc &&
( isrc == HERE || isrc == FROMFILE || isrc == FROMDATA ) ) stubstart = 1.0;
/* if doing Y axis with text stubs, and user didn't specify stubreverse: no,
reverse the stubs */
if( xory == 'y' && !stubreverse_given && stubreverse == 0 &&
( isrc == HERE || isrc == FROMFILE || isrc == FROMDATA ) && !selfloc ) { /* && !selfloc added scg 3/19/03 */
stubreverse = 1;
if( !stubrangegiven ) stubstop = max - 1.0;
}
if( stubformat[0] != '\0' && isrc == 0 )
Eerr( 2749, "warning, stubformat but no stubs specification", "" );
/* if( strncmp( scaleunits, "date", 4 )==0 && stubformat[0] == '\0' )
* Eerr( 319, "warning, no stubformat specified.. using current notation.. for better results try 'stubs: datematic'", "" );
*/
if( minorticinc > 0.0 && strnicmp( mtics, "no", 2 ) == 0 ) strcpy( mtics, "yes" );
/* compute abs grid line extent - added scg 11/22/00 */
if( doinggrid ) {
Eposex( glemins, opax, &glemin );
Eposex( glemaxs, opax, &glemax );
/* Eposex( "min", Y, &gbylast ); changed to below 5/17/01 */
Eposex( "min", xory, &gbylast );
gbstate = 0;
}
if( PLS.clickmap && clickmap ) {
Eposex( cmemins, opax, &cmemin );
Eposex( cmemaxs, opax, &cmemax );
Eposex( "min", xory, &cmylast );
}
/* stubround stuff.. added scg 5/29/06 */
if( stubround[0] != '\0' ) { /* stubround is useful when user requires min and max to be at exact oddball locations,
* but want the stubs to fall on round locations. Shouldn't come into play with 'datematic'
* since dm sets min and max to round (nearest) locations. */
char minval[40], maxval[40];
double ninc;
if( GL_smember( scaleunits, "date datetime time" )) {
Euprint( buf, xory, stubstart, "" );
PLP_findnearest( buf, buf, xory, stubround, minval, maxval );
stubstart = Econv( xory, maxval );
}
else if( stricmp( stubround, "useinc" )==0 ) { /* base it on whatever the axis increment value is/will be.. */
if( incamount > 0.0 ) stubstart = GL_numgroup( stubstart, incamount, "high" );
else {
PL_defaultinc( min, max, &ninc );
stubstart = GL_numgroup( stubstart, ninc, "high" );
}
}
else if( GL_goodnum( stubround, &prec )) stubstart = GL_numgroup( stubstart, atof( stubround ), "high" );
}
/* render minor tics.. */
if( isrc == INCREMENTAL && strnicmp( mtics, "no", 2 )!= 0 ) {
/* unit conversions.. */
if( stricmp( scaleunits, "time" )==0 && strnicmp( minorticunits, "hour", 4 ) ==0 ) {
strcpy( minorticunits, "" );
minorticinc = minorticinc * 60;
}
else if( stricmp( scaleunits, "datetime" )==0 &&
(strnicmp( minorticunits, "hour", 4 ) ==0 || strnicmp( minorticunits, "minute", 3 )==0 )) {
double winsize, mm; /* window size in hours */
DT_getwin( &winsize );
mm = ((24.0/winsize) / 24.0);
if( strnicmp( minorticunits, "minute", 3 )==0 ) mm /= 60.0;
minorticinc *= mm;
/* minorticinc = minorticinc / winsize;
* if( strnicmp( minorticunits, "minute", 3 )==0 ) minorticinc = minorticinc / 60.0;
* strcpy( minorticunits, "" );
*/
}
else if( stricmp( scaleunits, "time" )==0 && strnicmp( minorticunits, "second", 3 ) ==0 ) {
strcpy( minorticunits, "" );
minorticinc = minorticinc / 60.0;
}
else if( stricmp( scaleunits, "date" )==0 && strnicmp( minorticunits, "year", 4 ) ==0 ) {
strcpy( minorticunits, "month" );
minorticinc = minorticinc * 12;
}
else if( stricmp( scaleunits, "date" )==0 && strnicmp( minorticunits, "month", 5 ) ==0 ) {
strcpy( minorticunits, "month" );
minorticinc = minorticinc * (365.25/12.0);
}
linedet( "minortics", mtics, 0.5 );
if( minorticinc <= 0.0 ) {
Eerr( 2340, "warning, minorticinc must be specified if doing minor tics", "" );
minorticinc = 1.0;
}
y = stubstart;
while( 1 ) {
Emov( pos-mticout, Ea( Y, y ) );
Elin( pos+mticin, Ea( Y, y ) );
y += minorticinc;
if( y >= stubstop ) break;
}
}
/* --------------------------------- */
/* preliminaries based on stubs type */
/* --------------------------------- */
if( isrc == HERE ) bigbuflen = strlen( PL_bigbuf );
if( isrc == FROMFILE ) { /* if taking from file, read the file into PL_bigbuf */
stubfp = fopen( filename, "r" );
if( stubfp == NULL ) {
Eerr( 303, "warning, cannot open specified stub file.. using incremental stubs.", filename );
isrc = INCREMENTAL; /* fallback */
}
else {
i = 0;
while( fgets( buf, 128, stubfp ) != NULL ) {
strcpy( &PL_bigbuf[i], buf );
i += strlen( buf );
}
fclose( stubfp );
bigbuflen = i;
}
}
if( isrc == FROMDATA ) {
if( nstubdf >= 1 ) stubdf1--; /* off-by-one */
if( nstubdf >= 2 ) {
stubdf2--;
nstubdf = 2;
}
}
if( isrc == FROMCATS ) selfloc = 0; /* for rendering purposes don't treat category stubs as self locating */
if( isrc == 0 && (doingtics || doinggrid) ) { /* no stubs but doing tics or doing grid */
strcpy( incunits, ticincunits );
incamount = ticincamount;
}
/* incunit conversions.. */
if( stricmp( scaleunits, "time" )==0 && strnicmp( incunits, "hour", 4 ) ==0 ) {
strcpy( incunits, "" );
incamount = incamount * 60.0;
}
else if( stricmp( scaleunits, "datetime" )==0 &&
( strnicmp( incunits, "hour", 4 ) ==0 || strnicmp( incunits, "minute", 3 )==0 )) {
double winsize; /* window size in hours */
/* must be relative to window size.. */
DT_getwin( &winsize );
incamount = incamount / winsize;
if( strnicmp( incunits, "minute", 3 )==0 ) incamount = incamount / 60.0;
strcpy( incunits, "" );
/* incamount = incamount / 24.0; */
}
else if( stricmp( scaleunits, "datetime" )==0 && strnicmp( incunits, "minute", 3 ) ==0 ) {
strcpy( incunits, "" );
incamount = (incamount / 24.0) / 60.0;
}
else if( stricmp( scaleunits, "time" )==0 && strnicmp( incunits, "second", 3 ) ==0 ) {
strcpy( incunits, "" );
incamount = incamount / 60.0;
}
else if( stricmp( scaleunits, "date" )==0 && strnicmp( incunits, "year", 4 ) ==0 ) {
strcpy( incunits, "month" );
incamount = incamount * 12;
}
else if( strnicmp( incunits, "month", 5 )!=0 &&
atof( incunits ) == 0.0 ) strcpy( incunits, "" ); /* prevent racecon */
Egetunitsubtype( xory, scalesubtype );
/* yymm (etc) implies inc unit of "months" (yy implies years) */
if( scalesubtype[0] != '\0' ) {
if( GL_slmember( scalesubtype, "yymm yy?mm yyyy?mm mm?yy mm?yyyy" ) && incunits[0] == '\0' )
strcpy( incunits, "month" );
if( stricmp( scalesubtype, "yy" )==0 && incunits[0] == '\0' )
strcpy( incunits, "year" );
}
if( isrc == INCREMENTAL || ( isrc == 0 && (doingtics || doinggrid )) ) {
/* for special units, initialize */
if( strnicmp( incunits, "month", 5 )==0 ) {
long l;
if( ! GL_smember( scaleunits, "date datetime" )) /* changed to include datetime as well as date - scg 8/11/05 */
return( Eerr( 2476, "month increment only valid with date or datetime scale type", "" ) );
specialunits = MONTHS;
selfloc = 0; /* for rendering purposes don't treat month stubs as self locating.. */
/* do the following to get starting m, d, y.. */
Euprint( buf, xory, stubstart, "" );
stat = DT_jdate( buf, &l );
DT_getmdy( &mon, &day, &yr );
if( incamount > 0.0 ) inc = incamount;
else inc = 1; /* added scg 3/29 */
}
else if( stricmp( scaleunits, "datetime" )==0 &&
strnicmp( incunits, "hour", 4 ) ==0 ) {
inc = incamount / 24.0;
}
else {
if( incamount > 0.0 ) {
if( incunits[0] == '\0' ) inc = incamount;
else {
double ftest;
sscanf( incunits, "%lf", &ftest );
inc = incamount * ftest;
/* inc = incamount * atof( incunits ); repl scg 5/23/00 */
}
}
else {
/* try to be smart about choosing default inc */
PL_defaultinc( min, max, &inc );
if( stubevery > 1 ) inc = inc * (double)stubevery;
if( inc < stubmininc ) inc = stubmininc;
}
overrun = inc / 10.0;
}
}
if( xory == 'x' ) setfloatvar( "XINC", inc );
else if( xory == 'y' ) setfloatvar( "YINC", inc );
/* log mode */
logx = logy = 0;
if( Escaletype_x == E_LOG || Escaletype_x == E_LOGPLUS1 ) logx = 1;
if( Escaletype_y == E_LOG || Escaletype_y == E_LOGPLUS1 ) logy = 1;
/* sanity check.. added scg 8/7/00 */
if( inc <= 0.0 ) return( Eerr( 2705, "axis increment is zero or negative", "" ));
/* ---------------------------------------------- */
/* render the stubs and/or tics and/or grid lines.. */
/* ---------------------------------------------- */
if( stubreverse ) y = stubstop;
else y = stubstart;
ibb = 0;
irow = 0;
if( vertstub ) Etextdir(90);
prevstub = NEGHUGE;
firsttime = 1;
for( sanecount = 0; sanecount < 2000; sanecount++ ) {
if( circuit_breaker_disable ) sanecount = 0;
strcpy( txt, "" );
/* if( isrc == 0 ) goto DOTIC; */ /* no stubs */
if( isrc == INCREMENTAL ) {
/* exception for log 0.0 */
if( y <= 0.0 && ((xory == 'x' && logx ) || (xory == 'y' && logy ) ) ) goto NEXTSTUB;
}
if( isrc == INCREMENTAL ) {
double yy, fabs(), ftest, exp();
if( revsign && fabs(y) > 0.0001 ) yy = y * -1;
else yy = y;
if( stubexp == 1 ) yy = exp( yy );
else if( stubexp == 2 ) yy = exp( yy ) - 1;
/* when generating incremental axes moving from negative to positive, for zero sprintf sometimes
gives -0.00 or very tiny values like -5.5579e-17. The following is a workaround.. scg 7/5/01 */
/* if( stubstart < 0.0 && stubstop > 0.0 && yy < 0.0000000000001 && yy > -0.0000000000001 ) yy = 0.0; */
/* 5/18/06 scg - problem still occurring.. adjusting to: */
if( stubstart < 0.00001 && stubstop >= 0.0 && yy < 0.000000001 && yy > -0.000000001 ) yy = 0.0;
if( stubmult != 1.0 ) yy = yy * stubmult; /* added scg 10/2/03 */
nt = sscanf( incunits, "%lf", &ftest );
if( nt > 0 ) Euprint( txt, xory, yy/ftest, stubformat );
else Euprint( txt, xory, yy, stubformat );
if( PLS.clickmap && clickmap ) Euprint( cmtxt, xory, yy, cmvalfmt );
}
if( isrc == HERE || isrc == FROMFILE ) {
if( ibb >= bigbuflen ) break;
GL_getseg( txt, PL_bigbuf, &ibb, "\n" );
if( PLS.clickmap && clickmap ) strcpy( cmtxt, txt );
}
if( isrc == FROMDATA ) {
if( irow >= Nrecords ) break;
if( ( irow % stubevery ) != 0 ) { irow++; goto NEXTSTUB; }
if( nstubdf == 1 )
sprintf( txt, "%s", da( irow, stubdf1 ) );
else if( nstubdf == 2 )
sprintf( txt, "%s %s", da( irow, stubdf1 ), da( irow, stubdf2 ) );
if( PLS.clickmap && clickmap ) strcpy( cmtxt, txt );
irow++;
}
if( isrc == FROMCATS ) {
stat = PL_getcat( xory, irow, txt, 255 );
if( stat ) break; /* reached end of cat list */
if( ( irow % stubevery ) != 0 ) { irow++; goto NEXTSTUB; }
y = Econv( xory, txt ); /* error checking not needed */
if( PLS.clickmap && clickmap ) strcpy( cmtxt, txt );
irow++;
}
/* special units.. */
if( specialunits == MONTHS ) {
/* put a stub at current mon/year */
DT_makedate( yr, mon, day, "", buf );
y = Econv( xory, buf );
if( Econv_error() ) {
Eerr( 9675, "warning, error on date conversion", buf );
break; /* goto NEXTSTUB; changed to avoid inf loop - scg 2/12/03 */
}
if( day != 1 ) goto NEXTSTUB; /* added scg 9/12/01 */
if( ( y - stubstop ) > overrun ) break;
DT_formatdate( buf, stubformat, txt ); /* buf holds date string made above */
if( PLS.clickmap && clickmap ) DT_formatdate( buf, cmvalfmt, cmtxt ); /* buf holds date string made above */
}
/* autoyears */
if( autoyears[0] != '\0' ) {
int doit;
doit = 0;
if( specialunits == MONTHS ) {
if( (firsttime && mon < 11) || yr != curyr ) doit = 1; /* mon<11 added scg 9/12/01 */
}
else {
DT_getmdy( &mon, &day, &yr );
if( (firsttime && (mon < 11 || day < 18 )) || yr != curyr ) doit = 1;
}
curyr = yr;
if( doit ) {
if( strlen( autoyears ) == 2 ) sprintf( buf, "%s\n%02d", txt, yr % 100 );
else if( strlen( autoyears ) == 3 ) sprintf( buf, "%s\n'%02d", txt, yr % 100 );
else {
if( yr >= 100 ) sprintf( buf, "%s\n%d", txt, yr );
else if( yr >= PIVOTYEAR ) sprintf( buf, "%s\n%d", txt, 1900+yr );
else if( yr < PIVOTYEAR ) sprintf( buf, "%s\n%d", txt, 2000+yr );
}
strcpy( txt, buf );
}
}
/* autodays */
if( autodays[0] != '\0' ) {
if( stricmp( scaleunits, "datetime" )!=0 ) Eerr( 9677, "warning, autodays is only valid with datetime scaling", "" );
else {
double datepart, timepart;
char dt[40];
datepart = floor( y );
timepart = y - datepart;
if( firsttime || datepart != curday ) { /* render date */
DT_fromjul( (long)datepart, dt );
DT_formatdate( dt, autodays, buf );
strcat( txt, "\n" );
strcat( txt, buf );
}
curday = datepart;
}
}
/* automonths - can be used w/ date or datetime.. */
if( automonths[0] != '\0' ) {
char dt[40];
long foo;
int imon, iday, iyr;
DT_fromjul( (long) y, dt );
DT_jdate( dt, &foo ); /* to get m d y */
DT_getmdy( &imon, &iday, &iyr );
if( firsttime || imon != curmon ) {
DT_formatdate( dt, automonths, buf );
strcat( txt, "\n" );
strcat( txt, buf );
}
curmon = imon;
}
/* last minute stub content overrides.. */
if( stubsubpat[0] != '\0' && GL_wildcmp( txt, stubsubpat, strlen(stubsubpat), 0 )==0 ) strcpy( txt, stubsubnew );
if( firststub[0] != '\0' && firsttime ) strcpy( txt, firststub );
if( laststub[0] != '\0' && y+inc > stubstop ) strcpy( txt, laststub );
firsttime = 0;
/* by this point stub text (including any selfloc field)
should be in txt and location in y.. */
/* if selflocating, get embedded location */
if( selfloc ) {
i = 0;
GL_getchunk( buf, txt, &i, " \t" );
if( buf[0] == '\0' ) goto NEXTSTUB;
y = Econv( xory, buf );
if( Econv_error() ) {
Eerr( 9676, "warning, error on value conversion", buf );
goto NEXTSTUB;
}
if( y < stubstart || y > stubstop ) continue;
while( GL_member( txt[i], " \t" ) ) i++;
strcpy( txt, &txt[i] ); /* now obliterate the location field */
}
/* out of plotting area.. */
if( min - y > overrun ) goto NEXTSTUB;
if( y - max > overrun ) goto NEXTSTUB;
/* too close to previous stub.. supress.. */
if( stubcull > 0.0 ) {
double fabs();
if( fabs( Ea( Y, y ) - Ea( Y, prevstub )) < stubcull && prevstub != NEGHUGE ) goto NEXTSTUB;
/* fixed bug.. in log space, NEGHUGE becomes 1, sometimes causing 1st stub to be culled ... scg 9/21/04 */
else prevstub = y;
}
/* render grid line or block - done first so other content can be "on top" of it.. */
/* moved here from below, grid line extent and gridblocks added - scg 11/22/00 */
if( doinggrid ) {
if( gridskip[0] != '\0' && y <= min && GL_smember( gridskip, "min minmax both" ) );
else if( gridskip[0] != '\0' && y >= max &&
GL_smember( gridskip, "max minmax both" ) );
else if( gbcolor1[0] != '\0' ) { /* grid blocks */
if( gbstate == 0 ) {
Ecblock( glemin, gbylast, glemax, Ea( Y, y ), gbcolor1, 0 );
gbstate = 1;
}
else {
Ecblock( glemin, gbylast, glemax, Ea( Y, y ), gbcolor2, 0 );
gbstate = 0;
}
gbylast = Ea( Y, y );
}
else {
linedet( "grid", grid, 0.5 );
Emov( glemin, Ea( Y, y ) );
Elin( glemax, Ea( Y, y ) );
}
}
if( PLS.clickmap && clickmap ) { /* save region.. */
double halfdown, halfup;
if( specialunits == MONTHS ) { halfdown = halfup = ( Ea( Y, y ) - cmylast ) / 2.0; }
else {
/* handle linear & log.. (doesn't work quite right for months).. */
halfup = ( Ea( Y, y+inc ) - Ea( Y, y ) ) / 2.0;
halfdown = ( Ea( Y, y ) - Ea( Y, y-inc ) ) / 2.0;
/* halfdist = ( Ea( Y, y+inc ) - Ea( Y, y ) ) / 2.0; */
}
/* urlencode the value now.. scg 5/29/06 */
GL_urlencode( cmtxt, buf );
if( Eflip ) {
clickmap_entry( 'r', buf, clickmap, (Ea(Y,y)-halfdown)+stubslide, cmemin,
Ea(Y,y)+halfup+stubslide, cmemax, 0, 1, "" );
}
else {
clickmap_entry( 'r', buf, clickmap, cmemin, (Ea(Y,y)-halfdown)+stubslide,
cmemax, Ea(Y,y)+halfup+stubslide, 0, 2, "" );
}
cmylast = Ea( Y, y );
}
/* convert any embedded "\n" to newline.. */
convertnl( txt );
/* determine exact position and render stub text.. */
if( isrc > 0 && !stubhide && ! GL_slmember( txt, stubomit ) ) { /* stub can't be in omit list.. */
textdet( "stubdetails", stubdetails, &align, &adjx, &adjy, -2, "R", 1.0 );
if( vertstub && xory == 'x' ) {
if( align == '?' ) align = 'R';
ofsx = adjx + (ticout * -2.0) ;
ofsy = (adjy + 0.04) + stubslide;
}
else if( xory == 'y' ) {
if( align == '?' ) align = 'R';
ofsx = (adjx + -0.15) /* + stubslide*/;
/* ofsy = adjy + ( Ecurtextheight * -0.4 ); */
ofsy = adjy + ( Ecurtextheight * -0.3 ) + stubslide;
}
else if( xory == 'x' ) {
if( align == '?' ) align = 'C';
ofsx = adjx + (Ecurtextheight + ticout)*-1.0 ;
ofsy = adjy + stubslide;
}
/* render text.. but don't do last stub if it is past range.. */
if( ( (Ea(Y, y)+ofsy) - Ea(Y, stubstop ) <= overrun ) || stubreverse ) {
Emov( pos+ofsx, Ea( Y, y)+ofsy );
if( stublen && txt[stublen] != '\0' ) { txt[stublen] = '.'; txt[stublen+1] = '.'; txt[stublen+2] = '\0'; }
Edotext( txt, align );
}
}
/* render major tic mark */
if( doingtics ) {
linedet( "tics", tics, 0.5 );
Emov( pos-ticout, Ea( Y, y) + ticslide );
Elin( pos+ticin, Ea( Y, y ) + ticslide );
}
/* render grid line - was here */
NEXTSTUB:
/* increment stub location.. */
if( specialunits == MONTHS ) { /* increment to next */
int newmon;
mon += inc;
/* wrap around year.. */
newmon = ((mon-1) % 12 ) +1;
yr += ((mon-1) / 12);
mon = newmon;
/* fprintf( stderr, "[mon=%d yr=%d]", mon, yr ); */
day = 1;
}
else if( ! selfloc ) {
if( stubreverse ) {
y -= inc;
if( stubstart - y > overrun ) break;
}
else {
y += inc;
if( ( y - stubstop ) > overrun ) break;
}
}
}
if( vertstub ) Etextdir(0);
SKIPLOOP:
/* make the line.. do it last of all for appearance sake.. */
if( stricmp( axisline, "none" )!= 0 ) {
linedet( "axisline", axisline, 0.5 );
Emov( pos, Ea( Y, axlinestart ) ); Elin( pos, Ea( Y, axlinestop ) );
if( axis_arrow ) PLG_arrow( pos, Ea( Y, axlinestop), pos, Ea( Y, axlinestop)+(arrowheadsize*2.0), arrowheadsize, 0.3, Ecurcolor );
}
Eflip = 0;
if( sanecount >= 2000 ) return( Eerr( 5729, "warning, too many stubs/major tics, circuit breaker tripped", "" ));
return( 0 );
}
/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
syntax highlighted by Code2HTML, v. 0.9.1