/* @(#)plper.c 17.1.1.1 (ES0-DMD) 01/25/02 17:44:49 */ /*=========================================================================== 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 ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COPYRIGHT (c) 1993 European Southern Observatory .IDENTifer module PLPER .AUTHOR R.M. van Hees IPG-ESO Garching .KEYWORDS plot software, graphics, bulk data fame, perspective plotting .LANGUAGE C .PURPOSE Perspective plotting routine for two dimensional data .COMMENTS holds the functions : PLPER and PLPERI and static functions: TRANSPOSE, RC_COEF, L_STEEPER, L_CROSS, DRAW_LINES and HIDE_LINE .ENVIRONment MIDAS and AGL #include Prototypes for AGL application programs #include Prototypes for MIDAS interfaces #include Symbols used by the PLT interfaces .VERSION 1.3 24-Apr-1994 improved layout & removed bugs, RvH 1.2 30-Nov-1993 2-D & 3-D data is passed in structs, RvH 1.1 20-Sep-1993 Created by R.M. van Hees ------------------------------------------------------------*/ /* * Define _POSIX_SOURCE to indicate * that this is a POSIX program */ #define _POSIX_SOURCE 1 /* * definition of the used functions in this module */ #include #include #include #include #include /* * define some macros and constants */ #include #define CASE_A 0 /* Defined TRANSPOSE actions */ #define CASE_B 1 #define CASE_C 2 #define CASE_D 3 #define MAXCROSS 10 /* Maximum number of crossings */ #define MEMSIZE (4 * (ln_dim + ln_mx)) #define STEEPER TRUE /* Constants used by L_STEEPER */ #define NOT_STEEPER FALSE #define OUTSIDE -2 #define ABOVE -1 #define BELOW 0 /*++++++++++++++++++++++++++++++ .IDENTifer TRANSPOSE .PURPOSE Dedicated routine; leave projection as is, but change the indices in such a way that the image is build up from the users viewpoint (buttom to top) .INPUT/OUTPUT input float azim : viewing angle, only the azimuth double *step : distance between the pixels in w.c. int nxval : number of pixels along the first axis int nyval : number of pixels along the second axis in/ouput struct Pdata *data : data to be transposed --------------------------------*/ #ifdef __STDC__ static void TRANSPOSE( float azim, double *step, int nrx, int nry, struct Pdata *data ) #else static void TRANSPOSE( azim, step, nrx, nry, data ) int nrx, nry; float azim; double *step; struct Pdata *data; #endif { int trans; /* * Determine the type of transposition we have to do */ if ( azim < 90.0 ) { if ( step[0] > 0.0 && step[1] > 0.0 ) trans = CASE_A; else if ( step[0] > 0.0 ) trans = CASE_B; else if ( step[1] > 0.0 ) trans = CASE_D; else trans = CASE_C; } else if ( azim < 180.0 ) { if ( step[0] > 0.0 && step[1] > 0.0 ) trans = CASE_B; else if ( step[0] > 0.0 ) trans = CASE_A; else if ( step[1] > 0.0 ) trans = CASE_C; else trans = CASE_D; } else if ( azim < 270.0 ) { if ( step[0] > 0.0 && step[1] > 0.0 ) trans = CASE_C; else if ( step[0] > 0.0 ) trans = CASE_D; else if ( step[1] > 0.0 ) trans = CASE_B; else trans = CASE_A; } else { if ( step[0] > 0.0 && step[1] > 0.0 ) trans = CASE_D; else if ( step[0] > 0.0 ) trans = CASE_C; else if ( step[1] > 0.0 ) trans = CASE_A; else trans = CASE_B; } if ( trans != CASE_A ) { register int nx, ny, nr; register int nval = nrx * nry; struct Pdata *bgn_data, *bgn_buff, *buff; /* * make a copy */ bgn_buff = buff = (struct Pdata *) osmmget( nval* sizeof(struct Pdata)); bgn_data = data; while ( nval-- > 0 ) { buff->px = data->px; buff++->py = data++->py; } data = bgn_data; buff = bgn_buff; /* * transpose! */ switch ( trans ) { case CASE_B: while ( nry > 0 ) { buff = bgn_buff + nrx * (--nry); for ( nx = 0; nx < nrx; nx++ ) { data->px = buff->px; data++->py = buff++->py; } } break; case CASE_C: buff += (nval = nrx * nry) - 1; for ( nr = 0; nr < nval; nr++ ) { data->px = buff->px; data++->py = (buff--)->py; } break; case CASE_D: buff += nrx - 1; for ( ny = 0; ny < nry; ny++ ) { for ( nx = 0; nx < nrx; nx++ ) { data->px = buff->px; data++->py = (buff--)->py; } buff += 2 * nrx; } break; default: break; } (void) osmmfree( (char *) bgn_buff ); } } /*++++++++++++++++++++++++++++++ .IDENTifer RC_COEF .PURPOSE Dedicated routine, calculates TANGENT of a line between two points .INPUT/OUTPUT input struct Pdata *point1 struct Pdata *point2 .RETURNS (y2 - y1) / (x2 - x1) --------------------------------*/ #ifdef __STDC__ static double RC_COEF( struct Pdata *point1, struct Pdata *point2 ) #else static double RC_COEF( point1, point2 ) struct Pdata *point1, *point2; #endif { if ( point2->px == point1->px ) { if ( point2->py >= point1->py ) return (1.0e+20); else return (-1.0e+20); } else return (point2->py - point1->py) / (point2->px - point1->px); } /*++++++++++++++++++++++++++++++ .IDENTifer L_STEEPER .PURPOSE Dedicated routine; .INPUT/OUTPUT input int dir direction of the plot (see HIDE_LINE) struct Pdata *point3 in/output struct Pdata segmnt[2]: line segment point1 --> point2 .RETURNS STEEPER if a line point1 --> point2 is steeper then a line from point1 --> point3 NOT_STEEPER if this is not the case then point2 = point3 --------------------------------*/ #ifdef __STDC__ static int L_STEEPER( struct Pdata *point3, struct Pdata segmnt[2] ) #else static int L_STEEPER( point3, segmnt ) struct Pdata *point3, segmnt[2]; #endif { if ( RC_COEF( segmnt, point3 ) > RC_COEF( segmnt, segmnt+1 ) ) { (segmnt+1)->px = point3->px; (segmnt+1)->py = point3->py; return STEEPER; } else return NOT_STEEPER; } /*++++++++++++++++++++++++++++++ .IDENTifer L_CROSS .PURPOSE Dedicated routine; calculates an intersection between lines .INPUT/OUTPUT input int mx_dim : dimension of mx_plot struct Pdata *mx_plot : actual maxima in the plot struct Pdata newln[2] : new line segment to be plotted output struct Pdata cross[2] : coordinates of the intersections .RETURNS number of intersections or BELOW, ABOVE, OUTSIDE --------------------------------*/ #ifdef __STDC__ static int L_CROSS( int mx_dim, struct Pdata *mx_plot, struct Pdata newln[2], struct Pdata *cross ) #else static int L_CROSS( mx_dim, mx_plot, newln, cross ) int mx_dim; struct Pdata *mx_plot, newln[2], *cross; #endif { static int indx1 = 0; /* indices of mx_plot->px resp. smaller & */ register int indx2; /* larger than newln->px and (newln+1)->px */ register int indx, nc = 0; double cc_new, cc_mx, rc_new, rc_mx, mx_valy; /* * If the line segment has no overlap with the maxima of the current plot * we return to the calling routine */ if ( newln[1].px < mx_plot->px || newln->px >= mx_plot[mx_dim-1].px ) return OUTSIDE; else if ( newln[1].px == mx_plot->px && newln[1].py == mx_plot->py ) { cross[0].px = newln[1].px; cross[0].py = newln[1].py; return 1; } /* * Find last point along mx_plot->px smaller than newln->px */ if ( indx1 > mx_dim-1 || newln->px < mx_plot[indx1].px ) indx1 = 0; while ( indx1 < mx_dim-1 && newln->px > mx_plot[indx1+1].px ) indx1++; /* * Find first point along mx_plot->px larger or equal than newln[1].px */ indx2 = indx1 + 1; while ( indx2 < mx_dim-1 && newln[1].px > mx_plot[indx2].px ) indx2++; /* * check for each line segment of MX_PLOT between indx1 & indx2 * if it intersects with NEWLN */ rc_new = RC_COEF( newln, newln+1 ); cc_new = newln->py - rc_new * newln->px; indx = indx1; do { if ( newln[1].px == mx_plot[indx+1].px && newln[1].py == mx_plot[indx+1].py ) { cross[nc].px = newln[1].px; cross[nc].py = newln[1].py; nc++; } else { rc_mx = RC_COEF( mx_plot+indx, mx_plot+indx+1 ); cc_mx = mx_plot[indx].py - rc_mx * mx_plot[indx].px; if ( rc_mx != rc_new ) { cross[nc].px = (cc_new - cc_mx) / (rc_mx - rc_new); if ( cross[nc].px > MYMAX( newln->px, mx_plot[indx].px ) && cross[nc].px < MYMIN( newln[1].px, mx_plot[indx+1].px )) { cross[nc].py = cc_new + rc_new * cross[nc].px; nc++; } } } } while( ++indx < indx2 ); /* * Lays NEWLN[1] below MX_PLOT? ( only if no intersection is found ) */ if ( nc == 0 ) { nc = ABOVE; indx = indx1; do { if ( newln[1].px > mx_plot[indx].px && newln[1].px <= mx_plot[indx+1].px ) { rc_mx = RC_COEF( mx_plot+indx, mx_plot+indx+1 ); cc_mx = mx_plot[indx].py - rc_mx * mx_plot[indx].px; mx_valy = cc_mx + rc_mx * newln[1].px; if ( mx_valy > newln[1].py ) nc = BELOW; } } while( nc != BELOW && ++indx < indx2 ); } return nc; } /*+++++++++++++++++++++++++++++++ .IDENTifer DRAW_LINE .PURPOSE A given set of points are connected with straight lines starting from the first point and drawn on the graphics device .INPUT/OUTPUT input int dir : direction (see HIDE_LINE) int nr : dimension of new_line struct Pdata *new_line : data of the line given as (x,y) int cls_line[2] : flags to close the surface: [0] != FALSE take first point of old_line [1] != FALSE index to point in old_line struct Pdata *old_line : data of the previous line --------------------------------*/ #ifdef __STDC__ static void DRAW_LINE( int dir, int nr, struct Pdata *new_line, int cls_line[2], struct Pdata *old_line ) #else static void DRAW_LINE( dir, nr, new_line, cls_line, old_line ) int dir, nr, cls_line[2]; struct Pdata *new_line, *old_line; #endif { register int ii, np = 0; float *xval, *yval; static char *err_mem = "*** FATAL: HIDE_LINE: can't allocate enough memory"; xval = (float *) osmmget( (nr+2) * sizeof( float )); if ( xval == NULL ) SCETER( 1, err_mem ); yval = (float *) osmmget( (nr+2) * sizeof( float )); if ( yval == NULL ) SCETER( 2, err_mem ); if ( cls_line[0] ) { xval[np] = (float) old_line->px; yval[np++] = (float) old_line->py; } for ( ii = 0; ii < nr; ii++ ) { xval[np] = (float) (dir * new_line->px); yval[np++] = (float) new_line++->py; } if ( cls_line[1] ) { xval[np] = (float) old_line[cls_line[1]].px; yval[np++] = (float) old_line[cls_line[1]].py; } /* * draw the line */ AG_GPLL( xval, yval, np ); (void) osmmfree( (char *) xval ); (void) osmmfree( (char *) yval ); } /*+++++++++++++++++++++++++++++++ .IDENTifer HIDE_LINE .PURPOSE Check which part of a line is hidden and draw what can be seen on the graphics device .INPUT/OUTPUT input int ln_nr : sequence number of the line int ln_mx : maximum number of lines to be drawn int ln_dim : dimension of line DATA struct Pdata *data : data of the line given as (x,y) .COMMENT - the first line to be drawn has to have LN_NR = 1, to initialise backup arrays and no part of this line can be hiden by a line with a higher LN_NR. - Only after a call with LN_NR = LN_MX, LN_DIM can be changed, and we have to start again with LN_NR = 1 --------------------------------*/ #ifdef __STDC__ static void HIDE_LINE( int ln_nr, int ln_mx, int ln_dim, struct Pdata *data ) #else static void HIDE_LINE( ln_nr, ln_mx, ln_dim, data ) int ln_nr, ln_mx, ln_dim; struct Pdata *data; #endif { register int ii, np, nr; int ncross, cls_line[2], other_seg, plot_line; struct Pdata other_dir[1], segmnt[2], cross[MAXCROSS], *hd_line; /* * data which have to be kept in memory */ static char *err_mem = "FATAL error PLPER: can't allocate enough memory", *err_calc = "FATAL error PLPER: roundoff error occurred"; static int dir, mx_dim; static struct Pdata *old_data, *mx_plot; /* * Initialise number of point plotted and by default no connection * with previous line */ np = 0; for ( ii = 0; ii < 2; ii++ ) cls_line[ii] = FALSE; /* * HD_LINE contains the points which will be connected and drawn */ hd_line = (struct Pdata *) osmmget( MEMSIZE * sizeof(struct Pdata)); if ( hd_line == NULL ) SCETER( 3, err_mem ); /* * LN_NR == 1: allocate memory and collect points for first line */ plot_line = TRUE; if ( ln_nr == 1 ) { mx_dim = ln_dim; /* Dimension of the maxima line */ /* * DIRection in which lines are plotted: 1) left to right; -1) right to left */ dir = ( data->px > data[ln_dim-1].px ) ? -1 : 1; /* * old_data is the previous line */ old_data = (struct Pdata *) osmmget( ln_dim * sizeof(struct Pdata)); if ( old_data == NULL ) SCETER( 4, err_mem ); /* * mx_plot is the actual maximum in the plot */ mx_plot = (struct Pdata *) osmmget( MEMSIZE * sizeof(struct Pdata)); if ( mx_plot == NULL ) SCETER( 5, err_mem ); /* * we can draw the first line: no hidden points! */ while ( np < ln_dim ) { hd_line[np].px = dir * data->px; hd_line[np++].py = data++->py; } } else { cls_line[0] = TRUE; /* first point of previous line */ hd_line[np].px = dir * data->px; /* first point of new line */ hd_line[np++].py = data++->py; for ( nr = 1; nr < ln_dim; nr++, data++ ) { other_seg = FALSE; /* * We take the next line segment to be plotted */ for ( ii = 0; ii < 2; ii++ ) { segmnt[ii].px = dir * data[ii-1].px; segmnt[ii].py = data[ii-1].py; } /* * We take the connection to the previous line if this one is steeper */ if ( plot_line ) { other_dir->px = dir * old_data[nr-1].px; other_dir->py = old_data[nr-1].py; other_seg = L_STEEPER( other_dir, segmnt ); } /* * First a special case: we were OUTSIDE and do not know if we are * below or above MX_PLOT */ if ( ! other_seg && nr > 1 && ncross == OUTSIDE ) { ncross = L_CROSS( mx_dim, mx_plot, segmnt, cross ); if ( ncross > 0 ) plot_line = FALSE; /* effectively a CROSS_UP */ else if ( ncross == BELOW ) ncross = OUTSIDE; /* we are below MX_PLOT!! */ } else ncross = L_CROSS( mx_dim, mx_plot, segmnt, cross ); /* * if we (probably due to round off errors) can not close the surface with an * other segment use data... */ if ( other_seg && ncross < 1 ) { other_seg = FALSE; segmnt[1].px = dir * data->px; segmnt[1].py = data->py; ncross = L_CROSS( mx_dim, mx_plot, segmnt, cross ); } if ( other_seg ) { plot_line = FALSE; hd_line[np].px = cross[ncross-1].px; hd_line[np].py = cross[ncross-1].py; if ( dir * data->px > hd_line[np].px ) { np++; /* we have to plot np */ segmnt[1].px = dir * data->px; segmnt[1].py = data->py; ncross = L_CROSS( mx_dim, mx_plot, segmnt, cross ); for ( ii = 0; ii < ncross; ii++ ) { if ( cross[ii].px > hd_line[np-1].px ) { if ( plot_line ) plot_line = FALSE; else plot_line = TRUE; hd_line[np].px = cross[ii].px; hd_line[np++].py = cross[ii].py; } } if ( plot_line ) { hd_line[np].px = segmnt[1].px; hd_line[np++].py = segmnt[1].py; } } else { register int kk = np, jj = 0; float xval[2], yval[2]; /* * Draw this segment on the graphics display */ xval[0] = (float) dir * segmnt->px; yval[0] = (float) segmnt->py; xval[1] = (float) dir * hd_line[kk].px; yval[1] = (float) hd_line[kk++].py; AG_GPLL( xval, yval, 2 ); /* * Update MX_PLOT including the new line segment */ while ( jj < mx_dim && mx_plot[jj].px < hd_line[np].px ) jj++; while ( jj < mx_dim ) { hd_line[kk].px = mx_plot[jj].px; hd_line[kk++].py = mx_plot[jj++].py; } mx_dim = kk; while ( kk-- > 0 ) { mx_plot[kk].px = hd_line[kk].px; mx_plot[kk].py = hd_line[kk].py; } } } else if ( ncross == ABOVE || ncross == OUTSIDE ) { if ( ! plot_line ) { plot_line = TRUE; hd_line[np].px = segmnt[0].px; hd_line[np++].py = segmnt[0].py; } hd_line[np].px = segmnt[1].px; hd_line[np++].py = segmnt[1].py; } else { for ( ii = 0; ii < ncross; ii++ ) /* For each intersection */ { if ( plot_line ) /* CROSS_DOWN */ { plot_line = FALSE; hd_line[np].px = cross[ii].px; hd_line[np++].py = cross[ii].py; } else /* CROSS_UP */ { register int jj = 0; plot_line = TRUE; while ( jj < mx_dim && mx_plot[jj].px <= hd_line[np-1].px ) jj++; while ( jj < mx_dim && mx_plot[jj].px < cross[ii].px ) { hd_line[np].px = mx_plot[jj].px; hd_line[np++].py = mx_plot[jj++].py; } hd_line[np].px = cross[ii].px; hd_line[np++].py = cross[ii].py; } } if ( plot_line ) { hd_line[np].px = segmnt[1].px; hd_line[np++].py = segmnt[1].py; } } } /* * close the surface with last point of current line and previous line */ segmnt[0].px = dir * (data-1)->px; segmnt[0].py = (data-1)->py; segmnt[1].px = dir * old_data[ln_dim-1].px; segmnt[1].py = old_data[ln_dim-1].py; ncross = L_CROSS( mx_dim, mx_plot, segmnt, cross ); if ( ncross == ABOVE ) cls_line[1] = ln_dim - 1; else { for ( ii = 0; ii < ncross; ii++ ) /* For each intersection */ { if ( plot_line ) /* CROSS_DOWN */ { hd_line[np].px = cross[ii].px; hd_line[np++].py = cross[ii].py; plot_line = FALSE; } else /* CROSS_UP */ { register int jj = 0; while ( jj < mx_dim && mx_plot[jj].px <= hd_line[np-1].px ) jj++; while ( jj < mx_dim && mx_plot[jj].px < cross[ii].px ) { hd_line[np].px = mx_plot[jj].px; hd_line[np++].py = mx_plot[jj++].py; } hd_line[np].px = cross[ii].px; hd_line[np++].py = cross[ii].py; plot_line = TRUE; } } if ( plot_line ) cls_line[1] = ln_dim - 1; } } /* * draw the line */ DRAW_LINE( dir, np, hd_line, cls_line, old_data ); if ( ln_nr == ln_mx ) /* release allocated memory at last call */ { (void) osmmfree( (char *) old_data ); (void) osmmfree( (char *) mx_plot ); } else /* store data of last plotted line */ { data -= ln_dim; for ( nr = 0; nr < ln_dim; nr++ ) { old_data[nr].px = data->px; old_data[nr].py = data++->py; } if ( ln_nr != 1 && ! plot_line ) { ii = 0; while ( ii < mx_dim && mx_plot[ii].px <= hd_line[np-1].px ) ii++; while ( ii < mx_dim ) { hd_line[np].px = mx_plot[ii].px; hd_line[np++].py = mx_plot[ii++].py; } } for ( ii = 0; ii < np; ii++ ) { mx_plot[ii].px = hd_line[ii].px; mx_plot[ii].py = hd_line[ii].py; } mx_dim = np; } (void) osmmfree( (char *) hd_line ); } /*++++++++++++++++++++++++++++++++++++++++++++++++++ .IDENTifer PLPER .PURPOSE plot a perspective plot .INPUT/OUTPUT call as PLPER( wcfram, p_img, image, start, step, angle, scales, xyflag ) input: float wcfram[12] frame limits & ticks of (x,y,z) (amin, amax, abig & asmall) float *p_img pointer to the data of the frame float image[4] image size in pixel coordinates double start[2] start values of the X and Y axes double step[2] distance between pixels in world units float angle[2] viewing angles altitude and azimuth float scales[2] scale: scaling of the Z component, (= 1: screen filling) offset: offset of plot in units of the Z-axis int xyflag[2] if xyflag[0] = 1 plot lines along first axis if xyflag[1] = 1 plot lines along second axis .COMMENTS PLPER has a one serious restriction: - features unter the surface are not shown! ----------------------------------------------------*/ void PLPER( wcfram, p_img, image, start, step, angle, scales, xyflag ) int *xyflag; float *image, *wcfram, *p_img, *angle, *scales; double *start, *step; { register int nx, ny; int nrxval, nryval, nval; double xpos, ypos; struct Odata *data; struct Pdata *proj, *bgn_proj, *line; nrxval = (int) fabs( image[1] - image[0] ) + 1; nryval = (int) fabs( image[3] - image[2] ) + 1; nval = nrxval * nryval; data = (struct Odata *) osmmget( nval * sizeof( struct Odata)); /* * store the three-dimensional data in a array */ ypos = start[1] + (image[2] - 1) * step[1]; for ( ny = 0; ny < nryval; ny++ ) { xpos = start[0] + (image[0] - 1) * step[0]; for ( nx = 0; nx < nrxval; nx++ ) { data->xx = xpos; data->yy = ypos; data++->zz = *p_img++; xpos += *step; } ypos += *(step+1); } data -= nval; /* * Project the data on a two dimensional plane */ proj = (struct Pdata *) osmmget( nval * sizeof( struct Pdata)); GETPROJ( wcfram, angle, scales, nval, data, proj ); (void) osmmfree((char *) data ); /* * store the data in the right order w.r.t. the users viewpoint */ TRANSPOSE( angle[1], step, nrxval, nryval, proj ); /* * if lines in the plot have to be parallel to the first axis of the data... */ bgn_proj = proj; if ( xyflag[0] == 1 ) { for ( ny = 0; ny < nryval; ny++ ) { HIDE_LINE( ny+1, nryval, nrxval, proj ); proj += nrxval; } } /* * if lines in the plot have to be parallel to the first axis of the data... */ if ( xyflag[1] == 1 ) { line = (struct Pdata *) osmmget( nryval * sizeof( struct Pdata )); for ( nx = 0; nx < nrxval; nx++ ) { proj = bgn_proj + nx; for ( ny = 0; ny < nryval; ny++ ) { line[ny].px = proj->px; line[ny].py = proj->py; proj += nrxval; } HIDE_LINE( nx+1, nrxval, nryval, line ); } (void) osmmfree( (char *) line ); } (void) osmmfree( (char *) bgn_proj ); } /*++++++++++++++++++++++++++++++++++++++++++++++++++ .IDENTifer PLPERI .PURPOSE produce plot information for a three-dimensional perspective plot .INPUT/OUTPUT call as PLPERI( plmode, name, ident, image, angle, wcfram ) input: int plmode plot mode, see PMODE in PLISTAT char *name data frame name char *ident ascii identifier of image float *image size in PIXEL coordinates float *angles viewing angles altitude and azimuth float *wcfram frame values of resp. X, Y and Z axis (amin, amax, abig & asmall) .COMMENTS none ----------------------------------------------------*/ void PLPERI( plmode, name, ident, image, angle, wcfram ) char *name, *ident; int plmode; float *angle, *image, *wcfram; { int actvals; float one, ssize, tsize, x1, x2, y1, y2, xt, yt, yh; float xl[3], yl[3], clpl[4], wndl[4]; char buff[81]; /* * check if PMODE == 2 */ if ( plmode != 2 ) return; /* * get the symbol and character dimensions, from the MIDAS keywords */ PCKRDR( "SSIZE", 1, &actvals, &ssize ); PCKRDR( "TSIZE", 1, &actvals, &tsize ); /* * if the symbol size or the text size is not equal to 1, set it to 1 * and call PCTSET to get the proper sizes for the MIDAS layout */ if ( ssize != 1.0 || tsize != 1.0 ) { one = 1.0; PCKWRR( "SSIZE", 1, &one ); PCKWRR( "TSIZE", 1, &one ); } PCTSET(); AG_SSET( "norm"); AG_SSET( "linx"); AG_SSET( "liny"); (void) AG_RGET( "clpl", clpl ); (void) AG_RGET( "wndl", wndl ); x1 = clpl[1] + 0.01; x2 = 1.0; y1 = 0.0; y2 = clpl[3]; AG_CDEF( x1, x2, y1, y2); AG_WDEF( 0.0, 1.0, 0.0, 1.0 ); /* * plot MIDAS logo */ PLLOGI( &xt, &yt ); /* * set character height */ AG_SSET( "sydi=0.75;chdi=0.75,0.75" ); AG_TGET( "M", xl, yl ); yh = 2.0 * yl[1]; /* * plot user name */ PLUSER( buff ); AG_GTXT( xt, yt, buff, 1 ); /* * name of frame */ yt -= 2*yh; if ( strlen( name ) > (size_t) 12 ) { AG_GTXT( xt, yt, "Frame:", 1 ); yt -= yh; AG_GTXT( xt, yt, name, 1 ); } else { (void) sprintf( buff, "Frame: %s", name ); AG_GTXT( xt, yt, buff, 1 ); } /* * identification */ if ( strlen( ident ) > (size_t) 0 ) { yt -= 2*yh; AG_GTXT( xt, yt, "Identification:", 1 ); yt -= yh; AG_GTXT( xt, yt, ident, 1 ); } /* * area */ yt -= 2*yh; AG_GTXT( xt, yt, "Area:", 1 ); yt -= yh; (void) sprintf( buff, "X: %.0f to %.0f", image[0], image[1] ); AG_GTXT( xt, yt, buff, 1 ); yt -= yh; (void) sprintf( buff, "Y: %.0f to %.0f", image[2], image[3] ); AG_GTXT( xt, yt, buff, 1 ); /* * minimum and maximum */ yt -= 2*yh; (void) sprintf( buff, "Min: %-.3g ", wcfram[FOR_Z] ); AG_GTXT( xt, yt, buff, 1 ); yt -= yh; (void) sprintf( buff, "Max: %-.3g ", wcfram[FOR_Z+1] ); AG_GTXT( xt, yt, buff, 1 ); /* * view angles */ yt -= 2*yh; AG_GTXT( xt, yt, "View angles:", 1 ); yt -= yh; (void) sprintf( buff, "Altitude: %-.3g ", angle[0] ); AG_GTXT( xt, yt, buff, 1 ); yt -= yh; (void) sprintf( buff, "Azimuth : %-.3g ", angle[1] ); AG_GTXT( xt, yt, buff, 1 ); yt -= 2.*yh; PLDATI( &xt, &yt ); /* * back to standard sizes */ AG_CDEF( clpl[0], clpl[1], clpl[2], clpl[3] ); AG_WDEF( wndl[0], wndl[1], wndl[2], wndl[3] ); /* * reset if necessary the symbol and text size */ if ( ssize != 1.0 || tsize != 1.0 ) { PCKWRR( "SSIZE", 1, &ssize ); PCKWRR( "TSIZE", 1, &tsize ); PCTSET(); } }