/* SPECTRA.C version 2.0 * Display amplitude spectra of a GPR scan to the cRT and optionally save * to disk as a HPGL file. * * Jeff Lucius, Geophysicist * Department of Interior * U.S. Geological Survey * Geologic Division * Box 25046 Denver Federal Center MS 964 * Denver, CO 80225-0046 * 303-236-1413 (office), 303-236-1212 (secretary), 303-236-1425 (fax) * * Revision History: * March 22, 1993 - Completed. * March 18, 1994 - Revised to handle 8-bit and 16-bit unsigned data with a * known file header size. * - Calculation of fundamental freq. was corrected from * num_samps to num_samps-1 times the samp_rate. * March 13, 1995 - Added video_mode to command line arguments. * May 14, 1997 - Removed video_mode to command line arguments. * - added data type long * - Added trace header bytes * April 24, 2001 - Add nicer axes using DrawAxis(). * - Add nice fonts. * - Changed version to 2.0 * * Supported compilers: * Intel 386/486 C Code Builder 1.1a * To compile for 80386 executable: * icc /F /xnovm /s010000H spectra.c libhpgl.lib * To compile for 80486 executable : * icc /F /xnovm /s010000H /zmod486 spectra.c libhpgl.lib * * /F removes the floating point emulator, reduces binary size * /xnovm specifies no virtual memory manager, disk access is too slow * /s010000H allocates 64K of stack space (required by graphics module) * NOTE: This may have to be increased to 1 MB (/s0100000H) to * accomdate some imaging routines in the graphics module. * /zmod486 generates specific 80486 instructions, speeds up program on 80486 * Gary Olhoeft's 32-bit graphics modules are in libhpgl.lib * * To run: SPECTRA filename file_hdr trace_hdr samp_bytes num_samps num samp_rate [pltfile] */ /* Header files */ #include /* getch */ #include /* GRO HPGL graphics functions */ #include /* cos,sin,sqrt,log10 */ #include /* fopen/fclose,fread,FILE,fseek,puts,printf,NULL */ #include /* atoi */ #include /* strcpy */ #include "jl_defs.h" int test = 0; int Debug = 0; /* Function prototypes */ void FFT1D(double *data,int nn,int isign); int DrawAxis(int side,int pen_number,int vcols,int vrows, int tick_show,int tick_num,int tick_ano,int tick_skip,int tick_mid_skip, int ano_left,int ano_right,double axis_min,double axis_max, double tick_start,double tick_int,double tick_abs_min, double tick_abs_max,double title_size,double title_offset, double ano_size,double VX1,double VX2,double VY1,double VY2, char *title); int SetLabel(int *left,int *right,double val,char *str); int main(int argc, char *argv[]) { char plotfile[80],str[80]; void *scan = NULL; int video_mode; int modes[] = /* known 256-color video modes (exc. 18) */ { 263, 261, 56, 1024, 8514, 259, 48, 800, 99, 46, 257, 640, 98, 95, 20, 18 }; int period = 24; int i,j,itemp; int scan_bytes,scan_number,half_length,samp_bytes; int file_hdr_bytes,trace_hdr_bytes; int filebytes,filescans,num_samps; int vcols,vrows; double dmax,dtemp; double samp_rate; /* ns per scan point */ double mean; double *d_scan = NULL; double *cmplx_scan = NULL; double pi = 3.14159265358979323846; double twopi = 2*pi; double fundamental,nyquist,dmean; double step,t; FILE *infile; /* Get command line parameters */ if (argc < 8) { puts("\n\n#############################################################################"); puts("Usage:"); puts("SPECTRA filename file_hdr trace_hdr samp_bytes num_samps num samp_rate [pltfile]"); puts(" Display a GPR trace and its amplitude spectra as wiggle traces."); puts(" Computer code written by Jeff Lucius, USGS, lucius@usgs.gov."); puts(" \"filename\" is the input GPR file."); puts(" \"file_hdr\" is the number of bytes in the header at the start of"); puts(" the file. Enter 0 for no header."); puts(" \"trace_hdr\" is the number of bytes in the header at the start of"); puts(" each trace. Enter 0 for no header."); puts(" \"samp_bytes\" is the number of bytes in each scan sample. Use 1 for"); puts(" 8-bit data, 2 for 16-bit data, etc. Make negative for signed data."); puts(" \"num_samps\" is the number of samples in each trace."); puts(" \"num\" is the trace to use from the file. The first trace is trace 0."); puts(" \"samp_rate\" is the number of nanoseconds per trace sample."); puts(" \"pltfile\" is optional, if not given output is to the CRT only."); puts(" If given, then the screen plot is saved to a PLT file."); printf(" Version 2.0 - Last Revision Date: %s at %s\n","April 24, 2001",__TIME__); puts("#############################################################################"); return 1; } if ((infile = fopen(argv[1],"rb")) == NULL) { printf("\nERROR opening input file %s\n",argv[1]); return 2; } file_hdr_bytes = atoi(argv[2]); trace_hdr_bytes = atoi(argv[3]); samp_bytes = atoi(argv[4]); num_samps = atoi(argv[5]); scan_number = atoi(argv[6]); samp_rate = atof(argv[7]); if (argc > 8) strcpy(plotfile,argv[8]); else strcpy(plotfile,"CRT"); /* Validate parameters and initialize */ if (samp_rate <= 0.0) { puts("ERROR: Sample rate <= 0.0."); fclose(infile); return 3; } if (samp_bytes == 1 || samp_bytes == -1) mean = 0x80U; else if (samp_bytes == 2 || samp_bytes == -2) mean = 0x8000U; else if (samp_bytes == 4 || samp_bytes == -4) mean = 0x80000000U; else { puts("ERROR: samp_bytes must be 1, -1, 2, -2, 4, or -4."); fclose(infile); return 4; } half_length = num_samps / 2; scan_bytes = num_samps * samp_bytes; if (scan_bytes < 0) scan_bytes *= -1; fseek(infile, 0L, SEEK_END); /* go to end of file */ filebytes = ftell(infile); /* get last location (byte) */ rewind(infile); filescans = (filebytes - file_hdr_bytes) / scan_bytes; if (scan_number < 0) scan_number = 0; if (scan_number >= filescans) scan_number = filescans-1; fundamental = (1000.0/((double)(num_samps-1) * samp_rate)); /* MHz */ nyquist = fundamental * half_length; /* Dipslay info */ puts("\n"); printf("\nSpectra version 2.0\nComputer code written by Jeff Lucius, USGS, lucius@usgs.gov\n"); printf("filename = %s\n",argv[1]); printf("file_hdr_bytes = %d\n",file_hdr_bytes); printf("trace_hdr_bytes = %d\n",trace_hdr_bytes); printf("samp_bytes = %d\n",samp_bytes); printf("num_samps = %d\n",num_samps); printf("num_scans = %d\n",filescans); printf("scan_number = %d\n",scan_number); printf("samp_rate = %g\n",samp_rate); printf("fundamental = %g MHz\n",fundamental); printf("nyquist = %g MHz\n",nyquist); printf("plotfile = %s\n",plotfile); printf("\nPress a key to continue or to quit..."); if (getch() == 27) { fclose(infile); return 0; } puts(""); /* Allocate storage */ scan = (void *)malloc(scan_bytes); d_scan = (double *)malloc(scan_bytes*sizeof(double)); cmplx_scan = (double *)malloc(2*scan_bytes*sizeof(double)); if (scan==NULL || d_scan==NULL || cmplx_scan==NULL) { puts("\nERROR allocating storage."); fclose(infile); free(scan); free(d_scan); free(cmplx_scan); return 3; } /* Get the scan from the file */ fseek(infile,(long)(file_hdr_bytes + (scan_number*(scan_bytes+trace_hdr_bytes)) + trace_hdr_bytes),SEEK_SET); if ((fread(scan,(size_t)scan_bytes,(size_t)1,infile)) < 1) { puts("\nERROR getting scan from file."); fclose(infile); free(scan); free(d_scan); free(cmplx_scan); return 4; } fclose(infile); /* Convert to double and find average value of the time series */ dmean = 0.0; if (samp_bytes == 1) { for (i=0; i= 20) break; /* out of for loop */ } vcols = v_colx + 1; /* number of screen horizontal pixels */ vrows = v_rowy + 1; /* number of screen vertical pixels */ lorg(3); ldir(0.0); csize(1.0); hpgl_select_font("romtrplx"); /* Display input scan */ viewport(10.,125.,55.,90.); window(0.,(double)num_samps-1.,-mean,mean); pen(3); frame(); sprintf(str,"GPR wavelet #%d from %s",scan_number,argv[1]); label(0.,1.1 * mean,str); pen(15); plot(0.0,(double)((unsigned char *)scan)[0]-mean,-2); if (samp_bytes > 0) { for (i=1; i dmax) dmax = d_scan[i]; } if (!test) { viewport(10.,125.,8.,43.); window(0.,(double)num_samps-1.,-mean,mean); frame(); pen(3); csize(1.0); lorg(3); label(0.,1.1 * mean,"Amplitude spectra"); viewport(10.,125.,8.,43.); window(0.,(double)half_length,0.0,dmax); pen(15); plot(1.0,d_scan[1],-2); for (i=2; i. * Calls: none. * Returns: void. * * Author: Jeff Lucius USGS Branch of Geophysics Golden, CO * Date: November 10, 1992 */ void FFT1D (double *data,int nn,int isign) { int i,j,m,n,mmax,istep,jp1; double wr,wpr,wpi,wi,theta,tempr,tempi; static double twopi = 6.28318530717958647692; n = nn << 1; j = 0; for (i=0; i i) { tempr = data[j]; data[j] = data[i]; data[i] = tempr; tempr = data[j+1]; data[j+1] = data[i+1]; data[i+1] = tempr; } m = nn; while (m >= 2 && j >= m) { j -= m; m >>= 1; } j += m; } mmax=2; while (n > mmax) { istep = mmax << 1; theta = twopi/(double)(isign*mmax); tempr = sin(0.5*theta); wpr = -2.0*tempr*tempr; wpi = sin(theta); wr = 1.0; wi = 0.0; for (m=1; m0, suggested number of tick marks for axis (optional) * int tick_ano - 1 to label tick marks, 0 for no labels * int tick_skip - number of tick marks to skip between labels * int tick_mid_skip - number of tick marks to skip between 2nd order tick * int ano_left - number of places to left of the decimal for the tick label * int ano_right - number of places to right of the decimal for the tick label * double axis_max - value for top of left or right axes, or right on top or bottom axes * double axis_min - value for bottom of left or right axes or left on top or bottom axes * double tick_start - value for first tick mark (valid value optional) * double tick_int - separation between ticks (valid value optional) * double tick_abs_min - no ticks displayed "before" this value * double tick_abs_max - no ticks displayed "after" this value * double title_size - multiplier for axis title csize() * double title_offset - number of characters widths to move title closer (-) * or farther (+) from axis * double ano_size - multiplier for tick mark label csize() * double VX1,VX2 - horizontal left and right edges of screen viewport for * primary data display window (range is 0 to 133.333) * double VY1,VY2 - vertical left and right edges of screen viewport for * primary data display window (range is 0 to 100.00) * NOTE: viewport() origin is lower left screen corner. * char *title - axis label (none if NULL string) * * ERROR messages: * const char *DrawAxisMsg[] = * { "DrawAxis(): No errors.", * "DrawAxis() ERROR: Invalid value for \"side\".", * "DrawAxis() WARNING: No room for axis to attach to viewport.", * "DrawAxis() WARNING: Invalid range for viewport limits.", * "DrawAxis() ERROR: Axis endpoints out of SetLabel() range.", * } ; * * Manifest constants: * #define TRUE 1 * #define FALSE 0 * #define INVALID_VALUE 1.0E19 * #define DA_TITLE 0 * #define DA_RIGHT 1 * #define DA_TOP 2 * #define DA_LEFT (-1) * #define DA_BOTTOM (-2) * #define _ABS(a) ( ((a) < 0) ? (-(a)) : (a) ) * #define _MAXX(a,b) ( ((a)>(b)) ? (a) : (b) ) * * Globals: * int Debug; * * NOTES: * 1) The graphics in this function require GRO's protected mode graphics * libraries. * 2) This function inherits the graphics mode and coordinate systems * of the calling function. Plotting is 2D only. * * WARNINGS: * 1) The viewport is modified! * * Requires: , , "jl_defs.h". * Calls: unclip, lorg, ldir, csize, pen, plot, pow, modf, SetLabel, printf. * Returns: 0 on success, or * >0 on error. * * Author: Jeff Lucius USGS Central Mineral Resources Team Lakewood, CO * Date: September 15, 1995 */ int DrawAxis (int side,int pen_number,int vcols,int vrows, int tick_show,int tick_num,int tick_ano,int tick_skip,int tick_mid_skip, int ano_left,int ano_right,double axis_min,double axis_max, double tick_start,double tick_int,double tick_abs_min, double tick_abs_max,double title_size,double title_offset, double ano_size,double VX1,double VX2,double VY1,double VY2, char *title) { char str[20]; int itemp,i,left,right,tick_count,inside; double max_axis,chr_size,user_per_vp,tick_size,label_off; double ano_width,min_ano_sep,last_ano,first_ano; double dtemp,mult,frac,ipart; double pix_per_vp,axis_range; double var1,var2,var3,var4,var5,edge; double tick_set[5] = {1.0, 2.0, 2.5, 5.0, 10.0}; static int set_size = 5; static int tick_pix_width = 5; static double pi = 3.14159265358979323846; static double min_VX = 0.0; /* GRO hpgl lib limits for screen */ static double min_VY = 0.0; static double max_VX; static double max_VY = 100.0; static double rounding_error = 0.0001; extern int Debug; /* Reality check */ if (VX2 == VX1 || VY2 == VY1 || VX2 < VX1 || VY2 < VY1) return 3; if (tick_num == 0) tick_num = 9; if (side == DA_TITLE) tick_num = 0; inside = FALSE; if (tick_show == FALSE) tick_num = 0; if (tick_show < 0) inside = TRUE; if (title_size == 0.0 || title_size == INVALID_VALUE) { if (side) title_size = 0.85; else title_size = 1.10; } if (ano_size == 0.0 || ano_size == INVALID_VALUE) ano_size = 0.80; if (ano_left == INVALID_VALUE) ano_left = 0; if (ano_left > 6) ano_left = 6; if (ano_right == INVALID_VALUE) ano_right = -1; if (ano_right > 3) ano_right = 3; /* Set viewport to axis area, scale window so x and y user units the same, * get maximum viewport axis for csize(), set tick length to 1 viewport * horizontal unit. Viewport origin is lower left screen corner. * pix_per_vp converts viewport units to number of pixels. */ max_VX = 100.0 * ((double)vcols/(double)vrows); axis_range = _ABS(axis_max-axis_min); if (Debug) { printf("\nDrawAxis: xmin=%g xmax=%g ymin=%g ymax=%g\n",min_VX,max_VX,min_VY,max_VY); printf(" VX1=%G VX2=%G VY1=%G VY2=%G\n",VX1,VX2,VY1,VY2); printf(" axis_min=%g axis_max=%g axis_range=%g\n",axis_min,axis_max,axis_range); printf(" vcols = %d vrows = %d tick_ano = %d tick_skip = %d ano_left = %d ano_right = %d\n", vcols,vrows,tick_ano,tick_skip,ano_left,ano_right); printf(" tick_start = %g tick_num = %d tick_int = %g tick_abs_min = %g tick_abs_max = %g\n", tick_start,tick_num,tick_int,tick_abs_min,tick_abs_max); } else { unclip(); pen(pen_number); } switch (side) { case DA_RIGHT: /* 1: right side */ if (Debug) puts("DA_RIGHT"); if (max_VX == VX2) return 2; var1 = VX2; var2 = max_VX - VX2; var3 = VY2 - VY1; var4 = max_VY; var5 = vrows; edge = var1+(var2/var3)*axis_range; if (!Debug) viewport(VX2,max_VX,VY1,VY2); break; case DA_TITLE: case DA_TOP: /* 0 and 2: top side */ if (Debug) puts("DA_TITLE or DA_TOP"); if (max_VY == VY2) return 2; var1 = VY2; var2 = max_VY - VY2; var3 = VX2 - VX1; var4 = max_VX; var5 = vcols; edge = var1+(var2/var3)*axis_range; if (!Debug) viewport(VX1,VX2,VY2,max_VY); break; case DA_LEFT: /* left side */ if (Debug) puts("DA_LEFT"); if (VX1 == min_VX) return 2; var1 = VX1; var2 = VX1 - min_VX; var3 = VY2 - VY1; var4 = max_VY; var5 = vrows; edge = var1-(var2/var3)*axis_range; if (!Debug) viewport(min_VX,VX1,VY1,VY2); break; case DA_BOTTOM: /* bottom side */ if (Debug) puts("DA_BOTTOM"); if (VY1 == min_VY) return 2; var1 = VY1; var2 = VY1 - min_VY; var3 = VX2 - VX1; var4 = max_VX; var5 = vcols; edge = var1-(var2/var3)*axis_range; if (!Debug) viewport(VX1,VX2,min_VY,VY1); break; default: return 1; } if (var3 > var2) { max_axis = var3; user_per_vp = axis_range/max_axis; } else { max_axis = var2; user_per_vp = _ABS(edge-var1)/max_axis; } tick_size = _ABS(edge-var1)/(var2); pix_per_vp = var5 / var4; if (tick_num != 0) { while ((var3/tick_num)*pix_per_vp < tick_pix_width) { tick_num /= 2; if (tick_num == 0) break; } } if (!Debug) { switch (side) { case DA_RIGHT: window(VX2,edge,axis_min,axis_max); break; case DA_TITLE: case DA_TOP: window(axis_min,axis_max,VY2,edge); break; case DA_LEFT: window(edge,VX1,axis_min,axis_max); break; case DA_BOTTOM: window(axis_min,axis_max,edge,VY1); break; } } /* Calculate sizes; * csize(1.0) == 2% of maximum viewport axis; * chr_size is title_size * 2% of full screen viewport vertical axis (100.0); * chr_size and ano_size are in viewport units; * user_per_vp converts viewport units to user units; * ano_width is character block width and height in user units; * min_ano_sep will have to be calculated on the fly for horizontal axes; */ tick_size *= 0.90; /* reduce ticksize slighty */ label_off = tick_size; if (inside) { tick_size *= -1.0; label_off *= 0.5; } ano_size *= max_VY / max_axis; /* csize for tick annotation */ ano_width = ano_size * 0.02 * max_axis * user_per_vp; min_ano_sep = 1.5 * ano_width; /* this works good for left and right axes */ chr_size = title_size * (max_VY/max_axis); /* csize for axis labels */ if (Debug) printf("side=%d tick_num=%d chr_size=%g max_axis=%g user_per_vp=%g\ntick_size=%g ano_width=%g ano_size=%g\n", side,tick_num,chr_size,max_axis,user_per_vp,tick_size,ano_width,ano_size); /* Draw axis and labels */ if (side) { /* Calculate interval between tick marks and starting tick, if nec. */ if (tick_num && (tick_int==INVALID_VALUE || tick_start==INVALID_VALUE || tick_int==0.0)) { if (tick_int==INVALID_VALUE || tick_int==0.0) tick_int = (axis_max-axis_min)/tick_num; /* user units */ left = 0; right = -1; itemp = SetLabel(&left,&right,tick_int,str); if (itemp) return 4; if (left > 0) mult = pow(10.0,(double)left-1.0); if (left < 0) mult = pow(10.0,(double)(-left)-1.0); dtemp = _ABS(tick_int); if (left==1 && dtemp<1.0) { if (dtemp >= 0.001) mult = 0.001; if (dtemp >= 0.01) mult = 0.01; if (dtemp >= 0.1) mult = 0.1; } tick_set[0] *= mult; for (i=1; i=tick_set[i-1] && dtemp 0) tick_int = dtemp; else tick_int = -dtemp; if (tick_start == INVALID_VALUE) { frac = modf(axis_min/tick_int,&ipart); if (_ABS(frac) < rounding_error) tick_start = axis_min; else tick_start = ipart * tick_int; } } if (Debug) { printf("tick_int=%g tick_start=%g tick_skip=%d tick_ano=%d\n", tick_int,tick_start,tick_skip,tick_ano); if (!getch()) getch(); } /* Draw ticks and label */ first_ano = INVALID_VALUE; if (tick_num) { tick_count = 0; tick_skip++; /* turn 0 into 1, 1 into 2, etc. for modulo */ tick_mid_skip++; /* turn 0 into 1, 1 into 2, etc. for modulo */ switch (side) { case DA_RIGHT: /* right side */ if (!Debug) { ldir(0.0); lorg(2); csize(ano_size); } if (tick_ano) { if (tick_int > 0) last_ano = tick_start - 2*min_ano_sep; else last_ano = tick_start + 2*min_ano_sep; } for (dtemp=tick_start; ; dtemp+=tick_int,tick_count++) { if (_ABS(dtemp) <= rounding_error) dtemp = 0.0; if (tick_int > 0) { if (dtemp < axis_min) continue; if (dtemp > axis_max) break; if (dtemp < tick_abs_min) continue; if (dtemp > tick_abs_max) break; } else { if (dtemp > axis_min) continue; if (dtemp < axis_max) break; if (dtemp > tick_abs_min) continue; if (dtemp < tick_abs_max) break; } if (!Debug) { if ((tick_count % tick_skip)==0) { plot(VX2,dtemp,-2); plot(VX2+tick_size,dtemp,-1); } else if (tick_mid_skip > 0 && (tick_count % tick_mid_skip)==0) { plot(VX2,dtemp,-2); plot(VX2+0.75*tick_size,dtemp,-1); } else { plot(VX2,dtemp,-2); plot(VX2+0.5*tick_size,dtemp,-1); } } else printf("RIGHT tick: count=%d dtemp=%g\n",tick_count,dtemp); if (tick_ano) { if (Debug) { printf(" diff1=%g diff2=%g min_sep=%g last_ano=%g\n",_ABS(dtemp-last_ano),_ABS(axis_max-dtemp),min_ano_sep,last_ano); printf(" count=%d skip=%d mod=%d\n",tick_count,tick_skip,tick_count%tick_skip); } if ((tick_count % tick_skip) == 0) { if (_ABS(dtemp-last_ano) > min_ano_sep) { left = ano_left; right = ano_right; SetLabel(&left,&right,dtemp,str); if (!Debug) label(VX2+label_off,dtemp,str); else printf(" skip=%d left=%d right=%d x=%g y=%g\n",tick_skip,ano_left,ano_right,VX2+tick_size,dtemp); last_ano = dtemp; if (first_ano == INVALID_VALUE) first_ano = dtemp; } } } } break; case DA_LEFT: /* left side */ if (!Debug) { lorg(8); ldir(0.0); csize(ano_size); } if (tick_ano) { if (tick_int > 0) last_ano = tick_start - 2*min_ano_sep; else last_ano = tick_start + 2*min_ano_sep; } for (dtemp=tick_start; ; dtemp+=tick_int,tick_count++) { if (_ABS(dtemp) <= rounding_error) dtemp = 0.0; if (tick_int > 0) { if (dtemp < axis_min) continue; if (dtemp > axis_max) break; if (dtemp < tick_abs_min) continue; if (dtemp > tick_abs_max) break; } else { if (dtemp > axis_min) continue; if (dtemp < axis_max) break; if (dtemp > tick_abs_min) continue; if (dtemp < tick_abs_max) break; } if (!Debug) { if ((tick_count % tick_skip)==0) { plot(VX1,dtemp,-2); plot(VX1-tick_size,dtemp,-1); } else if (tick_mid_skip > 0 && (tick_count % tick_mid_skip)==0) { plot(VX1,dtemp,-2); plot(VX1-0.75*tick_size,dtemp,-1); } else { plot(VX1,dtemp,-2); plot(VX1-0.5*tick_size,dtemp,-1); } } else printf("LEFT tick: count=%d dtemp=%g\n",tick_count,dtemp); if (tick_ano) { if (Debug) { printf(" diff1=%g diff2=%g min_sep=%g last_ano=%g test=%d\n",_ABS(dtemp-last_ano),_ABS(axis_max-dtemp),min_ano_sep,last_ano,((_ABS(dtemp-last_ano) > min_ano_sep) && (_ABS(axis_max-dtemp) > min_ano_sep))); printf(" count=%d skip=%d mod=%d\n",tick_count,tick_skip,tick_count%tick_skip); } if ((tick_count % tick_skip) == 0) { if (_ABS(dtemp-last_ano) > min_ano_sep) { left = ano_left; right = ano_right; SetLabel(&left,&right,dtemp,str); if (!Debug) label(VX1-label_off,dtemp,str); else printf(" skip=%d left=%d right=%d x=%g y=%g\n",tick_skip,ano_left,ano_right,VX1-tick_size,dtemp); last_ano = dtemp; if (first_ano == INVALID_VALUE) first_ano = dtemp; } } } } break; case DA_TOP: /* top side */ if (!Debug) { lorg(6); ldir(0.0); csize(ano_size); } if (tick_ano) { left = ano_left; right = ano_right; SetLabel(&left,&right,axis_min,str); min_ano_sep = 1.5 * _ABS(_ABS(left)+right) * ano_width; if (Debug) printf("min_ano_sep = %g\n",min_ano_sep); if (tick_int > 0) last_ano = tick_start - 2*min_ano_sep; else last_ano = tick_start + 2*min_ano_sep; } for (dtemp=tick_start; ; dtemp+=tick_int,tick_count++) { if (_ABS(dtemp) <= rounding_error) dtemp = 0.0; if (tick_int > 0) { if (dtemp < axis_min) continue; if (dtemp > axis_max) break; if (dtemp < tick_abs_min) continue; if (dtemp > tick_abs_max) break; } else { if (dtemp > axis_min) continue; if (dtemp < axis_max) break; if (dtemp > tick_abs_min) continue; if (dtemp < tick_abs_max) break; } if (!Debug) { if ((tick_count % tick_skip)==0) { plot(dtemp,VY2,-2); plot(dtemp,VY2+tick_size,-1); } else if (tick_mid_skip > 0 && (tick_count % tick_mid_skip)==0) { plot(dtemp,VY2,-2); plot(dtemp,VY2+0.75*tick_size,-1); } else { plot(dtemp,VY2,-2); plot(dtemp,VY2+0.5*tick_size,-1); } } else printf("TOP tick: count=%d dtemp=%g\n",tick_count,dtemp); if (tick_ano) { if ((tick_count % tick_skip) == 0) { left = ano_left; right = ano_right; SetLabel(&left,&right,dtemp,str); min_ano_sep = 1.5 * _ABS(_ABS(left)+right) * ano_width; if (Debug) printf("min_ano_sep = %g\n",min_ano_sep); if (_ABS(dtemp-last_ano) > min_ano_sep) { if (!Debug) label(dtemp,VY2+2.0*label_off,str); last_ano = dtemp; if (first_ano == INVALID_VALUE) first_ano = dtemp; } } } } break; case DA_BOTTOM: /* bottom side */ if (!Debug) /* draw leftmost tick */ { lorg(4); ldir(0.0); csize(ano_size); } if (tick_ano) /* label leftmost tick */ { left = ano_left; right = ano_right; SetLabel(&left,&right,axis_min,str); min_ano_sep = 1.5 * _ABS(_ABS(left)+right) * ano_width; if (Debug) printf("min_ano_sep = %g\n",min_ano_sep); if (tick_int > 0) last_ano = tick_start - 2*min_ano_sep; else last_ano = tick_start + 2*min_ano_sep; } for (dtemp=tick_start; ; dtemp+=tick_int,tick_count++) { if (_ABS(dtemp) <= rounding_error) dtemp = 0.0; if (tick_int > 0) { if (dtemp < axis_min) continue; if (dtemp > axis_max) break; if (dtemp < tick_abs_min) continue; if (dtemp > tick_abs_max) break; } else { if (dtemp > axis_min) continue; if (dtemp < axis_max) break; if (dtemp > tick_abs_min) continue; if (dtemp < tick_abs_max) break; } if (!Debug) { if ((tick_count % tick_skip)==0) { plot(dtemp,VY1,-2); plot(dtemp,VY1-tick_size,-1); } else if (tick_mid_skip > 0 && (tick_count % tick_mid_skip)==0) { plot(dtemp,VY1,-2); plot(dtemp,VY1-0.75*tick_size,-1); } else { plot(dtemp,VY1,-2); plot(dtemp,VY1-0.5*tick_size,-1); } } else printf("BOTTOM tick: count=%d dtemp=%g\n",tick_count,dtemp); if (tick_ano) { if (Debug) printf(" count=%d skip=%d mod=%d\n",tick_count,tick_skip,tick_count%tick_skip); if (!(tick_count % tick_skip)) { left = ano_left; right = ano_right; SetLabel(&left,&right,dtemp,str); min_ano_sep = 1.5 * _ABS(_ABS(left)+right) * ano_width; if (Debug) printf("min_ano_sep = %g\n",min_ano_sep); if (_ABS(dtemp-last_ano) > min_ano_sep) { if (!Debug) label(dtemp,VY1-2.0*label_off,str); else printf(" left=%d right=%d x=%g y=%g\n",left,right,dtemp,VY1-2.0*tick_size); last_ano = dtemp; if (first_ano == INVALID_VALUE) first_ano = dtemp; } } } } break; } /* end of switch block */ } /* end of if (tick_num) */ if (title[0] != 0) { int left1,left2,right1,right2; csize(chr_size); switch (side) { case DA_RIGHT: /* right side */ if (first_ano != INVALID_VALUE) { left = ano_left; right = ano_right; if (ano_left == 0 || ano_right == -1) SetLabel(&ano_left,&ano_right,first_ano,str); left1 = ano_left; right1 = ano_right; ano_left = left; ano_right = right; if (left1 < 0) left1 = -left1 + 1; if (ano_left == 0 || ano_right == -1) SetLabel(&ano_left,&ano_right,last_ano,str); left2 = ano_left; right2 = ano_right; ano_left = left; ano_right = right; if (left2 < 0) left2 = -left2 + 1; left = _MAXX(left1,left2); right = _MAXX(right1,right2); } else { left = right = 0; } if (!Debug) { lorg(4); ldir(pi/2.0); label( VX2+((double)left+right+1.5+title_offset)*ano_width, (axis_max+axis_min)/2.0, title ); } else { printf("left1=%d left2=%d left=%d right1=%d right2=%d right=%d\n", left1,left2,left,right1,right2,right); printf("label at x=%g y=%g\n", VX2+((double)left+right+1.5+title_offset)*ano_width,(axis_max+axis_min)/2.0); } break; case DA_LEFT: if (first_ano != INVALID_VALUE) { left = ano_left; right = ano_right; if (ano_left == 0 || ano_right == -1) SetLabel(&ano_left,&ano_right,first_ano,str); left1 = ano_left; right1 = ano_right; ano_left = left; ano_right = right; if (left1 < 0) left1 = -left1 + 1; if (ano_left == 0 || ano_right == -1) SetLabel(&ano_left,&ano_right,last_ano,str); left2 = ano_left; right2 = ano_right; ano_left = left; ano_right = right; if (left2 < 0) left2 = -left2 + 1; left = _MAXX(left1,left2); right = _MAXX(right1,right2); } else { left = right = 0; } if (!Debug) { lorg(6); ldir(pi/2.0); label( VX1-((double)left+right+2.5+title_offset)*ano_width, (axis_max+axis_min)/2.0, title ); } else { printf("left1=%d left2=%d left=%d right1=%d right2=%d right=%d\n", left1,left2,left,right1,right2,right); printf("label at x=%g y=%g\n", VX1-((double)left+right+2.5+title_offset)*ano_width,(axis_max+axis_min)/2.0); } break; case DA_TOP: if (!Debug) { lorg(6); ldir(0.0); label( (axis_max+axis_min)/2.0, VY2+(3+title_offset)*ano_width, title ); } break; case DA_BOTTOM: if (!Debug) { lorg(4); ldir(0.0); label( (axis_max+axis_min)/2.0, VY1-(3+title_offset)*ano_width, title ); } break; } /* end of switch block */ } /* if (title[0]) */ } else /* if (side) */ { if (!Debug) { lorg(6); ldir(0.0); csize(chr_size); label((axis_max+axis_min)/2.0,VY2+(4+title_offset)*label_off,title); /* title label at top */ } } return 0; } /******************************** SetLabel() ********************************/ /* * This function formats a floating point value into a string. * * Parameter list: * int *left - address of variable holding number of characters to left of * of the decimal. If == 0, then this function determines the * count up to 6. Otherwise, this function uses the value in * "left" to format the string. * int *right - address of variable holding number of characters to right of * of the decimal. If == -1, then this function determines the * count up to 3. Otherwise, this function uses the value in * "right" to format the string. * double val - the floating point value. * char *str - pointer to a buffer large enough to hold the string. * 15 would be sufficient. * * Requires: , , "jl_defs.h". * Calls: ceil, log10, modf, sprintf, _ABS, _MAXX, printf. * Returns: 0 on success, or * >0 on error. * * Author: Jeff Lucius USGS Central Mineral Resources Team Lakewood, CO * Date: March 7, 1994 */ int SetLabel (int *left,int *right,double val,char *str) { char fmt[12]; int lft; double frac, ipart, dtemp; double delta = 1.0e-7; /* correct for floatingpoint round off error */ extern int Debug; if (Debug) printf("SetLabel(): left=%d right=%d val=%g\n",*left,*right,val); /* Get number of characters to the left of the decimal */ if (*left == 0) { if (val != 0.0) { if (val > 0) *left = _MAXX(1,(int)ceil(log10(_ABS(val)+.001))); else *left = _MAXX(1,(int)ceil(log10(_ABS(val)-.001))); } else *left = 1; if (val < 0.0) *left *= -1; } if (*left > 0 && val < 0) *left *= -1; if (*left > 6 || *left < -6) return 1; /* number too large */ /* Get number of characters to the right of the decimal */ /* NOTE: this part doesn't seem to always work correctly ! */ if (*right < 0) { *right = 0; dtemp = _ABS(val); frac = (modf(dtemp,&ipart)); /* get the fraction */ dtemp = (frac * 10.0) + delta; frac = modf(dtemp,&ipart); /* is there a digit in tenths? */ if (ipart > 0.0) (*right) = 1; dtemp = (frac * 10.0) + delta; frac = modf(dtemp,&ipart); /* is there a digit in hundredths? */ if (ipart > 0.0) (*right) = 2; dtemp = (frac * 10.0) + delta; frac = modf(dtemp,&ipart); /* is there a digit in thousandths? */ if (ipart > 0.0) (*right) = 3; } else if (*right > 3) (*right) = 3; lft = *left; /********/ if (*right == 0) { if (val > 0) sprintf(str,"%d",(int)(val+0.000001)); else sprintf(str,"%d",(int)(val-0.000001)); } /********/ else { if (lft < 0) lft = -lft + 1; sprintf(fmt,"%c%d.%df",'%',lft + *right + 1, *right); sprintf(str,fmt,val); if (Debug) printf(" fmt=%s str=%s\n",fmt,str); } return 0; }