/* @(#)ag_axes.c	19.1 (ES0-DMD) 02/25/03 13:52:57 */
/*===========================================================================
  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	19.1  (OAA-ASTRONET) 02/25/03 13:52:57   */
/*
 * 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 <aglenvr.h>
#include <aglaxes.h>

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

