#include #include /* calloc(), free() */ #include /* memset() */ #include #include #include /* fabs(), rint() */ #include "convert_datum.h" #define MAP_WIDTH 800 /* pixels */ #define MAP_MARGIN 100 /* pixels */ #define HEIGHT_LABEL_FONT "fixed" #define GRID_SPACING 100 /* pixels */ #define GRID_LABEL_LENGTH 4096 #define GRID_TOLERANCE 2000 /* meters */ #define CURSOR_TEXT_X (MAP_MARGIN / 2) /* pixels */ #define TEXT_HEIGHT 16 /* pixels */ #define COORD_UTM 0 #define COORD_LATLONG_DEG 1 #define COORD_LATLONG_DEG_MIN 2 #define COORD_LATLONG_DEG_MIN_SEC 3 #define LINEBUFSIZE 4096 /* * Peter Daly * Ocean Acoustics Group * Massachusetts Institute of Technology * Room 5-435 * Cambridge, Massachusetts, USA * * This program displays contour plots of the SBCX test area. * * Copyright (C) 1998, Massachusetts Institute of Technology * All Rights Reserved */ typedef struct vector_struct { double xb, yb, xa, ya; /* UTM */ } Vector; typedef struct vector_list_struct { int nvect; double depth; Vector *v; } VectorList; typedef struct bathymetric_point_struct { double x,y,z; } BathymetricPoint; typedef struct bathymetry_database_struct { int npts; BathymetricPoint *p; char grid_zone[GRID_ZONE_LENGTH]; } Bathymetry; typedef struct xinfo_struct { Display *display; int screen; unsigned long bg, fg; XSizeHints hint; Window window; GC gc; Colormap colormap; XColor black_color, white_color, dark_green_color, red_color, green_color, grey_color; XColor *overlay_color; unsigned int *overlay_line_width; unsigned char *overlay_line_flag; int num_overlay; XFontStruct *font; XEvent event; double meters_per_pixel; } XInfo; void x_event_loop (XInfo *, VectorList *, int, VectorList *, Bathymetry *, double, double, double, double, int, int, int, int); XInfo *setup_x (int, char **, int, int, int); int draw_vectors (XInfo *, VectorList *, int, VectorList *, double, double, double, double, int, int, int, int); VectorList *read_vector_data (FILE *, int *); void find_vector_min_max (VectorList *, int, double *, double *, double *, double *); void draw_grid (XInfo *, double, double, double, double, int, int, int, int); Bathymetry *load_bathymetric_database (FILE *fp); int bathymetric_compare (BathymetricPoint *, BathymetricPoint *); void cursor_track (XInfo *, double, double, double, double, int, int, int, int, Bathymetry *); void plot_ffp_array_location (XInfo *, double, double, double, double, int, int, int, int); Vector *read_overlay_file (FILE *, XInfo *, int *); int draw_overlays (XInfo *, VectorList *, double, double, double, double, int, int, int, int); VectorList *read_overlay_files (XInfo *, int, char **); int main (int argc, char **argv) { int arg_counter; char *vector_filename, *bathymetric_filename; VectorList *vl, *ovl; Bathymetry *b; FILE *vfp, *bfp; int num_vector_lists = 0; XInfo *xi; double min_x, min_y, max_x, max_y; int map_height; /* Parse the command line */ if (argc == 1) { fprintf (stderr, "usage: %s vector_filename bathymetric_filename overlay_file1 overlay_file2 ... overlay_fileN\n", argv[0]); return(-1); } arg_counter = 0; vector_filename = argv[++arg_counter]; bathymetric_filename = argv[++arg_counter]; /* Read in the vector database */ vfp = fopen (vector_filename, "r"); if (vfp == NULL) { perror ("fopen vfp"); fprintf (stderr, "error opening vector filename [%s] for reading, sorry!\n", vector_filename); return(-1); } vl = read_vector_data (vfp, &num_vector_lists); if (vl == NULL) { fprintf (stderr, "error reading vectors from [%s], sorry!\n", vector_filename); return(-1); } /* Find the min/max of the vector database */ find_vector_min_max (vl, num_vector_lists, &min_x, &min_y, &max_x, &max_y); /* Read the bathymetric database */ bfp = fopen (bathymetric_filename, "r"); if (bfp == NULL) { perror ("fopen bfp"); fprintf (stderr, "error opening bathymetric database [%s] for reading, sorry!\n", bathymetric_filename); return(-1); } b = load_bathymetric_database (bfp); if (b == NULL) { fprintf (stderr, "error loading bathymetric database, from [%s], sorry!\n", bathymetric_filename); return(-1); } fclose (bfp); /* Initialize X-windows */ map_height = (int) (MAP_WIDTH * (max_y - min_y) / (max_x - min_x)); xi = setup_x (argc, argv, MAP_MARGIN, MAP_WIDTH, map_height); if (xi == NULL) { fprintf (stderr, "error initializing x-windows, sorry!\n"); return(-1); } xi->meters_per_pixel = (max_x - min_x) / (double) MAP_WIDTH; /* Read in the overlay files */ arg_counter++; if (argc - arg_counter > 0) { ovl = read_overlay_files(xi, argc - arg_counter, &(argv[arg_counter])); if (ovl == NULL) { fprintf (stderr, "error reading in overlay files, continuing without overlays\n"); xi->num_overlay = 0; } } /* Enter event loop */ x_event_loop (xi, vl, num_vector_lists, ovl, b, min_x, min_y, max_x, max_y, MAP_WIDTH, map_height, MAP_MARGIN, MAP_MARGIN); return(0); } void x_event_loop (XInfo *xi, VectorList *vl, int num_vector_lists, VectorList *ovl, Bathymetry *b, double original_min_x, double original_min_y, double original_max_x, double original_max_y, int width, int height, int x_offset, int y_offset) { int done = 0; double min_x, min_y, max_x, max_y; double utm_xc, utm_yc; static int expose_latch = 0; min_x = original_min_x; min_y = original_min_y; max_x = original_max_x; max_y = original_max_y; while (!done) { /* Read the next event */ XNextEvent (xi->display, &(xi->event)); /* Decide what to do */ switch (xi->event.type) { /* Redraw the contour plot if necessary */ case Expose: if (xi->event.xexpose.count == 0 && expose_latch == 0) { if (draw_vectors (xi, vl, num_vector_lists, ovl, min_x, min_y, max_x, max_y, width, height, x_offset, y_offset) < 0) { fprintf (stderr, "error re-drawing vectors after expose event...\n"); } } expose_latch = 1; break; /* Handle keyboard mapping changes (why?) */ case MappingNotify: XRefreshKeyboardMapping ((XMappingEvent *) &(xi->event)); break; /* Process a mouse-button release */ case ButtonRelease: if (xi->event.xbutton.state & Button1Mask) { /* Zoom in */ utm_xc = min_x + (xi->event.xbutton.x - x_offset) * (max_x - min_x) / (double) (width); utm_yc = max_y - (xi->event.xbutton.y - y_offset) * (max_y - min_y) / (double) (height); (xi->meters_per_pixel) /= 2.0; min_x = utm_xc - (xi->meters_per_pixel) * (width / 2.0); max_x = utm_xc + (xi->meters_per_pixel) * (width / 2.0); min_y = utm_yc - (xi->meters_per_pixel) * (height / 2.0); max_y = utm_yc + (xi->meters_per_pixel) * (height / 2.0); } else if (xi->event.xbutton.state & Button2Mask) { /* Zoom out */ utm_xc = (min_x + max_x) * 0.5; utm_yc = (min_y + max_y) * 0.5; (xi->meters_per_pixel) *= 2.0; min_x = utm_xc - (xi->meters_per_pixel) * (width / 2.0); max_x = utm_xc + (xi->meters_per_pixel) * (width / 2.0); min_y = utm_yc - (xi->meters_per_pixel) * (height / 2.0); max_y = utm_yc + (xi->meters_per_pixel) * (height / 2.0); } /* Redraw */ if (draw_vectors (xi, vl, num_vector_lists, ovl, min_x, min_y, max_x, max_y, width, height, x_offset, y_offset) < 0) { fprintf (stderr, "error re-drawing after zoom event\n"); } (void)plot_ffp_array_location (xi, min_x, min_y, max_x, max_y, width, height, x_offset, y_offset); break; case MotionNotify: (void)cursor_track (xi, min_x, min_y, max_x, max_y, x_offset, y_offset, width, height, b); expose_latch = 0; break; default: break; } } return; } XInfo * setup_x (int argc, char **argv, int map_margin, int map_width, int map_height) { XInfo *xi; XColor color_exact; xi = (XInfo *) calloc (1, sizeof(XInfo)); if (xi == NULL) { perror ("calloc xi"); return(NULL); } /* Open the display */ xi->display = XOpenDisplay(""); xi->screen = DefaultScreen (xi->display); /* Allocate some pixel values */ xi->bg = WhitePixel (xi->display, xi->screen); xi->fg = BlackPixel (xi->display, xi->screen); /* Specify position and size of initial window */ xi->hint.x = 100; xi->hint.y = 100; xi->hint.width = 2 * map_margin + map_width; xi->hint.height = 2 * map_margin + map_height; xi->hint.flags = PPosition | PSize; /* Create the window */ xi->window = XCreateSimpleWindow (xi->display, DefaultRootWindow(xi->display), xi->hint.x, xi->hint.y, xi->hint.width, xi->hint.height, 5, xi->fg, xi->bg); XSetStandardProperties (xi->display, xi->window, "SBCX Cartographic Data", "SBCX Map", None, argv, argc, &(xi->hint)); /* GC Creation and initialization */ xi->gc = XCreateGC (xi->display, xi->window, 0, 0); XSetBackground (xi->display, xi->gc, xi->bg); XSetForeground (xi->display, xi->gc, xi->fg); /* Color allocation */ xi->colormap = XDefaultColormap (xi->display, xi->screen); memset (&(xi->black_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "Black", &color_exact, &(xi->black_color)) < 0) { fprintf (stderr, "unable to allocate black color for contour, sorry!\n"); return(NULL); } memset (&(xi->grey_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "Grey", &color_exact, &(xi->grey_color)) < 0) { fprintf (stderr, "unable to allocate grey color for contour, sorry!\n"); return(NULL); } memset (&(xi->white_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "White", &color_exact, &(xi->white_color)) < 0) { fprintf (stderr, "unable to allocate white color for contour, sorry!\n"); return(NULL); } memset (&(xi->dark_green_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "DarkGreen", &color_exact, &(xi->dark_green_color)) < 0) { fprintf (stderr, "unable to allocate dark green color for contour\n"); fprintf (stderr, "Using black instead\n"); memcpy (&(xi->dark_green_color), &(xi->black_color), sizeof(XColor)); } memset (&(xi->red_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "Red", &color_exact, &(xi->red_color)) < 0) { fprintf (stderr, "unable to allocate red color for contour\n"); fprintf (stderr, "Using black instead\n"); memcpy (&(xi->red_color), &(xi->black_color), sizeof(XColor)); } memset (&(xi->green_color), 0, sizeof(XColor)); if (XAllocNamedColor (xi->display, xi->colormap, "Green", &color_exact, &(xi->green_color)) < 0) { fprintf (stderr, "unable to allocate green color for contour\n"); fprintf (stderr, "Using black instead\n"); memcpy (&(xi->green_color), &(xi->black_color), sizeof(XColor)); } /* Font allocation */ xi->font = XLoadQueryFont (xi->display, HEIGHT_LABEL_FONT); XSetFont (xi->display, xi->gc, xi->font->fid); /* Select input */ XSelectInput (xi->display, xi->window, ButtonPressMask | ButtonReleaseMask | KeyPressMask | ExposureMask | PointerMotionMask); /* Map the window */ XMapRaised (xi->display, xi->window); /* All set */ return(xi); } int draw_vectors (XInfo *xi, VectorList *vl, int num_vector_lists, VectorList *ovl, double min_x, double min_y, double max_x, double max_y, int width, int height, int x_offset, int y_offset) { int i, j; int nseg; XSegment *xseg; /* Clear the contours */ XSetBackground (xi->display, xi->gc, xi->white_color.pixel); XClearArea (xi->display, xi->window, 0, 0, width + x_offset * 2, height + y_offset * 2, False); for (i = 0; i < num_vector_lists; i++) { /* Allocate space to hold the coordinates */ xseg = (XSegment *) calloc (vl[i].nvect, sizeof(XSegment)); if (xseg == NULL) { perror ("calloc xseg in draw_vectors()"); return(-1); } nseg = 0; for (j = 0; j < vl[i].nvect; j++) { /* Check to see if the vector falls within the bounding box */ if (vl[i].v[j].xb > min_x && vl[i].v[j].xb < max_x && vl[i].v[j].yb > min_y && vl[i].v[j].yb < max_y && vl[i].v[j].xa > min_x && vl[i].v[j].xa < max_x && vl[i].v[j].ya > min_y && vl[i].v[j].ya < max_y) { /* Add it to the list o'coordinates to draw */ xseg[nseg].x1 = x_offset + (int) (width * (vl[i].v[j].xb - min_x) / (max_x - min_x)); xseg[nseg].y1 = y_offset + height - (int) (height * (vl[i].v[j].yb - min_y) / (max_y - min_y)); xseg[nseg].x2 = x_offset + (int) (width * (vl[i].v[j].xa - min_x) / (max_x - min_x)); xseg[nseg].y2 = y_offset + height - (int) (height * (vl[i].v[j].ya - min_y) / (max_y - min_y)); nseg++; } /* bounding box test */ } /* j loop */ /* Set the color */ if (fabs(vl[i].depth - (2000.0 * rint(vl[i].depth / 2000.0))) < 1.0) { /* Set color to dark green */ XSetLineAttributes (xi->display, xi->gc, 3, LineSolid, CapButt, JoinMiter); XSetForeground (xi->display, xi->gc, xi->dark_green_color.pixel); } else if (fabs(vl[i].depth - (50.0 * rint(vl[i].depth / 50.0))) < 1.0) { /* Set color to red */ XSetLineAttributes (xi->display, xi->gc, 1, LineSolid, CapButt, JoinMiter); XSetForeground (xi->display, xi->gc, xi->red_color.pixel); } else { /* Set drawing color to grey */ XSetLineAttributes (xi->display, xi->gc, 1, LineSolid, CapButt, JoinMiter); XSetForeground (xi->display, xi->gc, xi->grey_color.pixel); } /* Draw the coordinates on the screen */ XDrawSegments (xi->display, xi->window, xi->gc, xseg, nseg); /* Free the space used to hold the coordinates */ free(xseg); } /* i loop */ /* Draw the overlays */ if (draw_overlays(xi, ovl, min_x, min_y, max_x, max_y, width, height, x_offset, y_offset) < 0) fprintf (stderr, "error drawing overlays\n"); /* Draw the grid */ (void)draw_grid (xi, min_x, min_y, max_x, max_y, width, height, x_offset, y_offset); /* All done */ return(0); } VectorList * read_vector_data (FILE *vfp, int *num_vector_lists) { int nvl = 0; VectorList *vl, *tvl; int i; do { /* Allocate space for a new vector */ tvl = (VectorList *) calloc (nvl + 1, sizeof(VectorList)); if (tvl == NULL) { perror("calloc tvl in read_vector_data()"); return(NULL); } if (nvl > 0) { memcpy (tvl, vl, nvl * sizeof(VectorList)); free(vl); } vl = tvl; /* Read in the depth */ if (fread (&(vl[nvl].depth), sizeof(double), 1, vfp) != 1) { if (!feof(vfp)) { perror ("fread vl[nvl].depth in read_vector_data()"); return(NULL); } } if (!feof(vfp)) { /* Read in the number of vectors */ if (fread(&(vl[nvl].nvect), sizeof(int), 1, vfp) != 1) { perror ("fread vl[nvl].nvect in read_vector_data()"); return(NULL); } /* Allocate the X,Y pairs */ vl[nvl].v = (Vector *) calloc (vl[nvl].nvect + 1, sizeof(Vector)); if (vl[nvl].v == NULL) { perror ("calloc vl[nvl].v"); return(NULL); } /* Read in the X,Y pairs */ for (i = 0; i < vl[nvl].nvect; i++) { if (fread(&(vl[nvl].v[i].xb), sizeof(double), 1, vfp) != 1) { perror ("fread vl[nvl].v[i].xb in read_vector_data()"); return(NULL); } if (fread(&(vl[nvl].v[i].yb), sizeof(double), 1, vfp) != 1) { perror ("fread vl[nvl].v[i].yb in read_vector_data()"); return(NULL); } if (fread(&(vl[nvl].v[i].xa), sizeof(double), 1, vfp) != 1) { perror ("fread vl[nvl].v[i].xa in read_vector_data()"); return(NULL); } if (fread(&(vl[nvl].v[i].ya), sizeof(double), 1, vfp) != 1) { perror ("fread vl[nvl].v[i].ya in read_vector_data()"); return(NULL); } } /* Increment the number of vector depths */ nvl++; } } while (!feof(vfp)); /* All set */ *num_vector_lists = nvl; return(vl); } void find_vector_min_max (VectorList *vl, int num_vector_lists, double *min_x, double *min_y, double *max_x, double *max_y) { int i, j; double px, py, gx, gy; px = gx = vl[0].v[0].xb; py = gy = vl[0].v[0].yb; for (i = 0; i < num_vector_lists; i++) { for (j = 0; j < vl[i].nvect; j++) { if (vl[i].v[j].xb < px) px = vl[i].v[j].xb; if (vl[i].v[j].xa < px) px = vl[i].v[j].xa; if (vl[i].v[j].yb < py) py = vl[i].v[j].yb; if (vl[i].v[j].ya < py) py = vl[i].v[j].ya; if (vl[i].v[j].xb > gx) gx = vl[i].v[j].xb; if (vl[i].v[j].xa > gx) gx = vl[i].v[j].xa; if (vl[i].v[j].yb > gy) gy = vl[i].v[j].yb; if (vl[i].v[j].ya > gy) gy = vl[i].v[j].ya; } /* j loop */ } /* i loop */ *min_x = px; *max_x = gx; *min_y = py; *max_y = gy; return; } void draw_grid (XInfo *xi, double min_x, double min_y, double max_x, double max_y, int width, int height, int x_offset, int y_offset) { double grid_block, raw_grid_block; double x, y; double starting_x, starting_y; char grid_label[GRID_LABEL_LENGTH]; unsigned int label_width; /* We want a grid every 100 pixels or so */ raw_grid_block = xi->meters_per_pixel * GRID_SPACING; /* Plot the grid */ grid_block = pow (10.0, rint(log10(raw_grid_block))); if (fabs ((grid_block / xi->meters_per_pixel) - GRID_SPACING) > 0.5 * GRID_SPACING) { /* Try using 5 meter intervals */ grid_block = pow (5.0, rint(log10(raw_grid_block)/log10(5.0))); if (fabs ((grid_block / xi->meters_per_pixel) - GRID_SPACING) > 0.5 * GRID_SPACING) { /* Try using 2 meter intervals */ grid_block = pow (2.0, rint(log10(raw_grid_block)/log10(2.0))); } } /* Set the GC to draw a black dotted line */ XSetForeground (xi->display, xi->gc, xi->black_color.pixel); XSetLineAttributes (xi->display, xi->gc, 1, LineOnOffDash, CapButt, JoinMiter); starting_x = grid_block * (rint(min_x / grid_block)); if (starting_x < min_x) starting_x += grid_block; for (x = starting_x; x < max_x; x += grid_block) { if ( (int) ((x - min_x) / xi->meters_per_pixel) < width) { XDrawLine (xi->display, xi->window, xi->gc, x_offset + (x - min_x) / xi->meters_per_pixel, y_offset, x_offset + (x - min_x) / xi->meters_per_pixel, y_offset + height); /* Draw grid labels */ memset (grid_label, 0, GRID_LABEL_LENGTH); if (fabs(grid_block) == grid_block) sprintf (grid_label, "%.0f", x); else if (fabs(grid_block * 10.0) == grid_block * 10.0) sprintf (grid_label, "%.1f", x); else if (fabs(grid_block * 100.0) == grid_block * 100.0) sprintf (grid_label, "%.2f", x); else if (fabs(grid_block * 1000.0) == grid_block * 1000.0) sprintf (grid_label, "%.3f", x); else if (fabs(grid_block * 10000.0) == grid_block * 10000.0) sprintf (grid_label, "%.3f", x); else if (fabs(grid_block * 100000.0) == grid_block * 100000.0) sprintf (grid_label, "%.3f", x); else if (fabs(grid_block * 1000000.0) == grid_block * 1000000.0) sprintf (grid_label, "%.3f", x); else sprintf (grid_label, "%e", x); label_width = XTextWidth (xi->font, grid_label, strlen(grid_label)); XDrawImageString (xi->display, xi->window, xi->gc, x_offset + (x - min_x) / xi->meters_per_pixel - label_width / 2, y_offset + height + 20, grid_label, strlen(grid_label)); } } starting_y = grid_block * (rint(min_y / grid_block)); if (starting_y < min_y) starting_y += grid_block; for (y = starting_y; y < max_y; y += grid_block) { if ( (int) ((y - min_y) / xi->meters_per_pixel) < height) { XDrawLine (xi->display, xi->window, xi->gc, x_offset, y_offset + height - (y - min_y) / xi->meters_per_pixel, x_offset + width, y_offset + height - (y - min_y) / xi->meters_per_pixel); } } /* Draw a thick black line surrounding the plot */ XSetForeground (xi->display, xi->gc, xi->black_color.pixel); XSetLineAttributes (xi->display, xi->gc, 4, LineSolid, CapButt, JoinMiter); XDrawLine (xi->display, xi->window, xi->gc, x_offset, y_offset, x_offset + width, y_offset); XDrawLine (xi->display, xi->window, xi->gc, x_offset + width, y_offset, x_offset + width, y_offset + height); XDrawLine (xi->display, xi->window, xi->gc, x_offset + width, y_offset + height, x_offset, y_offset + height); XDrawLine (xi->display, xi->window, xi->gc, x_offset, y_offset + height, x_offset, y_offset); /* Reset the line attribute */ XSetLineAttributes (xi->display, xi->gc, 1, LineSolid, CapButt, JoinMiter); } Bathymetry * load_bathymetric_database (FILE *fp) { int l, w; Bathymetry *b; int i; /* Allocate the Bathymetry structure */ b = (Bathymetry *) calloc (1, sizeof(Bathymetry)); if (b == NULL) { perror ("calloc bathymetry in load_bathymetry_database()"); return(NULL); } /* Read in the number of points (length x width) */ if (fscanf (fp, "%d %d", &l, &w) != 2) { fprintf (stderr, "error getting database dimensions from bathymetry file, sorry!\n"); return(NULL); } b->npts = l * w; /* Allocate space for the bathymetric points */ b->p = (BathymetricPoint *) calloc (b->npts, sizeof(BathymetricPoint)); if (b->p == NULL) { perror ("calloc b->p"); return(NULL); } /* Read in the bathymetric points */ for (i = 0; i < b->npts; i++) { if (fscanf(fp, "%lf %lf %lf %s", &(b->p[i].x), &(b->p[i].y), &(b->p[i].z), b->grid_zone) != 4) { fprintf (stderr, "error reading in bathymetric point %d from file\n", i); } } /* Sort the grid points */ qsort (b->p, b->npts, sizeof(BathymetricPoint), bathymetric_compare); /* All set! */ return(b); } int bathymetric_compare (BathymetricPoint *p1, BathymetricPoint *p2) { if (p1->x < p2->x) return(-1); if (p1->x > p2->x) return(1); if (p1->y < p2->y) return(-1); if (p1->y > p2->y) return(1); return(0); } void cursor_track (XInfo *xi, double min_x, double min_y, double max_x, double max_y, int x_offset, int y_offset, int width, int height, Bathymetry *b) { double utm_x, utm_y; int start_el, center_el, end_el; double distance, min_distance; int distance_index, cursor_text_y; UTM utm; LL ll; int i; int lat_deg, lat_min; double lat_sec; char lat_dir; int long_deg, long_min; double long_sec; char long_dir; char screen_text[LINEBUFSIZE]; cursor_text_y = height + MAP_MARGIN + 50; /* Convert cursor to UTM x,y coordinates */ utm_x = min_x + (xi->event.xbutton.x - x_offset) * (max_x - min_x) / (double) (width); utm_y = max_y - (xi->event.xbutton.y - y_offset) * (max_y - min_y) / (double) (height); /* Find which grid point is closest to the current x,y coordinate */ start_el = 0; end_el = b->npts - 1; do { center_el = (start_el + end_el) * 0.5; if (b->p[center_el].x > utm_x) end_el = center_el; else start_el = center_el; } while (end_el - start_el > 1); i = center_el; distance_index = i; min_distance = (utm_x - b->p[i].x) * (utm_x - b->p[i].x) + (utm_y - b->p[i].y) * (utm_y - b->p[i].y); while (++i < b->npts && fabs(b->p[i].x - utm_x) < GRID_TOLERANCE) { distance = (utm_x - b->p[i].x) * (utm_x - b->p[i].x) + (utm_y - b->p[i].y) * (utm_y - b->p[i].y); if (distance < min_distance) { min_distance = distance; distance_index = i; } } i = center_el; while (--i >= 0 && fabs(b->p[i].x - utm_x) < GRID_TOLERANCE) { distance = (utm_x - b->p[i].x) * (utm_x - b->p[i].x) + (utm_y - b->p[i].y) * (utm_y - b->p[i].y); if (distance < min_distance) { min_distance = distance; distance_index = i; } } /* Get the distance to the closest point */ distance = sqrt(min_distance); /* Convert the current utm x/y coordinate position to lat/long */ utm.x = utm_x; utm.y = utm_y; memcpy (utm.grid_zone, b->grid_zone, GRID_ZONE_LENGTH); utm2ll (&utm, &ll, WGS_84_DATUM); /* Plot the information on the screen */ sprintf (screen_text, "Cursor: UTM X: %12.3f UTM: Y: %12.3f (WGS-84) Grid %s", utm_x, utm_y, b->grid_zone); XDrawImageString (xi->display, xi->window, xi->gc, CURSOR_TEXT_X, cursor_text_y, screen_text, strlen(screen_text)); /* Convert lat/long to degrees/minutes/seconds, etc. */ lat_deg = (int) (ll.latitude < 0) ? fabs(-ll.latitude) : fabs(ll.latitude); lat_min = (int) ( ((ll.latitude < 0) ? (-ll.latitude - lat_deg) : (ll.latitude - lat_deg)) * 60.0); lat_sec = ((ll.latitude < 0) ? (-ll.latitude - lat_deg - lat_min / 60.0) : (ll.latitude - lat_deg - lat_min / 60.0)) * 3600.0; lat_dir = (ll.latitude < 0) ? 'S' : 'N'; long_deg = (int) (ll.longitude < 0) ? fabs(-ll.longitude) : fabs(ll.longitude); long_min = (int) ( ((ll.longitude < 0) ? (-ll.longitude - long_deg) : (ll.longitude - long_deg)) * 60.0); long_sec = ((ll.longitude < 0) ? (-ll.longitude - long_deg - long_min / 60.0) : (ll.longitude - long_deg - long_min / 60.0)) * 3600.0; long_dir = (ll.longitude < 0) ? 'W' : 'E'; sprintf (screen_text, " Latitude: %3d %2d' %5.2f'' %c Longitude: %3d %2d' %5.2f'' %c", lat_deg, lat_min, lat_sec, lat_dir, long_deg, long_min, long_sec, long_dir); XDrawImageString (xi->display, xi->window, xi->gc, CURSOR_TEXT_X + MAP_WIDTH / 2, cursor_text_y, screen_text, strlen(screen_text)); sprintf (screen_text, " Latitude: %3d %8.5f %c Longitude: %3d %8.5f %c", lat_deg, ( ((ll.latitude < 0) ? (-ll.latitude - lat_deg) : (ll.latitude - lat_deg)) * 60.0), lat_dir, long_deg, ( ((ll.longitude < 0) ? (-ll.longitude - long_deg) : (ll.longitude - long_deg)) * 60.0), long_dir); XDrawImageString (xi->display, xi->window, xi->gc, CURSOR_TEXT_X + MAP_WIDTH / 2, cursor_text_y + TEXT_HEIGHT, screen_text, strlen(screen_text)); sprintf (screen_text, " Depth: %9.3f meters below mean low tide", b->p[distance_index].z); XDrawImageString (xi->display, xi->window, xi->gc, CURSOR_TEXT_X, cursor_text_y + TEXT_HEIGHT, screen_text, strlen(screen_text)); sprintf (screen_text, " Bathymetric Point: %8.3f meters from cursor", distance); XDrawImageString (xi->display, xi->window, xi->gc, CURSOR_TEXT_X, cursor_text_y + 2 * TEXT_HEIGHT, screen_text, strlen(screen_text)); return; } void plot_ffp_array_location (XInfo *xi, double min_x, double min_y, double max_x, double max_y, int width, int height, int x_offset, int y_offset) { XPoint pt[6]; double alx[6], aly[6]; int i; /* Initialize with the current array location estimates */ alx[0] = 285057.021920; aly[0] = 3776960.524727; /* ACO 1 */ alx[1] = 284922.191911; aly[1] = 3776937.967178; /* ACO 3 */ alx[2] = 284910.364731; aly[2] = 3776798.488529; /* ACO 5 */ alx[3] = 285028.791066; aly[3] = 3776719.333442; /* ACO 4 */ alx[4] = 285119.571568; aly[4] = 3776824.222779; /* ACO 2 */ alx[5] = 285057.021920; aly[5] = 3776960.524727; /* ACO 1 */ /* Make sure the entire array would be visible in the current block */ if (min_x < alx[2] && max_x > alx[1] && min_y < aly[3] && max_y > aly[0]) { for (i = 0; i < 6; i++) { pt[i].x = x_offset + (int) (width * (alx[i] - min_x) / (max_x - min_x)); pt[i].y = y_offset + height - (int) (height * (aly[i] - min_y) / (max_y - min_y)); } /* Set the color to green */ XSetForeground (xi->display, xi->gc, xi->green_color.pixel); XSetLineAttributes (xi->display, xi->gc, 2, LineSolid, CapButt, JoinMiter); /* Draw the lines */ XDrawLines (xi->display, xi->window, xi->gc, pt, 6, CoordModeOrigin); } /* All done; reset the lines to solid black */ XSetForeground (xi->display, xi->gc, xi->black_color.pixel); XSetLineAttributes (xi->display, xi->gc, 1, LineSolid, CapButt, JoinMiter); return; } Vector * read_overlay_file (FILE *fp, XInfo *xi, int *num_vectors) { /* * Format of the file: * UTM or LL * color, width * UTM X, UTM Y, grid (or) * lat, long * until end of file */ char linebuf[LINEBUFSIZE], line_color[LINEBUFSIZE]; unsigned int line_width; XColor color_exact; int nvect; LL ll; UTM utm, utm_old; Vector *v, *tv; unsigned char latlong_flag, line_flag; int lat_deg_temp, long_deg_temp; int lat_min_temp, long_min_temp; memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); /* Decide whether this is lat/long or UTM */ if (strncmp (linebuf, "LLDMS", 5) == 0) latlong_flag = COORD_LATLONG_DEG_MIN_SEC; else if (strncmp (linebuf, "LLDM", 4) == 0) latlong_flag = COORD_LATLONG_DEG_MIN; else if (strncmp (linebuf, "LLD", 3) == 0) latlong_flag = COORD_LATLONG_DEG; else if (strncmp (linebuf, "LL", 2) == 0) latlong_flag = COORD_LATLONG_DEG; else if (strncmp (linebuf, "UTM", 3) == 0) latlong_flag = COORD_UTM; else { fprintf (stderr, "first line of overlay file must be LL, LLD, LLDM, LLDMS, or UTM, not [%s]\n", linebuf); return(NULL); } /* Check to see if we should be plotting a line or a series of dots */ memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); if (strncmp (linebuf, "L", 1) == 0) line_flag = 1; else if (strncmp (linebuf, "D", 1) == 0) line_flag = 0; else { fprintf (stderr, "second line of overlay file must be L (line) or D (dot), not [%s]\n", linebuf); return(NULL); } /* Read in the color and the line width */ memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); memset (line_color, 0, LINEBUFSIZE * sizeof(char)); if (sscanf (linebuf, "%s", line_color) != 1) { fprintf (stderr, "error reading in line color from third line of overlay file\n"); fprintf (stderr, "should be color, not [%s]\n", linebuf); return(NULL); } memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); if (sscanf (linebuf, "%d", &line_width) != 1) { fprintf (stderr, "error reading in line width from fourth line of overlay file\n"); fprintf (stderr, "should be width, not [%s]\n", linebuf); return(NULL); } /* Allocate the color */ if (xi->num_overlay == 0) { xi->overlay_color = (XColor *) calloc (1, sizeof(XColor)); if (xi->overlay_color == NULL) { perror ("calloc xi->overlay_color in read_overlay_file()"); return(NULL); } } else { xi->overlay_color = (XColor *) realloc (xi->overlay_color, sizeof(XColor) * (xi->num_overlay + 1)); if (xi->overlay_color == NULL) { perror ("realloc xi->overlay_color in read_overlay_file()"); fprintf (stderr, "(wanted %d colors)\n", xi->num_overlay + 1); return(NULL); } } if (XAllocNamedColor (xi->display, xi->colormap, line_color, &color_exact, &(xi->overlay_color[xi->num_overlay])) < 0) { fprintf (stderr, "unable to allocate %s color for overlay line;\n", line_color); fprintf (stderr, " using black instead.\n"); memcpy (&(xi->overlay_color[xi->num_overlay]), &(xi->black_color), sizeof(XColor)); } /* Allocate the line width */ if (xi->num_overlay == 0) { xi->overlay_line_width = (unsigned int *) calloc (1, sizeof(unsigned int)); if (xi->overlay_line_width == NULL) { perror ("calloc xi->overlay_line_width in read_overlay_file()"); return(NULL); } } else { xi->overlay_line_width = (unsigned int *) realloc (xi->overlay_line_width, sizeof(unsigned int) * (xi->num_overlay + 1)); if (xi->overlay_line_width == NULL) { perror ("realloc xi->overlay_line_width in read_overlay_file()"); fprintf (stderr, "(wanted %d lines)\n", xi->num_overlay + 1); return(NULL); } } /* Set the line width */ xi->overlay_line_width[xi->num_overlay] = line_width; /* Allocate the line/dot flag */ if (xi->num_overlay == 0) { xi->overlay_line_flag = (unsigned char *) calloc (1, sizeof(unsigned char)); if (xi->overlay_line_flag == NULL) { perror ("calloc xi->overlay_line_flag in read_overlay_file()"); return(NULL); } } else { xi->overlay_line_flag = (unsigned char *) realloc (xi->overlay_line_flag, sizeof(unsigned char) * (xi->num_overlay + 1)); if (xi->overlay_line_flag == NULL) { perror ("realloc xi->overlay_line_flag in read_overlay_file()"); return(NULL); } } /* Set the line/dot flag */ xi->overlay_line_flag[xi->num_overlay] = line_flag; /* Increment the number of overlays */ (xi->num_overlay)++; /* Allocate the vector structure */ nvect = 0; v = (Vector *) calloc (nvect + 1, sizeof(Vector)); if (v == NULL) { perror ("calloc v in read_overlay_file()"); return(NULL); } /* Read in the points */ memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); switch (latlong_flag) { case COORD_LATLONG_DEG: if (sscanf (linebuf, "%lf,%lf", &(ll.latitude), &(ll.longitude)) != 2) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees lat, degrees long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_LATLONG_DEG_MIN: if (sscanf (linebuf, "%d %lf,%d %lf", &(lat_deg_temp), &(ll.latitude), &(long_deg_temp), &(ll.longitude)) != 4) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees min lat, degrees min long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll.latitude = abs(lat_deg_temp) + ll.latitude / 60.0; ll.latitude = (lat_deg_temp < 0) ? -ll.latitude : ll.latitude; ll.longitude = abs(long_deg_temp) + ll.longitude / 60.0; ll.longitude = (long_deg_temp < 0) ? -ll.longitude : ll.longitude; ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_LATLONG_DEG_MIN_SEC: if (sscanf (linebuf, "%d %d %lf,%d %d %lf", &(lat_deg_temp), &(lat_min_temp), &(ll.latitude), &(long_deg_temp), &(long_min_temp), &(ll.longitude)) != 6) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees min sec lat, degrees min sec long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll.latitude = abs(lat_deg_temp) + lat_min_temp / 60.0 + ll.latitude / 3600.0; ll.latitude = (lat_deg_temp < 0) ? -ll.latitude : ll.latitude; ll.longitude = abs(long_deg_temp) + long_min_temp / 60.0 + ll.longitude / 3600.0; ll.longitude = (long_deg_temp < 0) ? -ll.longitude : ll.longitude; ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_UTM: if (sscanf (linebuf, "%lf,%lf,%s", &(utm.x), &(utm.y), utm.grid_zone) != 3) { if (!(feof(fp))) { fprintf (stderr, "malformed UTM line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be utm X, utm Y, grid zone separated by commas.\n"); return(NULL); } } break; } memcpy (&(utm_old), &(utm), sizeof(UTM)); /* Build a vector */ while (!feof(fp)) { memset (linebuf, 0, LINEBUFSIZE * sizeof(char)); fgets(linebuf, LINEBUFSIZE, fp); switch (latlong_flag) { case COORD_LATLONG_DEG: if (sscanf (linebuf, "%lf,%lf", &(ll.latitude), &(ll.longitude)) != 2) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees lat, degrees long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_LATLONG_DEG_MIN: if (sscanf (linebuf, "%d %lf,%d %lf", &(lat_deg_temp), &(ll.latitude), &(long_deg_temp), &(ll.longitude)) != 4) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees min lat, degrees min long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll.latitude = abs(lat_deg_temp) + ll.latitude / 60.0; ll.latitude = (lat_deg_temp < 0) ? -ll.latitude : ll.latitude; ll.longitude = abs(long_deg_temp) + ll.longitude / 60.0; ll.longitude = (long_deg_temp < 0) ? -ll.longitude : ll.longitude; ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_LATLONG_DEG_MIN_SEC: if (sscanf (linebuf, "%d %d %lf,%d %d %lf", &(lat_deg_temp), &(lat_min_temp), &(ll.latitude), &(long_deg_temp), &(long_min_temp), &(ll.longitude)) != 6) { if (!feof(fp)) { fprintf (stderr, "malformed lat/long line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be degrees min sec lat, degrees min sec long separated by a comma.\n"); return(NULL); } } else { /* Convert to UTM */ ll.latitude = abs(lat_deg_temp) + lat_min_temp / 60.0 + ll.latitude / 3600.0; ll.latitude = (lat_deg_temp < 0) ? -ll.latitude : ll.latitude; ll.longitude = abs(long_deg_temp) + long_min_temp / 60.0 + ll.longitude / 3600.0; ll.longitude = (long_deg_temp < 0) ? -ll.longitude : ll.longitude; ll2utm (&(ll), &(utm), WGS_84_DATUM); } break; case COORD_UTM: if (sscanf (linebuf, "%lf,%lf,%s", &(utm.x), &(utm.y), utm.grid_zone) != 3) { if (!(feof(fp))) { fprintf (stderr, "malformed UTM line in overlay file: [%s]\n", linebuf); fprintf (stderr, "should be utm X, utm Y, grid zone separated by commas.\n"); return(NULL); } } break; } /* Add to vector list */ v[nvect].xb = utm_old.x; v[nvect].yb = utm_old.y; v[nvect].xa = utm.x; v[nvect].ya = utm.y; /* Reallocate vector list */ tv = (Vector *) calloc (nvect+2, sizeof(Vector)); if (tv == NULL) { perror ("calloc tv in read_overlay_file()"); return(NULL); } memcpy (tv, v, (nvect+1) * sizeof(Vector)); free(v); v = tv; nvect++; /* Copy UTM points */ memcpy (&(utm_old), &(utm), sizeof(UTM)); /* Read in next point */ } *num_vectors = nvect; /* Now we've got a complete vector. Ready to plot... */ return(v); } int draw_overlays (XInfo *xi, VectorList *ovl, double min_x, double min_y, double max_x, double max_y, int width, int height, int x_offset, int y_offset) { int i, j; int nseg; XSegment *xseg; XArc *xarc; for (j = 0; j < xi->num_overlay; j++) { /* Reset the arc/segment counter */ nseg = 0; /* Are we drawing dots or lines? */ if (xi->overlay_line_flag[j]) { /* Allocate space to hold the coordinates */ xseg = (XSegment *) calloc (ovl[j].nvect, sizeof(XSegment)); if (xseg == NULL) { perror ("calloc xseg in draw_overlay()"); return(-1); } /* Set the line color and width */ XSetLineAttributes (xi->display, xi->gc, xi->overlay_line_width[j], LineSolid, CapButt, JoinMiter); XSetForeground (xi->display, xi->gc, xi->overlay_color[j].pixel); for (i = 0; i < ovl[j].nvect; i++) { /* Check to see if the vector falls within the bounding box */ if (ovl[j].v[i].xb > min_x && ovl[j].v[i].xb < max_x && ovl[j].v[i].yb > min_y && ovl[j].v[i].yb < max_y && ovl[j].v[i].xa > min_x && ovl[j].v[i].xa < max_x && ovl[j].v[i].ya > min_y && ovl[j].v[i].ya < max_y) { /* Add it to the list o'coordinates to draw */ xseg[nseg].x1 = x_offset + (int) (width * (ovl[j].v[i].xb - min_x) / (max_x - min_x)); xseg[nseg].y1 = y_offset + height - (int) (height * (ovl[j].v[i].yb - min_y) / (max_y - min_y)); xseg[nseg].x2 = x_offset + (int) (width * (ovl[j].v[i].xa - min_x) / (max_x - min_x)); xseg[nseg].y2 = y_offset + height - (int) (height * (ovl[j].v[i].ya - min_y) / (max_y - min_y)); nseg++; } } /* i loop */ /* Draw the coordinates on the screen */ XDrawSegments (xi->display, xi->window, xi->gc, xseg, nseg); /* Free the space used to hold the coordinates */ free(xseg); } else { /* Allocate space to hold the arcs */ xarc = (XArc *) calloc (ovl[j].nvect, sizeof(XArc)); if (xarc == NULL) { perror ("calloc xarc in draw_overlay()"); return(-1); } /* Set the line color */ XSetForeground (xi->display, xi->gc, xi->overlay_color[j].pixel); /* Run through the list of points */ for (i = 0; i < ovl[j].nvect; i++) { if (ovl[j].v[i].xb > min_x && ovl[j].v[i].xb < max_x && ovl[j].v[i].yb > min_y && ovl[j].v[i].yb < max_y) { xarc[nseg].x = x_offset + (int) (width * (ovl[j].v[i].xb - min_x) / (max_x - min_x)); xarc[nseg].y = y_offset + height - (int) (height * (ovl[j].v[i].yb - min_y) / (max_y - min_y)); xarc[nseg].width = xarc[nseg].height = xi->overlay_line_width[j]; xarc[nseg].x -= (xarc[nseg].width / 2); xarc[nseg].y -= (xarc[nseg].height / 2); xarc[nseg].angle1 = 0; xarc[nseg].angle2 = 360 * 64; nseg++; } /* if */ } /* i loop */ /* Draw the arcs on the screen */ XFillArcs (xi->display, xi->window, xi->gc, xarc, nseg); /* Free the arc space */ free (xarc); } /* dot/line */ /* Loop around to the next overlay */ } /* j loop */ /* All done */ return(0); } VectorList * read_overlay_files(XInfo *xi, int nfiles, char **filename) { VectorList *vl; FILE *ofp; int i; vl = (VectorList *) calloc (nfiles, sizeof(VectorList)); if (vl == NULL) { perror ("calloc vl in read_overlay_files()"); return(NULL); } /* Run through the files */ for (i = 0; i < nfiles; i++) { /* Open the overlay file */ ofp = fopen (filename[i], "r"); if (ofp == NULL) { perror ("fopen overlay file in read_overlay_files()"); fprintf (stderr, "error opening overlay file [%s] for reading\n", filename[i]); } else { /* Read in the overlay points */ vl[i].v = read_overlay_file (ofp, xi, &(vl[i].nvect)); if (vl[i].v == NULL) { fprintf (stderr, "error reading overlay data from [%s], sorry!\n", filename[i]); return(NULL); } /* Close the overlay file */ fclose(ofp); } } /* Return the vector list */ return(vl); }