/* * (C) 2001-2004 Diomidis Spinellis * This file is part of GTWeb. * * GTWeb 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, or (at your option) any later * version. * * GTWeb 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 groff; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * Ammend track log data with information about the nearest geographical name * The following fields are added: * Feature designation http://164.214.2.59/gns/html/fd_cross_ref.html * Administrative division http://164.214.2.59/gns/html/fips/fip10-4.html * Distance * Feature latitude * Feature longitude * Name * * Data should come from http://164.214.2.59/gns/html/cntry_files.html * * $Id: near.c 1.4 2004/02/07 08:35:19 dds Exp $ * */ #include #include #include #include struct point { float lat; float lon; enum {string, fileoffset} type; union { long offset; // Offset into data file char *name; // Saved name } u; }; static void skiptotab(FILE *f) { int c; while ((c = getc(f)) != '\t') ; } static void printtotab(FILE *f) { int c; while ((c = getc(f)) != '\t') putchar(c); } static void uscoord(char *s, float *lat, float *lon) { char coord[20]; char *d; s += 80; d = coord + 1; *d++ = *s++; *d++ = *s++; *d++ = '.'; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d = 0; coord[0] = (*s == 'N' ? ' ' : '-'); if (sscanf(coord, "%g", lat) != 1) *lat = 0.0; s += 2; d = coord + 1; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = '.'; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; *d = 0; coord[0] = (*s == 'W' ? '-' : ' '); if (sscanf(coord, "%g", lon) != 1) *lon = 0.0; } /* * Print feature type and county name and fill in the feature name */ static void us_scan(FILE *fp, char *name, int namelen) { char buff[512]; int i; fgets(buff, sizeof(buff), fp); // Feature type for (i = 62; i > 55; i--) if (buff[i - 1] != ' ') break; buff[i] = 0; fputs(buff + 54, stdout); putchar('\t'); // County for (i = 78; i > 65; i--) if (buff[i - 1] != ' ') break; buff[i] = 0; fputs(buff + 64, stdout); putchar('\t'); // Name for (i = 52; i > 4; i--) if (buff[i - 1] != ' ') break; buff[i] = 0; strcpy(name, buff + 3); } static void world_scan(FILE *fp, char *name, int namelen) { skiptotab(fp); // C skiptotab(fp); // UFI skiptotab(fp); // DLAT skiptotab(fp); // DLONG skiptotab(fp); // LAT skiptotab(fp); // LONG skiptotab(fp); // MGRS skiptotab(fp); // UTM skiptotab(fp); // JOG skiptotab(fp); // FC skiptotab(fp); // DSG printtotab(fp); // PC putchar('\t'); skiptotab(fp); // CC1 printtotab(fp); // ADM1 printtotab(fp); // ADM2 putchar('\t'); skiptotab(fp); // DIM skiptotab(fp); // CC2 skiptotab(fp); // NT skiptotab(fp); // LC skiptotab(fp); // SHORT_FORM skiptotab(fp); // GENERIC skiptotab(fp); // SORT_NAME skiptotab(fp); // FULL_NAME skiptotab(fp); fgets(name, namelen, fp); *strrchr(name, '\n') = 0; } main(int argc, char *argv[]) { FILE *fp; FILE *ft; char buff[1024]; int n; int i, j; char ew, ns; int latdeg, londeg; float latmin, lonmin; float lat, lon; float best, nbest; int besti; char feature[20]; char country[20]; char area[20]; char name[512]; struct point *p; int palloc; enum {f_us = 'u', f_world = 'w'} fmt; if (argc < 4 || *argv[1] != '-' || (argv[1][1] != 'u' && argv[1][1] != 'w')) { fprintf(stderr, "usage: %s -u|-w name-data [waypoints ... ] track-log ...\n", argv[0]); exit(1); } fmt = argv[1][1]; /* * The US data is delimited with a \n without a \r * Visual C 5 generates wrong offsets with ftell when opening as "r" */ // Read feature list if ((fp = fopen(argv[2], fmt == f_world ? "r" : "rb")) == NULL) { perror(argv[2]); exit(1); } p = (struct point *)malloc((palloc = 50000) * sizeof(struct point)); for (n = 0; p[n].u.offset = ftell(fp), fgets(buff, sizeof(buff), fp); n++) { if (n == palloc) p = (struct point *)realloc(p, (palloc *= 2) * sizeof(struct point)); switch (fmt) { case f_world: sscanf(buff, "%*d %*d %*d %g %g", &p[n].lat, &p[n].lon); break; case f_us: uscoord(buff, &p[n].lat, &p[n].lon); break; default: assert(0); } p[n].type = fileoffset; //printf("o=%d lat=%g lon=%g\n", p[n].offset, p[n].lat, p[n].lon); } for (i = 3; i < argc; i++) { if ((ft = fopen(argv[i], "r")) == NULL) { perror(argv[i]); exit(1); } while (fgets(buff, sizeof(buff), ft)) { if ((*buff != 'T' && *buff != 'W') || buff[1] != ' ') continue; switch (*buff) { case 'T': // T N38 04.8777 E023 49.9539 Sun Aug 19 08:48:55 2001 sscanf(buff, "%*c %c%d %g %c%d %g", &ns, &latdeg, &latmin, &ew, &londeg, &lonmin); break; case 'W': // W YPATI N38 52.1999 E022 14.4999 Sun Dec 31 00:00:00 1989 09-NOV-01 22:45 Ypati sscanf(buff + 10, "%c%d %g %c%d %g", &ns, &latdeg, &latmin, &ew, &londeg, &lonmin); break; default: assert(0); } //fputs(buff, stdout); //printf("%c %d %g|%c %d %g\n", ns, latdeg, latmin, ew, londeg, lonmin); lat = latdeg + latmin / 60; if (ns == 'S') lat = -lat; lon = londeg + lonmin / 60; if (ew == 'W') lon = -lon; if (*buff == 'W') { // Waypoint; store it for future reference if (n == palloc) p = (struct point *)realloc(p, (palloc *= 2) * sizeof(struct point)); p[n].lat = lat; p[n].lon = lon; p[n].type = string; if (buff[76] != ' ') { // Remove trailing spaces for (j = strlen(buff) - 2; j > 0; j++) if (buff[j] != ' ') { buff[j + 1] = 0; break; } p[n].u.name = strdup(buff + 76); } else { buff[9] = 0; p[n].u.name = strdup(buff + 3); } // printf("n=%s lat=%g lon=%g\n", p[n].u.name, p[n].lat, p[n].lon); n++; continue; } // Track point; use it // Linear search :-( best = 1e38; for (j = 0; j < n; j++) { if ((nbest = hypot(lat - p[j].lat, lon - p[j].lon)) < best) { best = nbest; besti = j; } //printf("best: %g %g %g %g %g\n", nbest, p[j].lat, p[j].lon, lat, lon); } *strrchr(buff, '\n') = 0; printf("%s ", buff); switch (p[besti].type) { case fileoffset: fseek(fp, p[besti].u.offset, SEEK_SET); //printf("o=%d\n", p[besti].offset); switch (fmt) { case f_us: us_scan(fp, name, sizeof(name)); break; case f_world: world_scan(fp, name, sizeof(name)); break; } break; case string: printf(" \t \t"); strcpy(name, p[besti].u.name); break; default: assert(0); } printf(" %g %g %g %s\n", best, p[besti].lat, p[besti].lon, name); } fclose(ft); } exit(0); }