1 /*
2 *
3 * XASTIR, Amateur Station Tracking and Information Reporting
4 * Copyright (C) 1999,2000 Frank Giannandrea
5 * Copyright (C) 2000-2019 The Xastir Group
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * Look at the README for more information on the program.
22 */
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif // HAVE_CONFIG_H
28
29 #include "snprintf.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <pwd.h>
38 #include <errno.h>
39
40 // Needed for Solaris
41 #ifdef HAVE_STRINGS_H
42 #include <strings.h>
43 #endif // HAVE_STRINGS_H
44
45 #include <dirent.h>
46 #include <netinet/in.h>
47 #include <Xm/XmAll.h>
48
49 #ifdef HAVE_X11_XPM_H
50 #include <X11/xpm.h>
51 #ifdef HAVE_LIBXPM // if we have both, prefer the extra library
52 #undef HAVE_XM_XPMI_H
53 #endif // HAVE_LIBXPM
54 #endif // HAVE_X11_XPM_H
55
56 #ifdef HAVE_XM_XPMI_H
57 #include <Xm/XpmI.h>
58 #endif // HAVE_XM_XPMI_H
59
60 #include <X11/Xlib.h>
61
62 #include <math.h>
63
64 #include "xastir.h"
65 #include "maps.h"
66 #include "alert.h"
67 #include "util.h"
68 #include "main.h"
69 #include "datum.h"
70 #include "draw_symbols.h"
71 #include "rotated.h"
72 #include "color.h"
73 #include "xa_config.h"
74
75 // Must be last include file
76 #include "leak_detection.h"
77
78
79
80 #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); }
81
82 //NOTE: This function has a problem if a non-gnis file is labeled
83 //with a ".gnis" extension. It causes a segfault in Xastir. More
84 //error checking needs to be done in order to prevent this.
85
86 // draw_gnis_map()
87 //
88 // Allows drawing a background map of labels for the viewport.
89 // Example format (old):
90 // "WA","Abbey View Memorial Park","cemetery","Snohomish","53","061","474647N","1221650W","47.77972","-122.28056","","","","","420","","Edmonds East"
91 //
92 // Example format (new):
93 // 376016|ID|12th Ave Drain|stream|Canyon|16|027|433107N|1163348W|43.51861|-116.56333||||||||Nampa
94 //
95 // These types of files are available from http://geonames.usgs.gov/
96 // under "Download State Gazetteer Data - Available Via Anonymous FTP".
97 // A typical filename would be: "WA_Features_20090401.zip". Do not get the other
98 // types of files which are columnar. The files that we parse are
99 // pipe-delimited.
100 //
draw_gnis_map(Widget w,char * dir,char * filenm,alert_entry * UNUSED (alert),u_char UNUSED (alert_color),int destination_pixmap,map_draw_flags * UNUSED (mdf))101 void draw_gnis_map (Widget w,
102 char *dir,
103 char *filenm,
104 alert_entry * UNUSED(alert),
105 u_char UNUSED(alert_color),
106 int destination_pixmap,
107 map_draw_flags * UNUSED(mdf) )
108 {
109 char file[MAX_FILENAME]; // Complete path/name of GNIS file
110 char short_filenm[MAX_FILENAME];
111 FILE *f; // Filehandle of GNIS file
112 char line[MAX_FILENAME]; // One line of text from file
113 char *i, *j;
114 char state[50];
115 char name[200];
116 char type[100];
117 char county[100];
118 char latitude[15];
119 char longitude[15];
120 char population[15];
121 char lat_dd[3];
122 char lat_mm[3];
123 char lat_ss[3];
124 char lat_dir[2];
125 char long_dd[4];
126 char long_mm[3];
127 char long_ss[3];
128 char long_dir[2];
129 char lat_str[15];
130 char long_str[15];
131 int temp1;
132 long coord_lon, coord_lat;
133 long min_lat, min_lon, max_lat, max_lon;
134 int ok;
135 long x,y;
136 char symbol_table, symbol_id, symbol_over;
137 unsigned long bottom_extent = 0l;
138 unsigned long top_extent = 0l;
139 unsigned long left_extent = 0l;
140 unsigned long right_extent = 0l;
141 char status_text[MAX_FILENAME];
142 int count = 0;
143
144
145 //fprintf(stderr,"draw_gnis_map starting: %s/%s\n",dir,filenm);
146
147 xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm);
148
149 // Create a shorter filename for display (one that fits the
150 // status line more closely). Subtract the length of the
151 // "Indexing " and/or "Loading " strings as well.
152 if (strlen(filenm) > (41 - 9))
153 {
154 int avail = 41 - 11;
155 int new_len = strlen(filenm) - avail;
156
157 xastir_snprintf(short_filenm,
158 sizeof(short_filenm),
159 "..%s",
160 &filenm[new_len]);
161 }
162 else
163 {
164 xastir_snprintf(short_filenm,
165 sizeof(short_filenm),
166 "%s",
167 filenm);
168 }
169
170 // Screen view
171 min_lat = SE_corner_latitude;
172 max_lat = NW_corner_latitude;
173 min_lon = NW_corner_longitude;
174 max_lon = SE_corner_longitude;
175
176
177 // The map extents in the map index are checked in draw_map to
178 // see whether we should draw the map at all.
179
180
181 // Update the statusline for this map name
182 // Check whether we're indexing or drawing the map
183 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
184 || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
185 {
186 xastir_snprintf(status_text,
187 sizeof(status_text),
188 langcode ("BBARSTA039"),
189 short_filenm);
190 }
191 else
192 {
193 xastir_snprintf(status_text,
194 sizeof(status_text),
195 langcode ("BBARSTA028"),
196 short_filenm);
197 }
198 statusline(status_text,0); // Loading/Indexing ...
199
200
201 HandlePendingEvents(app_context);
202 if (interrupt_drawing_now)
203 {
204 // Update to screen
205 (void)XCopyArea(XtDisplay(da),
206 pixmap,
207 XtWindow(da),
208 gc,
209 0,
210 0,
211 (unsigned int)screen_width,
212 (unsigned int)screen_height,
213 0,
214 0);
215 return;
216 }
217
218
219 /*
220 Latest pipe-delimited format from USGS (as of 08/12/2004):
221 ----------------------------------------------------------
222 Feature ID Number (FID)
223 State Alpha Code
224 Feature Name
225 Feature Type
226 County Name
227 State Number Code (FIPS Code)
228 County Number Code (FIPS Code)
229 Primary Latitude (DMS)
230 Primary Longitude (DMS)
231 Primary Latitude (decimal degrees)
232 Primary Longitude (decimal degrees)
233 Source Latitude (DMS)
234 Source Longitude (DMS)
235 Source Latitude (decimal degrees)
236 Source Longitude (decimal degrees)
237 Elevation
238 Estimated Population
239 Federal Status
240 Cell Name
241 */
242
243
244 // Attempt to open the file
245 f = fopen (file, "r");
246 if (f != NULL)
247 {
248 while (!feof (f)) // Loop through entire file
249 {
250 int lat_in_view = 0;
251
252 count++;
253 if ((count % 16) == 0)
254 {
255
256 // Check whether map drawing should be interrupted.
257 // Check every 16 lines.
258 //
259 HandlePendingEvents(app_context);
260 if (interrupt_drawing_now)
261 {
262 (void)fclose (f);
263 // Update to screen
264 (void)XCopyArea(XtDisplay(da),
265 pixmap,
266 XtWindow(da),
267 gc,
268 0,
269 0,
270 (unsigned int)screen_width,
271 (unsigned int)screen_height,
272 0,
273 0);
274 return;
275 }
276 }
277
278 if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data
279 {
280
281 // It is common for these lines to have incredible
282 // numbers of spaces at the end, so trim them here.
283 (void)remove_trailing_spaces(line);
284
285 if (strlen(line) > 0)
286 {
287
288 // Default population, in case the field isn't
289 // present in the file.
290 xastir_snprintf(population,sizeof(population),"0");
291
292 // Examples of old/new format:
293 // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria
294 // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria
295 // 2008 Format follows
296 //FEATURE_ID|FEATURE_NAME|FEATURE_CLASS|STATE_ALPHA|STATE_NUMERIC|COUNTY_NAME|COUNTY_NUMERIC|PRIMARY_LAT_DMS|PRIM_LONG_DMS|PRIM_LAT_DEC|PRIM_LONG_DEC|SOURCE_LAT_DMS|SOURCE_LONG_DMS|SOURCE_LAT_DEC|SOURCE_LONG_DEC|ELEVATION|MAP_NAME|DATE_CREATED|DATE_EDITED
297 //205110|Appalachian National Scenic Trail|Trail|PA|42|Perry|099|401920N|0770439W|40.3221113|-77.0775473|||||201|Wertzville|09/12/1979|05/19/2008
298
299 //NOTE: We handle running off the end of "line"
300 //via the "continue" statement. Skip the line
301 //if we don't find enough parameters while
302 //parsing.
303
304 // Find end of Feature ID Number field
305 j = index(line,'|');
306
307 if (j == NULL) // Pipe not found
308 {
309 continue; // Skip this line
310 }
311
312 //NOTE: It'd be nice to take the part after the comma and put it before the rest
313 // of the text someday, i.e. "Cassidy, Lake".
314
315 // Find end of Feature Name field
316 i = index(++j, '|');
317
318 if (i == NULL) // Pipe not found
319 {
320 continue; // Skip this line
321 }
322
323 i[0] = '\0';
324 xastir_snprintf(name,sizeof(name),"%s",j);
325
326 // Find end of Feature Type field
327 j = index(++i, '|');
328
329 if (j == NULL) // Pipe not found
330 {
331 continue; // Skip this line
332 }
333
334 j[0] = '\0';
335 xastir_snprintf(type,sizeof(type),"%s",i);
336
337 // Find end of State field
338 i = index(++j, '|');
339
340 if (i == NULL) // Pipe not found
341 {
342 continue; // Skip this line
343 }
344
345 i[0] = '\0';
346 xastir_snprintf(state,sizeof(state),"%s",j);
347
348 // Find end of State Number Code field
349 j = index(++i, '|');
350
351 if (j == NULL) // Pipe not found
352 {
353 continue; // Skip this line
354 }
355
356 j[0] = '\0';
357
358 // Find end of County Name field
359 i = index(++j, '|');
360
361 if (i == NULL) // Pipe not found
362 {
363 continue; // Skip this line
364 }
365
366 i[0] = '\0';
367 xastir_snprintf(county,sizeof(county),"%s",j);
368
369 // Find end of County Number Code field
370 j = index(++i, '|');
371
372 if (j == NULL) // Pipe not found
373 {
374 continue; // Skip this line
375 }
376
377 j[0] = '\0';
378
379 // Examples of old/new format:
380 // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria
381 // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria
382
383 // Find end of Primary Latitude field (DDMMSSN)
384 i = index(++j, '|');
385
386 if (i == NULL) // Pipe not found
387 {
388 continue; // Skip this line
389 }
390
391 i[0] = '\0';
392 xastir_snprintf(latitude,sizeof(latitude),"%s",j);
393 if (!isdigit((int)latitude[0])) // skip record if not
394 {
395 continue; // numeric! (e.g. "UNKNOWN")
396 }
397
398 //WE7U
399 clean_string(latitude);
400
401 // Find end of Primary Longitude field (DDDMMSSW)
402 j = index(++i, '|');
403
404 if (j == NULL) // Pipe not found
405 {
406 continue; // Skip this line
407 }
408
409 j[0] = '\0';
410 xastir_snprintf(longitude,sizeof(longitude),"%s",i);
411 if (!isdigit((int)longitude[0])) // skip record if not
412 {
413 continue; // numeric (e.g. UNKNOWN)
414 }
415
416 //WE7U
417 clean_string(longitude);
418
419 // Find end of Primary Latitude field (decimal
420 // degrees)
421 i = index(++j, '|');
422
423 if (i == NULL) // Pipe not found
424 {
425 goto FINISH; // We have enough to process now
426 }
427
428 i[0] = '\0';
429
430 // Find end of Primary Longitude field (decimal
431 // degrees)
432 j = index(++i, '|');
433
434 if (j == NULL) // Pipe not found
435 {
436 goto FINISH; // We have enough to process now
437 }
438
439 j[0] = '\0';
440
441 // Examples of old/new format:
442 // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria
443 // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria
444
445 // Find end of Source Latitude field (DMS) (old
446 // format) or elevation (new format)
447 i = index(++j, '|');
448
449 if (i == NULL) // Pipe not found
450 {
451 goto FINISH; // We have enough to process now
452 }
453
454 i[0] = '\0';
455
456 // Find end of Source Longitude field (DMS) (old
457 // format) or
458 j = index(++i, '|');
459
460 if (j == NULL) // Pipe not found
461 {
462 goto FINISH; // We have enough to process now
463 }
464
465 j[0] = '\0';
466
467 // Find end of Source Latitude field (decimal
468 // degrees)
469 i = index(++j, '|');
470
471 if (i == NULL) // Pipe not found
472 {
473 goto FINISH; // We have enough to process now
474 }
475
476 i[0] = '\0';
477
478 // Find end of Source Longitude field (decimal
479 // degrees)
480 j = index(++i, '|');
481
482 if (j == NULL) // Pipe not found
483 {
484 goto FINISH; // We have enough to process now
485 }
486
487 j[0] = '\0';
488
489 // Find end of Elevation field
490 i = index(++j, '|');
491
492 if (i == NULL) // Pipe not found
493 {
494 goto FINISH; // We have enough to process now
495 }
496
497 i[0] = '\0';
498
499 // Find end of Estimated Population field
500 j = index(++i, '|');
501
502 if (j == NULL) // Pipe not found
503 {
504 goto FINISH; // We have enough to process now
505 }
506
507 if ( j != NULL )
508 {
509 j[0] = '\0';
510 xastir_snprintf(population,sizeof(population),"%s",i);
511 }
512
513 FINISH:
514 // There are two more fields (old format),
515 // "Federal Status" and "Cell Name". We ignore
516 // those for now.
517
518 if (strlen(latitude) < 7)
519 {
520 continue; // We really don't have any latitude here.
521 }
522 lat_dd[0] = latitude[0];
523 lat_dd[1] = latitude[1];
524 lat_dd[2] = '\0';
525
526 lat_mm[0] = latitude[2];
527 lat_mm[1] = latitude[3];
528 lat_mm[2] = '\0';
529
530 lat_ss[0] = latitude[4];
531 lat_ss[1] = latitude[5];
532 lat_ss[2] = '\0';
533
534 lat_dir[0] = latitude[6];
535 lat_dir[1] = '\0';
536
537 // Now must convert from DD MM SS format to DD MM.MM format so that we
538 // can run it through our conversion routine to Xastir coordinates.
539 if (1 != sscanf(lat_ss, "%d", &temp1))
540 {
541 fprintf(stderr,"draw_gnis_map:sscanf parsing error\n");
542 }
543
544 temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding
545 xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd,
546 lat_mm, temp1, lat_dir);
547 coord_lat = convert_lat_s2l(lat_str);
548
549 // Quick test of latitude to see if it's within
550 // our view. If not and we're not doing
551 // indexing, skip this line and go on to the
552 // next.
553 if (coord_lat <= min_lat && coord_lat >= max_lat)
554 {
555 // Latitude is ok
556 lat_in_view++;
557 }
558 else // Latitude not in current view
559 {
560
561 // Check whether we're indexing the map
562 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
563 || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
564 {
565 // Process the line 'cuz we're indexing
566 }
567 else // Not indexing so skip to the next
568 {
569 // line in the file
570 continue;
571 }
572 }
573
574 if (strlen(longitude) < 8)
575 {
576 continue; // We really don't have any longitude here.
577 }
578 long_dd[0] = longitude[0];
579 long_dd[1] = longitude[1];
580 long_dd[2] = longitude[2];
581 long_dd[3] = '\0';
582
583 long_mm[0] = longitude[3];
584 long_mm[1] = longitude[4];
585 long_mm[2] = '\0';
586
587 long_ss[0] = longitude[5];
588 long_ss[1] = longitude[6];
589 long_ss[2] = '\0';
590
591 long_dir[0] = longitude[7];
592 long_dir[1] = '\0';
593
594 if (1 != sscanf(long_ss, "%d", &temp1))
595 {
596 fprintf(stderr,"draw_gnis_map:sscanf parsing error\n");
597 }
598
599 temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding
600 xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd,
601 long_mm, temp1, long_dir);
602 coord_lon = convert_lon_s2l(long_str);
603
604
605 // Check whether we're indexing the map
606 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
607 || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
608 {
609
610 // Save the min/max extents of the file. We
611 // should really initially set the extents
612 // to the min/max for the Xastir coordinate
613 // system, but in practice zeroes should
614 // work just as well.
615 //
616 if ((coord_lat > (long)bottom_extent) || (bottom_extent == 0l))
617 {
618 bottom_extent = coord_lat;
619 }
620 if ((coord_lat < (long)top_extent) || (top_extent == 0l))
621 {
622 top_extent = coord_lat;
623 }
624 if ((coord_lon < (long)left_extent) || (left_extent == 0l))
625 {
626 left_extent = coord_lon;
627 }
628 if ((coord_lon > (long)right_extent) || (right_extent == 0l))
629 {
630 right_extent = coord_lon;
631 }
632 }
633 // Now check whether this lat/lon is within our viewport. If it
634 // is, draw a text label at that location.
635 else if (coord_lon >= min_lon && coord_lon <= max_lon
636 && lat_in_view)
637 {
638
639 clean_string(state);
640 clean_string(name);
641 clean_string(type);
642 clean_string(county);
643 clean_string(population);
644
645 if (debug_level & 16)
646 {
647 fprintf(stderr,"%s\t%s\t%s\t%s\t%s\t%s\t\t",
648 state, name, type, county, latitude, longitude);
649 fprintf(stderr,"%s %s %s %s\t%s %s %s %s\t\t",
650 lat_dd, lat_mm, lat_ss, lat_dir, long_dd, long_mm, long_ss, long_dir);
651 fprintf(stderr,"%s\t%s\n", lat_str, long_str);
652 }
653
654 // Convert to screen coordinates. Careful
655 // here! The format conversions you'll need
656 // if you try to compress this into two
657 // lines will get you into trouble.
658 x = coord_lon - NW_corner_longitude;
659 y = coord_lat - NW_corner_latitude;
660 x /= scale_x;
661 y /= scale_y;
662
663 ok = 1;
664
665 /* set default symbol */
666 symbol_table = '/';
667 symbol_id = '.'; /* small x */
668 symbol_over = ' ';
669
670 if (strcasecmp(type,"airport") == 0)
671 {
672 symbol_id = '^';
673 if (scale_y > 100)
674 {
675 ok = 0;
676 }
677 }
678 else if (strcasecmp(type,"arch") == 0)
679 {
680 if (scale_y > 50)
681 {
682 ok = 0;
683 }
684 }
685 else if (strcasecmp(type,"area") == 0)
686 {
687 if (scale_y > 50)
688 {
689 ok = 0;
690 }
691 }
692 else if (strcasecmp(type,"arroyo") == 0)
693 {
694 if (scale_y > 50)
695 {
696 ok = 0;
697 }
698 }
699 else if (strcasecmp(type,"bar") == 0)
700 {
701 if (scale_y > 50)
702 {
703 ok = 0;
704 }
705 }
706 else if (strcasecmp(type,"basin") == 0)
707 {
708 if (scale_y > 50)
709 {
710 ok = 0;
711 }
712 }
713 else if (strcasecmp(type,"bay") == 0)
714 {
715 if (scale_y > 50)
716 {
717 ok = 0;
718 }
719 }
720 else if (strcasecmp(type,"beach") == 0)
721 {
722 if (scale_y > 50)
723 {
724 ok = 0;
725 }
726 }
727 else if (strcasecmp(type,"bench") == 0)
728 {
729 if (scale_y > 50)
730 {
731 ok = 0;
732 }
733 }
734 else if (strcasecmp(type,"bend") == 0)
735 {
736 if (scale_y > 50)
737 {
738 ok = 0;
739 }
740 }
741 else if (strcasecmp(type,"bridge") == 0)
742 {
743 if (scale_y > 50)
744 {
745 ok = 0;
746 }
747 }
748 else if (strcasecmp(type,"building") == 0)
749 {
750 if (scale_y > 50)
751 {
752 ok = 0;
753 }
754 }
755 else if (strcasecmp(type,"canal") == 0)
756 {
757 if (scale_y > 50)
758 {
759 ok = 0;
760 }
761 }
762 else if (strcasecmp(type,"cape") == 0)
763 {
764 if (scale_y > 50)
765 {
766 ok = 0;
767 }
768 }
769 else if (strcasecmp(type,"cave") == 0)
770 {
771 if (scale_y > 50)
772 {
773 ok = 0;
774 }
775 }
776 else if (strcasecmp(type,"cemetery") == 0)
777 {
778 symbol_table = '\\';
779 symbol_id = '+';
780 if (scale_y > 50)
781 {
782 ok = 0;
783 }
784 }
785 else if (strcasecmp(type,"census") == 0)
786 {
787 /* if (scale_y > 50)*/ /* Census divisions */
788 ok = 0;
789 }
790 else if (strcasecmp(type,"channel") == 0)
791 {
792 if (scale_y > 50)
793 {
794 ok = 0;
795 }
796 }
797 else if (strcasecmp(type,"church") == 0)
798 {
799 symbol_table = '\\';
800 symbol_id = '+';
801 if (scale_y > 50)
802 {
803 ok = 0;
804 }
805 }
806 else if (strcasecmp(type,"civil") == 0)
807 {
808 if (scale_y > 50)
809 {
810 ok = 0;
811 }
812 }
813 else if (strcasecmp(type,"cliff") == 0)
814 {
815 if (scale_y > 50)
816 {
817 ok = 0;
818 }
819 }
820 else if (strcasecmp(type,"crater") == 0)
821 {
822 if (scale_y > 50)
823 {
824 ok = 0;
825 }
826 }
827 else if (strcasecmp(type,"crossing") == 0)
828 {
829 if (scale_y > 50)
830 {
831 ok = 0;
832 }
833 }
834 else if (strcasecmp(type,"dam") == 0)
835 {
836 if (scale_y > 50)
837 {
838 ok = 0;
839 }
840 }
841 else if (strcasecmp(type,"falls") == 0)
842 {
843 if (scale_y > 50)
844 {
845 ok = 0;
846 }
847 }
848 else if (strcasecmp(type,"flat") == 0)
849 {
850 if (scale_y > 50)
851 {
852 ok = 0;
853 }
854 }
855 else if (strcasecmp(type,"forest") == 0)
856 {
857 if (scale_y > 50)
858 {
859 ok = 0;
860 }
861 }
862 else if (strcasecmp(type,"gap") == 0)
863 {
864 if (scale_y > 50)
865 {
866 ok = 0;
867 }
868 }
869 else if (strcasecmp(type,"geyser") == 0)
870 {
871 if (scale_y > 50)
872 {
873 ok = 0;
874 }
875 }
876 else if (strcasecmp(type,"glacier") == 0)
877 {
878 if (scale_y > 50)
879 {
880 ok = 0;
881 }
882 }
883 else if (strcasecmp(type,"gut") == 0)
884 {
885 if (scale_y > 50)
886 {
887 ok = 0;
888 }
889 }
890 else if (strcasecmp(type,"harbor") == 0)
891 {
892 if (scale_y > 50)
893 {
894 ok = 0;
895 }
896 }
897 else if (strcasecmp(type,"hospital") == 0)
898 {
899 symbol_id = 'h';
900 if (scale_y > 50)
901 {
902 ok = 0;
903 }
904 }
905 else if (strcasecmp(type,"island") == 0)
906 {
907 if (scale_y > 50)
908 {
909 ok = 0;
910 }
911 }
912 else if (strcasecmp(type,"isthmus") == 0)
913 {
914 if (scale_y > 50)
915 {
916 ok = 0;
917 }
918 }
919 else if (strcasecmp(type,"lake") == 0)
920 {
921 if (scale_y > 50)
922 {
923 ok = 0;
924 }
925 }
926 else if (strcasecmp(type,"lava") == 0)
927 {
928 if (scale_y > 50)
929 {
930 ok = 0;
931 }
932 }
933 else if (strcasecmp(type,"levee") == 0)
934 {
935 if (scale_y > 50)
936 {
937 ok = 0;
938 }
939 }
940 else if (strcasecmp(type,"locale") == 0)
941 {
942 if (scale_y > 50)
943 {
944 ok = 0;
945 }
946 }
947 else if (strcasecmp(type,"military") == 0)
948 {
949 if (scale_y > 50)
950 {
951 ok = 0;
952 }
953 }
954 else if (strcasecmp(type,"mine") == 0)
955 {
956 if (scale_y > 50)
957 {
958 ok = 0;
959 }
960 }
961 else if (strcasecmp(type,"oilfield") == 0)
962 {
963 if (scale_y > 50)
964 {
965 ok = 0;
966 }
967 }
968 else if (strcasecmp(type,"other") == 0)
969 {
970 if (scale_y > 50)
971 {
972 ok = 0;
973 }
974 }
975 else if (strcasecmp(type,"park") == 0)
976 {
977 symbol_table = '\\';
978 symbol_id = ';';
979 if (scale_y > 50)
980 {
981 ok = 0;
982 }
983 }
984 else if (strcasecmp(type,"pillar") == 0)
985 {
986 if (scale_y > 50)
987 {
988 ok = 0;
989 }
990 }
991 else if (strcasecmp(type,"plain") == 0)
992 {
993 if (scale_y > 50)
994 {
995 ok = 0;
996 }
997 }
998 else if (strcasecmp(type,"po") == 0)
999 {
1000 symbol_id = ']';
1001 if (scale_y > 50)
1002 {
1003 ok = 0;
1004 }
1005 }
1006 else if (strcasecmp(type,"ppl") == 0)
1007 {
1008 symbol_id = '/';
1009 if (scale_y > 20000) // Don't draw cities at zoom higher than 20,000
1010 {
1011 ok = 0;
1012 }
1013 else if (scale_y > 4000) // Don't draw cities of less than 20,000
1014 {
1015 if (atoi(population) < 50000)
1016 {
1017 ok = 0;
1018 }
1019 }
1020 else if (scale_y > 1500) // Don't draw cities of less than 10,000
1021 {
1022 if (atoi(population) < 20000)
1023 {
1024 ok = 0;
1025 }
1026 }
1027 else if (scale_y > 750) // Don't draw cities of less than 5,000
1028 {
1029 if (atoi(population) < 10000)
1030 {
1031 ok = 0;
1032 }
1033 }
1034 else if (scale_y > 200) // Don't draw cities
1035 {
1036 // of less than 1,000
1037 if (atoi(population) < 1000)
1038 {
1039 ok = 0;
1040 //fprintf(stderr,
1041 // "Name: %s\tPopulation: %s\n",name,
1042 // population);
1043 }
1044 }
1045 }
1046 else if (strcasecmp(type,"range") == 0)
1047 {
1048 if (scale_y > 50)
1049 {
1050 ok = 0;
1051 }
1052 }
1053 else if (strcasecmp(type,"rapids") == 0)
1054 {
1055 if (scale_y > 50)
1056 {
1057 ok = 0;
1058 }
1059 }
1060 else if (strcasecmp(type,"reserve") == 0)
1061 {
1062 if (scale_y > 50)
1063 {
1064 ok = 0;
1065 }
1066 }
1067 else if (strcasecmp(type,"reservoir") == 0)
1068 {
1069 if (scale_y > 50)
1070 {
1071 ok = 0;
1072 }
1073 }
1074 else if (strcasecmp(type,"ridge") == 0)
1075 {
1076 if (scale_y > 50)
1077 {
1078 ok = 0;
1079 }
1080 }
1081 else if (strcasecmp(type,"school") == 0)
1082 {
1083 symbol_id = 'K';
1084 if (scale_y > 50)
1085 {
1086 ok = 0;
1087 }
1088 }
1089 else if (strcasecmp(type,"sea") == 0)
1090 {
1091 if (scale_y > 50)
1092 {
1093 ok = 0;
1094 }
1095 }
1096 else if (strcasecmp(type,"slope") == 0)
1097 {
1098 if (scale_y > 50)
1099 {
1100 ok = 0;
1101 }
1102 }
1103 else if (strcasecmp(type,"spring") == 0)
1104 {
1105 if (scale_y > 50)
1106 {
1107 ok = 0;
1108 }
1109 }
1110 else if (strcasecmp(type,"stream") == 0)
1111 {
1112 if (scale_y > 50)
1113 {
1114 ok = 0;
1115 }
1116 }
1117 else if (strcasecmp(type,"summit") == 0)
1118 {
1119 if (scale_y > 100)
1120 {
1121 ok = 0;
1122 }
1123 }
1124 else if (strcasecmp(type,"swamp") == 0)
1125 {
1126 if (scale_y > 50)
1127 {
1128 ok = 0;
1129 }
1130 }
1131 else if (strcasecmp(type,"trail") == 0)
1132 {
1133 if (scale_y > 50)
1134 {
1135 ok = 0;
1136 }
1137 }
1138 else if (strcasecmp(type,"tower") == 0)
1139 {
1140 symbol_id = 'r';
1141 if (scale_y > 50)
1142 {
1143 ok = 0;
1144 }
1145 }
1146 else if (strcasecmp(type,"tunnel") == 0)
1147 {
1148 if (scale_y > 50)
1149 {
1150 ok = 0;
1151 }
1152 }
1153 else if (strcasecmp(type,"valley") == 0)
1154 {
1155 if (scale_y > 50)
1156 {
1157 ok = 0;
1158 }
1159 }
1160 else if (strcasecmp(type,"well") == 0)
1161 {
1162 if (scale_y > 50)
1163 {
1164 ok = 0;
1165 }
1166 }
1167 else if (strcasecmp(type,"woods") == 0)
1168 {
1169 if (scale_y > 50)
1170 {
1171 ok = 0;
1172 }
1173 }
1174 else if (strcasecmp(type,"ruin") == 0)
1175 {
1176 if (scale_y > 50)
1177 {
1178 ok = 0;
1179 }
1180 }
1181 else
1182 {
1183 fprintf(stderr,"Something unusual found, Type:%s\tState:%s\tCounty:%s\tName:%s\n",
1184 type,state,county,name);
1185 }
1186
1187 if (ok == 1) // If ok to draw it
1188 {
1189 symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' ');
1190 draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)name, 0xf, 0x10, strlen(name));
1191 }
1192
1193 }
1194 else
1195 {
1196 //fprintf(stderr,"Not in viewport. Coordinates: %ld %ld\n",coord_lat,coord_lon);
1197 //fprintf(stderr,"Min/Max Lat: %ld %ld\n",min_lat,max_lat);
1198 //fprintf(stderr,"Min/Max Lon: %ld %ld\n",min_lon,max_lon);
1199 }
1200 }
1201 }
1202 } // End of while
1203 (void)fclose (f);
1204
1205
1206 // Check whether we're indexing the map
1207 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
1208 || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
1209 {
1210
1211 // We're indexing only. Save the extents in the index.
1212 index_update_xastir(filenm, // Filename only
1213 bottom_extent, // Bottom
1214 top_extent, // Top
1215 left_extent, // Left
1216 right_extent, // Right
1217 99999); // Default Map Level
1218 }
1219 }
1220 else
1221 {
1222 fprintf(stderr,"Couldn't open file: %s\n", file);
1223 return;
1224 }
1225 if (debug_level & 16)
1226 {
1227 fprintf(stderr,"Exiting draw_gnis_map\n");
1228 }
1229 }
1230
1231
1232
1233
1234
1235 // Search for a placename among GNIS files
1236 //
1237 // We need to search a file in the map directory that has the filename
1238 // STATE.gis, where STATE is from the "state" variable passed to us.
1239 // Search for the placename/county/state/type that the user requested.
1240 // Once found, center the map on that location or bring up a response
1241 // dialog that asks whether one wants to go there, and that dialog
1242 // provides info about the place found, with a possible selection
1243 // out of a list of matches.
1244 // Might also need to place a label at that position on the map in
1245 // case that GNIS file isn't currently selected.
1246 //
gnis_locate_place(Widget UNUSED (w),char * name_in,char * state_in,char * county_in,char * quad_in,char * type_in,char * filename_in,int follow_case,int get_match,char match_array_name[50][200],long match_array_lat[50],long match_array_long[50])1247 int gnis_locate_place( Widget UNUSED(w),
1248 char *name_in,
1249 char *state_in,
1250 char *county_in,
1251 char *quad_in,
1252 char *type_in,
1253 char *filename_in,
1254 int follow_case,
1255 int get_match,
1256 char match_array_name[50][200],
1257 long match_array_lat[50],
1258 long match_array_long[50] )
1259 {
1260
1261 char file[MAX_FILENAME]; // Complete path/name of GNIS file
1262 FILE *f; // Filehandle of GNIS file
1263 char line[MAX_FILENAME]; // One line of text from file
1264 char *i, *j;
1265 char state[50];
1266 char state_in2[50];
1267 char name[200];
1268 char name_in2[50];
1269 char type[100];
1270 char type_in2[50];
1271 char county[100];
1272 char county_in2[50];
1273 char quad[100];
1274 char quad_in2[100];
1275 char latitude[15];
1276 char longitude[15];
1277 char population[15];
1278 char lat_dd[3];
1279 char lat_mm[3];
1280 char lat_ss[3];
1281 char lat_dir[2];
1282 char long_dd[4];
1283 char long_mm[3];
1284 char long_ss[3];
1285 char long_dir[2];
1286 char lat_str[15];
1287 char long_str[15];
1288 int temp1;
1289 long coord_lon, coord_lat;
1290 int ok;
1291 struct stat file_status;
1292 int my_count = 0;
1293
1294
1295 xastir_snprintf(file,sizeof(file),"%s",filename_in);
1296
1297 if (debug_level & 16)
1298 {
1299 fprintf(stderr,"File: %s\n",file);
1300 }
1301
1302
1303 xastir_snprintf(name_in2,sizeof(name_in2),"%s",name_in);
1304 xastir_snprintf(state_in2,sizeof(state_in2),"%s",state_in);
1305 xastir_snprintf(county_in2,sizeof(county_in2),"%s",county_in);
1306 xastir_snprintf(quad_in2,sizeof(quad_in2),"%s",quad_in);
1307 xastir_snprintf(type_in2,sizeof(type_in2),"%s",type_in);
1308
1309
1310 // Convert State/Province to upper-case always (they're
1311 // always upper-case in the GNIS files from USGS.
1312 to_upper(state_in2);
1313
1314
1315 if (debug_level & 16)
1316 fprintf(stderr,"Name:%s\tState:%s\tCounty:%s\tQuad:%s\tType:%s\n",
1317 name_in,state_in2,county_in,quad_in,type_in);
1318
1319
1320 // If "Match Case" togglebutton is not set, convert the
1321 // rest of the keys to upper-case.
1322 if (!follow_case)
1323 {
1324 to_upper(name_in2);
1325 to_upper(county_in2);
1326 to_upper(quad_in2);
1327 to_upper(type_in2);
1328 }
1329
1330
1331 // Check status of the file
1332 if (stat(file, &file_status) < 0)
1333 {
1334 // "Can't open file"
1335 popup_message( langcode("POPEM00028"), filename_in );
1336 return(0);
1337 }
1338 // Check for regular file
1339 if (!S_ISREG(file_status.st_mode))
1340 {
1341 // "Can't open file"
1342 popup_message( langcode("POPEM00028"), filename_in );
1343 return(0);
1344 }
1345 // Attempt to open the file
1346 f = fopen (file, "r");
1347 if (f == NULL)
1348 {
1349 // "Can't open file"
1350 popup_message_always( langcode("POPEM00028"), filename_in );
1351 return(0);
1352 }
1353
1354 while (!feof (f)) // Loop through entire file
1355 {
1356 if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data
1357 {
1358 if (strlen(line) > 0)
1359 {
1360
1361
1362 //NOTE: How do we handle running off the end of "line" while using "index"?
1363 // Short lines here can cause segfaults.
1364
1365 // Find end of Feature ID Number field
1366 j = index(line,'|');
1367
1368 if (j == NULL) // Pipe not found
1369 {
1370 continue; // Skip this line
1371 }
1372
1373 //NOTE: It'd be nice to take the part after the comma and put it before the rest
1374 // of the text someday, i.e. "Cassidy, Lake".
1375
1376 // Find end of Feature Name field
1377 i = index(++j, '|');
1378
1379 if (i == NULL) // Pipe not found
1380 {
1381 continue; // Skip line
1382 }
1383
1384 i[0] = '\0';
1385 xastir_snprintf(name,sizeof(name),"%s",j);
1386 clean_string(name);
1387
1388 // Find end of Feature Type field
1389 j = index(++i, '|');
1390
1391 if (j == NULL) // Pipe not found
1392 {
1393 continue; // Skip line
1394 }
1395
1396 j[0] = '\0';
1397 xastir_snprintf(type,sizeof(type),"%s",i);
1398 clean_string(type);
1399
1400 // Find end of State field
1401 i = index(++j,'|');
1402
1403 if (i == NULL) // Pipe not found
1404 {
1405 continue; // Skip line
1406 }
1407
1408 i[0] = '\0';
1409 xastir_snprintf(state,sizeof(state),"%s",j);
1410 clean_string(state);
1411
1412 // Find end of State Number Code field
1413 j = index(++i, '|');
1414
1415 if (j == NULL) // Pipe not found
1416 {
1417 continue; // Skip line
1418 }
1419
1420 j[0] = '\0';
1421
1422 // Find end of County Name field
1423 i = index(++j, '|');
1424
1425 if (i == NULL) // Pipe not found
1426 {
1427 continue; // Skip line
1428 }
1429
1430 i[0] = '\0';
1431 xastir_snprintf(county,sizeof(county),"%s",j);
1432 clean_string(county);
1433
1434 // Find end of County Number Code field
1435 j = index(++i, '|');
1436
1437 if (j == NULL) // Pipe not found
1438 {
1439 continue; // Skip line
1440 }
1441
1442 j[0] = '\0';
1443
1444 // Find end of Primary Latitude field (DDMMSSN)
1445 i = index(++j, '|');
1446
1447 if (i == NULL) // Pipe not found
1448 {
1449 continue; // Skip line
1450 }
1451
1452 i[0] = '\0';
1453 xastir_snprintf(latitude,sizeof(latitude),"%s",j);
1454 clean_string(latitude);
1455
1456 // Find end of Primary Longitude field (DDDMMSSW)
1457 j = index(++i, '|');
1458
1459 if (j == NULL) // Pipe not found
1460 {
1461 continue; // Skip line
1462 }
1463
1464 j[0] = '\0';
1465 xastir_snprintf(longitude,sizeof(longitude),"%s",i);
1466 clean_string(longitude);
1467
1468 // Find end of Primary Latitude field (decimal
1469 // degrees)
1470 i = index(++j, '|');
1471
1472 if (i == NULL) // Pipe not found
1473 {
1474 continue; // Skip line
1475 }
1476
1477 i[0] = '\0';
1478
1479 // Find end of Primary Longitude field (decimal
1480 // degrees)
1481 j = index(++i, '|');
1482
1483 if (j == NULL) // Pipe not found
1484 {
1485 continue; // Skip line
1486 }
1487
1488 j[0] = '\0';
1489
1490 // Find end of Source Latitude field (DMS)
1491 i = index(++j, '|');
1492
1493 if (i == NULL) // Pipe not found
1494 {
1495 continue; // Skip line
1496 }
1497
1498 i[0] = '\0';
1499
1500 // Find end of Source Longitude (DMS)
1501 j = index(++i, '|');
1502
1503 if (j == NULL) // Pipe not found
1504 {
1505 continue; // Skip line
1506 }
1507
1508 j[0] = '\0';
1509
1510 // Find end of Source Latitude field (decimal
1511 // degrees)
1512 i = index(++j, '|');
1513
1514 if (i == NULL) // Pipe not found
1515 {
1516 continue; // Skip line
1517 }
1518
1519 i[0] = '\0';
1520
1521 // Find end of Source Longitude field (decimal
1522 // degrees)
1523 j = index(++i, '|');
1524
1525 if (j == NULL) // Pipe not found
1526 {
1527 continue; // Skip line
1528 }
1529
1530 j[0] = '\0';
1531
1532 // Find end of Estimated Population field
1533 i = index(++j, '|');
1534
1535 if (i == NULL) // Pipe not found
1536 {
1537 continue; // Skip line
1538 }
1539
1540 i[0] = '\0';
1541
1542 xastir_snprintf(population,sizeof(population),"%s",j);
1543 clean_string(population);
1544
1545 // Find end of Quad field
1546 j = index(++i, '|');
1547
1548 if (j == NULL) // Pipe not found
1549 {
1550 continue; // Skip line
1551 }
1552
1553 j[0] = '\0';
1554
1555 xastir_snprintf(quad,sizeof(quad),"%s",i);
1556 clean_string(quad);
1557
1558 // If "Match Case" togglebutton is not set, convert
1559 // the data to upper-case before we do our compare.
1560 if (!follow_case)
1561 {
1562 to_upper(name);
1563 to_upper(state);
1564 to_upper(county);
1565 to_upper(quad);
1566 to_upper(type);
1567 }
1568
1569 // Still need to code for the "Match Exact" togglebutton.
1570
1571
1572 // Now compare the input variables with those we've
1573 // parsed. If a match, bring up a list of items which
1574 // match.
1575 //
1576 ok = 1;
1577 if (get_match) // Looking for exact match
1578 {
1579 if (name_in2[0] != '\0')
1580 if (strcmp(name,name_in2) != 0)
1581 {
1582 ok = 0;
1583 }
1584 if (state_in2[0] != '\0')
1585 if (strcmp(state,state_in2) != 0)
1586 {
1587 ok = 0;
1588 }
1589 if (county_in2[0] != '\0')
1590 if (strcmp(county,county_in2) != 0)
1591 {
1592 ok = 0;
1593 }
1594 if (quad_in2[0] != '\0')
1595 if (strcmp(quad,quad_in2) != 0)
1596 {
1597 ok = 0;
1598 }
1599 if (type_in2[0] != '\0')
1600 if (strcmp(type,type_in2) != 0)
1601 {
1602 ok = 0;
1603 }
1604 }
1605 else // Look for substring in file, not exact match
1606 {
1607 if (name_in2[0] != '\0')
1608 if (strstr(name,name_in2) == NULL)
1609 {
1610 ok = 0;
1611 }
1612 if (state_in2[0] != '\0')
1613 if (strstr(state,state_in2) == NULL)
1614 {
1615 ok = 0;
1616 }
1617 if (county_in2[0] != '\0')
1618 if (strstr(county,county_in2) == NULL)
1619 {
1620 ok = 0;
1621 }
1622 if (quad_in2[0] != '\0')
1623 if (strstr(quad,quad_in2) == NULL)
1624 {
1625 ok = 0;
1626 }
1627 if (type_in2[0] != '\0')
1628 if (strstr(type,type_in2) == NULL)
1629 {
1630 ok = 0;
1631 }
1632 }
1633
1634
1635 if (ok)
1636 {
1637 if (debug_level & 16)
1638 {
1639 fprintf(stderr,"Match: %s,%s,%s,%s\n",name,state,county,type);
1640 }
1641
1642 // This one pops up the names of whatever we found.
1643 // "Found It!"
1644 //popup_message_always( langcode("POPEM00029"), name );
1645
1646 if (strlen(latitude) < 7)
1647 {
1648 continue; // We really don't have any latitude here.
1649 }
1650 lat_dd[0] = latitude[0];
1651 lat_dd[1] = latitude[1];
1652 lat_dd[2] = '\0';
1653
1654 lat_mm[0] = latitude[2];
1655 lat_mm[1] = latitude[3];
1656 lat_mm[2] = '\0';
1657
1658 lat_ss[0] = latitude[4];
1659 lat_ss[1] = latitude[5];
1660 lat_ss[2] = '\0';
1661
1662 lat_dir[0] = latitude[6];
1663 lat_dir[1] = '\0';
1664
1665 if (strlen(longitude) < 8)
1666 {
1667 continue; // We really don't have any longitude here.
1668 }
1669 long_dd[0] = longitude[0];
1670 long_dd[1] = longitude[1];
1671 long_dd[2] = longitude[2];
1672 long_dd[3] = '\0';
1673
1674 long_mm[0] = longitude[3];
1675 long_mm[1] = longitude[4];
1676 long_mm[2] = '\0';
1677
1678 long_ss[0] = longitude[5];
1679 long_ss[1] = longitude[6];
1680 long_ss[2] = '\0';
1681
1682 long_dir[0] = longitude[7];
1683 long_dir[1] = '\0';
1684
1685 // Now must convert from DD MM SS format to DD MM.MM format so that we
1686 // can run it through our conversion routine to Xastir coordinates.
1687 if (1 != sscanf(lat_ss, "%d", &temp1))
1688 {
1689 fprintf(stderr,"locate_place:sscanf parsing error\n");
1690 }
1691
1692 temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding
1693 xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd,
1694 lat_mm, temp1, lat_dir);
1695 coord_lat = convert_lat_s2l(lat_str);
1696
1697 if (1 != sscanf(long_ss, "%d", &temp1))
1698 {
1699 fprintf(stderr,"locate_place:sscanf parsing error\n");
1700 }
1701
1702 temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding
1703 xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd,
1704 long_mm, temp1, long_dir);
1705 coord_lon = convert_lon_s2l(long_str);
1706
1707
1708 //set_map_position(w, coord_lat, coord_lon);
1709
1710 // Fill in the array values with what we just
1711 // found, increment the counter.
1712 xastir_snprintf(match_array_name[my_count],200,"%s",name);
1713 match_array_lat[my_count] = coord_lat;
1714 match_array_long[my_count] = coord_lon;
1715 my_count++;
1716
1717 // Check for a max array. Return if it is full.
1718 if (my_count > 50)
1719 {
1720 return(50);
1721 }
1722 }
1723 }
1724 }
1725 }
1726
1727 return(my_count);
1728 }
1729
1730
1731