/* @(#)ag_axes.c 17.1.1.1 (ES0-DMD) 01/25/02 17:33:29 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /* @(#)ag_axes.c 17.1.1.1 (OAA-ASTRONET) 01/25/02 17:33:29 */ /* * HEADER : ag_axes.c - Vers 3.6.004 - Oct 1993 - L. Fini, OAA * - Vers 3.6.003 - Sep 1993 - L. Fini, OAA * - Vers 3.6.002 - Oct 1992 - L. Fini, OAA */ #include #include #define TOP 1 #define RIGHT 1 #define BOTTOM 0 #define LEFT 0 static void ax_init(ax) /* Initialize status */ struct AX_STATUS *ax; { ax->X.man = AUTO; ax->X.Angmode = RADIANS; ax->Y.Angmode = RADIANS; ax->Y.man = AUTO; ax->X.mode = LIN; ax->Y.mode = LIN; ax->X.grid = FALSE; ax->Y.grid = FALSE; ax->X.fmark = FALSE; ax->Y.fmark = FALSE; ax->X.iexp = 0; ax->Y.iexp = 0; ax->Fixit=FALSE; ax->Bold=0; ax->Xspace = 0.0; ax->Txtdim = -1.0; ax->X.label[0] = '\0'; ax->Y.label[0] = '\0'; strcpy(ax->X.form,"%d"); strcpy(ax->Y.form,"%d"); ax->X.fact = 1.0; ax->Y.fact = 1.0; ax->X.offst = 0.0; ax->Y.offst = 0.0; ax->Geom = FALSE; ax->Title[0] = '\0'; } static int ax_setup (sel,token,ax) /* Set status according to select */ /* code */ /* Returns FALSE if no more tokens*/ /* remain to analyze */ int sel; /* select code */ char *token; /* select token (for parameters) */ struct AX_STATUS *ax; { int eos = FALSE; int nvals; float rbuf[4]; switch(sel) { case BOLD: ax->Bold=THICK_AXIS; break; case MAN1: /***** Set (manual) tiks values on X-axis **********/ nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>=1) { ax->X.man=MANUAL; ax->X.tikmj=rbuf[0]; } if(nvals>=2) ax->X.tikmn=rbuf[1]; break; case MAN2: /***** Set (manual) tiks values on Y-axis **********/ nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>=1) { ax->Y.man=MANUAL; ax->Y.tikmj=rbuf[0]; } if(nvals>=2) ax->Y.tikmn=rbuf[1]; break; case MARK1: nvals=1; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>=1) { ax->X.mark=rbuf[0]; ax->X.fmark=TRUE; } break; case MARK2: nvals=1; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>=1) { ax->Y.mark=rbuf[0]; ax->Y.fmark=TRUE; } break; case DEG12: /***** Set degree format on both axes **************/ ax->X.mode=ANG; ax->X.Angmode=DEGREES; ax->Y.mode=ANG; ax->Y.Angmode=DEGREES; break; case DEG1: /***** Set degree format on X axis *****************/ ax->X.mode=ANG; ax->X.Angmode=DEGREES; break; case DEG2: /***** Set degree format on Y axis *****************/ ax->Y.mode=ANG; ax->Y.Angmode=DEGREES; break; case DIV1: nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>1) ax->X.divs[1]=rbuf[1]; if(nvals>0) ax->X.divs[0]=rbuf[0]; break; case DIV2: nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>1) ax->Y.divs[1]=rbuf[1]; if(nvals>0) ax->Y.divs[0]=rbuf[0]; break; case LOG12: /***** Set logarithmic scale on both axes ***********/ ax->X.mode=LOG; ax->Y.mode=LOG; break; case LOG1: /***** Set logarithmic scale on X axis *************/ ax->X.mode=LOG; break; case LOG2: /***** Set logarithmic scale on Y axis *************/ ax->Y.mode=LOG; break; case LAB1: /***** Set label for X axis *************************/ nvals=MAXLABEL; strcpy(ax->X.label,"~+"); nvals=AG_SVAL(token,nvals,(ax->X.label+2)); break; case LAB2: /***** Set label for Y axis *************************/ nvals=MAXLABEL; strcpy(ax->Y.label,"~+"); nvals=AG_SVAL(token,nvals,(ax->Y.label+2)); break; case TITLE: /***** Set plot title ******************************/ nvals=MAXTITLE; strcpy(ax->Title,"~+~+"); nvals=AG_SVAL(token,nvals,(ax->Title+4)); break; case GRID12: /***** Set grid mode on both axes ******************/ ax->X.grid=TRUE; ax->Y.grid=TRUE; break; case GRID1: /***** Set grid mode on X axis *********************/ ax->X.grid=TRUE; break; case GRID2: /***** Set grid mode on Y axis *********************/ ax->Y.grid=TRUE; break; case NQUOT12: /***** Disable quotation on both axes ***************/ *ax->X.form='*'; *ax->Y.form='*'; break; case NQUOT1: /***** Disable quotation on X axis ******************/ *ax->X.form='*'; break; case NQUOT2: /***** Disable quotation on Y axis ******************/ *ax->Y.form='*'; break; case GEOM: /***** Set geometrical control *********************/ ax->Geom = TRUE; break; case FACT1: /***** set mult. factor for quotation on X axis *****/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->X.fact=rbuf[0]; break; case FACT2: /***** set mult. factor for quotation on Y axis *****/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->Y.fact=rbuf[0]; break; case FIXIT: /***** Fix the dimension of the clipping area ***/ ax->Fixit=TRUE; break; case OFST1: /***** Set offset factor for quotation on X axis ***/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->X.offst=rbuf[0]; break; case OFST2: /***** Set offset factor for quotation on Y axis ***/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->Y.offst=rbuf[0]; break; case TXDIM: nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->Txtdim=rbuf[0]; break; case XSPACE: nvals=1; nvals=AG_RVAL(token,nvals,&(ax->Xspace)); if(nvals<1) ax->Xspace=0.0; break; case EOS: eos=TRUE; break; default: break; } return eos; } /****************************************************************************/ /* isxy */ /* Depending on the last character of keyword returns 1 (x), 2(y) or */ /* 0 (neither) */ static int isxy(token) char *token; { char *ip = token; while(TRUE) { if( !(isalnum(*ip)) ) break; if( *ip == '=' ) break; ip++; } ip--; if( ip>=token ) switch(*(ip)) { case 'x': return 1; case 'y': return 2; } return 0; } /****************************************************************************/ /* analtok */ /* Analyzes a select token */ static int analtok(token) /* Returns an integer select code */ char *token; /* token to analize */ { int first,last,middle,found=(-1); int code=(-1); static struct jmptab { char cmnd[3]; char type; enum CASES code; } cases[] = { /* TO BE MAINTAINED SORTED !! */ { {'b','o','l'}, 0, BOLD }, { {'d','e','g'}, 2, DEG12 }, { {'d','i','v'}, 1, DIV1 }, { {'f','a','c'}, 1, FACT1 }, { {'f','i','x'}, 0, FIXIT }, { {'g','e','o'}, 0, GEOM }, { {'g','r','i'}, 2, GRID12 }, { {'l','a','b'}, 1, LAB1 }, { {'l','o','g'}, 2, LOG12 }, { {'m','a','n'}, 1, MAN1 }, { {'m','a','r'}, 1, MARK1 }, { {'n','q','u'}, 2, NQUOT12 }, { {'o','f','s'}, 1, OFST1 }, { {'t','i','t'}, 0, TITLE }, { {'t','x','d'}, 0, TXDIM }, { {'x','s','p'}, 0, XSPACE } }; if(*token=='\0') return (int)EOS; first=0; last=(sizeof(cases)/sizeof(struct jmptab))-1; while ((last>=first)&&(found<0)) { int cmp; middle = (last+first)/2; cmp=strncmp(token,cases[middle].cmnd,3); if(cmp < 0) last=middle-1; else if (cmp > 0) first=middle+1; else found=middle; } if(found>=0) { char *getxy = token+2; int xy; switch(cases[found].type) { case 1: xy=isxy(getxy); if(xy!=0) code=(int)cases[found].code+xy-1; break; case 2: xy=isxy(getxy); code=(int)cases[found].code+xy; break; case 0: code=(int)cases[found].code; break; } } return code; } /***************************************************************************/ /* trace_line */ static void trace_line(axis,which) /* Trace a straight line */ struct AXIS *axis; int which; { float xv[2], yv[2]; float *XV, *YV; if(axis->fmark) { if(which==0){ XV=xv; YV=yv; } else { XV=yv; YV=xv; } XV[0]=axis->wind[0]; XV[1]=axis->wind[1]; YV[0]=axis->mark; YV[1]=axis->mark; AG_GPLL(xv,yv,2); } } /***************************************************************************/ /* do_cartesian */ static void do_cartesian(ax) /* Draw the plot in cartesian mode */ struct AX_STATUS *ax; { float xv[5], yv[5]; double xxbot,xxtop,yybot,yytop; float data[11]; float *xd, *yd; char Txtmode[40]; int mmode; xd = data; yd = data+5; AG_RGET("VWPLIM",ax->Clpa); /* Get current viewport limits */ if(ax->Txtdim < 0.0) { /* Compute string dimensions */ float diffx,diffy; diffx=ax->Clpa[1]-ax->Clpa[0]; diffy=ax->Clpa[3]-ax->Clpa[2]; ax->Txtdim = MIN(diffx,diffy); } /* else ax->Txtdim=(1.0); */ sprintf(Txtmode,"lfrg;scale=%.2f",ax->Txtdim); AGLfmt(&(ax->X)); AGLfmt(&(ax->Y)); AG_IGET("mfmode",&mmode); if(mmode==2) AG_MSUS(); /* Suspend metafile recording */ AG_SSET(Txtmode); (void)AG_TGET("X",xd,yd); yytop = 4.5 * yd[1]; /* ... for title */ xxbot = xd[0]*6.55; /* Compute space at left */ yybot = yd[1] * 6.55; /* ...... for X label .... */ xxtop = xd[0] * 4.5; /* Compute space at right */ AG_SSET("bott"); AG_TGET("X",xd,yd); xxbot = xxbot + 5.5 * fabs((double)xd[2]); if(!ax->Fixit) { ax->Clpa[0] += xxbot; /* Compute resulting clipping area */ ax->Clpa[1] -= xxtop; ax->Clpa[2] += yybot; ax->Clpa[3] -= yytop; } /* now set AGL status */ (void)AG_CDEF(ax->Clpa[0],ax->Clpa[1],ax->Clpa[2],ax->Clpa[3]); (void)AG_WDEF(ax->X.wind[0],ax->X.wind[1],ax->Y.wind[0],ax->Y.wind[1]); if(ax->X.mode==LOG) (void)AG_SSET("LOGX"); else (void)AG_SSET("LINX"); if(ax->Y.mode==LOG) (void)AG_SSET("LOGY"); else (void)AG_SSET("LINY"); if(ax->Geom) (void)AG_SSET("GEOM"); else (void)AG_SSET("NGEOM"); AG_RGET("CLPLIM",ax->Clpa); /* GEOM could have changed the clip. area */ ax->Boxa[0] = ax->Clpa[0]-xxbot; /* This is the box */ ax->Boxa[1] = ax->Clpa[1]+xxtop; /* enclosing everyth. */ ax->Boxa[2] = ax->Clpa[2]-yybot; ax->Boxa[3] = ax->Clpa[3]+yytop; /* Now draw everything */ xv[0]=ax->X.wind[0]; yv[0]=ax->Y.wind[0]; /* Draw the box */ xv[1]=ax->X.wind[1]; yv[1]=ax->Y.wind[0]; xv[2]=ax->X.wind[1]; yv[2]=ax->Y.wind[1]; xv[3]=ax->X.wind[0]; yv[3]=ax->Y.wind[1]; xv[4]=ax->X.wind[0]; yv[4]=ax->Y.wind[0]; if(mmode==2) AG_MRES(); /* resume metafile recording */ /* (void)AG_GPLL(xv,yv,5); */ data[0] = ax->X.wind[0]; data[1] = ax->X.wind[1]; data[2] = ax->X.ftik; data[3] = ax->X.ltik; data[4] = ax->X.tikmj; data[5] = ax->X.tikmn; data[6] = ax->Y.wind[0]; if(ax->X.grid) data[7] = ax->Y.wind[1]; else data[7] = data[6]; data[8] = ax->X.offst; data[9] = ax->X.fact; data[10]= ax->X.iexp; AG_AXIS(ax->Bold|X_BOTTOM_AXIS,data,0.0,ax->X.form,ax->X.label); data[6] = ax->Y.wind[1]; data[7] = data[6]; data[9] = 0; AG_AXIS(ax->Bold|X_TOP_AXIS,data,1.0,ax->X.form,ax->Title); data[0] = ax->Y.wind[0]; data[1] = ax->Y.wind[1]; data[2] = ax->Y.ftik; data[3] = ax->Y.ltik; data[4] = ax->Y.tikmj; data[5] = ax->Y.tikmn; data[6] = ax->X.wind[0]; if(ax->Y.grid) data[7] = ax->X.wind[1]; else data[7] = data[6]; data[8] = ax->Y.offst; data[9] = ax->Y.fact; data[10]= ax->Y.iexp; AG_AXIS(ax->Bold|Y_LEFT_AXIS,data,ax->Xspace,ax->Y.form,ax->Y.label); data[6] = ax->X.wind[1]; data[7] = data[6]; data[9] = 0; AG_AXIS(ax->Bold|Y_RIGHT_AXIS,data,0.0,ax->Y.form,""); trace_line(&(ax->X),0); trace_line(&(ax->Y),1); (void)AG_VUPD(); if(mmode==2) AG_MSUS(); AG_SSET("lfrg;chbas"); if(mmode==2) AG_MRES(); } /****************************************************************************/ /*++ AG_AXES (User callable) */ /* AG_AXES */ /* This module computes and draws axes on the currently active viewport. */ /* The position of the axes is computed so that quotes, labels and title */ /* will fit into the currently defined viewport */ /* A variety of options and axes drawing modes can be selected by means of */ /* an option selection string. */ /* After the call the clipping area is set so that it encloses the box */ /* defined by the axes. The window is defined accordingly to limits passed */ /* as arguments and the USER mode is selected. */ /* N.B.: Character dimensions and orientation as set prior of the call are */ /* not preserved */ void AG_AXES(xl,xu,yl,yu,option) double xl,xu,yl,yu; /* User defined data window */ char *option; /* Option string (see below) */ /* Option string specifications: */ /* Syntax: "keywd[=value,value...][;keywd[=value...]]" */ /* Note: the keyword separator character ';' can be included into a string */ /* value by escaping it as in: "\;" */ /* Currently defined keyword and related specific sintax follows: */ /* BOLD */ /* Traces axes with thicker lines. Only axes are affected, if you also */ /* want labels written in bold face you must explicitly set it into the */ /* string with the standard AGL metacharacter sequence (~k). */ /* This feature is available only for devices supporting increased line */ /* width. */ /* DEGX */ /* DEGY */ /* Selects tiks position suitable for sexagesimal notation when automatic */ /* tik computing is enabled. It means that tik positions which are */ /* integral multiple of 3, 9, 1.5 and the like are selected. By default */ /* tik position at integral multiples of 1, 2, 5 are selected. */ /* DIVX=[start[,stop]] */ /* DIVY=[start[,stop]] */ /* Draw divisions and corresponding quotes only between given coordinates */ /* FACTX */ /* FACTY */ /* Specifies a multiplying factor for quotes. Numbers written at tick */ /* marks are computed as follows: */ /* quote = offst? + ( coord * fact? ) */ /* where: coord is the coordinate value at the tik, */ /* fact? is the factor set with this command (? = either x or y) */ /* offst? is an offset value (see OFFSTX, OFFSTY) */ /* quote is the numerical value actually written at the tik */ /* Default is 1.0 */ /* FIXIT */ /* Forces the plot area (i.e.: the axes box) to cover exactly the current */ /* clipping area, instead of computing a new clipping area in order to */ /* fit all the plot (quotes, labels, title, included) in the clipping */ /* area. When using this mode the caller must define a clipping area */ /* suitably smaller than the current viewport if everything that must be */ /* plotted outside the clipping area (quotes and so on ) is to be seen */ /* GEOM */ /* Set geometrical control on the user data window. It means that the */ /* actual aspect ratio of the plot is set equal to the ratio: */ /* (ymax-ymin)/(xmax-xmin) */ /* GRID */ /* GRIDX */ /* GRIDY */ /* Specifies that a grid of lines is desired on the given axis instead of */ /* major tiks. */ /* LABX=string */ /* Specifies a label to be written under the x-axis. */ /* LABY=string */ /* Specifies a label to be written to the left of the y-axis. */ /* LOGX */ /* LOGY */ /* Select logarithmic transformation. Default is linear. */ /* MANX=mjstep[,mnstep] */ /* MANY=mjstep[,mnstep] */ /* Select manual definition of tik positions. Mjstep define the spacing */ /* of major divisions; mnstep define the spacing of minor divisions. If */ /* mjstep is <= 0.0, then no divisions are traced; if mnstep is not */ /* specified, minor divisions are not traced. */ /* If logarithmic transformation is selected for the axis, mjstep and */ /* mnstep are multiplicative increments for major and minor divisions, */ /* respectively. Mjstep must be a power of 10 (but not equal to 1.0), and */ /* mnstep may be either 5 or a power of 10 not equal to 1.0. */ /* The default is automatic tik computation. */ /* MARKX=ycoord */ /* MARKY=xcoord */ /* Traces a straight line (either parallel to X-axis or to Y-axis) at the */ /* given coordinate (if that's within the user data window). */ /* Often useful as, e.g., MARKX=0, to trace a line at the origin. */ /* NQUOTX */ /* NQUOTY */ /* Suppresses quotes on the corresponding axis. */ /* OFFSTX */ /* OFFSTY */ /* Offset for quotes. Values written at tik marks are computed as: */ /* quote = offst? + ( coord * fact? ) */ /* where: coord is the coordinate value at the tik, */ /* fact? is the multiplicative factor (see FACTX, FACTY) */ /* offst? is an offset set with this command (? = either x or y) */ /* quote is the numerical value actually written at the tik */ /* Default is 0.0 */ /* TITLE=string */ /* Specifies a title to be written on top of the plot. */ /* TXDIM=mult */ /* Specifies a multiplying factor to apply to character, symbols and dash */ /* patterns. When TXDIM is specified the character dimension for labels, */ /* title and quotes is fixed as the given multiple of the device standard */ /* dimension. */ /* The default is to adjust string dimensions according to the dimension */ /* of the viewport. */ /* XSPACE=nchar */ /* Set the space (number of characters) left between the left Y axis and */ /* the Y axis label. Default is 5. */ /* Here follows a typical calling sequence: */ /* AG_VDEF (.......) Define graphic device */ /* AG_AXES(x0,x1,y0,y1,sel) Define and draw axes */ /* ... plot data .... */ /* AG_CLS() Close AGL */ /* REMARKS: */ /* Title and label strings may contain AGL standard metacharacters for */ /* superscripts, subscripts and font definition (See: AG_GTXT) */ /*--*/ { static char *modnam = "AXES"; int eos; char *ix = option; struct AX_STATUS ax_status; { char aux[80]; sprintf(aux,"AG_AXES %.6g,%.6g,%.6g,%.6g,",xl,xu,yl,yu); AG_DMSG(aux,option); } ax_init(&ax_status); ax_status.X.wind[0] = xl; ax_status.X.wind[1] = xu; ax_status.Y.wind[0] = yl; ax_status.Y.wind[1] = yu; ax_status.X.divs[0] = xl; ax_status.X.divs[1] = xu; ax_status.Y.divs[0] = yl; ax_status.Y.divs[1] = yu; eos=FALSE; while ( ! eos ) { /* String analysis loop */ int sel; char token[MAXTOKEN+1]; ix = AG_SCAN(ix,';',MAXTOKEN,token); /* Parse next token */ sel=analtok(token); eos = ax_setup(sel,token,&ax_status); } AGL_push(modnam); do_cartesian(&ax_status); /* Plot everything */ AGL_pop(); }