/* @(#)ag_nlin.c 17.1.1.1 (ES0-DMD) 01/25/02 17:33:32 */ /*=========================================================================== 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_nlin.c 17.1.1.1 (OAA-ASTRONET) 01/25/02 17:33:32 */ /* * HEADER : ag_nlin.c - Vers 3.6.004 - Sep 1993 - L. Fini, OAA * - Vers 3.6.003 - Jul 1993 - L. Fini, OAA * - Vers 3.6.002 - Jul 1992 - L. Fini, OAA * * AGL support for non linear coordinates */ #include #include #define BOUNDARY1(c,min,max) (((c)<(min)) ? 1 : ((c)>(max)) ? 2 : 0) #define BOUNDARY2(c,min,max) (((c)<(min)) ? 4 : ((c)>(max)) ? 8 : 0) static char *INT = "%d"; static char *FLOAT = "%5.2f"; static char *DDMM = "%2a"; static char *HHMM = "%2h"; static double c1fact,c2fact; /* Coordinate conversion factors */ static double c1ofs,c2ofs; /* used by all the projections */ static double c1_min,c1_max,c2_min,c2_max; static char *Range = "Range"; /***************************************************************************/ /* AGLatanh */ static double AGLatanh(x) /* Computes the inverse of the hyperbolic */ /* tangent */ double x; { return(0.5*log((1.0+x)/(1.0-x))); } /***************************************************************************/ static void init_gen(pl_stat) /* Initialize status (general) */ struct NLN_STATUS *pl_stat; { pl_stat->Proj = (-1); pl_stat->c1.man = AUTO; pl_stat->c2.man = AUTO; pl_stat->c1.grid = TRUE; pl_stat->c2.grid = TRUE; pl_stat->c1.mode = AX_UNDEF; pl_stat->c2.mode = AX_UNDEF; pl_stat->Bold=0; pl_stat->Fixit=FALSE; pl_stat->Windfix=FALSE; pl_stat->Txtdim = -11.0; pl_stat->c1.label[0] = '\0'; pl_stat->c2.label[0] = '\0'; pl_stat->Rlabel[0] = '\0'; pl_stat->Title[0] = '\0'; *pl_stat->c1.form = '\0'; *pl_stat->c2.form = '\0'; pl_stat->c1.Angmode = DEGREES; pl_stat->c2.Angmode = DEGREES; pl_stat->c1.fact = 1.0; pl_stat->c2.fact = 1.0; pl_stat->c1.offst = 0.0; pl_stat->c2.offst = 0.0; pl_stat->c1.iexp = 0.0; pl_stat->c2.iexp = 0.0; AG_IGET("mfode",&(pl_stat->Metamode)); } /*****************************************************************************/ /* MSSET */ static void MSSET(cmd,mmode) char *cmd; int mmode; { if(mmode==2) AG_MSUS(); AG_SSET(cmd); if(mmode==2) AG_MRES(); } static int lerange(axis,span) /* Check axis range <= span */ struct AXIS *axis; double span; { double angfct; double w0,w1; angfct = AGLAngF(axis->Angmode); w0=axis->wind[0]*angfct; w1=axis->wind[1]*angfct; if(w1-w0 > span) { AG_GERR(201,Range); return FAILURE; } return SUCCESS; } static int ltrange(axis,span) /* Check axis range < span */ struct AXIS *axis; double span; { double angfct; double w0,w1; angfct = AGLAngF(axis->Angmode); w0=axis->wind[0]*angfct; w1=axis->wind[1]*angfct; if(w1-w0 >= span) { AG_GERR(201,Range); return FAILURE; } return SUCCESS; } /****************************************************************************/ /* Polar routines */ static void pol_init() { float fact[6]; (void)AG_RGET("user",fact); /* retrieve transformation parameters */ c1fact=fact[0]; c2fact=fact[1]; c1_min=fact[2]; c1_max=fact[3]; c2_min=fact[4]; c2_max=fact[5]; } static int pol_direct(rho,theta) /* Convert a (rho,theta) value into */ /* (x,y) */ double *rho, *theta; { double c0,c1; int retval=0; c0= *rho; c1= *theta; retval |= BOUNDARY1(c0,c1_min,c1_max); retval |= BOUNDARY2(c1,c2_min,c2_max); c0=c0*c1fact; c1=c1*c2fact; *rho=c0*cos(c1); *theta=c0*sin(c1); return retval; } static int pol_reverse(xx,vyy) /* Convert a (x,y) value into */ /* (rho,theta) */ double *xx, *vyy; { double c0,c1,c2,c3; int retval=0; c2 = *xx; c3 = *vyy; c0 = hypot(c3,c2)/c1fact; c1 = atan2(c3,c2)/c2fact; retval |= BOUNDARY1(c0,c1_min,c1_max); retval |= BOUNDARY2(c1,c2_min,c2_max); *xx = c0; *vyy = c1; return retval; } /****************************************************************************/ /* Gnomonic routines */ static void gno_init() /* Also used by other projections .... */ { float fact[8]; (void)AG_RGET("user",fact); /* retrieve transformation parameters */ c1ofs = fact[0]; c1_min= fact[1]; c1_max= fact[2]; c1fact= fact[3]; c2ofs = fact[4]; c2_min= fact[5]; c2_max= fact[6]; c2fact= fact[7]; } static int gno_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double ang; register double cos1,sin1,cos2,sin2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = (cos1-c1ofs)*c1fact; /* Center transformation latitude */ cos1=cos(ang); sin1=sin(ang); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ cos2=cos(ang); sin2=sin(ang); ang = 1.0/(cos2*cos1); *c1 = (cos2*sin1)*ang; *c2 = sin2*ang; return retval; } static int gno_reverse(c1,c2) /* Reverse gnomonic conversion */ double *c1, *c2; { int retval=0; register double X= *c1,Y= *c2; X=atan(X); Y=atan(Y*cos(X)); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_gnomo(ax) /* Check gnomonic mode */ struct NLN_STATUS *ax; { ax->c1.mode = ANG; ax->c2.mode = LIN; if(*ax->c1.form!='*') strcpy(ax->c1.form,FLOAT); if(*ax->c2.form!='*') strcpy(ax->c2.form,FLOAT); return SUCCESS; } static int make_gnomo(ax) /* Set up the gnomonic transformation */ struct NLN_STATUS *ax; { float rfact[8]; double ac1,ac2; rfact[0] = (ax->c1.wind[1]+ /* Center of first axis */ ax->c1.wind[0])*0.5; rfact[1] = ax->c1.wind[0]; /* limits of first axis */ rfact[2] = ax->c1.wind[1]; rfact[3] = AGLAngF(ax->c1.Angmode); /* Angular factor of first axis */ rfact[4] = (ax->c2.wind[1]+ /* center of second axis */ ax->c2.wind[0])*0.5; rfact[5] = ax->c2.wind[0]; /* limits of second axis */ rfact[6] = ax->c2.wind[1]; rfact[7] = AGLAngF(ax->c2.Angmode); /* Angular factor of second axis */ AG_RSET(8,rfact); AG_TRNS(gno_init, /* Set up user defined transformation */ gno_direct, gno_reverse); gno_init(); /* Compute cartesian window */ /* and transformation center */ ac1=ax->c1.wind[0]; ac2=ax->c2.wind[0]; gno_direct(&ac1,&ac2); ax->Wind[0]=ac1; ax->Wind[2]=ac2; ac1=ax->c1.wind[1]; ac2=ax->c2.wind[1]; gno_direct(&ac1,&ac2); ax->Wind[1]=ac1; ax->Wind[3]=ac2; return SUCCESS; } /****************************************************************************/ /* make_polar */ static int make_polar(ax) /* Set up the polar transformation */ struct NLN_STATUS *ax; { float rfact[6]; double angfct; rfact[0]=1.0/ax->c1.wind[1]; angfct=AGLAngF(ax->c2.Angmode); rfact[1]=angfct; rfact[2] = ax->c1.wind[0]; rfact[3] = ax->c1.wind[1]; rfact[4] = ax->c2.wind[0]; rfact[5] = ax->c2.wind[1]; AG_RSET(6,rfact); /* Store data in User storage area */ AG_TRNS(pol_init, /* Set up user defined transformation */ pol_direct, pol_reverse); if(!ax->Windfix) { double t0=ax->c2.wind[0]; double t1=ax->c2.wind[1]; double minx=0,maxx=0,miny=0,maxy=0; t0 *= angfct ; t1 *= angfct ; if((t0<=0.0)&&(t1>=0.0)) maxx=1.0; if((t0<=AG_PI05)&&(t1>=AG_PI05)) maxy=1.0; if((t0<=AG_PI)&&(t1>=AG_PI)) minx=(-1.0); if((t0<=AG_PI15)&&(t1>=AG_PI15)) miny=(-1.0); if(minx==0.0) { double c0=cos(t0); double c1=cos(t1); minx=MIN3(minx,c0,c1); } if(maxx==0.0) { double c0=cos(t0); double c1=cos(t1); maxx=MAX3(maxx,c0,c1); } if(miny==0.0) { double s0=sin(t0); double s1=sin(t1); miny=MIN3(miny,s0,s1); } if(maxy==0.0) { double s0=sin(t0); double s1=sin(t1); maxy=MAX3(maxy,s0,s1); } ax->Wind[0]=minx; ax->Wind[1]=maxx; ax->Wind[2]=miny; ax->Wind[3]=maxy; } if(ax->c1.mode==LOG) MSSET("logx",ax->Metamode); else MSSET("linx",ax->Metamode); ax->c2.ftik= rfact[4]; ax->c2.ltik= rfact[5]; ax->c2.tikmj= 0.52359878/angfct; if(ax->c1.ftik<(0.5*ax->c1.tikmj)) ax->c1.ftik += ax->c1.tikmj; MSSET("geom",ax->Metamode); return SUCCESS; } static void polar_quote(ax) /* Quotes Polar c2 axis */ struct NLN_STATUS *ax; { double th,thmax; double rh; double angf=AGLAngF(ax->c2.Angmode); th=ax->c2.wind[0]; thmax=ax->c2.wind[1]*1.001; rh=ax->c1.wind[1]; MSSET("lfrg",ax->Metamode); while(th<=thmax) { double quote; double ct,st; char string[60]; int qct; quote = th; ct=cos(angf*quote); st=sin(angf*quote); if(ct<0.9961947) { if(ct<-0.9961947) qct=16; else if(st>0.9961947) qct=12; else if(st<-0.9961947) qct=20; else if(ct>0.0) qct = (st>0.0) ? 9 : 23; else qct = (st>0.0) ? 15 : 17; quote = quote*ax->c2.fact+ax->c2.offst; AGLConvert(ax->c2.form,quote,string); AG_GTXT(rh,th,string,qct); } th += ax->c2.tikmj; } } /****************************************************************************/ /* Aitoff routines */ static void ait_init() { float fact[8]; (void)AG_RGET("user",fact); /* retrieve transformation parameters */ c1ofs = fact[0]; c1_min= fact[1]; c1_max= fact[2]; c1fact= fact[3]*0.5; c2ofs = fact[4]; c2_min= fact[5]; c2_max= fact[6]; c2fact= fact[7]; } static int ait_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double ang; register double cos1,sin1,cos2,sin2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = (cos1-c1ofs)*c1fact; /* Center transformation latitude */ cos1=cos(ang); sin1=sin(ang); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ cos2=cos(ang); sin2=sin(ang); ang = 1.0/sqrt((1.0+cos2*cos1)*0.5); *c1 = 2.0*(cos2*sin1)*ang; *c2 = sin2*ang; return retval; } static int ait_reverse(c1,c2) /* Reverse aitoff conversion */ double *c1, *c2; /* Longitude,latitude */ { int retval=0; register double X= *c1,Y= *c2; double D,X2,Y2,D2; X2 = X*X; Y2 = Y*Y; D2 = 1.0 - (X2*0.0625) - (Y2*0.25); if(D2<0.0) return CRSUNDEF; D = sqrt(D2); X = atan2((X*D*(2.0*D2-1.0)),(1.0-D2*(X2*0.5+Y2))); Y = asin(Y*D); X = 0.5*X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_aitoff(ax) /* Initialize aitoff mode */ struct NLN_STATUS *ax; { ax->c1.mode = ANG; ax->c2.mode = ANG; if(*ax->c1.form!='*') strcpy(ax->c1.form,INT); if(*ax->c2.form!='*') strcpy(ax->c2.form,INT); return SUCCESS; } /****************************************************************************/ /* GLS routines */ static int gls_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double L,B; int retval = 0; L = *c1; B = *c2; retval |= BOUNDARY1(L,c1_min,c1_max); retval |= BOUNDARY2(B,c2_min,c2_max); L = (L-c1ofs)*c1fact; /* Center transformation latitude */ B = c2fact*(B-c2ofs); /* Center transformation longitude */ *c2 = B; *c1 = L*cos(B); return retval; } static int gls_reverse(c1,c2) /* Reverse gls conversion */ double *c1, *c2; /* Longitude,latitude */ { int retval=0; register double X= *c1,Y= *c2; X = X/cos(Y); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_gls(ax) /* Initialize gls mode */ struct NLN_STATUS *ax; { ax->c1.mode = LIN; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } /****************************************************************************/ /* SIN2 routines */ static int s2_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double ang; register double cos1,sin1,cos2,sin2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = c1fact*(cos1-c1ofs); /* Center transformation latitude */ cos1 = cos(ang); sin1 = sin(ang); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ cos2 = cos(ang); sin2 = sin(ang); ang = sqrt(2.0/(1.0+cos1*cos2)); *c1 = sin1*cos2*ang; *c2 = sin2*ang; return retval; } static int s2_reverse(c1,c2) /* Reverse gls conversion */ double *c1, *c2; /* Longitude,latitude */ { int retval=0; register double X= *c1,Y= *c2; register double rho2,D; rho2 = X*X+Y*Y; D = sqrt(1.0-0.25*rho2); X = atan2((X*D),(1.0-0.5*rho2)); Y = asin(Y*D); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_s2(ax) /* Initialize gls mode */ struct NLN_STATUS *ax; { ax->c1.mode = ANG; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } /****************************************************************************/ /* mercator routines */ static int mrc_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double X,Y; int retval = 0; X = *c1; Y = *c2; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); X = c1fact*(X-c1ofs); /* Center transformation latitude */ Y = c2fact*(Y-c2ofs); /* Center transformation longitude */ *c1 = X; *c2 = AGLatanh(sin(Y)); return retval; } static int mrc_reverse(c1,c2) /* Reverse gls conversion */ double *c1, *c2; /* Longitude,latitude */ { int retval=0; register double X= *c1,Y= *c2; Y = asin(tanh(Y)); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_mrc(ax) /* Initialize gls mode */ struct NLN_STATUS *ax; { ax->c1.mode = LIN; ax->c2.mode = LIN; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } /****************************************************************************/ /* ARC routines */ static int arc_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double vyy,ang; register double cos1,sin1,cos2,sin2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = c1fact*(cos1-c1ofs); /* Center transformation latitude */ cos1=cos(ang); sin1=sin(ang); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ cos2=cos(ang); sin2=sin(ang); vyy = sin1*cos2; ang=hypot(vyy,sin2); if(ang!=0) ang=acos(cos1*cos2)/ang; *c1 = vyy*ang; *c2 = sin2*ang; return retval; } static int arc_reverse(c1,c2) /* Reverse arcmonic conversion */ double *c1, *c2; { int retval=0; register double X= *c1,Y= *c2; register double D,D2,sinc; D2 = X*X+Y*Y; D = sqrt(D2); sinc = (D==0.0) ? 1.0 : sin(D)/D; X=atan2(X*sinc,cos(D2)); Y=asin(Y*sinc); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_arc(ax) /* Check arc transformation */ struct NLN_STATUS *ax; { ax->c1.mode = ANG; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } static int make_arc(ax) /* Set up the gnomonic transformation */ struct NLN_STATUS *ax; { float rfact[8]; double ac1,ac2; rfact[0] = (ax->c1.wind[1]+ /* Center of first axis */ ax->c1.wind[0])*0.5; rfact[1] = ax->c1.wind[0]; /* limits of first axis */ rfact[2] = ax->c1.wind[1]; rfact[3] = AGLAngF(ax->c1.Angmode); /* Angular factor of first axis */ rfact[4] = (ax->c2.wind[1]+ /* Center of second axis */ ax->c2.wind[0])*0.5; rfact[5] = ax->c2.wind[0]; /* limits of second axis */ rfact[6] = ax->c2.wind[1]; rfact[7] = AGLAngF(ax->c2.Angmode); /* Angular factor of second axis */ AG_RSET(8,rfact); AG_TRNS(gno_init, /* Set up user defined transformation */ arc_direct, arc_reverse); gno_init(); /* Compute cartesian window */ /* and transformation center */ ac1=ax->c1.wind[0]; ac2=0.0; arc_direct(&ac1,&ac2); ax->Wind[0]=ac1; ax->Wind[1]= -ac1; ac1=ax->c1.wind[1]; ac2=ax->c2.wind[1]; arc_direct(&ac1,&ac2); ax->Wind[2]= -ac2; ax->Wind[3]= ac2; MSSET("geom",ax->Metamode); return SUCCESS; } /****************************************************************************/ /* TAN2 routines Stereographics */ static void t2_init() { float fact[8]; (void)AG_RGET("user",fact); /* retrieve transformation parameters */ c1ofs = fact[0]; c1_min= fact[1]; c1_max= fact[2]; c1fact= fact[3]; c2ofs = fact[4]; c2_min= fact[5]; c2_max= fact[6]; c2fact= fact[7]; } static int t2_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double ang; register double cos1,sin1,cos2,sin2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = c1fact*(cos1-c1ofs); /* Center transformation latitude */ cos1=cos(ang); sin1=sin(ang); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ cos2=cos(ang); sin2=sin(ang); ang = 2.0/(1.0+cos1*cos2); *c1 = sin1*cos2*ang; *c2 = sin2*ang; return retval; } static int t2_reverse(c1,c2) /* Reverse arcmonic conversion */ double *c1, *c2; { int retval=0; register double X= *c1,Y= *c2; register double R2; R2 = (X*X+Y*Y)*0.25; X=atan2(X,(1.0-R2)); Y=asin(Y/(1.0+R2)); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_t2(ax) /* Check t2 transformation */ struct NLN_STATUS *ax; { ax->c1.mode = ANG; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } static int make_t2(ax) /* Set up the stereographic transformation */ struct NLN_STATUS *ax; { float rfact[8]; double ac1,ac2; rfact[0] = (ax->c1.wind[1]+ /* Center of first axis */ ax->c1.wind[0])*0.5; rfact[1] = ax->c1.wind[0]; /* limits of first axis */ rfact[2] = ax->c1.wind[1]; rfact[3] = AGLAngF(ax->c1.Angmode); /* Angular factor of first axis */ rfact[4] = (ax->c2.wind[1]+ /* Center of second axis */ ax->c2.wind[0])*0.5; rfact[5] = ax->c2.wind[0]; /* limits of second axis */ rfact[6] = ax->c2.wind[1]; rfact[7] = AGLAngF(ax->c2.Angmode); /* Angular factor of second axis */ AG_RSET(8,rfact); AG_TRNS(t2_init, /* Set up user defined transformation */ t2_direct, t2_reverse); t2_init(); /* Compute cartesian window */ /* and transformation center */ ac1=ax->c1.wind[0]; ac2=0.0; t2_direct(&ac1,&ac2); ax->Wind[0]=ac1; ax->Wind[1]= -ac1; ac1=ax->c1.wind[0]; ac2=ax->c2.wind[1]; t2_direct(&ac1,&ac2); ax->Wind[2]= -ac2; ax->Wind[3]= ac2; return SUCCESS; } /****************************************************************************/ /* SIN routines Stereographics */ static void sin_init() { float fact[8]; (void)AG_RGET("user",fact); /* retrieve transformation parameters */ c1ofs = fact[0]; c1_min= fact[1]; c1_max= fact[2]; c1fact= fact[3]; c2ofs = fact[4]; c2_min= fact[5]; c2_max= fact[6]; c2fact= fact[7]; } static int sin_direct(c1,c2) /* Convert a (c1,c2) value into (x,y) */ double *c1, *c2; /* Longitude,latitude */ { register double ang; register double cos1,cos2; int retval = 0; cos1 = *c1; cos2 = *c2; retval |= BOUNDARY1(cos1,c1_min,c1_max); retval |= BOUNDARY2(cos2,c2_min,c2_max); ang = c2fact*(cos2-c2ofs); /* Center transformation longitude */ *c2 = sin(ang); cos2=cos(ang); ang = c1fact*(cos1-c1ofs); /* Center transformation latitude */ *c1 = sin(ang)*cos2; return retval; } static int sin_reverse(c1,c2) /* Reverse arcmonic conversion */ double *c1, *c2; { int retval=0; register double X= *c1,Y= *c2; X=atan2(X,sqrt(1.0-X*X-Y*Y)); Y=asin(Y); X = X/c1fact+c1ofs; Y = Y/c2fact+c2ofs; retval |= BOUNDARY1(X,c1_min,c1_max); retval |= BOUNDARY2(Y,c2_min,c2_max); *c1=X; *c2=Y; return retval; } static int chk_sin(ax) /* Check sin transformation */ struct NLN_STATUS *ax; { ax->c1.mode = LIN; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,INT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); return SUCCESS; } static int make_sin(ax) /* Set up the stereographic transformation */ struct NLN_STATUS *ax; { float rfact[8]; double ac1,ac2; rfact[0] = (ax->c1.wind[1]+ /* Center of first axis */ ax->c1.wind[0])*0.5; rfact[1] = ax->c1.wind[0]; /* limits of first axis */ rfact[2] = ax->c1.wind[1]; rfact[3] = AGLAngF(ax->c1.Angmode); /* Angular factor of first axis */ rfact[4] = (ax->c2.wind[1]+ /* Center of second axis */ ax->c2.wind[0])*0.5; rfact[5] = ax->c2.wind[0]; /* limits of second axis */ rfact[6] = ax->c2.wind[1]; rfact[7] = AGLAngF(ax->c2.Angmode); /* Angular factor of second axis */ AG_RSET(8,rfact); AG_TRNS(sin_init, /* Set up user defined transformation */ sin_direct, sin_reverse); sin_init(); /* Compute cartesian window */ /* and transformation center */ ac1=ax->c1.wind[0]; ac2=0.0; sin_direct(&ac1,&ac2); ax->Wind[0]=ac1; ax->Wind[1]= -ac1; ac1=ax->c1.wind[0]; ac2=ax->c2.wind[1]; sin_direct(&ac1,&ac2); ax->Wind[2]= -ac2; ax->Wind[3]= ac2; return SUCCESS; } /****************************************************************************/ /* Some generic utilities */ static int make_some(ax) /* Set up some transformations */ struct NLN_STATUS *ax; { float rfact[8]; double ac1,ac2; int geom; int (*trn)(); ac1 = AGLAngF(ax->c1.Angmode); rfact[0] = (ax->c1.wind[1]+ /* Center of first axis */ ax->c1.wind[0])*0.5; ac2 = 1.0001*AG_PI/ac1; rfact[1] = rfact[0]-ac2; /* limits of first axis */ rfact[2] = rfact[0]+ac2; rfact[3] = ac1; /* Angular factor of first axis */ ax->c1.ftik= rfact[1]; ax->c1.ltik= rfact[2]; ax->c1.tikmj= 0.785398163397448/ac1; ac1 = AGLAngF(ax->c2.Angmode); rfact[4] = (ax->c2.wind[1]+ /* Center of second axis */ ax->c2.wind[0])*0.5; ac2 = 1.0001*AG_PI05/ac1; rfact[5] = rfact[4]-ac2; /* limits of second axis */ rfact[6] = rfact[4]+ac2; rfact[7] = ac1; /* Angular factor of second axis */ AG_RSET(8,rfact); switch(ax->Proj) { /* Set up user defined transformation */ case AITOFF: AG_TRNS(ait_init, ait_direct, ait_reverse); ait_init(); trn = ait_direct; geom=TRUE; break; case GLS: AG_TRNS(gno_init, gls_direct, gls_reverse); gno_init(); geom=TRUE; trn = gls_direct; break; case MERCATOR: AG_TRNS(gno_init, mrc_direct, mrc_reverse); gno_init(); trn = mrc_direct; geom=FALSE; break; case S2: AG_TRNS(gno_init, s2_direct, s2_reverse); gno_init(); geom=TRUE; trn = s2_direct; break; default: return FAILURE; } /* Compute cartesian window */ /* and transformation center */ ac1=ax->c1.wind[0]; ac2=0; trn(&ac1,&ac2); ax->Wind[0]=ac1; ac1=ax->c1.wind[1]; ac2=0; trn(&ac1,&ac2); ax->Wind[1]=ac1; ac1=0; ac2=ax->c2.wind[0]; trn(&ac1,&ac2); ax->Wind[2]=ac2; ac1=0; ac2=ax->c2.wind[1]; trn(&ac1,&ac2); ax->Wind[3]=ac2; if(geom) MSSET("geom",ax->Metamode); return SUCCESS; } static void plot_title(ax) struct NLN_STATUS *ax; { if(*(ax->Title) != '\0') { char Ssset[40]; float td=ax->Txtdim*1.5; float xc,yc; sprintf(Ssset,"lfrg;chdim=%5.2f,%5.2f;",td,td); MSSET(Ssset,ax->Metamode); xc = (ax->Boxa[1] + ax->Boxa[0])*0.5; yc = ax->Boxa[3]; AG_GTXT(xc,yc,ax->Title,20); } } static void plot_labels(ax) struct NLN_STATUS *ax; { if(*(ax->c1.label) != '\0') { float xc,yc; xc = (ax->Boxa[1] + ax->Boxa[0])/2.0; yc = ax->Boxa[2]; AG_GTXT(xc,yc,ax->c1.label,12); } if(*(ax->c2.label) != '\0') { float xc,yc; yc = (ax->Boxa[2] + ax->Boxa[3])/2.0; xc = ax->Boxa[0]; AG_GTXT(xc,yc,ax->c2.label,20); } if(*(ax->Rlabel) != '\0') { float xc,yc; yc = (ax->Boxa[2] + ax->Boxa[3])/2.0; xc = ax->Boxa[1]; AG_GTXT(xc,yc,ax->Rlabel,12); } } /****************************************************************************/ /* is12 */ /* Depending on the last character of keyword returns 1 (r), 2(t) or */ /* 0 (neither) */ static int is12(token) char *token; { char *ip = token; while(TRUE) { if( !(isalnum(*ip)) ) break; if( *ip == '=' ) break; ip++; } ip--; if( ip>=token ) switch(*(ip)) { case '1': return 1; case '2': return 2; } return 0; } /****************************************************************************/ /* analtok */ /* Analyzes a select token */ static enum CASES analtok(token) /* Returns an integer select code */ char *token; /* token to analize */ { int first,last,middle,found=(-1); enum CASES code=EOS; static struct jmptab { char cmnd[3]; char type; enum CASES code; } cases[] = { /* TO BE MAINTAINED SORTED !! */ { {'a','i','t'}, 0, AITOFF }, { {'a','r','c'}, 0, ARC }, { {'b','l','a'}, 0, BLAB }, { {'d','e','g'}, 2, DEG12 }, { {'d','i','v'}, 1, DIV1 }, { {'f','a','c'}, 1, FACT1 }, { {'f','i','x'}, 0, FIXIT }, { {'g','l','s'}, 0, GLS }, { {'g','n','o'}, 0, GNOMONIC }, { {'h','o','u'}, 2, HOUR12 }, { {'l','l','a'}, 0, LLAB }, { {'l','o','g'}, 2, LOG12 }, { {'m','a','n'}, 1, MAN1 }, { {'m','e','r'}, 0, MERCATOR }, { {'n','g','r'}, 2, NGRID12 }, { {'n','q','u'}, 2, NQUOT12 }, { {'o','f','f'}, 1, OFST1 }, { {'p','o','l'}, 0, POLAR }, { {'q','d','e'}, 2, QDEG12 }, { {'q','h','o'}, 2, QHOUR12 }, { {'q','r','a'}, 2, QRAD12 }, { {'r','a','d'}, 2, RAD12 }, { {'r','l','a'}, 0, RLAB }, { {'s','2','\0'}, 0, S2 }, { {'s','i','n'}, 0, SIN }, { {'s','t','e'}, 0, STEREO }, { {'t','i','t'}, 0, TITLE }, { {'t','x','d'}, 0, TXDIM }, { {'w','i','n'}, 0, WINDOW } }; if(*token=='\0') return 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 *getrt = token+2; int rt; switch(cases[found].type) { case 1: rt=is12(getrt); if(rt!=0) code=(enum CASES)((int)cases[found].code+rt-1); break; case 2: rt=is12(getrt); code=(enum CASES)((int)cases[found].code+rt); break; case 0: code=cases[found].code; break; } } return code; } /****************************************************************************/ /* setup_nlin */ static int setup_nlin (sel,token,ax) /* Set status according to */ /* select code */ enum CASES sel; /* select code */ char *token; /* select token (to get parameters) */ struct NLN_STATUS *ax; /* Status structure */ { /* Returns FALSE if no more tokens to anal. */ int eos = FALSE; int nvals; float rbuf[4]; switch(sel) { case MAN1: /***** Set (manual) tiks values on R-axis **********/ nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>=1) { ax->c1.man=MANUAL; ax->c1.tikmj=rbuf[0]; if(ax->c1.tikmj<=0.0) { ax->c1.man=NONE; if(*ax->c1.form!='*') strcpy(ax->c1.form,FLOAT); } } if(nvals>=2) ax->c1.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->c2.man=MANUAL; ax->c2.tikmj=rbuf[0]; if(ax->c2.tikmj<=0.0) { ax->c2.man=NONE; if(*ax->c2.form!='*') strcpy(ax->c2.form,FLOAT); } } if(nvals>=2) ax->c2.tikmn=rbuf[1]; break; /* Set up angular interpretation */ case DEG12: ax->c1.Angmode=DEGREES; ax->c2.Angmode=DEGREES; break; case DEG1: ax->c1.Angmode=DEGREES; break; case DEG2: ax->c2.Angmode=DEGREES; break; case HOUR12: ax->c1.Angmode=HOURS; ax->c2.Angmode=HOURS; break; case HOUR1: ax->c1.Angmode=HOURS; break; case HOUR2: ax->c2.Angmode=HOURS; break; case RAD12: ax->c1.Angmode=RADIANS; ax->c2.Angmode=RADIANS; break; case RAD1: ax->c1.Angmode=RADIANS; break; case RAD2: ax->c2.Angmode=RADIANS; break; /* Set up quote angular formats */ case QDEG12: strcpy(ax->c1.form,DDMM); strcpy(ax->c2.form,DDMM); break; case QDEG1: strcpy(ax->c1.form,DDMM); break; case QDEG2: strcpy(ax->c2.form,DDMM); break; case QHOUR12: strcpy(ax->c1.form,HHMM); strcpy(ax->c2.form,HHMM); break; case QHOUR1: strcpy(ax->c1.form,HHMM); break; case QHOUR2: strcpy(ax->c2.form,HHMM); break; case QRAD12: strcpy(ax->c1.form,FLOAT); strcpy(ax->c2.form,FLOAT); break; case QRAD1: strcpy(ax->c1.form,FLOAT); break; case QRAD2: strcpy(ax->c2.form,FLOAT); break; case DIV1: nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>1) ax->c1.divs[1]=rbuf[1]; if(nvals>0) ax->c1.divs[0]=rbuf[0]; break; case DIV2: nvals=2; nvals=AG_RVAL(token,nvals,rbuf); if(nvals>1) ax->c2.divs[1]=rbuf[1]; if(nvals>0) ax->c2.divs[0]=rbuf[0]; break; case LOG12: /***** Set logarithmic scale on R axis *************/ ax->c1.mode=LOG; ax->c2.mode=LOG; break; case LOG1: ax->c1.mode=LOG; break; case LOG2: ax->c2.mode=LOG; break; case BLAB: /***** Set Bottom label *************************/ nvals=MAXLABEL; nvals=AG_SVAL(token,nvals,ax->c1.label); break; case RLAB: /***** Set right label *************************/ nvals=MAXLABEL; nvals=AG_SVAL(token,nvals,ax->Rlabel); break; case LLAB: /***** Set left label *************************/ nvals=MAXLABEL; nvals=AG_SVAL(token,nvals,ax->c2.label); break; case TITLE: /***** Set plot title ******************************/ nvals=MAXTITLE; nvals=AG_SVAL(token,nvals,ax->Title); break; case NGRID12: /***** Disable grid tracing on both axes ***************/ ax->c1.grid=FALSE; ax->c2.grid=FALSE; break; case NGRID1: /***** Disable grid tracing on 1st axis ******************/ ax->c1.grid=FALSE; break; case NGRID2: /***** Disable grid tracing on 2nd axis ******************/ ax->c2.grid=FALSE; break; case NQUOT12: /***** Disable quotation on both axes ***************/ *ax->c1.form='*'; *ax->c2.form='*'; break; case NQUOT1: /***** Disable quotation on 1st axis ******************/ *ax->c1.form='*'; break; case NQUOT2: /***** Disable quotation on 2nd axis ******************/ *ax->c2.form='*'; break; case FACT1: /***** set mult. factor for quotation on R axis *****/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->c1.fact=rbuf[0]; break; case FACT2: /***** set mult. factor for quotation on T axis *****/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->c2.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 R axis ***/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->c1.offst=rbuf[0]; break; case OFST2: /***** Set offset factor for quotation on T axis ***/ nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->c2.offst=rbuf[0]; break; case TXDIM: nvals=1; nvals=AG_RVAL(token,nvals,rbuf); ax->Txtdim=rbuf[0]; break; case WINDOW: nvals=4; nvals=AG_RVAL(token,nvals,rbuf); if(nvals == 4){ ax->Windfix=TRUE; ax->Wind[0]=rbuf[0]; ax->Wind[1]=rbuf[1]; ax->Wind[2]=rbuf[2]; ax->Wind[3]=rbuf[3]; } break; case POLAR: case GNOMONIC: case AITOFF: case GLS: case S2: case MERCATOR: case ARC: case STEREO: case SIN: ax->Proj=(int)sel; break; case EOS: eos=TRUE; break; default: break; } return eos; } static void set_clpa(ax) struct NLN_STATUS *ax; { char Ssset[40]; float xd[3],yd[3]; AG_RGET("VWPLIM",ax->Clpa); /* Get current viewport limits */ AG_RGET("SCALE",xd); 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); } ax->Txtdim *= xd[0]; sprintf(Ssset,"lfrg;chdim=%5.2f,%5.2f", /* Set up required text dim. */ ax->Txtdim,ax->Txtdim); MSSET (Ssset,ax->Metamode); AG_TGET("X",xd,yd); ax->Boxa[3] = yd[1]*7.0; /* Set space on top */ ax->Boxa[2] = yd[1]*7.0; /* Set space on bottom */ ax->Boxa[1] = xd[0]*5.0; /* Set space at right */ ax->Boxa[0] = xd[0]*7.0; /* Set space at left */ if(!ax->Fixit) { ax->Clpa[0] += ax->Boxa[0]; /* Compute resulting clipping area */ ax->Clpa[1] -= ax->Boxa[1]; ax->Clpa[2] += ax->Boxa[2]; ax->Clpa[3] -= ax->Boxa[3]; } (void)AG_CDEF(ax->Clpa[0],ax->Clpa[1], /* set up the clipping area */ ax->Clpa[2],ax->Clpa[3]); } /****************************************************************************/ /* chk_polar */ static int chk_polar(ax) /* Check polar mode */ /* Returns 0 on success */ struct NLN_STATUS *ax; { ax->c1.mode = LIN; ax->c2.mode = ANG; if(*ax->c1.form!='*' ) strcpy(ax->c1.form,FLOAT); if(*ax->c2.form!='*' ) strcpy(ax->c2.form,INT); if(ax->c1.wind[0]<0.0) ax->c1.wind[0] = 0.0; if(ax->c1.wind[1]<=ax->c1.wind[0]) { AG_GERR(201,Range); return FAILURE; } return SUCCESS; } static int chk_proj(ax) struct NLN_STATUS *ax; { int retval=FAILURE; switch(ax->Proj) { case POLAR: retval = chk_polar(ax); break; case GNOMONIC: retval = chk_gnomo(ax); break; case AITOFF: retval = chk_aitoff(ax); break; case GLS: retval = chk_gls(ax); break; case MERCATOR: retval = chk_mrc(ax); break; case S2: retval = chk_s2(ax); break; case ARC: retval = chk_arc(ax); break; case STEREO: retval = chk_t2(ax); break; case SIN: retval = chk_sin(ax); break; default: AG_GERR(202,"Illegal tranformation"); retval = FAILURE; break; } return retval; } /****************************************************************************/ /* do_proj */ static void do_proj(ax) /* Draw the plot in gnomomonic coordinates */ struct NLN_STATUS *ax; { float data[11]; float *cc1,*cc2; int qdisp=0; int qdelay1=FALSE; int qdelay2=FALSE; int stat; void (*Draw_func)(); cc1 = data; cc2 = data+5; set_clpa(ax); AGLfmt(&(ax->c1)); AGLfmt(&(ax->c2)); switch(ax->Proj) { case POLAR: if((ax->c2.Angmode==RADIANS)&&(*ax->c2.form!='*')) strcpy(ax->c2.form,"%f"); qdelay2=TRUE; /* Disable quotes on theta axis */ qdisp=QUOTE_DISPL; /* To get displaced quote positions */ stat=make_polar(ax); break; case GNOMONIC: /* Check data window range */ if(ltrange(&(ax->c1),AG_PI)!=SUCCESS) return; if(ltrange(&(ax->c2),AG_PI)!=SUCCESS) return; stat=make_gnomo(ax); /* Set up things for gnomonic axis */ break; case ARC: /* Check data window range */ if(ltrange(&(ax->c1),AG_PI)!=SUCCESS) return; if(ltrange(&(ax->c2),AG_PI)!=SUCCESS) return; stat=make_arc(ax); break; case STEREO: /* Check data window range */ if(lerange(&(ax->c1),AG_PI05)!=SUCCESS) return; if(lerange(&(ax->c2),AG_PI05)!=SUCCESS) return; stat=make_t2(ax); qdelay1=TRUE; qdelay2=TRUE; break; case SIN: /* Check data window range */ if(lerange(&(ax->c1),AG_PI05)!=SUCCESS) return; if(lerange(&(ax->c2),AG_PI05)!=SUCCESS) return; qdelay1=TRUE; qdelay2=TRUE; stat=make_sin(ax); break; case AITOFF: /* Check data window range */ case GLS: case S2: stat=make_some(ax); qdelay1=TRUE; qdelay2=TRUE; break; case MERCATOR: stat=make_some(ax); break; } if(stat!=SUCCESS) { AG_GERR(203,"Transformation setup"); return; } AG_WDEF(ax->Wind[0],ax->Wind[1], /* Define cartesian Window limits */ ax->Wind[2],ax->Wind[3]); AG_RGET("CLPLIM",data); ax->Boxa[0] = data[0]-ax->Boxa[0]; /* box enclosing everything. */ ax->Boxa[1] = data[1]+ax->Boxa[1]; ax->Boxa[2] = data[2]-ax->Boxa[2]; ax->Boxa[3] = data[3]+ax->Boxa[3]; MSSET("special",ax->Metamode); /* reset SPECIAL mode spoiled by AG_WDEF() */ /* Now draw everything */ if(ax->c1.mode==ANG) Draw_func=AG_GINT; else Draw_func=AG_GPLL; cc1[0]=ax->c1.wind[0]; cc1[1]=ax->c1.wind[1]; cc2[0]=ax->c2.wind[0]; cc2[1]=cc2[0]; if(ax->c1.grid) Draw_func(cc1,cc2,2); cc2[0]=ax->c2.wind[1]; cc2[1]=cc2[0]; if(ax->c1.grid) Draw_func(cc1,cc2,2); if(ax->c2.mode==ANG) Draw_func=AG_GINT; else Draw_func=AG_GPLL; cc1[0]=ax->c1.wind[0]; cc1[1]=cc1[0]; cc2[0]=ax->c2.wind[0]; cc2[1]=ax->c2.wind[1]; if(ax->c2.grid) Draw_func(cc1,cc2,2); cc1[0]=ax->c1.wind[1]; cc1[1]=cc1[0]; if(ax->c2.grid) Draw_func(cc1,cc2,2); if((ax->c1.man!=NONE)&&ax->c1.grid) { data[0] = ax->c1.wind[0]; data[1] = ax->c1.wind[1]; data[2] = ax->c1.ftik; data[3] = ax->c1.ltik; data[4] = ax->c1.tikmj; data[5] = 0.0; data[6] = ax->c2.wind[0]; data[7] = ax->c2.wind[1]; data[8] = ax->c1.offst; data[9] = qdelay1 ? 0 : ax->c1.fact; data[10]= ax->c1.iexp; AG_AXIS(qdisp|ax->Bold|X_BOTTOM_AXIS|NO_AXIS_LINE, data,0.0,ax->c1.form,ax->c1.label); } if((ax->c2.man!=NONE)&&ax->c2.grid) { data[0] = ax->c2.wind[0]; data[1] = ax->c2.wind[1]; data[2] = ax->c2.ftik; data[3] = ax->c2.ltik; data[4] = ax->c2.tikmj; data[5] = 0.0; data[6] = ax->c1.wind[0]; data[7] = ax->c1.wind[1]; data[8] = ax->c2.offst; data[9] = qdelay2 ? 0 : ax->c2.fact; data[10]= ax->c2.iexp; AG_AXIS(ax->Bold|Y_LEFT_AXIS|NO_AXIS_LINE, data,0.0,ax->c2.form,ax->c2.label); } switch(ax->Proj) { case GNOMONIC: /* quotes have been written already */ case ARC: case MERCATOR: break; case POLAR: /* Special way to label c2 axis */ if((ax->c2.man!=NONE)&&(*ax->c2.form!='*')) polar_quote(ax); break; case AITOFF: /* Need a special way to draw quotes */ case SIN: case GLS: case S2: case STEREO: if(ax->c1.man != NONE) { data[0] = 0.0; data[1] = 0.0; data[2] = ax->c1.ftik; data[3] = ax->c1.ltik; data[4] = ax->c1.tikmj; data[5] = 0.0; data[6] = (ax->c2.wind[0]+ax->c2.wind[1])*0.5; data[7] = data[6]; data[8] = ax->c1.offst; data[9] = ax->c1.fact; data[10]= ax->c1.iexp; AG_AXIS(ax->Bold|QUOTE_DISPL|X_BOTTOM_AXIS, data,0.0,ax->c1.form,""); } if(ax->c2.man != NONE) { data[0] = 0.0; data[1] = 0.0; data[2] = ax->c2.ftik; data[3] = ax->c2.ltik; data[4] = ax->c2.tikmj; data[5] = 0.0; data[6] = (ax->c1.wind[0]+ax->c1.wind[1])*0.5; data[7] = data[6]; data[8] = ax->c2.offst; data[9] = ax->c2.fact; data[10]= ax->c2.iexp; AG_AXIS(ax->Bold|QUOTE_DISPL|Y_LEFT_AXIS, data,0.0,ax->c1.form,""); } break; } MSSET("normal",ax->Metamode); plot_labels(ax); /* Draw labels */ plot_title(ax); /* Draw plot title */ MSSET ("special;chbasic;sybasic",ax->Metamode); AG_VUPD(); } /****************************************************************************/ /*++ AG_NLIN (User callable) */ /* AG_NLIN */ /* This module computes and draws a grid on the currently active viewport */ /* using one of a set of non-linear coordinate projections. */ /* The position of the grid is computed so that quotes, labels and title */ /* will fit into viewport. */ /* A variety of options and axes drawing modes can be selected by means of */ /* an option selection string, this will also select the actual projection */ /* to be applied. */ /* After the call the the selected projection will remain active, so that */ /* subsequent graphic operations will be referred to the selecte corrdinate */ /* system. */ /* After the plot is drawn, the box enclosing it may be addressed by re- */ /* storing the cartesian transformation via a call: */ /* AG_TRNS(NULL,NULL,NULL) */ /* After the call the graphic status will be "USER" and a window suitable */ /* to enclose the polar plot is selected (see also WINDOW below) */ /* N.B.: Character dimensions and orientation as set prior of the call are */ /* not preserved */ void AG_NLIN(c1l,c1u,c2l,c2u,select) double c1l,c1u; /* User window limits on first axis */ /* Limits depend on the actual transformation */ /* selected. */ double c2l,c2u; /* User window limits on second axis */ /* Limits depend on the actual transformation */ /* selected. */ /* Actual axes meaning depends on the particu- */ /* lar projection selected. */ /* Angular values are interpreted as Radians */ /* by default, but it can be changed to */ /* Degrees or Hours (See items: DEG and HOUR */ /* below) */ char *select; /* Option string (see below) */ /* Option string specifications: */ /* Syntax: "keywd[=value,value...][;keywd[=value...]]" */ /* The keyword spacifying the type of transformation is required, it must be */ /* one of the following: */ /* AITOFF */ /* Selects the transformation: */ /* X=2*cos(c2)sin(c1/2)/d */ /* Y=sin(c2)/d */ /* with: d=sqrt((1+cos(c2)cos(c1/2))/2) */ /* This transformation will map the sphere onto an ellipse with conser- */ /* vation of surfaces */ /* When this transformation is selected the user window arguments are only*/ /* used in order to determine the center of the projection, the projection*/ /* limits will always be [-180,+180] degrees on first axis and [-90,+90] */ /* on the second axis. */ /* ARC */ /* Selects the arc transformation (Schmidt plates projection) */ /* X=(sin(c1)cos(c2))*acos((cos(c1)cos(c2)))/d */ /* Y=sin(c2)*acos((cos(c1)cos(c2)))/d */ /* where: d=sqrt((sin(c1)cos(c2))**2+sin(c2)**2) */ /* GLS */ /* Selects the Global Sinusoidal transformation: */ /* X=c1*cos(c2) */ /* Y=c2 */ /* This transformation will map the sphere into two opposite sinusoids */ /* GNOMONIC */ /* Selects gnomonic transformation: */ /* X=((sin(c1)cos(c2))/(cos(c1)cos(c2))) */ /* Y=(sin(c2)/(cos(c1)cos(c2))) */ /* The transformation is centered in the center point of the defined data */ /* window. */ /* Limits: (maxc1 - minc1) < pi */ /* (maxc2 - minc2) < pi */ /* MERCATOR */ /* Selects the Mercator transformation: */ /* X=c1 */ /* Y=atanh(sin(c2)) */ /* POLAR */ /* Selects polar Transformation. */ /* X=c1*cos(c2) */ /* Y=c1*sin(c2) */ /* Limits: 0 < minc1 < maxc1 */ /* S2 */ /* selects the sin2 transformation: */ /* X=(sin(c1)cos(c2))*sqrt(2/(1+(cos(c1)cos(c2)))) */ /* Y=sin(c2)*sqrt(2/(1+(cos(c1)cos(c2)))) */ /* This transformation will map the sphere onto a circle */ /* SIN */ /* Selects the Sin transformation: */ /* X=(sin(c1)cos(c2)) */ /* Y=sin(c2) */ /* STEREO */ /* Selects the stereographic transformation: */ /* X=(2(sin(c1)cos(c2))/(1+(cos(c1)cos(c2)))) */ /* Y=(2*sin(c2)/(1+(cos(c1)cos(c2)))) */ /* The following keywords are not required in that suitable defaults are */ /* provided: */ /* DEG */ /* DEG1 */ /* DEG2 */ /* Select interpretation of values on the selected axis (or both) to */ /* degrees. */ /* Default interpretation depends on the particular transformation */ /* selected. */ /* DIV1=[start[,stop]] */ /* DIV2=[start[,stop]] */ /* Draw divisions and corresponding quotes only between given coordinates */ /* FACT1 */ /* FACT2 */ /* Specifies a multiplying factor for quotes. Numbers written at tik */ /* 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 1 or 2) */ /* offst? is an offset value (see OFFST1, OFFST2) */ /* 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 */ /* HOUR */ /* HOUR1 */ /* HOUR2 */ /* Select interpretation of values on the selected axis (or both) to */ /* hours. */ /* */ /* Default interpretation depends on the particular transformation */ /* selected. */ /* LABB=string */ /* Specifies a label to be written on the bottom of plot */ /* LABL=string */ /* Specifies a label to be written to the left of plot */ /* LOG */ /* LOG1 */ /* LOG2 */ /* Select logarithmic transformation on the selected axis (or both) */ /* Default is Linear */ /* MAN1=mjstep[,mnstep] */ /* MAN2=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. */ /* NGRID */ /* NGRID1 */ /* NGRID2 */ /* do not draw grid lines along the corresponding axis */ /* NQUOT */ /* NQUOT1 */ /* NQUOT2 */ /* Suppresses quotes on the corresponding axis. */ /* OFFST1 */ /* OFFST2 */ /* 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 FACTR, FACTT) */ /* 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 */ /* QDEG */ /* QDEG1 */ /* QDEG2 */ /* Select degrees format for quotes on angular valued axis */ /* It also affects preferred tiks positions when automatic tik computing */ /* is enabled. */ /* Default format depends on the particular transformation selected. */ /* QHOUR */ /* QHOUR1 */ /* QHOUR2 */ /* Select hour format for quotes on angular valued axis */ /* */ /* Default format depends on the particular transformation selected. */ /* QRAD */ /* QRAD1 */ /* QRAD2 */ /* Select radiant format for quotes on angular valued axis */ /* It also affects preferred tiks positions when automatic tik computing */ /* is enabled. */ /* Default format depends on the particular transformation selected. */ /* RAD */ /* RAD1 */ /* RAD2 */ /* Select interpretation of values on the selected axis (or both) to */ /* radiants. */ /* */ /* Default interpretation depends on the particular transformation */ /* selected. */ /* TITLE=string */ /* Specifies a title to be written on top of the plot. */ /* TXDIM=mult */ /* Specifies a multiplying factor to apply to all text strings */ /* WINDOW=xmin,xmax,ymin,ymax */ /* Specifies limits for the cartesian window. E.g.: WINDOW=-1,1,-1,1 */ /* would enclose all the four quadrants of a polar plot, WINDOW=0,1,0,1 */ /* would enclose the first quadrant only, and so on. */ /* By default the window limits are automatically adjusted. */ /* Here follows a typical calling sequence: */ /* AG_VDEF (.......) Define graphic device */ /* AG_NLIN(r0,r1,t0,t1,"polar") 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) */ /*--*/ { int eos; char *ix = select; struct NLN_STATUS my_status; { char aux[64]; sprintf(aux,"AG_NLIN(%g,%g,%g,%g,",c1l,c1u,c2l,c2u); (void)AG_DMSG(aux,select); } my_status.c1.wind[0] = c1l; my_status.c1.wind[1] = c1u; my_status.c2.wind[0] = c2l; my_status.c2.wind[1] = c2u; my_status.c1.divs[0] = c1l; my_status.c1.divs[1] = c1u; my_status.c2.divs[0] = c2l; my_status.c2.divs[1] = c2u; init_gen(&my_status); eos=FALSE; while ( ! eos ) { /* String analysis loop */ enum CASES sel; char token[MAXTOKEN+1]; ix = AG_SCAN(ix,';',MAXTOKEN,token); /* Parse next token */ sel=analtok(token); eos = setup_nlin(sel,token,&my_status); } if(chk_proj(&my_status)==SUCCESS) do_proj(&my_status); }