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 //#define MAP_SCALE_CHECK
25 
26 
27 #ifdef HAVE_CONFIG_H
28   #include "config.h"
29 #endif  // HAVE_CONFIG_H
30 
31 #include "snprintf.h"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <ctype.h>
38 #include <sys/types.h>
39 #include <pwd.h>
40 #include <errno.h>
41 
42 // Needed for Solaris
43 #ifdef HAVE_STRINGS_H
44   #include <strings.h>
45 #endif  // HAVE_STRINGS_H
46 
47 #ifdef HAVE_MAGICK
48   #if TIME_WITH_SYS_TIME
49     #include <sys/time.h>
50     #include <time.h>
51   #else   // TIME_WITH_SYS_TIME
52     #if HAVE_SYS_TIME_H
53       #include <sys/time.h>
54     #else  // HAVE_SYS_TIME_H
55       #include <time.h>
56     #endif // HAVE_SYS_TIME_H
57   #endif  // TIME_WITH_SYS_TIME
58   #undef RETSIGTYPE
59   // TVR: "stupid ImageMagick"
60   // The problem is that magick/api.h includes Magick's config.h file, and that
61   // pulls in all the same autoconf-generated defines that we use.
62   // plays those games below, but I don't think in the end that they actually
63   // make usable macros with our own data in them.
64   // Fortunately, we don't need them, so I'll just undef the ones that are
65   // causing problems today.  See main.c for fixes that preserve our values.
66   #undef PACKAGE
67   #undef VERSION
68   /* JMT - stupid ImageMagick */
69   #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT
70   #undef PACKAGE_BUGREPORT
71   #define XASTIR_PACKAGE_NAME PACKAGE_NAME
72   #undef PACKAGE_NAME
73   #define XASTIR_PACKAGE_STRING PACKAGE_STRING
74   #undef PACKAGE_STRING
75   #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME
76   #undef PACKAGE_TARNAME
77   #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION
78   #undef PACKAGE_VERSION
79   #ifdef HAVE_MAGICK
80     #ifdef HAVE_MAGICKCORE_MAGICKCORE_H
81       #include <MagickCore/MagickCore.h>
82     #else
83       #ifdef HAVE_MAGICK_API_H
84         #include <magick/api.h>
85       #endif // HAVE_MAGICK_API_H
86     #endif //HAVE_MAGICKCORE_MAGICKCORE_H
87   #endif //HAVE_MAGICK
88   #undef PACKAGE_BUGREPORT
89   #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT
90   #undef XASTIR_PACKAGE_BUGREPORT
91   #undef PACKAGE_NAME
92   #define PACKAGE_NAME XASTIR_PACKAGE_NAME
93   #undef XASTIR_PACKAGE_NAME
94   #undef PACKAGE_STRING
95   #define PACKAGE_STRING XASTIR_PACKAGE_STRING
96   #undef XASTIR_PACKAGE_STRING
97   #undef PACKAGE_TARNAME
98   #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME
99   #undef XASTIR_PACKAGE_TARNAME
100   #undef PACKAGE_VERSION
101   #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION
102   #undef XASTIR_PACKAGE_VERSION
103 #endif // HAVE_MAGICK
104 
105 #include <dirent.h>
106 #include <netinet/in.h>
107 #include <Xm/XmAll.h>
108 
109 #ifdef HAVE_X11_XPM_H
110   #include <X11/xpm.h>
111   #ifdef HAVE_LIBXPM // if we have both, prefer the extra library
112     #undef HAVE_XM_XPMI_H
113   #endif // HAVE_LIBXPM
114 #endif // HAVE_X11_XPM_H
115 
116 #ifdef HAVE_XM_XPMI_H
117   #include <Xm/XpmI.h>
118 #endif // HAVE_XM_XPMI_H
119 
120 #include <X11/Xlib.h>
121 
122 #include <math.h>
123 
124 #include "xastir.h"
125 #include "maps.h"
126 #include "alert.h"
127 #include "util.h"
128 #include "main.h"
129 #include "datum.h"
130 #include "draw_symbols.h"
131 #include "rotated.h"
132 #include "color.h"
133 #include "xa_config.h"
134 
135 // Must be last include file
136 #include "leak_detection.h"
137 
138 extern XmFontList fontlist1;    // Menu/System fontlist
139 
140 #define GRID_MORE 5000
141 
142 #define CHECKMALLOC(m)  if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); }
143 
144 
145 // Check for XPM and/or ImageMagick.  We use "NO_GRAPHICS"
146 // to disable some routines below if the support for them
147 // is not compiled in.
148 #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK))
149   #define NO_GRAPHICS 1
150 #endif  // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK)
151 
152 #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM))
153   #define NO_XPM 1
154 #endif  // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM)
155 
156 
157 void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color);
158 int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize);
159 
160 // Constants defining the color of the labeled grid border.
161 int outline_border_labels = TRUE;   // if true put an outline around the border labels
162 int border_foreground_color = 0x20; // color of the map border, if shown
163 // 0x08 is black.
164 // 0x20 is white.
165 int outline_border_labels_color = 0x20;
166 // outline_border_labels_color = border_foreground_color;
167 // color of outline to draw around border labels
168 // use color of border to help make text more legible.
169 
170 // Print options
171 Widget print_properties_dialog = (Widget)NULL;
172 static xastir_mutex print_properties_dialog_lock;
173 Widget print_postscript_dialog = (Widget)NULL;
174 static xastir_mutex print_postscript_dialog_lock;
175 Widget printer_data;
176 Widget previewer_data;
177 
178 Widget rotate_90 = (Widget)NULL;
179 Widget auto_rotate = (Widget)NULL;
180 //char  print_paper_size[20] = "Letter";  // Displayed in dialog, but not used yet.
181 int   print_rotated = 0;
182 int   print_auto_rotation = 0;
183 //float print_scale = 1.0;                // Not used yet.
184 int   print_auto_scale = 0;
185 //int   print_blank_background_color = 0; // Not used yet.
186 int   print_in_monochrome = 0;
187 int   print_resolution = 150;           // 72 dpi is normal for Postscript.
188 // 100 or 150 dpi work well with HP printer
189 int   print_invert = 0;                 // Reverses black/white
190 
191 char printer_program[MAX_FILENAME+1];
192 char previewer_program[MAX_FILENAME+1];
193 
194 time_t last_snapshot = 0;               // Used to determine when to take next snapshot
195 time_t last_kmlsnapshot = 0;               // Used to determine when to take next kml snapshot
196 int doing_snapshot = 0;
197 int snapshot_interval = 0;
198 
199 
200 int mag;
201 int npoints;    /* number of points in a line */
202 
203 
204 float raster_map_intensity = 0.65;    // Raster map color intensity, set from Maps->Map Intensity
205 float imagemagick_gamma_adjust = 0.0;  // Additional imagemagick map gamma correction, set from Maps->Adjust Gamma
206 
207 // Storage for the index file timestamp
208 time_t map_index_timestamp;
209 
210 int grid_size = 0;
211 
212 // Rounding
213 #ifndef HAVE_ROUNDF
214 // Poor man's rounding, but rounds away from zero as roundf is supposed to.
215 
roundf(float x)216 float roundf(float x)
217 {
218   int i;
219   i= (((x)>=0)?(((x)+.5)):(((x)-.5)));
220   return ((float)i);
221 }
222 
223 #endif
224 
225 
226 // UTM Grid stuff
227 //
228 //#define UTM_DEBUG
229 //#define UTM_DEBUG_VERB
230 //#define UTM_DEBUG_ALLOC
231 //
max_i(int a,int b)232 static inline int  max_i(int  a, int  b)
233 {
234   return (a > b ? a : b);
235 }
236 #define UTM_GRID_EQUATOR 10000000
237 // the maximum number of UTM zones that will appear on a screen that has a
238 // high enough resolution to display the within-zone utm grid
239 #define UTM_GRID_MAX_ZONES      4
240 // the maximum number of grid lines in each direction shown in each zone
241 // on the screen at one time
242 #define UTM_GRID_MAX_COLS_ROWS 64
243 #define UTM_GRID_DEF_NALLOCED   8
244 #define UTM_GRID_RC_EMPTY  0xffff
245 
246 // the hash stores the upper left and lower right boundaries of the
247 // display of a utm grid to determine whether it matches the current
248 // screen boundaries or whether the grid needs to be recalculated
249 // for the current screen.
250 typedef struct
251 {
252   long ul_x;
253   long ul_y;
254   long lr_x;
255   long lr_y;
256 } hash_t;
257 
258 // The utm grid is drawn by connecting a grid of points marking the
259 // intersection of the easting and northing lines.  col_or_row holds
260 // this grid of points for the portion of a utm zone visible on the
261 // screen.  Zone boundaries are not directly represented here.
262 // In particular, the parallels separating lettered zone rows are
263 // not directly represented here.
264 typedef struct
265 {
266   int firstpoint;
267   int npoints;
268   int nalloced;
269   XPoint *points;
270 } col_or_row_t;
271 
272 // The portion of a utm zone visible on the screen has some number of
273 // visible easting lines and northing lines forming a grid that covers
274 // part or all of the screen.  Zone holds arrays of the coordinates
275 // of the visible easting and northing intersections, and the next set
276 // of intersections off screen.  The coarseness of this grid is
277 // determined by the current scale and stored in utm_grid_spacing_m.
278 typedef struct
279 {
280   unsigned int ncols;
281   col_or_row_t col[UTM_GRID_MAX_COLS_ROWS];
282   unsigned int nrows;
283   col_or_row_t row[UTM_GRID_MAX_COLS_ROWS];
284   int          boundary_x;
285 } zone_t;
286 
287 // A utm grid is represented by its hash (upper left and lower right coordinates)
288 // which are used to check whether or not it fits the current screen or needs to
289 // be recalculated, and an array of the zones visible on the screen, each containing
290 // arrays of the points marking the easting/northing intersections of a zone (with
291 // one or more lettered zone rows).
292 typedef struct
293 {
294   hash_t       hash;
295   unsigned int nzones;
296   zone_t       zone[UTM_GRID_MAX_ZONES];
297 } utm_grid_t;
298 
299 utm_grid_t utm_grid;
300 
301 unsigned int utm_grid_spacing_m;
302 // ^ the above is extern'ed in maps.h for use by draw_ruler_text in
303 // db.c
304 
305 
306 
307 
308 
309 // Clear out/set up the UTM/MGRS minor grid intersection arrays.
310 //
311 // do_alloc = 0:  Don't allocate memory
312 //            1:  Allocate memory for the points
313 //
314 // Returns: 0 if ok
315 //          1 if malloc problem
316 //
utm_grid_clear(int do_alloc)317 int utm_grid_clear(int do_alloc)
318 {
319   int i, j;
320 
321   utm_grid.hash.ul_x = 0;
322   utm_grid.hash.ul_y = 0;
323   utm_grid.hash.lr_x = 0;
324   utm_grid.hash.lr_y = 0;
325   utm_grid.nzones    = 0;
326 
327   for (i=0; i < UTM_GRID_MAX_ZONES; i++)
328   {
329 
330     utm_grid.zone[i].ncols = utm_grid.zone[i].nrows = 0;
331     utm_grid.zone[i].boundary_x = 0;
332 
333     for (j=0; j < UTM_GRID_MAX_COLS_ROWS; j++)
334     {
335 
336       //
337       // Clear out column arrays
338       //
339       utm_grid.zone[i].col[j].firstpoint = UTM_GRID_RC_EMPTY;
340       utm_grid.zone[i].col[j].npoints    = 0;
341 
342       if (utm_grid.zone[i].col[j].nalloced)
343       {
344         free(utm_grid.zone[i].col[j].points);
345       }
346 
347       utm_grid.zone[i].col[j].nalloced   = 0;
348       utm_grid.zone[i].col[j].points = NULL;
349 
350       if (do_alloc)
351       {
352 
353         // Allocate enough space for 8 points
354         utm_grid.zone[i].col[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint));
355         if (!utm_grid.zone[i].col[j].points)
356         {
357           fprintf(stderr,"calloc(%d, %d) for z=%d col=%d FAILED!\n",
358                   UTM_GRID_DEF_NALLOCED,
359                   (int)sizeof(XPoint),
360                   i,
361                   j);
362 //                    abort();  // Causes a segfault
363           return(1);
364         }
365         utm_grid.zone[i].col[j].nalloced = UTM_GRID_DEF_NALLOCED;
366       }
367 
368       //
369       // Clear out row arrays
370       //
371       utm_grid.zone[i].row[j].firstpoint = UTM_GRID_RC_EMPTY;
372       utm_grid.zone[i].row[j].npoints    = 0;
373       utm_grid.zone[i].row[j].nalloced   = 0;
374 
375       if (utm_grid.zone[i].row[j].nalloced)
376       {
377         free(utm_grid.zone[i].row[j].points);
378       }
379 
380       utm_grid.zone[i].row[j].nalloced   = 0;
381       utm_grid.zone[i].row[j].points = NULL;
382 
383       if (do_alloc)
384       {
385 
386         // Allocate enough space for 8 points
387         utm_grid.zone[i].row[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint));
388         if (!utm_grid.zone[i].row[j].points)
389         {
390           fprintf(stderr,"calloc(%d, %d) for z=%d row=%d FAILED!\n",
391                   UTM_GRID_DEF_NALLOCED,
392                   (int)sizeof(XPoint),
393                   i,
394                   j);
395 //                    abort();  // Causes a segfault
396           return(1);
397         }
398         utm_grid.zone[i].row[j].nalloced = UTM_GRID_DEF_NALLOCED;
399       }
400     }
401   }
402   return(0);
403 }
404 
405 
406 
407 
408 
maps_init(void)409 void maps_init(void)
410 {
411   fprintf(stderr,"\n\nBuilt-in map types:\n");
412   fprintf(stderr,"%10s   USGS GNIS Datapoints\n","gnis");
413   fprintf(stderr,"%10s   USGS GNIS Datapoints w/population\n","pop");
414   fprintf(stderr,"%10s   APRSdos Maps\n","map");
415   fprintf(stderr,"%10s   WinAPRS/MacAPRS/X-APRS Maps\n","map");
416 
417   fprintf(stderr,"\nSupport for these additional map types has been compiled in: \n");
418 
419 #ifdef HAVE_MAGICK
420   fprintf(stderr,"%10s   Image Map (ImageMagick/GraphicsMagick library, many formats allowed)\n","geo");
421 #endif  // HAVE_MAGICK
422 
423 #ifndef NO_GRAPHICS
424 #ifdef HAVE_LIBCURL
425   fprintf(stderr,"%10s   URL (Internet maps via libcurl library)\n","geo");
426   fprintf(stderr,"%10s   URL (OpenStreetMaps via libcurl library\n","geo");
427   fprintf(stderr,"%10s        Copyright OpenStreetMap and contributors, CC-BY-SA)\n", "");
428 
429 #else
430 #ifdef HAVE_WGET
431   fprintf(stderr,"%10s   URL (Internet maps via wget)\n","geo");
432   fprintf(stderr,"%10s   URL (OpenStreetMaps via wget\n","geo");
433   fprintf(stderr,"%10s        Copyright OpenStreetMap and contributors, CC-BY-SA)\n", "");
434 #endif  // HAVE_WGET
435 #endif  // HAVE_LIBCURL
436 #endif  // NO_GRAPHICS
437 
438 
439 #ifdef HAVE_LIBSHP
440   fprintf(stderr,"%10s   ESRI Shapefile Maps (Shapelib library)\n","shp");
441 #endif  // HAVE_LIBSHP
442 
443 
444 #ifdef HAVE_LIBGEOTIFF
445   fprintf(stderr,"%10s   USGS DRG Geotiff Topographic Maps (libgeotiff/libproj)\n","tif");
446 #endif  // HAVE_LIBGEOTIFF
447 
448 #ifndef NO_XPM
449   fprintf(stderr,"%10s   X Pixmap Maps (XPM library)\n","xpm");
450 #endif  // NO_XPM
451 
452   init_critical_section( &print_properties_dialog_lock );
453   init_critical_section( &print_postscript_dialog_lock );
454 
455   // Clear the minor UTM/MGRS grid arrays.  Do _not_ allocate
456   // memory for the points.
457   (void)utm_grid_clear(0);
458 }
459 
460 
461 
462 
463 
464 /*
465  *  Calculate NS distance scale at a given location
466  *  in meters per Xastir unit
467  */
calc_dscale_y(long UNUSED (x),long UNUSED (y))468 double calc_dscale_y(long UNUSED(x), long UNUSED(y) )
469 {
470 
471   // approximation by looking at +/- 0.5 minutes offset
472   //    (void)(calc_distance(y-3000, x, y+3000, x)/6000.0);
473   // but this scale is fixed at 1852/6000
474   return((double)(1852.0/6000.0));
475 }
476 
477 
478 
479 
480 
481 /*
482  *  Calculate EW distance scale at a given location
483  *  in meters per Xastir unit
484  */
calc_dscale_x(long x,long y)485 double calc_dscale_x(long x, long y)
486 {
487 
488   // approximation by looking at +/- 0.5 minutes offset
489   // we should find a better formula...
490   return(calc_distance(y, x-3000, y, x+3000)/6000.0);
491 }
492 
493 
494 
495 
496 
497 /*
498  *  Calculate x map scaling for current location
499  *  With that we could have equal distance scaling or a better
500  *  view for pixel maps
501  */
get_x_scale(long x,long y,long ysc)502 long get_x_scale(long x, long y, long ysc)
503 {
504   long   xsc;
505   double sc_x;
506   double sc_y;
507 
508   sc_x = calc_dscale_x(x,y);          // meter per Xastir unit
509   sc_y = calc_dscale_y(x,y);
510   if (sc_x < 0.01 || ysc > 50000)
511     // keep it near the poles (>88 deg) or if big parts of world seen
512   {
513     xsc = ysc;
514   }
515   else
516     // adjust y scale, so that the distance is identical in both directions:
517   {
518     xsc = (long)(ysc * sc_y / sc_x +0.4999);
519   }
520 
521   //fprintf(stderr,"Scale: x %5.3fkm/deg, y %5.3fkm/deg, x %ld y %ld\n",sc_x*360,sc_y*360,xsc,ysc);
522   return(xsc);
523 }
524 
525 
526 
527 
528 
529 /** MAP DRAWING ROUTINES **/
530 
531 
532 
533 // Function to perform 2D line-clipping Using the improved parametric
534 // line-clipping algorithm by Liang, Barsky, and Slater published in
535 // the paper: "Some Improvements to a Parametric Line Clipping
536 // Algorithm", 1992.  Called by clip2d() function below.  This
537 // function is set up for float values.  See the clipt_long() and
538 // clipt_int() functions for use with other types of values.
539 //
540 // Returns False if the line is rejected, True otherwise.  May modify
541 // t0 and t1.
542 //
clipt(float p,float q,float * t0,float * t1)543 int clipt(float p, float q, float *t0, float *t1)
544 {
545   float r;
546   int accept = True;
547 
548 
549   if (p < 0)    // Entering visible region, so compute t0
550   {
551 
552     if (q < 0)    // t0 will be non-negative, so continue
553     {
554 
555       r = q / p;
556 
557       if (r > *t1)    // t0 will exceed t1, so reject
558       {
559         accept = False;
560       }
561       else if (r > *t0)    // t0 is max of r's
562       {
563         *t0 = r;
564       }
565     }
566   }
567   else
568   {
569 
570     if (p > 0)    // Exiting visible region, so compute t1
571     {
572 
573       if (q < p)    // t1 will be <= 1, so continue
574       {
575 
576         r = q / p;
577 
578         if (r < *t0)    // t1 will be <= t0, so reject
579         {
580           accept = False;
581         }
582         else if (r < *t1)    // t1 is min of r's
583         {
584           *t1 = r;
585         }
586       }
587     }
588     else    // p == 0
589     {
590 
591       if (q < 0)    // Line parallel and outside, so reject
592       {
593         accept = False;
594       }
595     }
596   }
597   return(accept);
598 }
599 
600 
601 
602 
603 
604 // Function to perform 2D line-clipping using the improved parametric
605 // line-clipping algorithm by Liang, Barsky, and Slater published in
606 // the paper: "Some Improvements to a Parametric Line Clipping
607 // Algorithm", 1992.  Uses the clipt() function above.
608 //
609 // Returns False if the line is rejected, True otherwise.  x0, y0,
610 // x1, y1 may get modified by this function.  These will be the new
611 // clipped line ends that fit inside the window.
612 //
613 // Clip 2D line segment with endpoints (x0,y0) and (x1,y1).  The clip
614 // window is x_left <= x <= x_right and y_bottom <= y <= y_top.
615 //
616 // This function is set up for float values.  See the clip2d_long()
617 // and clip2d_screen() functions for use with other types of values.
618 //
clip2d(float * x0,float * y0,float * x1,float * y1)619 int clip2d(float *x0, float *y0, float *x1, float *y1)
620 {
621   float t0, t1;
622   float delta_x, delta_y;
623   int visible = False;
624   float x_left, y_top;        // NW corner of screen
625   float x_right, y_bottom;    // SE corner of screen
626 
627 
628   // Assign floating point values for screen corners
629   y_top = f_NW_corner_latitude;
630   y_bottom = f_SE_corner_latitude;
631   x_left = f_NW_corner_longitude;
632   x_right =  f_SE_corner_longitude;
633 
634   if (       ((*x0 < x_left)   && (*x1 < x_left))
635              || ((*x0 > x_right)  && (*x1 > x_right))
636              || ((*y0 < y_bottom) && (*y1 < y_bottom))
637              || ((*y0 > y_top)    && (*y1 > y_top)) )
638   {
639 
640     // Both endpoints are on outside and same side of visible
641     // region, so reject.
642     return(visible);
643   }
644 
645   t0 = 0;
646   t1 = 1;
647   delta_x = *x1 - *x0;
648 
649   if ( clipt(-delta_x, *x0 - x_left, &t0, &t1) )             // left
650   {
651 
652     if ( clipt(delta_x, x_right - *x0, &t0, &t1) )         // right
653     {
654 
655       delta_y = *y1 - *y0;
656 
657       if ( clipt(-delta_y, *y0 - y_bottom, &t0, &t1) )   // bottom
658       {
659 
660         if ( clipt(delta_y, y_top - *y0, &t0, &t1) )   // top
661         {
662           // Compute coordinates
663 
664           if (t1 < 1)     // Compute V1' (new x1,y1)
665           {
666             *x1 = *x0 + t1 * delta_x;
667             *y1 = *y0 + t1 * delta_y;
668           }
669 
670           if (t0 > 0)     // Compute V0' (new x0,y0)
671           {
672             *x0 = *x0 + t0 * delta_x;
673             *y0 = *y0 + t0 * delta_y;
674           }
675           visible = True;
676         }
677       }
678     }
679   }
680   return(visible);
681 }
682 
683 
684 
685 
686 
687 // Function to perform 2D line-clipping Using the improved parametric
688 // line-clipping algorithm by Liang, Barsky, and Slater published in
689 // the paper: "Some Improvements to a Parametric Line Clipping
690 // Algorithm", 1992.  Called by clip2d_long() function below.  This
691 // function is set up for Xastir coordinate values (unsigned longs).
692 // See the clipt() and clipt_int() functions for use with other
693 // types of values.
694 //
695 // Returns False if the line is rejected, True otherwise.  May modify
696 // t0 and t1.
697 //
clipt_long(long p,long q,float * t0,float * t1)698 int clipt_long(long p, long q, float *t0, float *t1)
699 {
700   float r;
701   int accept = True;
702 
703 
704   if (p < 0)    // Entering visible region, so compute t0
705   {
706 
707     if (q < 0)    // t0 will be non-negative, so continue
708     {
709 
710       r = q / (p * 1.0);
711 
712       if (r > *t1)    // t0 will exceed t1, so reject
713       {
714         accept = False;
715       }
716       else if (r > *t0)    // t0 is max of r's
717       {
718         *t0 = r;
719       }
720     }
721   }
722   else
723   {
724 
725     if (p > 0)    // Exiting visible region, so compute t1
726     {
727 
728       if (q < p)    // t1 will be <= 1, so continue
729       {
730 
731         r = q / (p * 1.0);
732 
733         if (r < *t0)    // t1 will be <= t0, so reject
734         {
735           accept = False;
736         }
737         else if (r < *t1)    // t1 is min of r's
738         {
739           *t1 = r;
740         }
741       }
742     }
743     else    // p == 0
744     {
745 
746       if (q < 0)    // Line parallel and outside, so reject
747       {
748         accept = False;
749       }
750     }
751   }
752   //fprintf(stderr,"clipt_long: %d\n",accept);
753   return(accept);
754 }
755 
756 
757 
758 
759 
760 // Function to perform 2D line-clipping using the improved parametric
761 // line-clipping algorithm by Liang, Barsky, and Slater published in
762 // the paper: "Some Improvements to a Parametric Line Clipping
763 // Algorithm", 1992.  Uses the clipt_long() function above.
764 //
765 // Returns False if the line is rejected, True otherwise.  x0, y0,
766 // x1, y1 may get modified by this function.  These will be the new
767 // clipped line ends that fit inside the window.
768 //
769 // Clip 2D line segment with endpoints (x0,y0) and (x1,y1).  The clip
770 // window is x_left <= x <= x_right and y_bottom <= y <= y_top.
771 //
772 // This function uses the Xastir coordinate system.  We had to flip
773 // y_bottom/y_top below due to the coordinate system being
774 // upside-down.
775 //
776 // This function is set up for Xastir coordinate values (unsigned
777 // longs).  See the clip2d() or clip2d_screen() functions for use
778 // with other types of values.
779 //
clip2d_long(unsigned long * x0,unsigned long * y0,unsigned long * x1,unsigned long * y1)780 int clip2d_long(unsigned long *x0, unsigned long *y0, unsigned long *x1, unsigned long *y1)
781 {
782   float t0, t1;
783   long delta_x, delta_y;
784   int visible = False;
785   unsigned long x_left   = NW_corner_longitude;
786   unsigned long x_right = SE_corner_longitude;
787   // Reverse the following two as our Xastir coordinate system is
788   // upside down.  The algorithm requires this order.
789   unsigned long y_top = SE_corner_latitude;
790   unsigned long y_bottom = NW_corner_latitude;
791 
792 
793   if (       ( (*x0 < x_left  ) && (*x1 < x_left  ) )
794              || ( (*x0 > x_right ) && (*x1 > x_right ) )
795              || ( (*y0 < y_bottom) && (*y1 < y_bottom) )
796              || ( (*y0 > y_top   ) && (*y1 > y_top   ) ) )
797   {
798 
799     // Both endpoints are on same side of visible region and
800     // outside of it, so reject.
801     //fprintf(stderr,"reject 1\n");
802     return(visible);
803   }
804 
805   t0 = 0;
806   t1 = 1;
807   delta_x = *x1 - *x0;
808 
809   if ( clipt_long(-delta_x, *x0 - x_left, &t0, &t1) )             // left
810   {
811 
812     if ( clipt_long(delta_x, x_right - *x0, &t0, &t1) )         // right
813     {
814 
815       delta_y = *y1 - *y0;
816 
817       if ( clipt_long(-delta_y, *y0 - y_bottom, &t0, &t1) )   // bottom
818       {
819 
820         if ( clipt_long(delta_y, y_top - *y0, &t0, &t1) )   // top
821         {
822           // Compute coordinates
823 
824           if (t1 < 1)     // Compute V1' (new x1,y1)
825           {
826             *x1 = *x0 + t1 * delta_x;
827             *y1 = *y0 + t1 * delta_y;
828           }
829 
830           if (t0 > 0)     // Compute V0' (new x0,y0)
831           {
832             *x0 = *x0 + t0 * delta_x;
833             *y0 = *y0 + t0 * delta_y;
834           }
835           visible = True;
836         }
837         else
838         {
839           //fprintf(stderr,"reject top\n");
840         }
841       }
842       else
843       {
844         //fprintf(stderr,"reject bottom\n");
845       }
846     }
847     else
848     {
849       //fprintf(stderr,"reject right\n");
850     }
851   }
852   else
853   {
854     //fprintf(stderr,"reject left\n");
855   }
856   return(visible);
857 }
858 
859 
860 
861 
862 
863 // Function to perform 2D line-clipping Using the improved parametric
864 // line-clipping algorithm by Liang, Barsky, and Slater published in
865 // the paper: "Some Improvements to a Parametric Line Clipping
866 // Algorithm", 1992.  Called by clip2d_screen() function below.  This
867 // function is set up for screen coordinate values (unsigned ints).
868 // See the clipt() and clipt_long functions for use with other types
869 // of values.
870 //
871 // Returns False if the line is rejected, True otherwise.  May modify
872 // t0 and t1.
873 //
clipt_int(int p,int q,float * t0,float * t1)874 int clipt_int(int p, int q, float *t0, float *t1)
875 {
876   float r;
877   int accept = True;
878 
879 
880   if (p < 0)    // Entering visible region, so compute t0
881   {
882 
883     if (q < 0)    // t0 will be non-negative, so continue
884     {
885 
886       r = q / (p * 1.0);
887 
888       if (r > *t1)    // t0 will exceed t1, so reject
889       {
890         accept = False;
891       }
892       else if (r > *t0)    // t0 is max of r's
893       {
894         *t0 = r;
895       }
896     }
897   }
898   else
899   {
900 
901     if (p > 0)    // Exiting visible region, so compute t1
902     {
903 
904       if (q < p)    // t1 will be <= 1, so continue
905       {
906 
907         r = q / (p * 1.0);
908 
909         if (r < *t0)    // t1 will be <= t0, so reject
910         {
911           accept = False;
912         }
913         else if (r < *t1)    // t1 is min of r's
914         {
915           *t1 = r;
916         }
917       }
918     }
919     else    // p == 0
920     {
921 
922       if (q < 0)    // Line parallel and outside, so reject
923       {
924         accept = False;
925       }
926     }
927   }
928   //fprintf(stderr,"clipt_int: %d\n",accept);
929   return(accept);
930 }
931 
932 
933 
934 
935 
936 // Function to perform 2D line-clipping using the improved parametric
937 // line-clipping algorithm by Liang, Barsky, and Slater published in
938 // the paper: "Some Improvements to a Parametric Line Clipping
939 // Algorithm", 1992.  Uses the clipt_int() function above.
940 //
941 // Returns False if the line is rejected, True otherwise.  x0, y0,
942 // x1, y1 may get modified by this function.  These will be the new
943 // clipped line ends that fit inside the window.
944 //
945 // Clip 2D line segment with endpoints (x0,y0) and (x1,y1).  The clip
946 // window is x_left <= x <= x_right and y_bottom <= y <= y_top.
947 //
948 // This function uses the screen coordinate system.  We had to flip
949 // y_bottom/y_top below due to the coordinate system being
950 // upside-down.
951 //
952 // This function is set up for screen coordinate values (unsigned
953 // ints).  See the clip2d() and clip2d_long() functions for use
954 // with other types of values.
955 //
clip2d_screen(unsigned int * x0,unsigned int * y0,unsigned int * x1,unsigned int * y1)956 int clip2d_screen(unsigned int *x0, unsigned int *y0, unsigned int *x1, unsigned int *y1)
957 {
958   float t0, t1;
959   int delta_x, delta_y;
960   int visible = False;
961   unsigned int x_right  = screen_width;
962   unsigned int x_left   = 0;
963   // Reverse the following two as our screen coordinate system is
964   // upside down.  The algorithm requires this order.
965   unsigned int y_top    = screen_height;
966   unsigned int y_bottom = 0;
967 
968 
969   if (       ( (*x0 < x_left  ) && (*x1 < x_left  ) )
970              || ( (*x0 > x_right ) && (*x1 > x_right ) )
971              || ( (*y0 < y_bottom) && (*y1 < y_bottom) )
972              || ( (*y0 > y_top   ) && (*y1 > y_top   ) ) )
973   {
974 
975     // Both endpoints are on same side of visible region and
976     // outside of it, so reject.
977     //fprintf(stderr,"reject 1\n");
978     return(visible);
979   }
980 
981   t0 = 0;
982   t1 = 1;
983   delta_x = *x1 - *x0;
984 
985   if ( clipt_int(-delta_x, *x0 - x_left, &t0, &t1) )             // left
986   {
987 
988     if ( clipt_int(delta_x, x_right - *x0, &t0, &t1) )         // right
989     {
990 
991       delta_y = *y1 - *y0;
992 
993       if ( clipt_int(-delta_y, *y0 - y_bottom, &t0, &t1) )   // bottom
994       {
995 
996         if ( clipt_int(delta_y, y_top - *y0, &t0, &t1) )   // top
997         {
998           // Compute coordinates
999 
1000           if (t1 < 1)     // Compute V1' (new x1,y1)
1001           {
1002             *x1 = *x0 + t1 * delta_x;
1003             *y1 = *y0 + t1 * delta_y;
1004           }
1005 
1006           if (t0 > 0)     // Compute V0' (new x0,y0)
1007           {
1008             *x0 = *x0 + t0 * delta_x;
1009             *y0 = *y0 + t0 * delta_y;
1010           }
1011           visible = True;
1012         }
1013         else
1014         {
1015           //fprintf(stderr,"reject top\n");
1016         }
1017       }
1018       else
1019       {
1020         //fprintf(stderr,"reject bottom\n");
1021       }
1022     }
1023     else
1024     {
1025       //fprintf(stderr,"reject right\n");
1026     }
1027   }
1028   else
1029   {
1030     //fprintf(stderr,"reject left\n");
1031   }
1032   return(visible);
1033 }
1034 
1035 
1036 
1037 
1038 
1039 // Draws a point onto a pixmap.  Assumes that the proper GC has
1040 // already been set up for drawing the correct color/width/linetype,
1041 // etc.  If the bounding box containing the point doesn't intersect
1042 // with the current view, the point isn't drawn.
1043 //
1044 // Input point is in the Xastir coordinate system.
1045 //
draw_point(Widget w,unsigned long x1,unsigned long y1,GC gc,Pixmap which_pixmap,int skip_duplicates)1046 void draw_point(Widget w,
1047                 unsigned long x1,
1048                 unsigned long y1,
1049                 GC gc,
1050                 Pixmap which_pixmap,
1051                 int skip_duplicates)
1052 {
1053 
1054   int x1i, y1i;
1055   static int last_x1i;
1056   static int last_y1i;
1057 
1058 
1059   // Check whether the two bounding boxes intersect.  If not, skip
1060   // the rest of this function.  Do we need to worry about
1061   // special-case code here to handle vertical/horizontal lines
1062   // (width or length of zero)?
1063   //
1064 //
1065 // WE7U
1066 // Check to see if we can do this faster than map_visible() can.  A
1067 // point is a special case that should take only four compares
1068 // against the map window boundaries.
1069 //
1070   if (!map_visible(y1, y1, x1, x1))
1071   {
1072     // Skip this vector
1073     //fprintf(stderr,"Point not visible\n");
1074     return;
1075   }
1076 
1077   // Convert to screen coordinates.  Careful here!
1078   // The format conversions you'll need if you try to
1079   // compress this into two lines will get you into
1080   // trouble.
1081   x1i = x1 - NW_corner_longitude;
1082   x1i = x1i / scale_x;
1083 
1084   y1i = y1 - NW_corner_latitude;
1085   y1i = y1i / scale_y;
1086 
1087   if (skip_duplicates)
1088   {
1089     if (x1i == last_x1i && y1i == last_y1i)
1090     {
1091       return;
1092     }
1093   }
1094 
1095   // XDrawPoint uses 16-bit unsigned integers
1096   // (shorts).  Make sure we stay within the limits.
1097   (void)XDrawPoint(XtDisplay(w),
1098                    which_pixmap,
1099                    gc,
1100                    l16(x1i),
1101                    l16(y1i));
1102 
1103   last_x1i = x1i;
1104   last_y1i = y1i;
1105 }
1106 
1107 
1108 
1109 
1110 
1111 // Draws a vector onto a pixmap.  Assumes that the proper GC has
1112 // already been set up for drawing the correct color/width/linetype,
1113 // etc.
1114 //
1115 // Input points are in lat/long coordinates.
1116 //
draw_point_ll(Widget w,float y1,float x1,GC gc,Pixmap which_pixmap,int skip_duplicates)1117 void draw_point_ll(Widget w,
1118                    float y1,   // lat1
1119                    float x1,   // long1
1120                    GC gc,
1121                    Pixmap which_pixmap,
1122                    int skip_duplicates)
1123 {
1124 
1125   unsigned long x1L, y1L;
1126 
1127 //
1128 // WE7U
1129 // We should probably do four floating point compares against the
1130 // map boundaries here in order to speed up rejection of points that
1131 // don't fit our window.  If we change to that, copy the conversion-
1132 // to-screen-coordinates and drawing stuff from draw_point() down to
1133 // this routine so that we don't go through the comparisons again
1134 // there.
1135 //
1136   // Convert the point to the Xastir coordinate system.
1137   convert_to_xastir_coordinates(&x1L,
1138                                 &y1L,
1139                                 x1,
1140                                 y1);
1141 
1142   // Call the draw routine above.
1143   draw_point(w, x1L, y1L, gc, which_pixmap, skip_duplicates);
1144 }
1145 
1146 
1147 
1148 
1149 
1150 // Draws a vector onto a pixmap.  Assumes that the proper GC has
1151 // already been set up for drawing the correct color/width/linetype,
1152 // etc.  If the bounding box containing the vector doesn't intersect
1153 // with the current view, the line isn't drawn.
1154 //
1155 // Input points are in the Xastir coordinate system.
1156 //
draw_vector(Widget w,unsigned long x1,unsigned long y1,unsigned long x2,unsigned long y2,GC gc,Pixmap which_pixmap,int skip_duplicates)1157 void draw_vector(Widget w,
1158                  unsigned long x1,
1159                  unsigned long y1,
1160                  unsigned long x2,
1161                  unsigned long y2,
1162                  GC gc,
1163                  Pixmap which_pixmap,
1164                  int skip_duplicates)
1165 {
1166 
1167   int x1i, x2i, y1i, y2i;
1168   static int last_x1i, last_x2i, last_y1i, last_y2i;
1169 
1170 
1171   //fprintf(stderr,"%ld,%ld  %ld,%ld\t",x1,y1,x2,y2);
1172   if ( !clip2d_long(&x1, &y1, &x2, &y2) )
1173   {
1174     // Skip this vector
1175     //fprintf(stderr,"Line not visible\n");
1176     //fprintf(stderr,"%ld,%ld  %ld,%ld\n",x1,y1,x2,y2);
1177     return;
1178   }
1179   //fprintf(stderr,"%ld,%ld  %ld,%ld\n",x1,y1,x2,y2);
1180 
1181   // Convert to screen coordinates.  Careful here!
1182   // The format conversions you'll need if you try to
1183   // compress this into two lines will get you into
1184   // trouble.
1185   x1i = x1 - NW_corner_longitude;
1186   x1i = x1i / scale_x;
1187 
1188   y1i = y1 - NW_corner_latitude;
1189   y1i = y1i / scale_y;
1190 
1191   x2i = x2 - NW_corner_longitude;
1192   x2i = x2i / scale_x;
1193 
1194   y2i = y2 - NW_corner_latitude;
1195   y2i = y2i / scale_y;
1196 
1197   if (skip_duplicates)
1198   {
1199     if (last_x1i == x1i
1200         && last_x2i == x2i
1201         && last_y1i == y1i
1202         && last_y2i == y2i)
1203     {
1204       return;
1205     }
1206   }
1207 
1208   // XDrawLine uses 16-bit unsigned integers
1209   // (shorts).  Make sure we stay within the limits.
1210   // clip2d_long() should make sure of this anyway as it clips
1211   // lines to fit the window.
1212   //
1213   (void)XDrawLine(XtDisplay(w),
1214                   which_pixmap,
1215                   gc,
1216                   l16(x1i),
1217                   l16(y1i),
1218                   l16(x2i),
1219                   l16(y2i));
1220 
1221   last_x1i = x1i;
1222   last_x2i = x2i;
1223   last_y1i = y1i;
1224   last_y2i = y2i;
1225 }
1226 
1227 
1228 
1229 
1230 
1231 // Draws a vector onto a pixmap.  Assumes that the proper GC has
1232 // already been set up for drawing the correct color/width/linetype,
1233 // etc.
1234 //
1235 // Input points are in lat/long coordinates.
1236 //
draw_vector_ll(Widget w,float y1,float x1,float y2,float x2,GC gc,Pixmap which_pixmap,int skip_duplicates)1237 void draw_vector_ll(Widget w,
1238                     float y1,   // lat1
1239                     float x1,   // long1
1240                     float y2,   // lat2
1241                     float x2,   // long2
1242                     GC gc,
1243                     Pixmap which_pixmap,
1244                     int skip_duplicates)
1245 {
1246 
1247   unsigned long x1L, x2L, y1L, y2L;
1248   int x1i, x2i, y1i, y2i;
1249   static int last_x1i, last_x2i, last_y1i, last_y2i;
1250 
1251 
1252   //fprintf(stderr,"%lf,%lf  %lf,%lf\t",x1,y1,x2,y2);
1253   if ( !clip2d(&x1, &y1, &x2, &y2) )
1254   {
1255     // Skip this vector
1256 //fprintf(stderr,"Line not visible: %lf,%lf  %lf,%lf\n",y1,x1,y2,x2);
1257     return;
1258   }
1259 //fprintf(stderr,"%lf,%lf  %lf,%lf\n",x1,y1,x2,y2);
1260 
1261   // Convert the points to the Xastir coordinate system.
1262   convert_to_xastir_coordinates(&x1L,
1263                                 &y1L,
1264                                 x1,
1265                                 y1);
1266 
1267   convert_to_xastir_coordinates(&x2L,
1268                                 &y2L,
1269                                 x2,
1270                                 y2);
1271 
1272 //fprintf(stderr,"%ld,%ld  %ld,%ld\n",x1L,y1L,x2L,y2L);
1273 
1274   // Convert to screen coordinates.  Careful here!
1275   // The format conversions you'll need if you try to
1276   // compress this into two lines will get you into
1277   // trouble.
1278   x1i = (int)(x1L - NW_corner_longitude);
1279   x1i = x1i / scale_x;
1280 
1281   y1i = (int)(y1L - NW_corner_latitude);
1282   y1i = y1i / scale_y;
1283 
1284   x2i = (int)(x2L - NW_corner_longitude);
1285   x2i = x2i / scale_x;
1286 
1287   y2i = (int)(y2L - NW_corner_latitude);
1288   y2i = y2i / scale_y;
1289 
1290   if (skip_duplicates)
1291   {
1292     if (last_x1i == x1i
1293         && last_x2i == x2i
1294         && last_y1i == y1i
1295         && last_y2i == y2i)
1296     {
1297 //            fprintf(stderr,"Duplicate line\n");
1298       return;
1299     }
1300   }
1301 //fprintf(stderr,"NW_corner_latitude:%ld, NW_corner_longitude:%ld, scale_x:%ld, scale_y:%ld\n",
1302 //    NW_corner_latitude,
1303 //    NW_corner_longitude,
1304 //    scale_x,
1305 //    scale_y);
1306 
1307 //fprintf(stderr,"%d,%d  %d,%d\n\n",x1i,y1i,x2i,y2i);
1308 
1309   // XDrawLine uses 16-bit unsigned integers
1310   // (shorts).  Make sure we stay within the limits.
1311   // clip2d() should make sure of this anyway as it clips lines to
1312   // fit the window.
1313   //
1314   (void)XDrawLine(XtDisplay(w),
1315                   which_pixmap,
1316                   gc,
1317                   l16(x1i),
1318                   l16(y1i),
1319                   l16(x2i),
1320                   l16(y2i));
1321 
1322   last_x1i = x1i;
1323   last_x2i = x2i;
1324   last_y1i = y1i;
1325   last_y2i = y2i;
1326 }
1327 
1328 
1329 
1330 
1331 
1332 // Find length of a standard string of seven zeroes in the border font.
1333 // Supporting function for draw_grid() and the grid drawing functions.
get_standard_border_string_width_pixels(Widget w,int length)1334 int get_standard_border_string_width_pixels(Widget w, int length)
1335 {
1336   int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels.
1337   char seven_zeroes[8] = "0000000";
1338   char five_zeroes[6]  = "00000";
1339 
1340   if (length==5)
1341   {
1342     string_width_pixels = get_rotated_label_text_length_pixels(w, five_zeroes, FONT_BORDER);
1343   }
1344 
1345   string_width_pixels = get_rotated_label_text_length_pixels(w, seven_zeroes, FONT_BORDER);
1346   return string_width_pixels;
1347 }
1348 
1349 
1350 
1351 
1352 
1353 // Find height of a standard string in the border font
1354 // Supporting function for draw_grid() and the grid drawing functions.
get_standard_border_string_height_pixels(Widget w)1355 int get_standard_border_string_height_pixels(Widget w)
1356 {
1357   int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels.
1358   char one_zero[2] = "0";
1359 
1360   string_width_pixels = get_rotated_label_text_height_pixels(w, one_zero, FONT_BORDER);
1361   return string_width_pixels;
1362 }
1363 
1364 
1365 
1366 
1367 
1368 // Find out the width to use for the border to apply when uing a labeled grid.
1369 // Border width is determined from the height of the border font.
1370 // Supporting function for draw_grid() and the grid drawing functions.
get_border_width(Widget w)1371 int get_border_width(Widget w)
1372 {
1373   int border_width = 14;      // The width of the border to draw around the
1374   // map to place labeled tick marks into
1375   // should be an even number.
1376   // The default here is overidden by size of the border font.
1377   int string_height_pixels = 0; // Height of a string in the border font in pixels
1378 
1379   string_height_pixels = get_standard_border_string_height_pixels(w);
1380   // Rotated text functions used to draw the border text add some
1381   // blank space at the bottom of the text so make the border wide enough
1382   // to compensate for this.
1383   border_width = string_height_pixels + (string_height_pixels/2) + 1;
1384   // check to see if string_height_pixels is even
1385   if ((float)string_height_pixels/2.0!=floor((float)string_height_pixels/2.0))
1386   {
1387     border_width++;
1388   }
1389   // we are using draw nice string to write the metadata in the top border, so
1390   // make sure the border is wide enough for it, even if the grid labels are small.
1391   if (border_width < 14)
1392   {
1393     border_width = 14;
1394   }
1395   return border_width;
1396 }
1397 
1398 
1399 
1400 
1401 
1402 // ***********************************************************
1403 //
1404 // get_horizontal_datum()
1405 //
1406 // Provides the current map datum.  Current default is WGS84.
1407 // Parameters: datum, character array ponter for the string
1408 //             that will be filled with the current datum
1409 // sizeof_datum, the size of the datum character array.
1410 //
1411 //***********************************************************
get_horizontal_datum(char * datum,int sizeof_datum)1412 void get_horizontal_datum(char *datum, int sizeof_datum)
1413 {
1414   char metadata_datum[6] = "WGS84";  // datum to display in metadata on top border
1415   xastir_snprintf(datum, sizeof_datum, "%s", metadata_datum);
1416   if (sizeof_datum<6)
1417   {
1418     fprintf(stderr,"Datum [%s] truncated to [%s]\n",metadata_datum,datum);
1419   }
1420 }
1421 
1422 
1423 
1424 
1425 
1426 // Lat/Long coordinate system, draw lat/long lines.  Called by
1427 // draw_grid() below.
1428 //
draw_complete_lat_lon_grid(Widget w)1429 void draw_complete_lat_lon_grid(Widget w)
1430 {
1431 
1432   int coord;
1433   char dash[2];
1434   unsigned int x,x1,x2;
1435   unsigned int y,y1,y2;
1436   unsigned int stepsx;         // spacing of grid lines
1437   unsigned int stepsy;         // spacing of grid lines
1438   int coordinate_format;      // Format to use for coordinates on border (e.g. decimal degrees).
1439   char grid_label[25];        // String to draw labels on grid lines
1440   int screen_width_xastir;  // screen width in xastir units (1/100 of a second)
1441 //  int screen_height_xastir; // screen height in xastir units (1/100 of a second)
1442   int border_width;          // the width of the labeled border in pixels.
1443   int string_width_pixels = 0;// Width of a grid label string in pixels.
1444   float screen_width_degrees;   // Width of the screen in degrees
1445   int log_screen_width_degrees; // Log10 of the screen width in degrees, used to scale degrees
1446   long xx2, yy2;
1447   long xx, yy;
1448   unsigned int last_label_end;  // cordinate of the end of the previous label
1449   char metadata_datum[6];  // datum to display in metadata on top border
1450   char grid_label1[25];       // String to draw latlong metadata
1451   char grid_label2[25];       // String to draw latlong metadata
1452   char top_label[180];        // String to draw metadata on top border
1453 
1454   if (!long_lat_grid) // We don't wish to draw a map grid
1455   {
1456     return;
1457   }
1458 
1459   // convert between selected coordinate format constant and display format constants
1460   if (coordinate_system == USE_DDDDDD)
1461   {
1462     coordinate_format = CONVERT_DEC_DEG;
1463   }
1464   else if (coordinate_system == USE_DDMMSS)
1465   {
1466     coordinate_format = CONVERT_DMS_NORMAL_FORMATED;
1467   }
1468   else
1469   {
1470     coordinate_format = CONVERT_HP_NORMAL_FORMATED;
1471   }
1472   border_width = get_border_width(w);
1473   // Find xastir coordinates of upper left and lower right corners.
1474   xx = NW_corner_longitude  + (border_width * scale_x);
1475   yy = NW_corner_latitude   + (border_width * scale_y);
1476   xx2 = NW_corner_longitude  + ((screen_width - border_width) * scale_x);
1477   yy2 = NW_corner_latitude   + ((screen_height - border_width) * scale_y);
1478   screen_width_xastir = xx2 - xx;
1479 //  screen_height_xastir = yy2 - yy;
1480   // Determine some parameters used in drawing the border.
1481   string_width_pixels = get_standard_border_string_width_pixels(w, 7);
1482   // 1 xastir coordinate = 1/100 of a second
1483   // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree
1484   // 64800000 xastir coordinates = 180 degrees
1485   // 360000   xastir coordinates = 1 degree
1486   // scale_x * (screen_width/10) = one tenth of the screen width in xastir coordinates
1487   // scale_x number of xastir coordinates per pixel
1488   screen_width_degrees = (float)(screen_width_xastir / (float)360000);
1489   log_screen_width_degrees = log10(screen_width_degrees);
1490 
1491 
1492   if (draw_labeled_grid_border==TRUE)
1493   {
1494     get_horizontal_datum(metadata_datum, sizeof(metadata_datum));
1495 
1496     // Put metadata in top border.
1497     // find location of upper left corner of map, convert to Lat/Long
1498     convert_lon_l2s(xx, grid_label1, sizeof(grid_label1), coordinate_format);
1499     convert_lat_l2s(yy, grid_label2, sizeof(grid_label2), coordinate_format);
1500 
1501     strcpy(grid_label, grid_label1);
1502     grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
1503     strcat(grid_label, " ");
1504     grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
1505     strcat(grid_label, grid_label2);
1506     grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
1507 
1508     // find location of lower right corner of map, convert to Lat/Long
1509     convert_lon_l2s(xx2, grid_label1, sizeof(grid_label1), coordinate_format);
1510     convert_lat_l2s(yy2, grid_label2, sizeof(grid_label2), coordinate_format);
1511     //"XASTIR Map of %s (upper left) to %s %s (lower right).  Lat/Long grid, %s datum. ",
1512     xastir_snprintf(top_label,
1513                     sizeof(top_label),
1514                     langcode("MDATA002"),
1515                     grid_label,grid_label1,grid_label2,metadata_datum);
1516     draw_rotated_label_text_to_target (w, 270,
1517                                        border_width+2,
1518                                        border_width-1,
1519                                        sizeof(top_label),colors[0x10],top_label,FONT_BORDER,
1520                                        pixmap_final,
1521                                        outline_border_labels, colors[outline_border_labels_color]);
1522   }
1523 
1524   // A crude grid spacing can be obtained from scaling one tenth of the screen width.
1525   // This works, but puts the grid lines at arbitrary increments of a degree.
1526   //stepsx = (scale_x*(screen_width/10));
1527 
1528   // Setting the grid using the base 10 log of the screen width in degrees allows
1529   // both scaling the grid to the screen and spacing the grid lines at appropriately
1530   // rounded increments of a degree.
1531   //
1532   // Set default grid to 0.1 degree.  This will be used when the screen width is about 1 degree.
1533   stepsx = 36000;  // if (log_screen_width_degrees == 0)
1534   // Work out an appropriate grid spacing for the screen size and coordinate system.
1535   if (log_screen_width_degrees > 0)
1536   {
1537     // grid spacing is rounded to 10 degree increment.
1538     stepsx = ((int)(screen_width_degrees / (pow(10,log_screen_width_degrees)))*pow(10,log_screen_width_degrees)) * 36000;
1539   }
1540   if (log_screen_width_degrees < 0)
1541   {
1542     // Grid spacing is rounded to less than one degree.
1543     if (coordinate_system == USE_DDDDDD)
1544     {
1545       // Round to tenths or hundrethds or thousanths of a degree.
1546       stepsx = ((float)(int)(((float)screen_width_degrees / pow(10,log_screen_width_degrees)*10.0)))*pow(10,log_screen_width_degrees) * 3600;
1547     }
1548     else
1549     {
1550       // For decimal minutes or minutes and seconds.
1551       // Find screen width and log screen width in minutes.
1552       screen_width_degrees = screen_width_degrees * 60.0;
1553       log_screen_width_degrees = log10(screen_width_degrees);
1554       // round to minutes or tenths of minutes.
1555       stepsx = ((float)(int)
1556                 ((float)(screen_width_degrees) / pow(10,log_screen_width_degrees) * 10.0)
1557                )
1558                * pow(10,log_screen_width_degrees) * 3600;
1559       if (log_screen_width_degrees==0)
1560       {
1561         stepsx = 600; // 6000 = 1 minute
1562       }
1563     }
1564   }
1565   // Grid should now be close to reasonable spacing for screen size, but
1566   // may need to be tuned.
1567   // Test for too tightly or too coarsely spaced grid.
1568   if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5))
1569   {
1570     stepsx = stepsx * 2.0;
1571   }
1572   if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5))
1573   {
1574     stepsx = stepsx * 2.0;
1575   }
1576   if (stepsx>(unsigned int)((scale_x * screen_width)/3.5))
1577   {
1578     stepsx = stepsx / 2.0;
1579   }
1580   // Handle special case of very small screen - only draw a single grid line
1581   if (screen_width < (string_width_pixels * 2))
1582   {
1583     stepsx = (scale_x*(screen_width/2));
1584   }
1585   // Make sure we don't pass an erronous stepsx of 0 on.
1586   if (stepsx==0)
1587   {
1588     stepsx=36000;
1589   }
1590 
1591   // Use the same grid spacing for both latitude and longitude grids.
1592   // We could use a scaling factor related to the screen height width ratio here.
1593   stepsy = stepsx;
1594 
1595   // protect against division by zero
1596   if (scale_x==0)
1597   {
1598     scale_x = 1;
1599   }
1600   if (scale_y==0)
1601   {
1602     scale_y = 1;
1603   }
1604 
1605   // Now draw and label the grid.
1606   // Draw vertical longitude lines
1607   if (NW_corner_latitude >= 0)
1608   {
1609     y1 = 0;
1610   }
1611   else
1612   {
1613     y1 = -NW_corner_latitude/scale_y;
1614   }
1615 
1616   y2 = (180*60*60*100-NW_corner_latitude)/scale_y;
1617 
1618   if (y2 > (unsigned int)screen_height)
1619   {
1620     y2 = screen_height-1;
1621   }
1622 
1623   coord = NW_corner_longitude+stepsx-(NW_corner_longitude%stepsx);
1624   if (coord < 0)
1625   {
1626     coord = 0;
1627   }
1628 
1629   last_label_end = 0;
1630   for (; coord < SE_corner_longitude && coord <= 360*60*60*100; coord += stepsx)
1631   {
1632 
1633     x = (coord-NW_corner_longitude)/scale_x;
1634 
1635     if ((coord%(648000*100)) == 0)
1636     {
1637       (void)XSetLineAttributes (XtDisplay (w),
1638                                 gc_tint,
1639                                 1,
1640                                 LineSolid,
1641                                 CapButt,
1642                                 JoinMiter);
1643       (void)XDrawLine (XtDisplay (w),
1644                        pixmap_final,
1645                        gc_tint,
1646                        l16(x),
1647                        l16(y1),
1648                        l16(x),
1649                        l16(y2));
1650       (void)XSetLineAttributes (XtDisplay (w),
1651                                 gc_tint,
1652                                 1,
1653                                 LineOnOffDash,
1654                                 CapButt,
1655                                 JoinMiter);
1656       continue;   // Go to next iteration of for loop
1657     }
1658     else if ((coord%(72000*100)) == 0)
1659     {
1660       dash[0] = dash[1] = 8;
1661       (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2);
1662     }
1663     else if ((coord%(7200*100)) == 0)
1664     {
1665       dash[0] = dash[1] = 4;
1666       (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2);
1667     }
1668     else if ((coord%(300*100)) == 0)
1669     {
1670       dash[0] = dash[1] = 2;
1671       (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2);
1672     }
1673 
1674     (void)XDrawLine (XtDisplay (w),
1675                      pixmap_final,
1676                      gc_tint,
1677                      l16(x),
1678                      l16(y1),
1679                      l16(x),
1680                      l16(y2));
1681 
1682     if (draw_labeled_grid_border==TRUE)
1683     {
1684       // Label the longitudes in lower border.
1685       convert_lon_l2s(coord, grid_label, sizeof(grid_label), coordinate_format);
1686       if (log_screen_width_degrees > 0 && strlen(grid_label) > 5)
1687       {
1688         // truncate the grid_label string
1689         if (coordinate_system==USE_DDMMMM)
1690         {
1691           // Add ' and move EW and null characters forward.
1692           grid_label[strlen(grid_label)-5] = '\'';
1693           grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1];
1694           grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)];
1695         }
1696         else
1697         {
1698           // Move EW and null characters forward.
1699           grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1];
1700           grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)];
1701         }
1702       }
1703       string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER);
1704       // test for overlap of label with previously printed label
1705       if (x > last_label_end + 3 && x < (unsigned int)(screen_width - string_width_pixels))
1706       {
1707         draw_rotated_label_text_to_target (w, 270,
1708                                            x,
1709                                            screen_height,
1710                                            sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER,
1711                                            pixmap_final,
1712                                            outline_border_labels, colors[outline_border_labels_color]);
1713         last_label_end = x + string_width_pixels;
1714       }
1715     }
1716   }
1717 
1718   // Draw horizontal latitude lines.
1719   last_label_end = 0;
1720   if (NW_corner_longitude >= 0)
1721   {
1722     x1 = 0;
1723   }
1724   else
1725   {
1726     x1 = -NW_corner_longitude/scale_x;
1727   }
1728 
1729   x2 = (360*60*60*100-NW_corner_longitude)/scale_x;
1730   if (x2 > (unsigned int)screen_width)
1731   {
1732     x2 = screen_width-1;
1733   }
1734 
1735   coord = NW_corner_latitude+stepsy-(NW_corner_latitude%stepsy);
1736   if (coord < 0)
1737   {
1738     coord = 0;
1739   }
1740 
1741   for (; coord < SE_corner_latitude && coord <= 180*60*60*100; coord += stepsy)
1742   {
1743 
1744     y = (coord-NW_corner_latitude)/scale_y;
1745 
1746     if ((coord%(324000*100)) == 0)
1747     {
1748       (void)XSetLineAttributes (XtDisplay (w),
1749                                 gc_tint,
1750                                 1,
1751                                 LineSolid,
1752                                 CapButt,
1753                                 JoinMiter);
1754       (void)XDrawLine (XtDisplay (w),
1755                        pixmap_final,
1756                        gc_tint,
1757                        l16(x1),
1758                        l16(y),
1759                        l16(x2),
1760                        l16(y));
1761       (void)XSetLineAttributes (XtDisplay (w),
1762                                 gc_tint,
1763                                 1,
1764                                 LineOnOffDash,
1765                                 CapButt,
1766                                 JoinMiter);
1767       continue;   // Go to next iteration of for loop
1768     }
1769     else if ((coord%(36000*100)) == 0)
1770     {
1771       dash[0] = dash[1] = 8;
1772       (void)XSetDashes (XtDisplay (w), gc_tint, 4, dash, 2);
1773     }
1774     else if ((coord%(3600*100)) == 0)
1775     {
1776       dash[0] = dash[1] = 4;
1777       (void)XSetDashes (XtDisplay (w), gc_tint, 2, dash, 2);
1778     }
1779     else if ((coord%(150*100)) == 0)
1780     {
1781       dash[0] = dash[1] = 2;
1782       (void)XSetDashes (XtDisplay (w), gc_tint, 1, dash, 2);
1783     }
1784 
1785     (void)XDrawLine (XtDisplay (w),
1786                      pixmap_final,
1787                      gc_tint,
1788                      l16(x1),
1789                      l16(y),
1790                      l16(x2),
1791                      l16(y));
1792 
1793     if (draw_labeled_grid_border==TRUE)
1794     {
1795       // label the latitudes on left and right borders
1796       // (unlike UTM where easting before northing order is important)
1797       convert_lat_l2s(coord, grid_label, sizeof(grid_label), coordinate_format);
1798       if (log_screen_width_degrees > 0 && strlen(grid_label) > 5)
1799       {
1800         // truncate the grid_label string
1801         if (coordinate_system==USE_DDMMMM)
1802         {
1803           // Add ' and move EW and null characters forward.
1804           grid_label[strlen(grid_label)-5] = '\'';
1805           grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1];
1806           grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)];
1807         }
1808         else
1809         {
1810           // Move EW and null characters forward.
1811           grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1];
1812           grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)];
1813         }
1814       }
1815       string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER);
1816       // check to make sure we aren't overwriting the previous label text
1817       if ((y > last_label_end+3) && (y > (unsigned int)string_width_pixels))
1818       {
1819         draw_rotated_label_text_to_target (w, 180,
1820                                            screen_width,
1821                                            y,
1822                                            sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER,
1823                                            pixmap_final,
1824                                            outline_border_labels, colors[outline_border_labels_color]);
1825         draw_rotated_label_text_to_target (w, 180,
1826                                            border_width,
1827                                            y,
1828                                            sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER,
1829                                            pixmap_final,
1830                                            outline_border_labels, colors[outline_border_labels_color]);
1831         last_label_end = y + string_width_pixels;
1832       }
1833     }
1834   }
1835 } // End of draw_complete_lat_lon_grid()
1836 
1837 
1838 
1839 
1840 
1841 // Draw the major zones for UTM and MGRS.  Called by draw_grid()
1842 // below.
1843 //
1844 // These are based off 6-degree lat/long lines, with a few irregular
1845 // zones that have to be special-cased.  This part of the code
1846 // handles the irregular zones in SW Norway (31V/32V) and the
1847 // regions near Svalbard (31X/33X/35X/37X) just fine.
1848 
1849 // These are based off the central meridian running up the middle of
1850 // each zone (3 degrees from either side of the standard six-degree
1851 // zones).  Even the irregular zones key off the same medians.  UTM
1852 // grids are defined in terms of meters instead of lat/long, so they
1853 // don't line up with the left/right edges of the zones or with the
1854 // longitude lines.
1855 //
1856 // According to Peter Dana (Geographer's Craft web pages), even when
1857 // the major grid boundaries have been shifted, the meridian used
1858 // for drawing the subgrids is still based on six-degree boundaries
1859 // (as if the major grid hadn't been shifted at all).  That means we
1860 // are drawing the subgrids correctly as it stands now for the
1861 // irregular grids (31V/32V/31X/33X/35X/37X).  The irregular zones
1862 // have sizes of 3/9/12 degrees (width) instead of 6 degrees.
1863 //
1864 // UTM NOTES:  84 degrees North to 80 degrees South. 60 zones, each
1865 // covering six (6) degrees of longitude. Each zone extends three
1866 // degrees eastward and three degrees westward from its central
1867 // meridian.  Zones are numbered consecutively west to east from the
1868 // 180 degree meridian. From 84 degrees North and 80 degrees South
1869 // to the respective poles, the Universal Polar Stereographic (UPS)
1870 // is used.
1871 //
1872 // For MGRS and UTM-Special grid only:
1873 // UTM Zone 32 has been widened to 9� (at the expense of zone 31)
1874 // between latitudes 56� and 64� (band V) to accommodate southwest
1875 // Norway. Thus zone 32 extends westwards to 3�E in the North Sea.
1876 // Similarly, between 72� and 84� (band X), zones 33 and 35 have
1877 // been widened to 12� to accommodate Svalbard. To compensate for
1878 // these 12� wide zones, zones 31 and 37 are widened to 9� and zones
1879 // 32, 34, and 36 are eliminated. Thus the W and E boundaries of
1880 // zones are 31: 0 - 9 E, 33: 9 - 21 E, 35: 21 - 33 E and 37: 33 -
1881 // 42 E.
1882 //
1883 // UTM is depending on the ellipsoid and the datum used.  For our
1884 // purposes, we're always using WGS84 ellipsoid and datum, so it's a
1885 // non-issue.
1886 //
1887 // Horizontal bands corresponding to the NATO UTM/UPS lettering:
1888 // Zones go from A (south pole) to Z (north pole).  South of -80 are
1889 // zones A/B, north of +84 are zones Y/Z.  "I" and "O" are not used.
1890 // Zones from C to W are 8 degrees high.  Zone X is 12 degrees high.
1891 //
1892 // We need these NATO letters or a N/S designator in order to
1893 // specify which hemisphere the UTM coordinates are in.  Often, the
1894 // same coordinates can appear in either hemisphere.  Some computer
1895 // software uses +/- to designate northings instead of N/S or the
1896 // NATO lettered bands.
1897 //
1898 // UPS system is used at the poles instead of UTM.  UPS uses a false
1899 // northing and easting of 2,000,000 meters.
1900 //
1901 // An arbitrary false northing of 10,000,000 at the equator is used
1902 // for southern latitudes only.  Northern latitudes assume the
1903 // equator northing is at zero.  An arbitrary false easting of
1904 // 500,000 is along the meridian of each zone (3 degrees from each
1905 // side).  The lettered grid lines are necessary due to some
1906 // coordinates being valid in both the northern and the southern
1907 // hemisphere.
1908 //
1909 // Y/Z  84N to 90N (UPS System) false N/E = 2,000,000
1910 // X    72N to 84N (12 degrees latitude, equator=0)
1911 // W    64N to 72N ( 8 degrees latitude, equator=0)
1912 // V    56N to 64N ( 8 degrees latitude, equator=0)
1913 // U    48N to 56N ( 8 degrees latitude, equator=0)
1914 // T    40N to 48N ( 8 degrees latitude, equator=0)
1915 // S    32N to 40N ( 8 degrees latitude, equator=0)
1916 // R    24N to 32N ( 8 degrees latitude, equator=0)
1917 // Q    16N to 24N ( 8 degrees latitude, equator=0)
1918 // P     8N to 16N ( 8 degrees latitude, equator=0)
1919 // N     0N to  8N ( 8 degrees latitude, equator=0)
1920 // M     0S to  8S ( 8 degrees latitude, equator=10,000,000)
1921 // L     8S to 16S ( 8 degrees latitude, equator=10,000,000)
1922 // K    16S to 24S ( 8 degrees latitude, equator=10,000,000)
1923 // J    24S to 32S ( 8 degrees latitude, equator=10,000,000)
1924 // H    32S to 40S ( 8 degrees latitude, equator=10,000,000)
1925 // G    40S to 48S ( 8 degrees latitude, equator=10,000,000)
1926 // F    48S to 56S ( 8 degrees latitude, equator=10,000,000)
1927 // E    56S to 64S ( 8 degrees latitude, equator=10,000,000)
1928 // D    64S to 72S ( 8 degrees latitude, equator=10,000,000)
1929 // C    72S to 80S ( 8 degrees latitude, equator=10,000,000)
1930 // A/B  80S to 90S (UPS System) false N/E = 2,000,000
1931 //
draw_major_utm_mgrs_grid(Widget w)1932 void draw_major_utm_mgrs_grid(Widget w)
1933 {
1934   int ii;
1935 
1936 // need to move metadata to its own function and put it up after grids have been drawn.
1937 //*******
1938   // variables for metadata in grid border
1939   long xx2, yy2;  // coordinates of screen corners used for metadata
1940   int border_width;           // Width of the border to draw labels into.
1941   double easting, northing;   // Values used in border metadata.
1942   int x, y;                   // Screen coordinates for border labels.
1943   char zone_str[10];
1944   char zone_str2[10];
1945   char metadata_datum[6];
1946   char grid_label[25];        // String to draw labels on grid lines
1947   char grid_label1[25];       // String to draw latlong metadata
1948   char top_label[180];        // String to draw metadata on top border
1949 
1950   // variables to support components of MGRS strings in the metadata
1951   char mgrs_zone[4] = "   ";   // MGRS zone letter
1952   char mgrs_eastingL[3] = "  ";
1953   char mgrs_northingL[3] = "  ";
1954   unsigned int int_utmEasting;
1955   unsigned int int_utmNorthing;
1956   char mgrs_space_string[4] = "   ";
1957 //  int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
1958   char mgrs_ul_digraph[3] = "  ";  // MGRS digraph for upper left corner of screen
1959   char mgrs_lr_digraph[3] = "  ";  // MGRS digraph for lower right corner of screen
1960 
1961 
1962 //fprintf(stderr,"draw_major_utm_mgrs_grid start\n");
1963 
1964   if (!long_lat_grid) // We don't wish to draw a map grid
1965   {
1966     return;
1967   }
1968 
1969   // Vertical lines:
1970 
1971   // Draw the vertical vectors (except for the irregular regions
1972   // and the prime meridian).  The polar areas only have two zones
1973   // each, so we don't want to draw through those areas.
1974 
1975   for (ii = -180; ii < 0; ii += 6)
1976   {
1977     draw_vector_ll(w, -80.0,  (float)ii, 84.0,  (float)ii, gc_tint, pixmap_final, 0);
1978   }
1979   for (ii = 42; ii <= 180; ii += 6)
1980   {
1981     draw_vector_ll(w, -80.0,  (float)ii, 84.0,  (float)ii, gc_tint, pixmap_final, 0);
1982   }
1983 
1984   // Draw the short vertical vectors in the polar regions
1985   draw_vector_ll(w, -90.0, -180.0, -80.0, -180.0, gc_tint, pixmap_final, 0);
1986   draw_vector_ll(w, -90.0,  180.0, -80.0,  180.0, gc_tint, pixmap_final, 0);
1987   draw_vector_ll(w,  84.0, -180.0,  90.0, -180.0, gc_tint, pixmap_final, 0);
1988   draw_vector_ll(w,  84.0,  180.0,  90.0,  180.0, gc_tint, pixmap_final, 0);
1989 
1990   if (coordinate_system == USE_UTM_SPECIAL
1991       || coordinate_system == USE_MGRS)
1992   {
1993     // For MGRS, we need to draw irregular zones in certain
1994     // areas.
1995 
1996     // Draw the partial vectors from 80S to the irregular region
1997     draw_vector_ll(w, -80.0,    6.0,  56.0,    6.0, gc_tint, pixmap_final, 0);
1998     draw_vector_ll(w, -80.0,   12.0,  72.0,   12.0, gc_tint, pixmap_final, 0);
1999     draw_vector_ll(w, -80.0,   18.0,  72.0,   18.0, gc_tint, pixmap_final, 0);
2000     draw_vector_ll(w, -80.0,   24.0,  72.0,   24.0, gc_tint, pixmap_final, 0);
2001     draw_vector_ll(w, -80.0,   30.0,  72.0,   30.0, gc_tint, pixmap_final, 0);
2002     draw_vector_ll(w, -80.0,   36.0,  72.0,   36.0, gc_tint, pixmap_final, 0);
2003 
2004     // Draw the short vertical vectors in the irregular region
2005     draw_vector_ll(w,  56.0,    3.0,  64.0,    3.0, gc_tint, pixmap_final, 0);
2006     draw_vector_ll(w,  64.0,    6.0,  72.0,    6.0, gc_tint, pixmap_final, 0);
2007     draw_vector_ll(w,  72.0,    9.0,  84.0,    9.0, gc_tint, pixmap_final, 0);
2008     draw_vector_ll(w,  72.0,   21.0,  84.0,   21.0, gc_tint, pixmap_final, 0);
2009     draw_vector_ll(w,  72.0,   33.0,  84.0,   33.0, gc_tint, pixmap_final, 0);
2010 
2011     // Draw the short vertical vectors above the irregular region
2012     draw_vector_ll(w,  84.0,    6.0,  84.0,    6.0, gc_tint, pixmap_final, 0);
2013     draw_vector_ll(w,  84.0,   12.0,  84.0,   12.0, gc_tint, pixmap_final, 0);
2014     draw_vector_ll(w,  84.0,   18.0,  84.0,   18.0, gc_tint, pixmap_final, 0);
2015     draw_vector_ll(w,  84.0,   24.0,  84.0,   24.0, gc_tint, pixmap_final, 0);
2016     draw_vector_ll(w,  84.0,   30.0,  84.0,   30.0, gc_tint, pixmap_final, 0);
2017     draw_vector_ll(w,  84.0,   36.0,  84.0,   36.0, gc_tint, pixmap_final, 0);
2018   }
2019   else
2020   {
2021     // Draw normal zone boundaries used for civilian UTM
2022     // grid.
2023     for (ii = 6; ii < 42; ii += 6)
2024     {
2025       draw_vector_ll(w, -80.0,  (float)ii, 84.0,  (float)ii, gc_tint, pixmap_final, 0);
2026     }
2027   }
2028 
2029 
2030   // Horizontal lines:
2031 
2032   // Draw the 8 degree spaced lines, except for the equator
2033   for (ii = -80; ii < 0; ii += 8)
2034   {
2035     draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0);
2036   }
2037   // Draw the 8 degree spaced lines
2038   for (ii = 8; ii <= 72; ii += 8)
2039   {
2040     draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0);
2041   }
2042 
2043   // Draw the one 12 degree spaced line
2044   draw_vector_ll(w, 84.0, -180.0, 84.0, 180.0, gc_tint, pixmap_final, 0);
2045 
2046   // Draw the pole lines
2047   draw_vector_ll(w, -90.0, -180.0, -90.0, 180.0, gc_tint, pixmap_final, 0);
2048   draw_vector_ll(w,  90.0, -180.0,  90.0, 180.0, gc_tint, pixmap_final, 0);
2049 
2050   // Set to solid line for the equator.  Make it extra wide as
2051   // well.
2052   (void)XSetLineAttributes (XtDisplay (w), gc_tint, 3, LineSolid, CapButt,JoinMiter);
2053 
2054   // Draw the equator as a solid line
2055   draw_vector_ll(w, 0.0, -180.0, 0.0, 180.0, gc_tint, pixmap_final, 0);
2056 
2057   (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineSolid, CapButt,JoinMiter);
2058 
2059   // Draw the prime meridian in the same manner
2060   draw_vector_ll(w, -80.0, 0.0, 84.0, 0.0, gc_tint, pixmap_final, 0);
2061 
2062   // add metadata and labels
2063   if (draw_labeled_grid_border==TRUE && scale_x > 3000)
2064   {
2065     // Determine the width of the border
2066     border_width = get_border_width(w);
2067     // Find out what the map datum is.
2068     get_horizontal_datum(metadata_datum, sizeof(metadata_datum));
2069 
2070     // Put metadata in top border.
2071     // find location of upper left corner of map, convert to UTM
2072     xx2 = NW_corner_longitude  + (border_width * scale_x);
2073     yy2 = NW_corner_latitude   + (border_width * scale_y);
2074     convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2075                           xx2, yy2);
2076     if (coordinate_system == USE_MGRS)
2077     {
2078       convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2079                                             mgrs_eastingL,   sizeof(mgrs_eastingL),
2080                                             mgrs_northingL,  sizeof(mgrs_northingL),
2081                                             &int_utmEasting, &int_utmNorthing,
2082                                             xx2, yy2,
2083                                             0, mgrs_space_string, strlen(mgrs_space_string));
2084       xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph),
2085                       "%c%c", mgrs_eastingL[0], mgrs_northingL[0]);
2086       xastir_snprintf(grid_label,
2087                       sizeof(grid_label),
2088                       "%s %s %05.0f %05.0f",
2089                       mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing);
2090     }
2091     else
2092     {
2093       char easting_str[10];
2094       char northing_str[10];
2095 
2096       xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting);
2097       xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing);
2098       strcpy(grid_label, zone_str);
2099       grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2100       strcat(grid_label, easting_str);
2101       grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2102       strcat(grid_label, northing_str);
2103       grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2104     }
2105     // find location of lower right corner of map, convert to UTM
2106     xx2 = NW_corner_longitude  + ((screen_width - border_width) * scale_x);
2107     yy2 = NW_corner_latitude   + ((screen_height - border_width) * scale_y);
2108     convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2109                           xx2, yy2);
2110     if (coordinate_system == USE_MGRS)
2111     {
2112       convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2113                                             mgrs_eastingL,   sizeof(mgrs_eastingL),
2114                                             mgrs_northingL,  sizeof(mgrs_northingL),
2115                                             &int_utmEasting, &int_utmNorthing,
2116                                             xx2, yy2,
2117                                             0, mgrs_space_string, strlen(mgrs_space_string));
2118       xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph),
2119                       "%c%c", mgrs_eastingL[0], mgrs_northingL[0]);
2120       xastir_snprintf(grid_label1,
2121                       sizeof(grid_label1),
2122                       "%s %s %05.0f %05.0f",
2123                       mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing);
2124       if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0)
2125       {
2126 //             mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
2127       }
2128       else
2129       {
2130 //             mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
2131       }
2132     }
2133     else
2134     {
2135       char easting_str[10];
2136       char northing_str[10];
2137 
2138       xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting);
2139       xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing);
2140       strcpy(grid_label1, zone_str);
2141       grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2142       strcat(grid_label1, easting_str);
2143       grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2144       strcat(grid_label1, northing_str);
2145       grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2146     }
2147     // Write metadata on upper border of map.
2148     //"XASTIR Map of %s (upper left) to %s (lower right).  UTM zones, %s datum. ",
2149     xastir_snprintf(top_label,
2150                     sizeof(top_label),
2151                     langcode("MDATA003"),
2152                     grid_label,grid_label1,metadata_datum);
2153     draw_rotated_label_text_to_target (w, 270,
2154                                        border_width+2,
2155                                        border_width-1,
2156                                        sizeof(top_label),colors[0x10],top_label,FONT_BORDER,
2157                                        pixmap_final,
2158                                        outline_border_labels, colors[outline_border_labels_color]);
2159     // Crudely identify zone boundaries by
2160     // iterating across bottom border.
2161     xastir_snprintf(zone_str2,
2162                     sizeof(zone_str2),
2163                     "%s"," ");
2164     for (x=1; x<(screen_width - border_width); x++)
2165     {
2166       xx2 = NW_corner_longitude  + (x * scale_x);
2167       yy2 = NW_corner_latitude   + ((screen_height - border_width) * scale_y);
2168       convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2169                             xx2, yy2);
2170       zone_str[strlen(zone_str)-1] = '\0';
2171       if (strcmp(zone_str,zone_str2) !=0)
2172       {
2173         draw_rotated_label_text_to_target (w, 270,
2174                                            x + 1,
2175                                            screen_height,
2176                                            sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER,
2177                                            pixmap_final,
2178                                            outline_border_labels, colors[outline_border_labels_color]);
2179       }
2180       xastir_snprintf(zone_str2,
2181                       sizeof(zone_str2),
2182                       "%s",zone_str);
2183     }
2184     // Crudely identify zone letters by iterating down left border
2185     for (y=(border_width*2); y<(screen_height - border_width); y++)
2186     {
2187       xx2 = NW_corner_longitude   + (border_width * scale_x);
2188       yy2 = NW_corner_latitude   + (y * scale_y);
2189       convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2190                             xx2, yy2);
2191       zone_str[0] = zone_str[strlen(zone_str)-1];
2192       zone_str[1] = '\0';
2193       if (strcmp(zone_str,zone_str2) !=0)
2194       {
2195         draw_rotated_label_text_to_target (w, 270,
2196                                            1,
2197                                            y,
2198                                            sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER,
2199                                            pixmap_final,
2200                                            outline_border_labels, colors[outline_border_labels_color]);
2201       }
2202       xastir_snprintf(zone_str2,
2203                       sizeof(zone_str2),
2204                       "%s",zone_str);
2205     }
2206   } // end if draw labeled border
2207 
2208   // Set the line width and style in the GC to 1 pixel wide for
2209   // drawing the smaller grid
2210   (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt,JoinMiter);
2211 
2212 //fprintf(stderr,"draw_major_utm_mgrs_grid end\n");
2213 
2214 } // End of draw_major_utm_mgrs_grid()
2215 
2216 
2217 
2218 
2219 
2220 // This is the function which actually draws a minor UTM grid.
2221 // Called by draw_minor_utm_mgrs_grid() function below.
2222 // draw_minor_utm_mgrs_grid() is the function which calculates the
2223 // grid points.
2224 //
actually_draw_utm_minor_grid(Widget w)2225 void actually_draw_utm_minor_grid(Widget w)
2226 {
2227 
2228 
2229   int border_width;           // Width of the border to draw labels into.
2230   int numberofzones = 0;      // number of elements in utm_grid.zone[] that are used
2231   int Zone;
2232   int ii;
2233   int easting_color;          // Colors for the grid labels
2234   int northing_color;
2235   int zone_color;             // zone label color
2236   int label_on_left;          // if true, draw northing labels on left
2237   long xx, yy, xx2, yy2;
2238   char zone_str[10];
2239   char zone_str2[10];
2240   double easting, northing;
2241   int short_width_pixels = 0; // Width of an unrotated string of five_zeroes in the border font in pixels.
2242   int string_width_pixels = 0;// Width of an unrotated string of seven_zeroes in the border font in pixels.
2243   char metadata_datum[6];
2244   char grid_label[25];        // String to draw labels on grid lines
2245   char grid_label1[25];       // String to draw latlong metadata
2246   char top_label[180];        // String to draw metadata on top border
2247   int grid_spacing_pixels;    // Spacing of fine grid lines in pixels.
2248   int bottom_point;           // utm_grid.zone[].col[].npoints can extend past the
2249   // bottom of the screen, this is the lowest point in the
2250   // points array that is on the screen.
2251   int  skip_alternate_label;  // Skip alternate easting and northing labels
2252   // if they would overlap on the
2253   // display.
2254   int last_line_labeled;      // Marks lines that were labeled
2255   // when alternate lines are not
2256   // being labeled.
2257 
2258   // variables to support components of MGRS strings
2259   char mgrs_zone[4] = "   ";   // MGRS zone letter
2260   char mgrs_eastingL[3] = "  ";
2261   char mgrs_northingL[3] = "  ";
2262   unsigned int int_utmEasting;
2263   unsigned int int_utmNorthing;
2264   char mgrs_space_string[4] = "   ";
2265   int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
2266   char mgrs_ul_digraph[3] = "  ";  // MGRS digraph for upper left corner of screen
2267   char mgrs_lr_digraph[3] = "  ";  // MGRS digraph for lower right corner of screen
2268 
2269   if (!long_lat_grid) // We don't wish to draw a map grid
2270   {
2271     return;
2272   }
2273 
2274   // OLD: Draw grid in dashed white lines.
2275   // NEW: Tint the lines as they go along, making them appear
2276   // no matter what color is underneath.
2277   (void)XSetForeground(XtDisplay(w), gc_tint, colors[0x27]);
2278 
2279   // Note:  npoints can be negative here!  Make sure our code
2280   // checks for that.  Initially npoints was an unsigned int.
2281   // Changed it to an int so that we can get and check for
2282   // negative values, bypassing segfaults.
2283   //
2284   numberofzones = 0;
2285 
2286   // Determine the width of the border
2287   border_width = get_border_width(w);
2288   // Determine some parameters used in drawing the border.
2289   string_width_pixels = get_standard_border_string_width_pixels(w, 7);
2290   short_width_pixels = get_standard_border_string_width_pixels(w,5);
2291 
2292   for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++)
2293   {
2294 
2295     if (utm_grid.zone[Zone].ncols > 0)
2296     {
2297       // find out how many zones are actually drawn on the map
2298       numberofzones++;
2299     }
2300   }
2301 
2302   for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++)
2303   {
2304 
2305     for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++)
2306     {
2307       if (utm_grid.zone[Zone].col[ii].npoints > 1)
2308       {
2309 
2310         // We need to check for points that are more
2311         // than +/- 16383.  If we have any, it can cause
2312         // X11 to lock up for a while drawing lots of
2313         // extra lines, due to bugs in X11.  We do that
2314         // checking above with xx and yy.
2315         //
2316         (void)XDrawLines(XtDisplay(w),
2317                          pixmap_final,
2318                          gc_tint,
2319                          utm_grid.zone[Zone].col[ii].points,
2320                          l16(utm_grid.zone[Zone].col[ii].npoints),
2321                          CoordModeOrigin);
2322       }
2323     }
2324 
2325     for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++)
2326     {
2327       if (utm_grid.zone[Zone].row[ii].npoints > 1)
2328       {
2329 
2330         // We need to check for points that are more
2331         // than +/- 16383.  If we have any, it can cause
2332         // X11 to lock up for a while drawing lots of
2333         // extra lines, due to bugs in X11.  We do that
2334         // checking above with xx and yy.
2335         //
2336         (void)XDrawLines(XtDisplay(w),
2337                          pixmap_final,
2338                          gc_tint,
2339                          utm_grid.zone[Zone].row[ii].points,
2340                          l16(utm_grid.zone[Zone].row[ii].npoints),
2341                          CoordModeOrigin);
2342       }
2343     }
2344 
2345     // Check each of the 4 possible utm_grid.zone array elements
2346     // that might contain a grid, and label the grid if it exists.
2347     if (utm_grid.zone[Zone].nrows>0 && utm_grid.zone[Zone].ncols>0)
2348     {
2349       if (draw_labeled_grid_border==TRUE)
2350       {
2351         // Label the UTM grid on the border.
2352         // Since the coordinate of the current mouse pointer position is
2353         // continually updated, labeling the grid is primarily for the
2354         // purpose of printing maps and saving screenshots.
2355         //
2356         // ******* Doesn't work properly near poles when 3 zones are on screen
2357         // ******* (e.g. 13,14,15) - overlaps northings for 14 and 15.
2358         // ******* Doesn't clearly distinguish one zone with 2 lettered rows
2359         // ******* (e.g. 18T,18U) needs color distinction between northings
2360         // ******* to indicate which northings are in which lettered row.
2361         //
2362 
2363         // Default labels for just one zone on screen are black text for
2364         // zone at lower left corner, eastings on bottom, and northings
2365         // at right.
2366         // Idea is to normally start at the lower left corner
2367         // users can then easily follow left to right to get easting,
2368         // and bottom to top to get northing.
2369         // For two zones, second zone uses blue text for eastings and northings.
2370         easting_color = 0x08;  // black text
2371         northing_color = 0x08; // black text
2372         zone_color = 0x08;     // black text
2373         // 0x09=blue (0x0e=yellow works well with outline, but not without).
2374         label_on_left = FALSE;
2375 
2376         // Find out what the map datum is.
2377         get_horizontal_datum(metadata_datum, sizeof(metadata_datum));
2378 
2379         if (numberofzones>1)
2380         {
2381           // check to see if the upper left and lower left corners are in the same zone
2382           // if not, label the upper left corner
2383           xx = (border_width * scale_x) + NW_corner_longitude;
2384           yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude;
2385           convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2386           yy = (border_width * scale_y) + NW_corner_latitude;
2387           convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy);
2388           if (strcmp(zone_str,zone_str2)!=0)
2389           {
2390             xastir_snprintf(grid_label,
2391                             sizeof(grid_label),
2392                             "%s",
2393                             zone_str2);
2394             //draw_nice_string(w,pixmap_final,0,
2395             //    border_width+2,
2396             //    (2*border_width)+2,
2397             //    grid_label,
2398             //    0x10,zone_color,(int)strlen(grid_label));
2399             draw_rotated_label_text_to_target (w, 270,
2400                                                border_width+2,
2401                                                (2*border_width)+2,
2402                                                sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER,
2403                                                pixmap_final,
2404                                                1, colors[0x0f]);
2405           }
2406           if (strcmp(zone_str,zone_str2)!=0)
2407           {
2408             xastir_snprintf(grid_label,
2409                             sizeof(grid_label),
2410                             "%s",
2411                             zone_str);
2412             draw_rotated_label_text_to_target (w, 270,
2413                                                border_width+2,
2414                                                screen_height - (2*border_width) - 2,
2415                                                sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER,
2416                                                pixmap_final,
2417                                                1, colors[0x0f]);
2418           }
2419           zone_color = 0x09;
2420           // likewise for upper and lower right corners
2421           xx = ((screen_width - border_width) * scale_x) + NW_corner_longitude;
2422           yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude;
2423           convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2424           yy = (border_width * scale_y) + NW_corner_latitude;
2425           convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy);
2426           if (strcmp(zone_str,zone_str2)!=0)
2427           {
2428             xastir_snprintf(grid_label,
2429                             sizeof(grid_label),
2430                             "%s",
2431                             zone_str2);
2432             //draw_nice_string(w,pixmap_final,0,
2433             //    screen_width - (border_width * 3) ,
2434             //    (2*border_width)+2,
2435             //    grid_label,
2436             //    0x10,zone_color,(int)strlen(grid_label));
2437             draw_rotated_label_text_to_target (w, 270,
2438                                                screen_width - (border_width * 3),
2439                                                (2*border_width)+2,
2440                                                sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER,
2441                                                pixmap_final,
2442                                                1, colors[0x0f]);
2443           }
2444           if (strcmp(zone_str,zone_str2)!=0)
2445           {
2446             xastir_snprintf(grid_label,
2447                             sizeof(grid_label),
2448                             "%s",
2449                             zone_str);
2450             draw_rotated_label_text_to_target (w, 270,
2451                                                screen_width - (border_width * 3),
2452                                                screen_height - (2*border_width) - 2,
2453                                                sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER,
2454                                                pixmap_final,
2455                                                1, colors[0x0f]);
2456           }
2457 
2458           // are we currently the same zone as the upper left corner
2459           // if so, we need to place the northing labels on the left side
2460           xx = (utm_grid.zone[Zone].col[0].points[0].x * scale_x) + NW_corner_longitude;
2461           yy = (utm_grid.zone[Zone].col[0].points[0].y * scale_y) + NW_corner_latitude;
2462           convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2463           convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), NW_corner_longitude, NW_corner_latitude);
2464           if (strcmp(zone_str,zone_str2)==0)
2465           {
2466             northing_color = 0x08;  // 0x08 = black, same as lower left easting
2467             label_on_left = TRUE;
2468           }
2469 
2470         }
2471         // check to see if there is a horizontal boundary
2472         // compare xone of upper left and lower left corners
2473         convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), NW_corner_longitude, NW_corner_latitude);
2474 
2475         // Overwrite defaults as appropriate and
2476         // label zones differently if more than one appears on the screen.
2477 
2478         if (Zone > 0)
2479         {
2480           // write the zone label on the bottom border
2481           zone_color = 0x09;     // blue
2482           easting_color = 0x09;  // blue
2483           northing_color = 0x09; // blue
2484           xx2 = utm_grid.zone[Zone].col[0].points[0].x;
2485           xx = (xx2 * scale_x) + NW_corner_longitude;
2486           yy2 = utm_grid.zone[Zone].col[0].points[utm_grid.zone[Zone].col[0].npoints-1].y;
2487           yy = (yy2 * scale_y) +  NW_corner_latitude;
2488           convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx,yy);
2489           xastir_snprintf(grid_label,
2490                           sizeof(grid_label),
2491                           "%s",
2492                           zone_str);
2493           draw_rotated_label_text_to_target (w, 270,
2494                                              xx2,
2495                                              screen_height,
2496                                              sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER,
2497                                              pixmap_final,
2498                                              outline_border_labels, colors[outline_border_labels_color]);
2499           //draw_nice_string(w,pixmap_final,0,
2500           //    xx2,
2501           //    screen_height - 2,
2502           //    grid_label,
2503           //    0x10,zone_color,(int)strlen(grid_label));
2504         }
2505 
2506         if (Zone==0)
2507         {
2508           // write the zone of the lower left corner of the map
2509           xx = (border_width * scale_x) + NW_corner_longitude;
2510           yy = ((screen_height - border_width) * scale_y) +  NW_corner_latitude;
2511           convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2512           xastir_snprintf(grid_label,
2513                           sizeof(grid_label),
2514                           "%s",
2515                           zone_str);
2516           draw_rotated_label_text_to_target (w, 270,
2517                                              1,
2518                                              screen_height,
2519                                              sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER,
2520                                              pixmap_final,
2521                                              outline_border_labels, colors[outline_border_labels_color]);
2522           //draw_nice_string(w,pixmap_final,0,
2523           //    1,
2524           //    screen_height - 2,
2525           //    grid_label,
2526           //    0x10,0x20,(int)strlen(grid_label));
2527         }
2528         // Put metadata in top border.
2529         // find location of upper left corner of map, convert to UTM
2530         xx2 = NW_corner_longitude  + (border_width * scale_x);
2531         yy2 = NW_corner_latitude   + (border_width * scale_y);
2532         convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2533                               xx2, yy2);
2534         if (coordinate_system == USE_MGRS)
2535         {
2536           convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2537                                                 mgrs_eastingL,   sizeof(mgrs_eastingL),
2538                                                 mgrs_northingL,  sizeof(mgrs_northingL),
2539                                                 &int_utmEasting, &int_utmNorthing,
2540                                                 xx2, yy2,
2541                                                 0, mgrs_space_string, strlen(mgrs_space_string));
2542           xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph),
2543                           "%c%c", mgrs_eastingL[0], mgrs_northingL[0]);
2544           xastir_snprintf(grid_label,
2545                           sizeof(grid_label),
2546                           "%s %s %05.0f %05.0f",
2547                           mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing);
2548         }
2549         else
2550         {
2551           char easting_str[10];
2552           char northing_str[10];
2553 
2554           xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting);
2555           xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing);
2556           strcpy(grid_label, zone_str);
2557           grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2558           strcat(grid_label, easting_str);
2559           grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2560           strcat(grid_label, northing_str);
2561           grid_label[sizeof(grid_label)-1] = '\0';  // Terminate string
2562         }
2563         // find location of lower right corner of map, convert to UTM
2564         xx2 = NW_corner_longitude  + ((screen_width - border_width) * scale_x);
2565         yy2 = NW_corner_latitude   + ((screen_height - border_width) * scale_y);
2566         convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str),
2567                               xx2, yy2);
2568         if (coordinate_system == USE_MGRS)
2569         {
2570           convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2571                                                 mgrs_eastingL,   sizeof(mgrs_eastingL),
2572                                                 mgrs_northingL,  sizeof(mgrs_northingL),
2573                                                 &int_utmEasting, &int_utmNorthing,
2574                                                 xx2, yy2,
2575                                                 0, mgrs_space_string, strlen(mgrs_space_string));
2576           xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph),
2577                           "%c%c", mgrs_eastingL[0], mgrs_northingL[0]);
2578           xastir_snprintf(grid_label1,
2579                           sizeof(grid_label1),
2580                           "%s %s %05.0f %05.0f",
2581                           mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing);
2582           if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0)
2583           {
2584             mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
2585           }
2586           else
2587           {
2588             mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same.
2589           }
2590         }
2591         else
2592         {
2593           char easting_str[10];
2594           char northing_str[10];
2595 
2596           xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting);
2597           xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing);
2598           strcpy(grid_label1, zone_str);
2599           grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2600           strcat(grid_label1, easting_str);
2601           grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2602           strcat(grid_label1, northing_str);
2603           grid_label1[sizeof(grid_label1)-1] = '\0';  // Terminate string
2604         }
2605         //"XASTIR Map of %s (upper left) to %s (lower right).  UTM %d m grid, %s datum. ",
2606         xastir_snprintf(top_label,
2607                         sizeof(top_label),
2608                         langcode("MDATA001"),
2609                         grid_label,grid_label1,utm_grid_spacing_m,metadata_datum);
2610         //draw_nice_string(w,pixmap_final,0,
2611         //    border_width+2,
2612         //    border_width-2,
2613         //    top_label,
2614         //    0x10,0x20,(int)strlen(top_label));
2615         draw_rotated_label_text_to_target (w, 270,
2616                                            border_width+2,
2617                                            border_width-1,
2618                                            sizeof(top_label),colors[0x10],top_label,FONT_BORDER,
2619                                            pixmap_final,
2620                                            outline_border_labels, colors[outline_border_labels_color]);
2621 
2622         // deterimne whether the easting and northing strings will fit
2623         // in a grid box, or whether easting strings in adjacent boxes
2624         // will overlap (so that alternate strings can be skipped).
2625         if (utm_grid.zone[Zone].ncols > 1)
2626         {
2627           // find out the number of pixels beteen two grid lines
2628           grid_spacing_pixels =
2629             utm_grid.zone[Zone].col[1].points[0].x  -
2630             utm_grid.zone[Zone].col[0].points[0].x;
2631 
2632           if (grid_spacing_pixels == 0)
2633           {
2634             grid_spacing_pixels = -1;  // Skip
2635           }
2636 
2637         }
2638         else
2639         {
2640           // only one column in this zone, skip alternate doesn't matter
2641           grid_spacing_pixels = -1;
2642         }
2643 
2644         // Is truncated easting or northing larger than grid spacing?
2645         // If so, skip alternate labels
2646         // short_width_pixels+2 seems to work well.
2647         if (short_width_pixels+2>grid_spacing_pixels)
2648         {
2649           skip_alternate_label = TRUE;
2650         }
2651         else
2652         {
2653           skip_alternate_label = FALSE;
2654         }
2655 
2656         // Label the grid lines on the border.
2657         // Put easting along the bottom for easier correct ordering of easting and northing
2658         // by people who are reading the map.
2659         last_line_labeled = FALSE;
2660         for (ii=1; ii < (int)utm_grid.zone[Zone].ncols; ii++)
2661         {
2662           // label meridianal grid lines with easting
2663 
2664           if (utm_grid.zone[Zone].col[ii].npoints > 1)
2665           {
2666 
2667             // adjust up in case npoints goes far below the screen
2668             if (grid_spacing_pixels == 0)
2669             {
2670               continue;  // Go to next iteration of for loop
2671             }
2672 
2673             bottom_point = (int)(screen_height/grid_spacing_pixels);
2674 
2675             if (bottom_point >= utm_grid.zone[Zone].col[ii].npoints)
2676             {
2677               bottom_point = utm_grid.zone[Zone].col[ii].npoints - 1;
2678             }
2679             if (skip_alternate_label==TRUE && last_line_labeled==TRUE)
2680             {
2681               last_line_labeled = FALSE;
2682             }
2683             else
2684             {
2685               xx = (utm_grid.zone[Zone].col[ii].points[bottom_point].x * scale_x) + NW_corner_longitude;
2686               yy = (utm_grid.zone[Zone].col[ii].points[bottom_point].y * scale_y) + NW_corner_latitude;
2687               convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2688               // To display full precision to one meter, use:
2689               //xastir_snprintf(grid_label,
2690               //    sizeof(grid_label),
2691               //    "%06.0f0",
2692               //    (float)((utm_grid_spacing_m/10) * roundf(easting/(utm_grid_spacing_m))));
2693               //
2694               // Divide easting by utm_grid_spacing to make sure the line is labeled
2695               // correctly, and not a few meters off, and truncate to at least 100 m.
2696               xastir_snprintf(grid_label,
2697                               sizeof(grid_label),
2698                               "%05.0f",
2699                               (float)((utm_grid_spacing_m/100) * roundf(easting/(utm_grid_spacing_m))));
2700               // truncate the label to an appropriate level of precision for the grid
2701               if (utm_grid_spacing_m ==1000)
2702               {
2703                 grid_label[4] = ' ';
2704               }
2705               if (utm_grid_spacing_m ==10000)
2706               {
2707                 grid_label[3] = ' ';
2708                 grid_label[4] = ' ';
2709               }
2710               if (utm_grid_spacing_m ==100000)
2711               {
2712                 grid_label[2] = ' ';
2713                 grid_label[3] = ' ';
2714                 grid_label[4] = ' ';
2715               }
2716               if (coordinate_system == USE_MGRS)
2717               {
2718                 convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2719                                                       mgrs_eastingL,   sizeof(mgrs_eastingL),
2720                                                       mgrs_northingL,  sizeof(mgrs_northingL),
2721                                                       &int_utmEasting, &int_utmNorthing,
2722                                                       xx, yy,
2723                                                       0, mgrs_space_string, strlen(mgrs_space_string));
2724                 grid_label[0] = mgrs_eastingL[0];
2725                 grid_label[1] = mgrs_northingL[0];
2726                 if (mgrs_single_digraph==FALSE)
2727                 {
2728                   grid_label[1] = '_';
2729                 }
2730               }
2731               // draw each number at the bottom of the screen just to the right of the
2732               // relevant grid line at its location at the bottom of the screen
2733               //draw_nice_string(w,pixmap_final,0,
2734               //    utm_grid.zone[Zone].col[i].points[bottom_point].x+1,
2735               //    screen_height-2,
2736               //    grid_label,
2737               //    0x10,easting_color,(int)strlen(grid_label));
2738 
2739               // Don't overwrite the zone label, half the seven zeros string should give it room.
2740               // Don't draw the label if it will go off the left edge fo the screen.
2741               if ((utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 > (string_width_pixels/2))
2742                   && (utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 < (screen_width - string_width_pixels))
2743                  )
2744               {
2745                 // ok to draw the label
2746                 last_line_labeled = TRUE;
2747                 draw_rotated_label_text_to_target (w, 270,
2748                                                    utm_grid.zone[Zone].col[ii].points[bottom_point].x+1,
2749                                                    screen_height,
2750                                                    sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER,
2751                                                    pixmap_final,
2752                                                    outline_border_labels, colors[outline_border_labels_color]);
2753               }
2754             }
2755           }
2756         }
2757         last_line_labeled = FALSE;
2758         // put northing along the right border, again for easier correct ordering of easting and northing.
2759         for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++)
2760         {
2761           // label latitudinal grid lines with northing
2762           if (utm_grid.zone[Zone].row[ii].npoints > 1)
2763           {
2764             if (skip_alternate_label==TRUE && last_line_labeled==TRUE)
2765             {
2766               last_line_labeled = FALSE;
2767             }
2768             else
2769             {
2770               if (label_on_left==TRUE)
2771               {
2772                 xx = (utm_grid.zone[Zone].row[ii].points[0].x * scale_x) + NW_corner_longitude;
2773               }
2774               else
2775               {
2776                 xx = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].x * scale_x) + NW_corner_longitude;
2777               }
2778               yy = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y * scale_y) +  NW_corner_latitude;
2779               convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy);
2780               // To display to full 1 meter precision use:
2781               //xastir_snprintf(grid_label,
2782               //    sizeof(grid_label),
2783               //    "%06.0f0",
2784               //    (float)((utm_grid_spacing_m/10) * roundf(northing/(utm_grid_spacing_m))));
2785               //
2786               // Divide northing by utm grid spacing to make sure the line is labeled correctly
2787               // and displays zeroes in its least significant digits, and truncate to 100 m
2788               xastir_snprintf(grid_label,
2789                               sizeof(grid_label),
2790                               "%05.0f",
2791                               (float)((utm_grid_spacing_m/100) * roundf(northing/(utm_grid_spacing_m))));
2792               if (utm_grid_spacing_m ==1000)
2793               {
2794                 grid_label[4] = ' ';
2795               }
2796               if (utm_grid_spacing_m ==10000)
2797               {
2798                 grid_label[3] = ' ';
2799                 grid_label[4] = ' ';
2800               }
2801               if (utm_grid_spacing_m ==100000)
2802               {
2803                 grid_label[2] = ' ';
2804                 grid_label[3] = ' ';
2805                 grid_label[4] = ' ';
2806               }
2807               if (coordinate_system == USE_MGRS)
2808               {
2809                 convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone),
2810                                                       mgrs_eastingL,   3,
2811                                                       mgrs_northingL,  3,
2812                                                       &int_utmEasting, &int_utmNorthing,
2813                                                       xx, yy,
2814                                                       0, mgrs_space_string, strlen(mgrs_space_string));
2815                 grid_label[0] = mgrs_eastingL[0];
2816                 if (mgrs_single_digraph==FALSE)
2817                 {
2818                   grid_label[0] = '_';
2819                 }
2820                 grid_label[1] = mgrs_northingL[0];
2821               }
2822               // Draw northing labels.
2823               // Draw each number just above the relevant grid line along the right side
2824               // of the screen.  Don't write in the bottom border or off the top of the screen.
2825               if (label_on_left==TRUE)
2826               {
2827                 // label northings on left border
2828                 // don't overwrite the zone designator in  the lower left border
2829                 if ((utm_grid.zone[Zone].row[ii].points[0].y < (screen_height - border_width))
2830                     &&
2831                     (utm_grid.zone[Zone].row[ii].points[0].y > (string_width_pixels))
2832                    )
2833                 {
2834                   last_line_labeled = TRUE;
2835                   draw_rotated_label_text_to_target (w, 180,
2836                                                      border_width,
2837                                                      utm_grid.zone[Zone].row[ii].points[0].y,
2838                                                      sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER,
2839                                                      pixmap_final,
2840                                                      outline_border_labels, colors[outline_border_labels_color]);
2841                 }
2842               }
2843               else
2844               {
2845                 if (((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1)
2846                      < (screen_height - border_width))
2847                     &&
2848                     ((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1)
2849                      > (string_width_pixels))
2850                    )
2851                 {
2852                   // label northings on right border
2853                   last_line_labeled = TRUE;
2854                   draw_rotated_label_text_to_target (w, 180,
2855                                                      screen_width,
2856                                                      utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1,
2857                                                      sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER,
2858                                                      pixmap_final,
2859                                                      outline_border_labels, colors[outline_border_labels_color]);
2860                 }
2861               }
2862             }
2863           }
2864         } // for i=0 to nrows
2865       } // if draw labeled grid border
2866     } // if utm_grid.zone[Zone] is non-empty
2867   } // for each zone in utm_grid.zone
2868 } // End of actually_draw_utm_minor_grid() function
2869 
2870 
2871 
2872 
2873 
2874 // Calculate the minor UTM grids.  Called by draw_grid() below.
2875 // This function calculates and caches a within-zone UTM grid
2876 // for the current map view if one does not allready exist, it
2877 // then calls actually_draw_utm_minor_grid() function above to do
2878 // the drawing once the grid has been calculated.  Zone boundaries
2879 // are drawn separately by draw_major_utm_mgrs_grid().
2880 //
2881 // This routine appears to draw most of the UTM/UPS grid ok, with
2882 // the exceptions of:
2883 //
2884 // 1) Sometimes fails to draw vertical lines nearest zone
2885 //    boundaries.
2886 // 2) Lines connect across zone boundaries in an incorrect manner,
2887 //    jumping up one grid interval across the boundary.
2888 // 3) Segfaults near the special zone intersections as you zoom in.
2889 //
2890 // The code currently creates a col and row array per zone visible,
2891 // with XPoints malloced that contain the grid intersections in
2892 // screen coordinates.  If the screen is zoomed or panned they are
2893 // recalculated.
2894 //
2895 // Perhaps we could do the same but with lat/long coordinates in the
2896 // future so that we'd only have to recalculate when a new Zone came
2897 // into view.  We'd use the lat/long vector drawing programs above
2898 // then, with a possible slowdown due to more calculations if we're
2899 // not moving around.
2900 //
2901 // Returns: 0 if successful or nothing to draw
2902 //          1 if malloc error
2903 //          2 if iterations error
2904 //          3 if out of zones
2905 //          4 if realloc failure
2906 //
draw_minor_utm_mgrs_grid(Widget w)2907 int draw_minor_utm_mgrs_grid(Widget w)
2908 {
2909 
2910   long xx, yy, xx1, yy1;
2911   double e[4], n[4];
2912   char place_str[10], zone_str[10];
2913   int done = 0;
2914   int z1, z2, Zone, col, col_point, row, row_point, row_point_start;
2915   int iterations = 0;
2916   int finished_with_current_zone = 0;
2917   int ii, jj;
2918   float slope;
2919   int coordinate_system_backup = coordinate_system;
2920 
2921 
2922   col = 0;
2923   row = 0;
2924   col_point = 0;
2925   row_point = 0;
2926   row_point_start = 0;
2927   Zone = 0;
2928 
2929   // Set up for drawing zone grid(s)
2930   if (scale_x < 15)
2931   {
2932     utm_grid_spacing_m =    100;
2933   }
2934   else if (scale_x < 150)
2935   {
2936     utm_grid_spacing_m =   1000;
2937   }
2938   else if (scale_x < 1500)
2939   {
2940     utm_grid_spacing_m =  10000;
2941   }
2942   else if (scale_x < 3000)
2943   {
2944     utm_grid_spacing_m = 100000;
2945   }
2946   else
2947   {
2948     utm_grid_spacing_m = 0;
2949     // All done!  Don't draw the minor grids.  Major grids
2950     // have already been drawn by this point.
2951     return(0);
2952   }
2953 
2954   // Check hash to see if utm_grid is already set up
2955   if (utm_grid.hash.ul_x == NW_corner_longitude &&
2956       utm_grid.hash.ul_y == NW_corner_latitude &&
2957       utm_grid.hash.lr_x == SE_corner_longitude &&
2958       utm_grid.hash.lr_y == SE_corner_latitude)
2959   {
2960 
2961     // XPoint arrays are already set up.  Go draw the grid.
2962     actually_draw_utm_minor_grid(w);
2963 
2964     return(0);
2965   }
2966 
2967 
2968 // If we get to this point, we need to re-create the minor UTM/MGRS
2969 // grids as they haven't been set up yet or they don't match the
2970 // current view.
2971 
2972 
2973   // Clear the minor UTM/MGRS grid arrays.  Alloc space for
2974   // the points in the grid structure.
2975   if (utm_grid_clear(1))
2976   {
2977     // If we got here, we had a problem with malloc's
2978     return(1);
2979   }
2980 
2981   // Find top left point of current view
2982   xx = NW_corner_longitude;
2983   yy = NW_corner_latitude;
2984 
2985   // Note that the minor grid depends on the STANDARD six degree
2986   // UTM zones, not the UTM-Special/MGRS zones.  Force our
2987   // calculations to use the standard zones.
2988   coordinate_system = USE_UTM;
2989   convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy);
2990   coordinate_system = coordinate_system_backup;
2991 
2992   n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere
2993 
2994 
2995 // Select starting point, NW corner of NW zone
2996 
2997   // Move the coordinates to the nearest subgrid intersection,
2998   // based on our current grid spacing.  The grid intersection
2999   // we calculate here is northwest of our view's northwest
3000   // corner.
3001   e[0] /= utm_grid_spacing_m;
3002   e[0]  = (double)((int)e[0] * utm_grid_spacing_m);
3003   n[0] /= utm_grid_spacing_m;
3004   n[0]  = (double)((int)n[0] * utm_grid_spacing_m);
3005   n[0] += utm_grid_spacing_m;
3006 
3007 
3008 //WE7U
3009 // It appears that the horizontal grid lines get messed up in cases
3010 // where the top horizontal line isn't in view on it's left end.
3011 // That's a major clue!  Read the comment below (again with a "WE7U"
3012 // tag).  The problem occurs at the point where we copy the last
3013 // point from the previous grid over to the first point of a new
3014 // grid.  That can cause us to be off by one, as for the grid on the
3015 // left, the top horizontal line _is_ in view on the left.  We end
3016 // up connecting the wrong horizontal lines together because of this
3017 // mismatch, but again, only if the top horizontal line on the left
3018 // grid is above the current view.
3019 //
3020 // It also appears that the vertical lines that are missing in some
3021 // cases are on the right of the zone boundary.  This is probably
3022 // because the top of that line doesn't go to the top of the view.
3023 // On views where it does, the line is drawn.  I assume this is
3024 // because we're drawing from NW corner to the right, and then down,
3025 // which would cause that line to be skipped if it's not present on
3026 // the first line?
3027 
3028 
3029   e[1] = e[0];
3030   n[1] = n[0];
3031 
3032 
3033 
3034 
3035 
3036 /////////////////////////////////////////////////////////////////////
3037 /////////////////////////////////////////////////////////////////////
3038   // Start filling in the row/column arrays of grid intersections
3039   while (!done)
3040   {
3041     XPoint *temp_point;
3042 
3043 
3044     // Here's our escape in case we get stuck in this loop.
3045     // We can go through this loop multiple times for each
3046     // zone though, depending on our grid spacing.  64 rows * 64
3047     // colums * 8 points each = 32768, which gives us our upper
3048     // limit.
3049     if (iterations++ > 32768)
3050     {
3051       fprintf(stderr,
3052               "draw_minor_utm_mgrs_grid() looped too many times, escaping.\n");
3053       utm_grid_clear(1);
3054       return(2);
3055     }
3056 
3057 
3058     if (finished_with_current_zone)
3059     {
3060       // Set up to compute the next zone
3061 
3062       xx = NW_corner_longitude + ((utm_grid.zone[Zone].boundary_x + 1) * scale_x);
3063 
3064       yy = NW_corner_latitude;
3065 
3066       // Note that the minor grid depends on the STANDARD six
3067       // degree UTM zones, not the UTM-Special/MGRS zones.
3068       // Force our calculations to use the standard zones.
3069       coordinate_system = USE_UTM;
3070       convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy);
3071       coordinate_system = coordinate_system_backup;
3072 
3073       n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere
3074 
3075 // Fix the coordinates to the nearest subgrid intersection based on
3076 // our current grid spacing.  Bump both the easting and northing up
3077 // by one subgrid.
3078       e[0] /= utm_grid_spacing_m;
3079       e[0]  = (double)((int)e[0] * utm_grid_spacing_m);
3080       e[0] += utm_grid_spacing_m;
3081       n[0] /= utm_grid_spacing_m;
3082       n[0]  = (double)((int)n[0] * utm_grid_spacing_m);
3083       n[0] += utm_grid_spacing_m;
3084 
3085       e[1] = e[0];
3086       n[1] = n[0];
3087 
3088 #ifdef UTM_DEBUG
3089       fprintf(stderr,"\nFinished Zone=%d\n", Zone);
3090 #endif
3091 
3092       // We're all done with the current zone.  Increment
3093       // to the next zone and set up to calculate its
3094       // points.
3095       Zone++;
3096 
3097 #ifdef UTM_DEBUG
3098       fprintf(stderr,"\nstarting Zone=%d, row_point_start=1\n", Zone);
3099 #endif
3100 
3101       row_point = row_point_start = 1;
3102       col = row = col_point = 0;
3103       finished_with_current_zone = 0;
3104 
3105       if (Zone >= UTM_GRID_MAX_ZONES)
3106       {
3107         fprintf(stderr,"Error: Zone=%d: out of zones!\n", Zone);
3108         Zone = 0;
3109         done = 1;
3110         utm_grid_clear(1);
3111         return(3);
3112       }
3113     }   // End of if(finished_with_current_zone)
3114 
3115     // Note that the minor grid depends on the STANDARD six
3116     // degree UTM zones, not the UTM-Special/MGRS zones.  Force
3117     // our calculations to use the standard zones.
3118     coordinate_system = USE_UTM;
3119     convert_UTM_to_xastir(e[1], n[1]-UTM_GRID_EQUATOR, place_str, &xx, &yy);
3120     coordinate_system = coordinate_system_backup;
3121 
3122     xx1 = xx; // Save
3123     yy1 = yy; // Save
3124 
3125     // Note that the minor grid depends on the STANDARD six
3126     // degree UTM zones, not the UTM-Special/MGRS zones.  Force
3127     // our calculations to use the standard zones.
3128     coordinate_system = USE_UTM;
3129     convert_xastir_to_UTM(&e[2], &n[2], zone_str, sizeof(zone_str), xx, yy);
3130     coordinate_system = coordinate_system_backup;
3131 
3132     n[2] += UTM_GRID_EQUATOR;
3133     xx = (xx - NW_corner_longitude) / scale_x;
3134     yy = (yy - NW_corner_latitude)  / scale_y;
3135 
3136     // Not all columns (and maybe rows) will start at point
3137     // 0
3138     if (utm_grid.zone[Zone].col[col].firstpoint == UTM_GRID_RC_EMPTY)
3139     {
3140       utm_grid.zone[Zone].col[col].firstpoint = l16(col_point);
3141 #ifdef UTM_DEBUG
3142       fprintf(stderr,"col[%d] started at point %d\n", col, col_point);
3143 #endif
3144     }
3145     if (utm_grid.zone[Zone].row[row].firstpoint == UTM_GRID_RC_EMPTY)
3146     {
3147       utm_grid.zone[Zone].row[row].firstpoint = l16(row_point);
3148 #ifdef UTM_DEBUG
3149       fprintf(stderr,"row[%d] started at point %d\n", row, row_point);
3150 #endif
3151     }
3152 
3153     // Check to see if we need to alloc more space for
3154     // column points
3155     ii = utm_grid.zone[Zone].col[col].npoints +
3156          utm_grid.zone[Zone].col[col].firstpoint + 1;
3157     if (ii > utm_grid.zone[Zone].col[col].nalloced)
3158     {
3159 #ifdef UTM_DEBUG_ALLOC
3160       fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].col[%d].points, ",
3161               ii, utm_grid.zone[Zone].col[col].nalloced, Zone, col);
3162 #endif
3163       ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED;
3164 #ifdef UTM_DEBUG_ALLOC
3165       fprintf(stderr,"%d)\n", ii);
3166 #endif
3167 
3168       temp_point = realloc(utm_grid.zone[Zone].col[col].points,
3169                            ii * sizeof(XPoint));
3170 
3171       if (temp_point)
3172       {
3173         utm_grid.zone[Zone].col[col].points = temp_point;
3174         utm_grid.zone[Zone].col[col].nalloced = ii;
3175       }
3176       else
3177       {
3178         puts("realloc FAILED!");
3179         (void)utm_grid_clear(1); // Clear arrays and allocate memory for points
3180         return(4);
3181       }
3182     }
3183 
3184     // Check to see if we need to alloc more space for row
3185     // points
3186     ii = utm_grid.zone[Zone].row[row].npoints +
3187          utm_grid.zone[Zone].row[row].firstpoint + 1;
3188     if (ii > utm_grid.zone[Zone].row[row].nalloced)
3189     {
3190 #ifdef UTM_DEBUG_ALLOC
3191       fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].row[%d].points, ",
3192               ii, utm_grid.zone[Zone].row[row].nalloced, Zone, row);
3193 #endif
3194       ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED;
3195 #ifdef UTM_DEBUG_ALLOC
3196       fprintf(stderr,"%d)\n", ii);
3197 #endif
3198 
3199       temp_point = realloc(utm_grid.zone[Zone].row[row].points,
3200                            ii * sizeof(XPoint));
3201 
3202       if (temp_point)
3203       {
3204         utm_grid.zone[Zone].row[row].points = temp_point;
3205         utm_grid.zone[Zone].row[row].nalloced = ii;
3206       }
3207       else
3208       {
3209         puts("realloc FAILED!");
3210         (void)utm_grid_clear(1); // Clear arrays and allocate memory for points
3211         return(4);
3212       }
3213     }
3214 
3215     // Here we check to see whether we are inserting points
3216     // that are greater than about +/- 32767.  If so,
3217     // truncate at that.  This prevents XDrawLines() from
3218     // going nuts and drawing hundreds of extra lines.
3219     //
3220     xx = l16(xx);
3221     yy = l16(yy);
3222 
3223     utm_grid.zone[Zone].col[col].points[col_point].x = l16(xx);
3224     utm_grid.zone[Zone].col[col].points[col_point].y = l16(yy);
3225     utm_grid.zone[Zone].col[col].npoints++;
3226     utm_grid.zone[Zone].row[row].points[row_point].x = l16(xx);
3227     utm_grid.zone[Zone].row[row].points[row_point].y = l16(yy);
3228     utm_grid.zone[Zone].row[row].npoints++;
3229 
3230 #ifdef UTM_DEBUG
3231     fprintf(stderr,"utm_grid.zone[%d].col[%d].points[%d] = [ %ld,%ld ] npoints=%d\n",
3232             Zone, col, col_point, xx, yy, utm_grid.zone[Zone].col[col].npoints);
3233     fprintf(stderr,"utm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n",
3234             Zone, row, row_point, xx, yy);
3235 #endif
3236 
3237     col++;
3238     row_point++;
3239     if (col >= UTM_GRID_MAX_COLS_ROWS)
3240     {
3241       finished_with_current_zone++;
3242     }
3243 
3244     z1 = atoi(place_str);
3245     z2 = atoi(zone_str);
3246     if (z1 != z2 || xx > screen_width)   // We hit a boundary
3247     {
3248 
3249 #ifdef UTM_DEBUG_VERB
3250       if (z1 != z2)
3251       {
3252         fprintf(stderr,"Zone boundary! \"%s\" -> \"%s\"\n", place_str, zone_str);
3253       }
3254       else
3255       {
3256         puts("Screen boundary!");
3257       }
3258 #endif
3259 
3260 //#warning
3261 //#warning I suspect that I should not use just col for the following.
3262 //#warning
3263       if (col-2 >= 0)
3264         slope = (float)(yy - utm_grid.zone[Zone].col[col-2].points[col_point].y) /
3265                 (float)(xx - utm_grid.zone[Zone].col[col-2].points[col_point].x + 0.001);
3266       else
3267       {
3268         slope = 0.0;
3269       }
3270 
3271       if (xx > screen_width)
3272       {
3273         xx1 = screen_width;
3274       }
3275       else
3276       {
3277 
3278         // 360,000 Xastir units equals one degree.  This
3279         // code appears to be adjusting xx1 to a major
3280         // zone edge.
3281         xx1 = (xx1 / (6 * 360000)) * 6 * 360000;
3282         xx1 = (xx1 - NW_corner_longitude) / scale_x;
3283       }
3284 
3285       utm_grid.zone[Zone].boundary_x = xx1;
3286       yy1 = yy - (xx - xx1) * slope;
3287 
3288 #ifdef UTM_DEBUG
3289       fprintf(stderr,"_tm_grid.zone[%d].col[%d].points[%d] =  [ %ld,%ld ]\n",
3290               Zone, col-1, col_point, xx1, yy1);
3291       fprintf(stderr,"_tm_grid.zone[%d].row[%d].points[%d] =  [ %ld,%ld ]\n",
3292               Zone, row, row_point-1, xx1, yy1);
3293 #endif
3294 
3295       if (col-1 >= 0 && row_point-1 >= 0)
3296       {
3297         utm_grid.zone[Zone].col[col-1].points[col_point].x = l16(xx1);
3298         utm_grid.zone[Zone].col[col-1].points[col_point].y = l16(yy1);
3299         utm_grid.zone[Zone].row[row].points[row_point-1].x = l16(xx1);
3300         utm_grid.zone[Zone].row[row].points[row_point-1].y = l16(yy1);
3301         if (z1 != z2 && Zone+1 < UTM_GRID_MAX_ZONES)
3302         {
3303           // copy over last points to start off new
3304           // zone
3305 #ifdef UTM_DEBUG
3306           fprintf(stderr,"ztm_grid.zone[%d].row[%d].points[%d] =  [ %ld,%ld ]\n",
3307                   Zone+1, row, 0, xx1, yy1);
3308 #endif
3309 
3310 //WE7U
3311 // This is where we can end up linking up/down one grid width
3312 // between zones!!!  Without it though, we end up have a blank
3313 // section to the right of the zone boundary.  Perhaps we could do
3314 // this here, but when we get the next points calculated, we could
3315 // check to see if we're off by about one grid width in the vertical
3316 // direction.  If so, shift the initial point by that amount?
3317 //
3318 // Another possibility might be to draw bottom-to-top if in northern
3319 // hemisphere, and top-to-bottom if in southern hemisphere.  That
3320 // way we'd have the max amount of lines present when we start, and
3321 // some might peter out as we draw along N/S.  Looking at the
3322 // southern hemisphere right now though, that method doesn't appear
3323 // to work.  We get the same problems there even though we're
3324 // drawing top to bottom.
3325 //
3326           utm_grid.zone[Zone+1].row[row].points[0].x = l16(xx1);
3327           utm_grid.zone[Zone+1].row[row].points[0].y = l16(yy1);
3328           utm_grid.zone[Zone+1].row[row].firstpoint =  0;
3329           utm_grid.zone[Zone+1].row[row].npoints    =  1;
3330         }
3331       }
3332 
3333 
3334       // Check last built row to see if it is all off
3335       // screen
3336       finished_with_current_zone++; // Assume we're done with this zone
3337       for (ii=0; ii < utm_grid.zone[Zone].row[row].npoints; ii++)
3338       {
3339         if (utm_grid.zone[Zone].row[row].points[ii].y <= screen_height)
3340         {
3341           finished_with_current_zone = 0;  // Some points were within the zone, keep computing
3342         }
3343       }
3344 
3345 
3346       e[1]  = e[0];               // carriage return
3347       n[1] -= utm_grid_spacing_m; // line feed
3348 // Yea, your comments are real funny Olivier...  Gets the point
3349 // across though!
3350 
3351 
3352       row++;
3353       if (row >= UTM_GRID_MAX_COLS_ROWS)
3354       {
3355         finished_with_current_zone++;
3356       }
3357 
3358       utm_grid.zone[Zone].ncols = max_i(col, utm_grid.zone[Zone].ncols);
3359       utm_grid.zone[Zone].nrows = max_i(row, utm_grid.zone[Zone].nrows);
3360       col = 0;
3361       row_point = row_point_start;
3362       col_point++;
3363 
3364       if (n[1] < 0)
3365       {
3366         fprintf(stderr,"n[1] < 0\n");
3367         finished_with_current_zone++;
3368       }
3369 
3370       if (finished_with_current_zone && xx > screen_width)
3371       {
3372         done = 1;
3373       }
3374 
3375       // Go to next iteration of while loop (skip next statement)
3376       continue;
3377     }
3378 
3379     e[1] += utm_grid_spacing_m;
3380 
3381   }   // End of while (done) loop
3382 
3383 /////////////////////////////////////////////////////////////////////
3384 /////////////////////////////////////////////////////////////////////
3385 
3386 
3387 
3388 //fprintf(stderr, "After while loop\n");
3389 
3390   // utm_grid.zone[] now contains an array of points marking fine grid
3391   // line intersections for parts of 1 to 4 zones that appear on
3392   // the screen.  Each utm_grid.zone[] is a vertical stripe, and may include
3393   // more than one zone letter, e.g. zone[0] might include 15U and 15T,
3394   // while zone[1] might include 16U and 16T.
3395 
3396 //#define UTM_DEBUG_VERB
3397 
3398   for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++)
3399   {
3400 
3401 #ifdef UTM_DEBUG_VERB
3402     fprintf(stderr,"\nutm_grid.zone[%d].ncols=%d\nutm_grid.zone[%d].nrows=%d\n",
3403             Zone, utm_grid.zone[Zone].ncols, Zone, utm_grid.zone[Zone].nrows);
3404 #endif
3405 
3406     // Cleanup columns
3407     for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++)
3408     {
3409       int np = utm_grid.zone[Zone].col[ii].npoints;
3410       int fp = utm_grid.zone[Zone].col[ii].firstpoint;
3411       int nbp = 0;
3412 
3413 #ifdef UTM_DEBUG_VERB
3414       fprintf(stderr,"utm_grid.zone[%d].col[%d].npoints=%d .firstpoint=%d\n",
3415               Zone, ii, np, fp);
3416       if (np < 2)
3417       {
3418         puts(" Not enough points!");
3419       }
3420       else
3421       {
3422         puts("");
3423       }
3424 
3425       for (jj=fp; jj < fp+np; jj++)
3426       {
3427         fprintf(stderr,"         col[%d].points[%d] = [ %d, %d ]", ii, jj,
3428                 utm_grid.zone[Zone].col[ii].points[jj].x,
3429                 utm_grid.zone[Zone].col[ii].points[jj].y);
3430         if (utm_grid.zone[Zone].col[ii].points[jj].x ==
3431             utm_grid.zone[Zone].boundary_x)
3432         {
3433           puts(" Boundary");
3434         }
3435         else
3436         {
3437           puts("");
3438         }
3439       }
3440 #endif
3441       for (jj=fp; jj < fp+np; jj++)
3442       {
3443         if (utm_grid.zone[Zone].col[ii].points[jj].x ==
3444             utm_grid.zone[Zone].boundary_x)
3445         {
3446           nbp++;
3447         }
3448         else if (nbp > 0)   // We had a boundary point, but not anymore
3449         {
3450           fp = utm_grid.zone[Zone].col[ii].firstpoint = l16(jj - 1);
3451 //fprintf(stderr,"np:%d, jj:%d\n",np,jj);
3452           // This can result in negative numbers!
3453           np = utm_grid.zone[Zone].col[ii].npoints = np - jj + 1;
3454 //fprintf(stderr,"new np:%d\n",np);
3455           if (np < 0)
3456           {
3457             np = 0; // Prevents segfaults in
3458             // XDrawLines() and memmove()
3459             // below.
3460           }
3461           break;  // Exit from for loop
3462         }
3463         if (nbp == np)   // All points are boundary points
3464         {
3465           fp = utm_grid.zone[Zone].col[ii].firstpoint = 0;
3466           np = utm_grid.zone[Zone].col[ii].npoints    = 0;
3467         }
3468       }
3469 
3470 // What's the below code doing?  Can get a segfault without this in
3471 // the XDrawLines() functions below (fixed by making npoints an int
3472 // instead of an unsigned int).  Sometimes we get a segfault right
3473 // here due to the memmove() function.  In one such case, np was -2.
3474 // Latest code keeps some lines from getting drawn, but at least we
3475 // don't get a segfault.
3476 //
3477       if (fp > 0)
3478       {
3479         if (np > 0)
3480         {
3481           memmove(&utm_grid.zone[Zone].col[ii].points[0],
3482                   &utm_grid.zone[Zone].col[ii].points[fp], np * sizeof(XPoint));
3483           fp = utm_grid.zone[Zone].col[ii].firstpoint = 0;
3484         }
3485         else
3486         {
3487 //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint));
3488 //fprintf(stderr,"Problem1: in draw_minor_utm_mgrs_grid() memmove, np was %d.  Skipping memmove.\n",np);
3489         }
3490       }
3491 
3492 #ifdef UTM_DEBUG_VERB
3493       fprintf(stderr,"_tm_grid.zone[%d].col[%d].npoints=%d.firstpoint=%d\n",
3494               Zone, ii, np, fp);
3495       for (jj=fp; jj < fp+np; jj++)
3496       {
3497         fprintf(stderr,"         col[%d].points[%d] = [ %d, %d ]", ii, jj,
3498                 utm_grid.zone[Zone].col[ii].points[jj].x,
3499                 utm_grid.zone[Zone].col[ii].points[jj].y);
3500         if (utm_grid.zone[Zone].col[ii].points[jj].x ==
3501             utm_grid.zone[Zone].boundary_x)
3502         {
3503           puts(" Boundary");
3504         }
3505         else
3506         {
3507           puts("");
3508         }
3509       }
3510       puts("");
3511 #endif
3512     }
3513 
3514     // Cleanup rows
3515     for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++)
3516     {
3517       int np = utm_grid.zone[Zone].row[ii].npoints;
3518       int fp = utm_grid.zone[Zone].row[ii].firstpoint;
3519 #ifdef UTM_DEBUG_VERB
3520       fprintf(stderr,"utm_grid.zone[%d].row[%d].npoints=%d.firstpoint=%d\n",
3521               Zone, ii, np, fp);
3522       if (np < 2)
3523       {
3524         puts(" Not enough points!");
3525       }
3526       else
3527       {
3528         puts("");
3529       }
3530 #endif
3531 // What's this doing?  This appears to be important, as things get
3532 // really messed up if it's commented out.
3533       if (fp > 0)
3534       {
3535         if (np > 0)
3536         {
3537           memmove(&utm_grid.zone[Zone].row[ii].points[0],
3538                   &utm_grid.zone[Zone].row[ii].points[fp], np * sizeof(XPoint));
3539           fp = utm_grid.zone[Zone].row[ii].firstpoint = 0;
3540         }
3541         else
3542         {
3543 //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint));
3544 //fprintf(stderr,"Problem2: in draw_minor_utm_mgrs_grid() memmove, np was %d.  Skipping memmove.\n",np);
3545         }
3546 
3547       }
3548 #ifdef UTM_DEBUG_VERB
3549       for (jj=fp; jj < fp+np; jj++)
3550       {
3551         fprintf(stderr,"         row[%d].points[%d] = [ %d, %d ]\n", ii, jj,
3552                 utm_grid.zone[Zone].row[ii].points[jj].x,
3553                 utm_grid.zone[Zone].row[ii].points[jj].y);
3554       }
3555 #endif
3556     }
3557   }
3558 
3559   // Rows and columns ready to go so setup hash
3560   utm_grid.hash.ul_x = NW_corner_longitude;
3561   utm_grid.hash.ul_y = NW_corner_latitude;
3562   utm_grid.hash.lr_x = SE_corner_longitude;
3563   utm_grid.hash.lr_y = SE_corner_latitude;
3564 
3565   // XPoint arrays are set up.  Go draw the grid.
3566   actually_draw_utm_minor_grid(w);
3567 
3568   return(0);
3569 
3570 }   // End of draw_minor_utm_mgrs_grid() function
3571 
3572 
3573 
3574 
3575 
3576 //*****************************************************************
3577 // draw_grid()
3578 //
3579 // Draws a lat/lon or UTM/UPS grid on top of the view.
3580 //
3581 //*****************************************************************
draw_grid(Widget w)3582 void draw_grid(Widget w)
3583 {
3584   int half;                   // Center of the white lines used to draw the borders
3585   int border_width = 14;      // The width of the border to draw around the
3586   // map to place labeled tick marks into
3587   // should be an even number.
3588   // The default here is overidden by the border fontsize.
3589 
3590 
3591   if (!long_lat_grid) // We don't wish to draw a map grid
3592   {
3593     return;
3594   }
3595 
3596   if (draw_labeled_grid_border==TRUE)
3597   {
3598     // Determine how wide the border should be.
3599     border_width = get_border_width(w);
3600     half = border_width/2;
3601     // draw a white border around the map.
3602     (void)XSetLineAttributes(XtDisplay(w),
3603                              gc,
3604                              border_width,
3605                              LineSolid,
3606                              CapRound,
3607                              JoinRound);
3608     (void)XSetForeground(XtDisplay(w),
3609                          gc,
3610                          colors[border_foreground_color]);         // white
3611     (void)XDrawLine(XtDisplay(w),
3612                     pixmap_final,
3613                     gc,
3614                     0,
3615                     l16(half),
3616                     l16(screen_width),
3617                     l16(half));
3618     (void)XDrawLine(XtDisplay(w),
3619                     pixmap_final,
3620                     gc,
3621                     l16(half),
3622                     0,
3623                     l16(half),
3624                     l16(screen_height));
3625     (void)XDrawLine(XtDisplay(w),
3626                     pixmap_final,
3627                     gc,
3628                     0,
3629                     l16(screen_height-half),
3630                     l16(screen_width),
3631                     l16(screen_height-half));
3632     (void)XDrawLine(XtDisplay(w),
3633                     pixmap_final,
3634                     gc,
3635                     l16(screen_width-half),
3636                     0,
3637                     l16(screen_width-half),
3638                     l16(screen_height));
3639   }
3640 
3641   // Set the line width in the GC to 2 pixels wide for the larger
3642   // UTM grid and the complete Lat/Long grid.
3643   (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineOnOffDash, CapButt,JoinMiter);
3644   (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]);
3645   (void)XSetFunction (XtDisplay (da), gc_tint, GXxor);
3646 
3647   if (coordinate_system == USE_UTM
3648       || coordinate_system == USE_UTM_SPECIAL
3649       || coordinate_system == USE_MGRS)
3650   {
3651 
3652     int ret_code;
3653 
3654 //draw_vector_ll(w, -5.0, -5.0,  5.0,  5.0, gc_tint, pixmap_final, 0);
3655 //draw_vector_ll(w,  5.0,  5.0, -5.0, -5.0, gc_tint, pixmap_final, 0);
3656 
3657     // Draw major UTM/MGRS zones
3658     draw_major_utm_mgrs_grid(w);
3659 
3660     // Draw minor UTM/MGRS zones
3661     ret_code = draw_minor_utm_mgrs_grid(w);
3662     if (ret_code)
3663     {
3664       fprintf(stderr,
3665               "Encountered problem %d while calculating minor utm grid!\n",
3666               ret_code);
3667     }
3668 
3669   }   // End of UTM grid section
3670   else   // Lat/Long coordinate system, draw lat/long lines
3671   {
3672     draw_complete_lat_lon_grid(w);
3673   }   // End of Lat/Long section
3674 }  // End of draw_grid()
3675 
3676 
3677 
3678 
3679 
3680 /**********************************************************
3681  * get_map_ext()
3682  *
3683  * Returns the extension for the filename.  We use this to
3684  * determine which sort of map file it is.
3685  **********************************************************/
get_map_ext(char * filename)3686 char *get_map_ext (char *filename)
3687 {
3688   int len;
3689   int i;
3690   char *ext;
3691 
3692   ext = NULL;
3693   len = (int)strlen (filename);
3694   for (i = len; i >= 0; i--)
3695   {
3696     if (filename[i] == '.')
3697     {
3698       ext = filename + (i + 1);
3699       break;
3700     }
3701   }
3702   return (ext);
3703 }
3704 
3705 
3706 
3707 
3708 
3709 /**********************************************************
3710  * get_map_dir()
3711  *
3712  * Used to snag just the pathname from a complete filename.
3713  * Modifies input parameter "fullpath".
3714  **********************************************************/
get_map_dir(char * fullpath)3715 char *get_map_dir (char *fullpath)
3716 {
3717   int len;
3718   int i;
3719 
3720   len = (int)strlen (fullpath);
3721   for (i = len; i >= 0; i--)
3722   {
3723     if (fullpath[i] == '/')
3724     {
3725       fullpath[i + 1] = '\0';
3726       break;
3727     }
3728   }
3729   return (fullpath);
3730 }
3731 
3732 
3733 
3734 
3735 
3736 /***********************************************************
3737  * map_visible()
3738  *
3739  * Tests whether a particular path/filename is within our
3740  * current view.  We use this to decide whether to plot or
3741  * skip a particular image file (major speed-up!).
3742  * Input coordinates are in the Xastir coordinate system.
3743  *
3744  * Had to fix a bug here where the viewport glanced over the
3745  * edge of the earth, causing strange results like this.
3746  * Notice the View Edges Top value is out of range:
3747  *
3748  *
3749  *                Bottom         Top          Left       Right
3750  * View Edges:  31,017,956  4,290,923,492  35,971,339  90,104,075
3751  *  Map Edges:  12,818,482     12,655,818  64,079,859  64,357,110
3752  *
3753  * Left map boundary inside view
3754  * Right map boundary inside view
3755  * map_inside_view: 1  view_inside_map: 0  parallel_edges: 0
3756  * Map not within current view.
3757  * Skipping map: /usr/local/share/xastir/maps/tif/uk/425_0525_bng.tif
3758  *
3759  *
3760  * I had to check for out-of-bounds numbers for the viewport and
3761  * set them to min or max values so that this function always
3762  * works properly.  Here are the bounds of the earth (Xastir
3763  * Coordinate System):
3764  *
3765  *              0 (90 deg. or 90N)
3766  *
3767  * 0 (-180 deg. or 180W)      129,600,000 (180 deg. or 180E)
3768  *
3769  *          64,800,000 (-90 deg. or 90S)
3770  *
3771  ***********************************************************/
map_visible(unsigned long map_max_y,unsigned long map_min_y,unsigned long map_min_x,unsigned long map_max_x)3772 int map_visible (unsigned long map_max_y,   // bottom_map_boundary
3773                  unsigned long map_min_y,   // top_map_boundary
3774                  unsigned long map_min_x,   // left_map_boundary
3775                  unsigned long map_max_x)   // right_map_boundary) {
3776 {
3777 
3778   //fprintf(stderr,"map_visible\n");
3779 
3780   // From computation geometry equations, intersection of two line
3781   // segments, they use the bounding box for two lines.  This is
3782   // the same as what we want to do:
3783   //
3784   // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa
3785   // http://www.gamedev.net/reference/articles/article735.asp
3786   //
3787   // The quick rejection algorithm:
3788   //
3789   if (NW_corner_latitude > (long)map_max_y)
3790   {
3791     if (debug_level & 16)
3792     {
3793       fprintf(stderr,
3794               "map_visible, rejecting: NW_corner_latitude:%ld > map_max_y:%ld\n",
3795               NW_corner_latitude,
3796               map_max_y);
3797       fprintf(stderr,
3798               "\tmap or object is above viewport\n");
3799     }
3800     return(0);
3801   }
3802 
3803   if ((long)map_min_y > SE_corner_latitude)
3804   {
3805     if (debug_level & 16)
3806     {
3807       fprintf(stderr,
3808               "map_visible, rejecting: map_min_y:%ld > SE_corner_latitude:%ld\n",
3809               map_min_y,
3810               SE_corner_latitude);
3811       fprintf(stderr,
3812               "\tmap or object is below viewport\n");
3813     }
3814     return(0);
3815   }
3816 
3817   if (NW_corner_longitude > (long)map_max_x)
3818   {
3819     if (debug_level & 16)
3820     {
3821       fprintf(stderr,
3822               "map_visible, rejecting: NW_corner_longitude:%ld > map_max_x:%ld\n",
3823               NW_corner_longitude,
3824               map_max_x);
3825       fprintf(stderr,
3826               "\tmap or object is left of viewport\n");
3827     }
3828     return(0);
3829   }
3830 
3831   if ((long)map_min_x > SE_corner_longitude)
3832   {
3833     if (debug_level & 16)
3834     {
3835       fprintf(stderr,
3836               "map_visible, rejecting: map_min_x:%ld > SE_corner_longitude:%ld\n",
3837               map_min_x,
3838               SE_corner_longitude);
3839       fprintf(stderr,
3840               "\tmap or object is right of viewport\n");
3841     }
3842     return(0);
3843   }
3844 
3845   return (1); // At least part of the map is on-screen
3846 }
3847 
3848 
3849 
3850 /////////////////////////////////////////////////////////////////////
3851 // get_viewport_lat_lon(double *xmin, double *ymin, double* xmax, double *ymax)
3852 // Simply returns the floating point corners of the map display.
3853 /////////////////////////////////////////////////////////////////////
get_viewport_lat_lon(double * xmin,double * ymin,double * xmax,double * ymax)3854 void get_viewport_lat_lon(double *xmin,
3855                           double *ymin,
3856                           double* xmax,
3857                           double *ymax)
3858 {
3859 
3860   *xmin=(double)f_NW_corner_longitude;
3861   *ymin=(double)f_SE_corner_latitude;
3862   *xmax=(double)f_SE_corner_longitude;
3863   *ymax=(double)f_NW_corner_latitude;
3864 }
3865 
3866 /////////////////////////////////////////////////////////////////////
3867 // map_inside_viewport_lat_lon()
3868 //  Returns 1 if the given set of xmin,xmax, ymin,ymax defines a
3869 //  rectangle entirely contained in the current viewport (as opposed to
3870 //  merely partially overlapping it.  Returns zero otherwise.
3871 /////////////////////////////////////////////////////////////////////
map_inside_viewport_lat_lon(double map_min_y,double map_max_y,double map_min_x,double map_max_x)3872 int map_inside_viewport_lat_lon(double map_min_y,
3873                                 double map_max_y,
3874                                 double map_min_x,
3875                                 double map_max_x)
3876 {
3877   int retval=0;
3878   if (map_min_x >= f_NW_corner_longitude &&
3879       map_min_y >= f_SE_corner_latitude &&
3880       map_max_x <= f_SE_corner_longitude &&
3881       map_max_y <= f_NW_corner_latitude)
3882   {
3883     retval=1;
3884   }
3885 
3886   return (retval);
3887 }
3888 
3889 
3890 /////////////////////////////////////////////////////////////////////
3891 // map_visible_lat_lon()
3892 //
3893 // We have the center of the view in floating point format:
3894 //
3895 //   float f_center_longitude; // Floating point map center longitude
3896 //   float f_center_latitude;  // Floating point map center latitude
3897 //
3898 // So we just need to compute the top/bottom/left/right using those
3899 // values and the scale_x/scale_y values before doing the compare.
3900 //
3901 // y scaling in 1/100 sec per pixel
3902 // x scaling in 1/100 sec per pixel, calculated from scale_y
3903 //
3904 //
3905 //              0 (90 deg. or 90N)
3906 //
3907 // 0 (-180 deg. or 180W)      129,600,000 (180 deg. or 180E)
3908 //
3909 //          64,800,000 (-90 deg. or 90S)
3910 //
3911 // *******************                  ******************* max_y
3912 // *NW               * +                *                 * +
3913 // *                 *                  *                 *
3914 // *                 *                  *                 *
3915 // *      View       * latitude (y)     *       Map       *
3916 // *                 *                  *                 *
3917 // *                 *                  *                 *
3918 // *               SE* -                *                 * -
3919 // *******************                  ******************* min_y
3920 // -  longitude(x)   +                  - min_x     max_x +
3921 
3922 /////////////////////////////////////////////////////////////////////
map_visible_lat_lon(double map_min_y,double map_max_y,double map_min_x,double map_max_x)3923 int map_visible_lat_lon (double map_min_y,    // f_bottom_map_boundary
3924                          double map_max_y,    // f_top_map_boundary
3925                          double map_min_x,    // f_left_map_boundary
3926                          double map_max_x)    // f_right_map_boundary
3927 {
3928 
3929 //fprintf(stderr,"map_visible_lat_lon\n");
3930 
3931   // From computation geometry equations, intersection of two line
3932   // segments, they use the bounding box for two lines.  This is
3933   // the same as what we want to do:
3934   //
3935   // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa
3936   // http://www.gamedev.net/reference/articles/article735.asp
3937   //
3938   // The quick rejection algorithm:
3939   //
3940   if (map_max_y < f_SE_corner_latitude )
3941   {
3942     return(0);  // map below view
3943   }
3944   if (map_max_x < f_NW_corner_longitude)
3945   {
3946     return(0);  // map left of view
3947   }
3948   if (map_min_y > f_NW_corner_latitude )
3949   {
3950     return(0);  // view below map
3951   }
3952   if (map_min_x > f_SE_corner_longitude)
3953   {
3954     return(0);  // view left of  map
3955   }
3956 
3957   return (1); // Draw this map onto the screen
3958 }
3959 
3960 
3961 
3962 
3963 
3964 /**********************************************************
3965  * draw_label_text()
3966  *
3967  * Does what it says.  Used to draw strings onto the
3968  * display.
3969  **********************************************************/
draw_label_text(Widget w,int x,int y,int label_length,int color,char * label_text)3970 void draw_label_text (Widget w, int x, int y, int label_length, int color, char *label_text)
3971 {
3972 
3973   // This draws a gray background rectangle upon which we draw the text.
3974   // Probably not needed.  It ends up obscuring details underneath.
3975   //(void)XSetForeground (XtDisplay (w), gc, colors[0x0ff]);
3976   //(void)XFillRectangle (XtDisplay (w), pixmap, gc, x - 1, (y - 10),(label_length * 6) + 2, 11);
3977 
3978   (void)XSetForeground (XtDisplay (w), gc, color);
3979   (void)XDrawString (XtDisplay (w), pixmap, gc, x, y, label_text, label_length);
3980 }
3981 
3982 
3983 
3984 
3985 
3986 // Must make sure that fonts are not loaded again and again, as this
3987 // takes a big chunk of memory each time.  Can you say "memory
3988 // leak"?
3989 
3990 XFontStruct *rotated_label_font[FONT_MAX]= {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
3991 char rotated_label_fontname[FONT_MAX][MAX_LABEL_FONTNAME];
3992 static char
3993 current_rotated_label_fontname[FONT_MAX][sizeof(rotated_label_fontname)] = {"","","","","","","","",""};
3994 
3995 /**********************************************************
3996  * draw_rotated_label_text_common()
3997  * call through wrappers:
3998  * draw_rotated_label_text_to_pixmap()
3999  * draw_rotated_label_text()
4000  * draw_centered_label_text()
4001  *
4002  * Does what it says.  Used to draw strings onto the
4003  * display.
4004  *
4005  * Use "xfontsel" or other tools to figure out what fonts
4006  * to use here.
4007  *
4008  * Paramenters:
4009  * target_pixmap specifies the pixmap the text is to be drawn to.
4010  * draw_outline specifies whether a 1 pixel outline around the
4011  *    text, TRUE to draw outline.
4012  * outline_bg_color is the color of the outline.
4013  * color is the color of the text inside the outline, or the
4014  *    color of the text itself if no outline is added.
4015  **********************************************************/
4016 /* common code used by the two entries --- a result of retrofitting a new
4017    feature (centered) */
draw_rotated_label_text_common(Widget w,float my_rotation,int x,int y,int UNUSED (label_length),int color,char * label_text,int align,int fontsize,Pixmap target_pixmap,int draw_outline,int outline_bg_color)4018 static void draw_rotated_label_text_common (Widget w, float my_rotation, int x, int y, int UNUSED(label_length), int color, char *label_text, int align, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color)
4019 {
4020 //    XPoint *corner;
4021 //    int i;
4022   int x_outline;
4023   int y_outline;
4024 
4025 
4026   // Do some sanity checking
4027   if (fontsize < 0 || fontsize >= FONT_MAX)
4028   {
4029     fprintf(stderr,"Font size is out of range: %d\n", fontsize);
4030     return;
4031   }
4032 
4033   /* see if fontname has changed */
4034   if (rotated_label_font[fontsize] &&
4035       strcmp(rotated_label_fontname[fontsize],current_rotated_label_fontname[fontsize]) != 0)
4036   {
4037     XFreeFont(XtDisplay(w),rotated_label_font[fontsize]);
4038     rotated_label_font[fontsize] = NULL;
4039     xastir_snprintf(current_rotated_label_fontname[fontsize],
4040                     sizeof(rotated_label_fontname),
4041                     "%s",
4042                     rotated_label_fontname[fontsize]);
4043   }
4044   /* load font */
4045   if(!rotated_label_font[fontsize])
4046   {
4047     rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w),
4048                                  rotated_label_fontname[fontsize]);
4049     if (rotated_label_font[fontsize] == NULL)      // Couldn't get the font!!!
4050     {
4051       fprintf(stderr,"draw_rotated_label_text: Couldn't get font %s\n",
4052               rotated_label_fontname[fontsize]);
4053       return;
4054     }
4055   }
4056 
4057   if (draw_outline)
4058   {
4059     // make outline style
4060     (void)XSetForeground(XtDisplay(w),gc,outline_bg_color);
4061     // Draw the string repeatedly with 1 pixel offsets in the
4062     // background color to make an outline.
4063 
4064     for (x_outline=-1; x_outline<2; x_outline++)
4065     {
4066       for (y_outline=-1; y_outline<2; y_outline++)
4067       {
4068         // draws one extra copy at x,y
4069         (void)XRotDrawAlignedString(XtDisplay (w),
4070                                     rotated_label_font[fontsize],
4071                                     my_rotation,
4072                                     target_pixmap,
4073                                     gc,
4074                                     x+x_outline,
4075                                     y+y_outline,
4076                                     label_text,
4077                                     align);
4078       }
4079     }
4080   }
4081 
4082 
4083   // Code to determine the bounding box corner points for the rotated text
4084 //    corner = XRotTextExtents(w,rotated_label_font,my_rotation,x,y,label_text,BLEFT);
4085 //    for (i=0;i<5;i++) {
4086 //        fprintf(stderr,"%d,%d\t",corner[i].x,corner[i].y);
4087 //    }
4088 //    fprintf(stderr,"\n");
4089 
4090   (void)XSetForeground (XtDisplay (w), gc, color);
4091 
4092   //fprintf(stderr,"%0.1f\t%s\n",my_rotation,label_text);
4093 
4094   (void)XRotDrawAlignedString(XtDisplay (w),
4095                               rotated_label_font[fontsize],
4096                               my_rotation,
4097                               target_pixmap,
4098                               gc,
4099                               x,
4100                               y,
4101                               label_text,
4102                               align);
4103 }
4104 
4105 
4106 
4107 
4108 
4109 // Find the pixel length of an unrotated string in the rotated_label_font.
4110 // Parameters:
4111 //    w - the XtDisplay.
4112 //    label_text - the string of which the length is to be found.
4113 //    fontsize - the fontsize in the rotated_label_font in which the string
4114 //    is to be rendered.
4115 // Returns: the length in pixels of the string, -1 on an error.
get_rotated_label_text_length_pixels(Widget w,char * label_text,int fontsize)4116 int get_rotated_label_text_length_pixels(Widget w, char *label_text, int fontsize)
4117 {
4118   int dir, asc, desc;   // parameters returned by XTextExtents, but not used here.
4119   XCharStruct overall;  // description of the space occupied by the string.
4120   int return_value;     // value to return
4121   int got_font;         // flag indicating that a font is available
4122 
4123   return_value = -1;
4124   got_font = TRUE;
4125 
4126   /* load font */
4127   if(!rotated_label_font[fontsize])
4128   {
4129     rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w),
4130                                  rotated_label_fontname[fontsize]);
4131     if (rotated_label_font[fontsize] == NULL)      // Couldn't get the font!!!
4132     {
4133       fprintf(stderr,"get_rotated_label_text_length_pixels: Couldn't get font %s\n",
4134               rotated_label_fontname[fontsize]);
4135       got_font = FALSE;
4136     }
4137   }
4138 
4139   if (got_font)
4140   {
4141     // find out the width in pixels of the unrotated label_text string.
4142     XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc,
4143                  &overall);
4144     return_value = overall.width;
4145   }
4146 
4147   return return_value;
4148 }
4149 
4150 
4151 
4152 
4153 
4154 // Find the pixel height of an unrotated string in the rotated_label_font.
4155 // Parameters:
4156 //    w - the XtDisplay.
4157 //    label_text - the string of which the length is to be found.
4158 //    fontsize - the fontsize in the rotated_label_font in which the string
4159 //    is to be rendered.
4160 // Returns: the height in pixels of the string, -1 on an error.
get_rotated_label_text_height_pixels(Widget w,char * label_text,int fontsize)4161 int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize)
4162 {
4163   int dir, asc, desc;   // parameters returned by XTextExtents, but not used here.
4164   XCharStruct overall;  // description of the space occupied by the string.
4165   int return_value;     // value to return
4166   int got_font;         // flag indicating that a font is available
4167 
4168   return_value = -1;
4169   got_font = TRUE;
4170 
4171   /* load font */
4172   if(!rotated_label_font[fontsize])
4173   {
4174     rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w),
4175                                  rotated_label_fontname[fontsize]);
4176     if (rotated_label_font[fontsize] == NULL)      // Couldn't get the font!!!
4177     {
4178       fprintf(stderr,"get_rotated_label_text_height_pixels: Couldn't get font %s\n",
4179               rotated_label_fontname[fontsize]);
4180       got_font = FALSE;
4181     }
4182   }
4183 
4184   if (got_font)
4185   {
4186     // find out the width in pixels of the unrotated label_text string.
4187     XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc,
4188                  &overall);
4189     return_value = overall.ascent + overall.descent;
4190   }
4191 
4192   return return_value;
4193 }
4194 
4195 
4196 
4197 
4198 
4199 // Draw a rotated label onto the specified pixmap.
4200 // Wrapper for draw_rotated_label_text-common().
draw_rotated_label_text_to_target(Widget w,int rotation,int x,int y,int label_length,int color,char * label_text,int fontsize,Pixmap target_pixmap,int draw_outline,int outline_bg_color)4201 void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color)
4202 {
4203   float my_rotation = (float)((-rotation)-90);
4204 
4205   if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) )
4206        || ( (my_rotation >  90.0) && (my_rotation <  270.0) ) )
4207   {
4208     my_rotation = my_rotation + 180.0;
4209     (void)draw_rotated_label_text_common(w,
4210                                          my_rotation,
4211                                          x,
4212                                          y,
4213                                          label_length,
4214                                          color,
4215                                          label_text,
4216                                          BRIGHT,
4217                                          fontsize,
4218                                          target_pixmap,
4219                                          draw_outline,
4220                                          outline_bg_color);
4221   }
4222   else
4223   {
4224     (void)draw_rotated_label_text_common(w,
4225                                          my_rotation,
4226                                          x,
4227                                          y,
4228                                          label_length,
4229                                          color,
4230                                          label_text,
4231                                          BLEFT,
4232                                          fontsize,
4233                                          target_pixmap,
4234                                          draw_outline,
4235                                          outline_bg_color);
4236   }
4237 }
4238 
4239 
4240 
4241 
4242 
draw_rotated_label_text(Widget w,int rotation,int x,int y,int label_length,int color,char * label_text,int fontsize)4243 void draw_rotated_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize)
4244 {
4245   float my_rotation = (float)((-rotation)-90);
4246 
4247   if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) )
4248        || ( (my_rotation >  90.0) && (my_rotation <  270.0) ) )
4249   {
4250     my_rotation = my_rotation + 180.0;
4251     (void)draw_rotated_label_text_common(w,
4252                                          my_rotation,
4253                                          x,
4254                                          y,
4255                                          label_length,
4256                                          color,
4257                                          label_text,
4258                                          BRIGHT,
4259                                          fontsize,
4260                                          pixmap, 0, 0);
4261   }
4262   else
4263   {
4264     (void)draw_rotated_label_text_common(w,
4265                                          my_rotation,
4266                                          x,
4267                                          y,
4268                                          label_length,
4269                                          color,
4270                                          label_text,
4271                                          BLEFT,
4272                                          fontsize,
4273                                          pixmap, 0, 0);
4274   }
4275 }
4276 
draw_centered_label_text(Widget w,int rotation,int x,int y,int label_length,int color,char * label_text,int fontsize)4277 void draw_centered_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize)
4278 {
4279   float my_rotation = (float)((-rotation)-90);
4280 
4281   (void)draw_rotated_label_text_common(w,
4282                                        my_rotation,
4283                                        x,
4284                                        y,
4285                                        label_length,
4286                                        color,
4287                                        label_text,
4288                                        BCENTRE,
4289                                        fontsize,
4290                                        pixmap, 0, 0);
4291 }
4292 
4293 
4294 
4295 
4296 
Print_postscript_destroy_shell(Widget UNUSED (widget),XtPointer clientData,XtPointer UNUSED (callData))4297 static void Print_postscript_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) )
4298 {
4299   Widget shell = (Widget) clientData;
4300   char *temp_ptr;
4301 
4302 
4303   XtPopdown(shell);
4304 
4305   begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" );
4306 
4307   if (print_postscript_dialog)
4308   {
4309     // Snag the path to the printer program from the print dialog
4310     temp_ptr = XmTextFieldGetString(printer_data);
4311     xastir_snprintf(printer_program,
4312                     sizeof(printer_program),
4313                     "%s",
4314                     temp_ptr);
4315     XtFree(temp_ptr);
4316     (void)remove_trailing_spaces(printer_program);
4317 
4318     // Check for empty variable
4319     if (printer_program[0] == '\0')
4320     {
4321 
4322 #ifdef LPR_PATH
4323       // Path to LPR if defined
4324       xastir_snprintf(printer_program,
4325                       sizeof(printer_program),
4326                       "%s",
4327                       LPR_PATH);
4328 #else // LPR_PATH
4329       // Empty path
4330       printer_program[0]='\0';
4331 #endif // LPR_PATH
4332     }
4333 
4334 //fprintf(stderr,"%s\n", printer_program);
4335 
4336     // Snag the path to the previewer program from the print dialog
4337     temp_ptr = XmTextFieldGetString(previewer_data);
4338     xastir_snprintf(previewer_program,
4339                     sizeof(previewer_program),
4340                     "%s",
4341                     temp_ptr);
4342     XtFree(temp_ptr);
4343     (void)remove_trailing_spaces(previewer_program);
4344 
4345     // Check for empty variable
4346     if (previewer_program[0] == '\0')
4347     {
4348 
4349 #ifdef GV_PATH
4350       // Path to GV if defined
4351       xastir_snprintf(previewer_program,
4352                       sizeof(previewer_program),
4353                       "%s",
4354                       GV_PATH);
4355 #else // GV_PATH
4356       // Empty string
4357       previewer_program[0] = '\0';
4358 #endif // GV_PATH
4359     }
4360 //fprintf(stderr,"%s\n", previewer_program);
4361   }
4362 
4363   XtDestroyWidget(shell);
4364   print_postscript_dialog = (Widget)NULL;
4365 
4366   end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" );
4367 
4368 }
4369 
4370 
4371 
4372 
4373 
Print_properties_destroy_shell(Widget UNUSED (widget),XtPointer clientData,XtPointer UNUSED (callData))4374 static void Print_properties_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) )
4375 {
4376   Widget shell = (Widget) clientData;
4377 
4378   if (!shell)
4379   {
4380     return;
4381   }
4382 
4383   XtPopdown(shell);
4384 
4385   begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" );
4386 
4387   XtDestroyWidget(shell);
4388   print_properties_dialog = (Widget)NULL;
4389 
4390   end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" );
4391 
4392 }
4393 
4394 
4395 
4396 
4397 
4398 // Print_window:  Prints the drawing area to a Postscript file and
4399 // then sends it to the printer program (usually "lpr).
4400 //
Print_window(Widget widget,XtPointer UNUSED (clientData),XtPointer UNUSED (callData))4401 static void Print_window( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
4402 {
4403 
4404 #ifdef NO_XPM
4405 //    fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n");
4406   popup_message_always(langcode("POPEM00035"),
4407                        "XPM or ImageMagick support not compiled into Xastir! Cannot Print!");
4408 #else   // NO_XPM
4409 
4410   char xpm_filename[MAX_FILENAME];
4411   char ps_filename[MAX_FILENAME];
4412   char command[MAX_FILENAME*2];
4413   char temp[MAX_FILENAME];
4414   int xpmretval;
4415   char temp_base_dir[MAX_VALUE];
4416 
4417   get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir));
4418 
4419   xastir_snprintf(xpm_filename,
4420                   sizeof(xpm_filename),
4421                   "%s/print.xpm",
4422                   temp_base_dir);
4423 
4424   xastir_snprintf(ps_filename,
4425                   sizeof(ps_filename),
4426                   "%s/print.ps",
4427                   temp_base_dir);
4428 
4429   busy_cursor(appshell);  // Show a busy cursor while we're doing all of this
4430 
4431   // Get rid of the Print dialog
4432   Print_postscript_destroy_shell(widget, print_postscript_dialog, NULL );
4433 
4434   if ( debug_level & 512 )
4435   {
4436     fprintf(stderr,"Creating %s\n", xpm_filename );
4437   }
4438 
4439   xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") );
4440   statusline(temp,1);       // Dumping image to file...
4441 
4442   if (chdir(temp_base_dir) != 0)
4443   {
4444     fprintf(stderr,"Couldn't chdir to %s directory for print_window\n", temp_base_dir);
4445     return;
4446   }
4447 
4448   xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display
4449                                    "print.xpm",                                 // char *filename
4450                                    pixmap_final,                                // Pixmap pixmap
4451                                    (Pixmap)NULL,                                // Pixmap shapemask
4452                                    NULL );
4453 
4454   if (xpmretval != XpmSuccess)
4455   {
4456     fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename,
4457             XpmGetErrorString(xpmretval));
4458     popup_message_always(langcode("POPEM00035"),
4459                          "Error writing xpm image file! Cannot Print!");
4460     return;
4461   }
4462   else            // We now have the xpm file created on disk
4463   {
4464 
4465     chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
4466 
4467     if ( debug_level & 512 )
4468     {
4469       fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename );
4470     }
4471 
4472 
4473     // Convert it to a postscript file for printing.  This depends
4474     // on the ImageMagick command "convert".
4475     //
4476 
4477     if (debug_level & 512)
4478     {
4479       fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height);
4480     }
4481 
4482     xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") );
4483     statusline(temp,1);       // Converting to Postscript...
4484 
4485 
4486 #ifdef HAVE_CONVERT
4487     strcpy(command, CONVERT_PATH);
4488     command[sizeof(command)-1] = '\0';  // Terminate string
4489     strcat(command, " -filter Point ");
4490     command[sizeof(command)-1] = '\0';  // Terminate string
4491     strcat(command, xpm_filename);
4492     command[sizeof(command)-1] = '\0';  // Terminate string
4493     strcat(command, " ");
4494     command[sizeof(command)-1] = '\0';  // Terminate string
4495     strcat(command, ps_filename);
4496     command[sizeof(command)-1] = '\0';  // Terminate string
4497 
4498     if ( debug_level & 512 )
4499     {
4500       fprintf(stderr,"%s\n", command );
4501     }
4502 
4503     if ( system( command ) != 0 )
4504     {
4505 //            fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n");
4506       popup_message_always(langcode("POPEM00035"),
4507                            "Couldn't convert from XPM to PS!");
4508       return;
4509     }
4510 #endif  // HAVE_CONVERT
4511 
4512     chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
4513 
4514     // Delete temporary xpm file
4515     if ( !(debug_level & 512) )
4516     {
4517       unlink( xpm_filename );
4518     }
4519 
4520     if ( debug_level & 512 )
4521     {
4522       fprintf(stderr,"Printing postscript file %s\n", ps_filename);
4523     }
4524 
4525 // Note: This needs to be changed to "lp" for Solaris.
4526 // Also need to have a field to configure the printer name.  One
4527 // fill-in field could do both.
4528 //
4529 // Since we could be running SUID root, we don't want to be
4530 // calling "system" anyway.  Several problems with it.
4531 
4532     strcpy(command, printer_program);
4533     command[sizeof(command)-1] = '\0';  // Terminate string
4534     strcat(command, " ");
4535     command[sizeof(command)-1] = '\0';  // Terminate string
4536     strcat(command, ps_filename);
4537     command[sizeof(command)-1] = '\0';  // Terminate string
4538 
4539     if ( debug_level & 512 )
4540     {
4541       fprintf(stderr,"%s\n", command);
4542     }
4543 
4544     if (printer_program[0] == '\0')
4545     {
4546 //            fprintf(stderr,"\n\nPrint: No print program defined!\n\n\n");
4547       popup_message_always(langcode("POPEM00035"),
4548                            "No print program defined!");
4549       return;
4550     }
4551 
4552     if ( system( command ) != 0 )
4553     {
4554 //            fprintf(stderr,"\n\nPrint: Couldn't send to the printer!\n\n\n");
4555       popup_message_always(langcode("POPEM00035"),
4556                            "Couldn't send to the printer!");
4557       return;
4558     }
4559 
4560     /*
4561             if ( !(debug_level & 512) )
4562                 unlink( ps_filename );
4563     */
4564 
4565     if ( debug_level & 512 )
4566     {
4567       fprintf(stderr,"  Done printing.\n");
4568     }
4569   }
4570 
4571   xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") );
4572   statusline(temp,1);       // Finished creating print file.
4573 
4574   //popup_message( langcode("PRINT0015"), langcode("PRINT0014") );
4575 
4576 #endif // NO_XPM
4577 
4578 }
4579 
4580 
4581 
4582 
4583 
4584 // Print_preview:  Prints the drawing area to a Postscript file.  If
4585 // previewer_program has "gv" in it, then use the various options
4586 // selected by the user.  If not, skip those options.
4587 //
Print_preview(Widget widget,XtPointer UNUSED (clientData),XtPointer UNUSED (callData))4588 static void Print_preview( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
4589 {
4590 
4591 #ifdef NO_XPM
4592 //    fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n");
4593   popup_message_always(langcode("POPEM00035"),
4594                        "XPM or ImageMagick support not compiled into Xastir! Cannot Print!");
4595 #else   // NO_GRAPHICS
4596 
4597   char xpm_filename[MAX_FILENAME];
4598   char ps_filename[MAX_FILENAME];
4599   char mono[50] = "";
4600   char invert[50] = "";
4601   char rotate[50] = "";
4602   char scale[50] = "";
4603   char density[50] = "";
4604   char command[MAX_FILENAME*2];
4605   char temp[MAX_FILENAME];
4606   char format[100] = " ";
4607   int xpmretval;
4608   char temp_base_dir[MAX_VALUE];
4609 
4610   get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir));
4611 
4612 
4613   xastir_snprintf(xpm_filename,
4614                   sizeof(xpm_filename),
4615                   "%s/print.xpm",
4616                   temp_base_dir);
4617 
4618   xastir_snprintf(ps_filename,
4619                   sizeof(ps_filename),
4620                   "%s/print.ps",
4621                   temp_base_dir);
4622 
4623   busy_cursor(appshell);  // Show a busy cursor while we're doing all of this
4624 
4625   // Get rid of the Print Properties dialog if it exists
4626   Print_properties_destroy_shell(widget, print_properties_dialog, NULL );
4627 
4628   if ( debug_level & 512 )
4629   {
4630     fprintf(stderr,"Creating %s\n", xpm_filename );
4631   }
4632 
4633   xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") );
4634   statusline(temp,1);       // Dumping image to file...
4635 
4636   if (chdir(temp_base_dir) != 0)
4637   {
4638     fprintf(stderr,"Couldn't chdir to %s directory for print_preview\n", temp_base_dir);
4639     return;
4640   }
4641 
4642   xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display
4643                                    "print.xpm",                                 // char *filename
4644                                    pixmap_final,                                // Pixmap pixmap
4645                                    (Pixmap)NULL,                                // Pixmap shapemask
4646                                    NULL );
4647 
4648   if (xpmretval != XpmSuccess)
4649   {
4650     fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename,
4651             XpmGetErrorString(xpmretval));
4652     popup_message_always(langcode("POPEM00035"),
4653                          "Error writing XPM file!");
4654     return;
4655   }
4656   else            // We now have the xpm file created on disk
4657   {
4658 
4659     chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
4660 
4661     if ( debug_level & 512 )
4662     {
4663       fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename );
4664     }
4665 
4666 
4667     // If we're not using "gv", skip most of the code below and
4668     // go straight to the previewer program portion of the code.
4669     //
4670     if ( strstr(previewer_program,"gv") )
4671     {
4672 
4673       // Convert it to a postscript file for printing.  This
4674       // depends on the ImageMagick command "convert".
4675       //
4676       // Other options to try in the future:
4677       // -label
4678       //
4679       if ( print_auto_scale )
4680       {
4681 //                sprintf(scale, "-geometry 612x792 -page 612x792 ");   // "Letter" size at 72 dpi
4682 //                sprintf(scale, "-sample 612x792 -page 612x792 ");     // "Letter" size at 72 dpi
4683         xastir_snprintf(scale, sizeof(scale), "-page 1275x1650+0+0 "); // "Letter" size at 150 dpi
4684       }
4685       else
4686       {
4687         scale[0] = '\0';  // Empty string
4688       }
4689 
4690 
4691       if ( print_in_monochrome )
4692       {
4693         xastir_snprintf(mono, sizeof(mono), "-monochrome +dither " );  // Monochrome
4694       }
4695       else
4696       {
4697         xastir_snprintf(mono, sizeof(mono), "+dither ");  // Color
4698       }
4699 
4700 
4701       if ( print_invert )
4702       {
4703         xastir_snprintf(invert, sizeof(invert), "-negate " );  // Reverse Colors
4704       }
4705       else
4706       {
4707         invert[0] = '\0';  // Empty string
4708       }
4709 
4710 
4711       if (debug_level & 512)
4712       {
4713         fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height);
4714       }
4715 
4716 
4717       if ( print_rotated )
4718       {
4719         xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " );
4720 
4721 #ifdef HAVE_OLD_GV
4722         xastir_snprintf(format, sizeof(format), "-landscape " );
4723 #else   // HAVE_OLD_GV
4724         xastir_snprintf(format, sizeof(format), "--orientation=landscape " );
4725 #endif  // HAVE_OLD_GV
4726 
4727       }
4728       else if ( print_auto_rotation )
4729       {
4730         // Check whether the width or the height of the
4731         // pixmap is greater.  If width is greater than
4732         // height, rotate the image by 270 degrees.
4733         if (screen_width > screen_height)
4734         {
4735           xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " );
4736 
4737 #ifdef HAVE_OLD_GV
4738           xastir_snprintf(format, sizeof(format), "-landscape " );
4739 #else   // HAVE_OLD_GV
4740           xastir_snprintf(format, sizeof(format), "--orientation=landscape " );
4741 #endif  // HAVE_OLD_GV
4742 
4743           if (debug_level & 512)
4744           {
4745             fprintf(stderr,"Rotating\n");
4746           }
4747         }
4748         else
4749         {
4750           rotate[0] = '\0';   // Empty string
4751           if (debug_level & 512)
4752           {
4753             fprintf(stderr,"Not Rotating\n");
4754           }
4755         }
4756       }
4757       else
4758       {
4759         rotate[0] = '\0';   // Empty string
4760         if (debug_level & 512)
4761         {
4762           fprintf(stderr,"Not Rotating\n");
4763         }
4764       }
4765 
4766 
4767       // Higher print densities require more memory and time
4768       // to process
4769       xastir_snprintf(density, sizeof(density), "-density %dx%d", print_resolution,
4770                       print_resolution );
4771 
4772       xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") );
4773       statusline(temp,1);       // Converting to Postscript...
4774 
4775 
4776       // Filters:
4777       // Point (ok at higher dpi's)
4778       // Box  (not too bad)
4779       // Triangle (no)
4780       // Hermite (no)
4781       // Hanning (no)
4782       // Hamming (no)
4783       // Blackman (better but still not good)
4784       // Gaussian (no)
4785       // Quadratic (no)
4786       // Cubic (no)
4787       // Catrom (not too bad)
4788       // Mitchell (no)
4789       // Lanczos (no)
4790       // Bessel (no)
4791       // Sinc (not too bad)
4792 
4793     }
4794 
4795 #ifdef HAVE_CONVERT
4796     strcpy(command, CONVERT_PATH);
4797     command[sizeof(command)-1] = '\0';  // Terminate string
4798     strcat(command, " -filter Point ");
4799     command[sizeof(command)-1] = '\0';  // Terminate string
4800     strcat(command, mono);
4801     command[sizeof(command)-1] = '\0';  // Terminate string
4802     strcat(command, invert);
4803     command[sizeof(command)-1] = '\0';  // Terminate string
4804     strcat(command, rotate);
4805     command[sizeof(command)-1] = '\0';  // Terminate string
4806     strcat(command, scale);
4807     command[sizeof(command)-1] = '\0';  // Terminate string
4808     strcat(command, density);
4809     command[sizeof(command)-1] = '\0';  // Terminate string
4810     strcat(command, " ");
4811     command[sizeof(command)-1] = '\0';  // Terminate string
4812     strcat(command, xpm_filename);
4813     command[sizeof(command)-1] = '\0';  // Terminate string
4814     strcat(command, " ");
4815     command[sizeof(command)-1] = '\0';  // Terminate string
4816     strcat(command, ps_filename);
4817     command[sizeof(command)-1] = '\0';  // Terminate string
4818 
4819     if ( debug_level & 512 )
4820     {
4821       fprintf(stderr,"%s\n", command );
4822     }
4823 
4824     if ( system( command ) != 0 )
4825     {
4826 //            fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n");
4827       popup_message_always(langcode("POPEM00035"),
4828                            "Couldn't convert from XPM to PS!");
4829       return;
4830     }
4831 #endif  // HAVE_CONVERT
4832 
4833     chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
4834 
4835     // Delete temporary xpm file
4836     if ( !(debug_level & 512) )
4837     {
4838       unlink( xpm_filename );
4839     }
4840 
4841     if ( debug_level & 512 )
4842     {
4843       fprintf(stderr,"Printing postscript file %s\n", ps_filename);
4844     }
4845 
4846 // Since we could be running SUID root, we don't want to be
4847 // calling "system" anyway.  Several problems with it.
4848 
4849     // Bring up the postscript viewer
4850     strcpy(command, previewer_program);
4851     command[sizeof(command)-1] = '\0';  // Terminate string
4852     strcat(command, " ");
4853     command[sizeof(command)-1] = '\0';  // Terminate string
4854     strcat(command, format);
4855     command[sizeof(command)-1] = '\0';  // Terminate string
4856     strcat(command, " ");
4857     command[sizeof(command)-1] = '\0';  // Terminate string
4858     strcat(command, ps_filename);
4859     command[sizeof(command)-1] = '\0';  // Terminate string
4860     strcat(command, " &");
4861     command[sizeof(command)-1] = '\0';  // Terminate string
4862 
4863     if ( debug_level & 512 )
4864     {
4865       fprintf(stderr,"%s\n", command);
4866     }
4867 
4868     if (previewer_program[0] == '\0')
4869     {
4870 //            fprintf(stderr,"\n\nPrint: No print previewer defined!\n\n\n");
4871       popup_message_always(langcode("POPEM00035"),
4872                            "No print previewer defined!");
4873       return;
4874     }
4875 
4876     if ( system( command ) != 0 )
4877     {
4878 //            fprintf(stderr,"\n\nPrint: Couldn't bring up the postscript viewer!\n\n\n");
4879       popup_message_always(langcode("POPEM00035"),
4880                            "Couldn't bring up the viewer!");
4881       return;
4882     }
4883 
4884     /*
4885             if ( !(debug_level & 512) )
4886                 unlink( ps_filename );
4887     */
4888 
4889     if ( debug_level & 512 )
4890     {
4891       fprintf(stderr,"  Done printing.\n");
4892     }
4893   }
4894 
4895   xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") );
4896   statusline(temp,1);       // Finished creating print file.
4897 
4898   //popup_message( langcode("PRINT0015"), langcode("PRINT0014") );
4899 
4900 #endif // NO_XPM
4901 
4902 }
4903 
4904 
4905 
4906 
4907 
4908 /*
4909  *  Auto_rotate
4910  *
4911  */
Auto_rotate(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)4912 static void  Auto_rotate( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
4913 {
4914   char *which = (char *)clientData;
4915   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
4916 
4917   if(state->set)
4918   {
4919     print_auto_rotation = atoi(which);
4920     print_rotated = 0;
4921     XmToggleButtonSetState(rotate_90, FALSE, FALSE);
4922   }
4923   else
4924   {
4925     print_auto_rotation = 0;
4926   }
4927 }
4928 
4929 
4930 
4931 
4932 
4933 /*
4934  *  Rotate_90
4935  *
4936  */
Rotate_90(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)4937 static void  Rotate_90( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
4938 {
4939   char *which = (char *)clientData;
4940   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
4941 
4942   if(state->set)
4943   {
4944     print_rotated = atoi(which);
4945     print_auto_rotation = 0;
4946     XmToggleButtonSetState(auto_rotate, FALSE, FALSE);
4947   }
4948   else
4949   {
4950     print_rotated = 0;
4951   }
4952 }
4953 
4954 
4955 
4956 
4957 
4958 /*
4959  *  Auto_scale
4960  *
4961  */
Auto_scale(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)4962 static void  Auto_scale( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
4963 {
4964   char *which = (char *)clientData;
4965   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
4966 
4967   if(state->set)
4968   {
4969     print_auto_scale = atoi(which);
4970   }
4971   else
4972   {
4973     print_auto_scale = 0;
4974   }
4975 }
4976 
4977 
4978 
4979 
4980 
4981 /*
4982  *  Monochrome
4983  *
4984  */
Monochrome(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)4985 void  Monochrome( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
4986 {
4987   char *which = (char *)clientData;
4988   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
4989 
4990   if(state->set)
4991   {
4992     print_in_monochrome = atoi(which);
4993   }
4994   else
4995   {
4996     print_in_monochrome = 0;
4997   }
4998 }
4999 
5000 
5001 
5002 
5003 
5004 /*
5005  *  Invert
5006  *
5007  */
Invert(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)5008 static void  Invert( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
5009 {
5010   char *which = (char *)clientData;
5011   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
5012 
5013   if(state->set)
5014   {
5015     print_invert = atoi(which);
5016   }
5017   else
5018   {
5019     print_invert = 0;
5020   }
5021 }
5022 
5023 
5024 
5025 
5026 
5027 // Print_properties:  Prints the drawing area to a PostScript file.
5028 // Provides various togglebuttons for configuring the "gv" previewer
5029 // only.
5030 //
5031 // Perhaps later:
5032 // 1) Select an area on the screen to print
5033 // 2) -label
5034 //
Print_properties(Widget w,XtPointer UNUSED (clientData),XtPointer UNUSED (callData))5035 void Print_properties( Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
5036 {
5037   static Widget pane, scrollwindow, form, button_ok, button_cancel,
5038          sep, auto_scale,
5039 //            paper_size, paper_size_data, scale, scale_data, blank_background,
5040 //            res_label1, res_label2, res_x, res_y,
5041          monochrome, invert;
5042   Atom delw;
5043 
5044   // Get rid of the Print dialog
5045   Print_postscript_destroy_shell(w, print_postscript_dialog, NULL );
5046 
5047 
5048   // If we're not using "gv", skip the entire dialog below and go
5049   // straight to the actual previewer function.
5050   //
5051   if ( !strstr(previewer_program,"gv") )
5052   {
5053     Print_preview(w, NULL, NULL);
5054     return;
5055   }
5056 
5057 
5058   if (!print_properties_dialog)
5059   {
5060 
5061 
5062     begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" );
5063 
5064 
5065     print_properties_dialog = XtVaCreatePopupShell(langcode("PRINT0001"),
5066                               xmDialogShellWidgetClass, appshell,
5067                               XmNdeleteResponse, XmDESTROY,
5068                               XmNdefaultPosition, FALSE,
5069                               XmNfontList, fontlist1,
5070                               NULL);
5071 
5072     pane = XtVaCreateWidget("Print_properties pane",xmPanedWindowWidgetClass, print_properties_dialog,
5073                             XmNbackground, colors[0xff],
5074                             NULL);
5075 
5076     scrollwindow = XtVaCreateManagedWidget("scrollwindow",
5077                                            xmScrolledWindowWidgetClass,
5078                                            pane,
5079                                            XmNscrollingPolicy, XmAUTOMATIC,
5080                                            NULL);
5081 
5082     form =  XtVaCreateWidget("Print_properties form",
5083                              xmFormWidgetClass,
5084                              scrollwindow,
5085                              XmNfractionBase, 2,
5086                              XmNbackground, colors[0xff],
5087                              XmNautoUnmanage, FALSE,
5088                              XmNshadowThickness, 1,
5089                              NULL);
5090 
5091     /*
5092             paper_size = XtVaCreateManagedWidget(langcode("PRINT0002"),xmLabelWidgetClass, form,
5093                                           XmNtopAttachment, XmATTACH_FORM,
5094                                           XmNtopOffset, 10,
5095                                           XmNbottomAttachment, XmATTACH_NONE,
5096                                           XmNleftAttachment, XmATTACH_FORM,
5097                                           XmNleftOffset, 10,
5098                                           XmNrightAttachment, XmATTACH_NONE,
5099                                           XmNbackground, colors[0xff],
5100                                           XmNfontList, fontlist1,
5101                                           NULL);
5102     XtSetSensitive(paper_size,FALSE);
5103 
5104 
5105             paper_size_data = XtVaCreateManagedWidget("Print_properties paper_size_data", xmTextFieldWidgetClass, form,
5106                                           XmNeditable,   TRUE,
5107                                           XmNcursorPositionVisible, TRUE,
5108                                           XmNsensitive, TRUE,
5109                                           XmNshadowThickness,    1,
5110                                           XmNcolumns, 15,
5111                                           XmNwidth, ((15*7)+2),
5112                                           XmNmaxLength, 15,
5113                                           XmNbackground, colors[0x0f],
5114                                           XmNtopAttachment,XmATTACH_FORM,
5115                                           XmNtopOffset, 5,
5116                                           XmNbottomAttachment,XmATTACH_NONE,
5117                                           XmNleftAttachment, XmATTACH_WIDGET,
5118                                           XmNleftWidget, paper_size,
5119                                           XmNleftOffset, 10,
5120                                           XmNrightAttachment,XmATTACH_FORM,
5121                                           XmNrightOffset, 10,
5122                                           XmNnavigationType, XmTAB_GROUP,
5123                                           XmNtraversalOn, TRUE,
5124                                           XmNfontList, fontlist1,
5125                                           NULL);
5126     XtSetSensitive(paper_size_data,FALSE);
5127     */
5128 
5129 
5130     auto_rotate  = XtVaCreateManagedWidget(langcode("PRINT0003"),xmToggleButtonWidgetClass,form,
5131 //                                      XmNtopAttachment, XmATTACH_WIDGET,
5132 //                                      XmNtopWidget, paper_size_data,
5133 //                                      XmNtopOffset, 5,
5134                                            XmNtopAttachment, XmATTACH_FORM,
5135                                            XmNtopOffset, 10,
5136                                            XmNbottomAttachment, XmATTACH_NONE,
5137                                            XmNleftAttachment, XmATTACH_FORM,
5138                                            XmNleftOffset,10,
5139                                            XmNrightAttachment, XmATTACH_NONE,
5140                                            XmNbackground, colors[0xff],
5141                                            XmNnavigationType, XmTAB_GROUP,
5142                                            XmNtraversalOn, TRUE,
5143                                            XmNfontList, fontlist1,
5144                                            NULL);
5145     XtAddCallback(auto_rotate,XmNvalueChangedCallback,Auto_rotate,"1");
5146 
5147 
5148     rotate_90  = XtVaCreateManagedWidget(langcode("PRINT0004"),xmToggleButtonWidgetClass,form,
5149 //                                      XmNtopAttachment, XmATTACH_WIDGET,
5150 //                                      XmNtopWidget, paper_size_data,
5151 //                                      XmNtopOffset, 5,
5152                                          XmNtopAttachment, XmATTACH_FORM,
5153                                          XmNtopOffset, 10,
5154                                          XmNbottomAttachment, XmATTACH_NONE,
5155                                          XmNleftAttachment, XmATTACH_WIDGET,
5156                                          XmNleftWidget, auto_rotate,
5157                                          XmNleftOffset,10,
5158                                          XmNrightAttachment, XmATTACH_FORM,
5159                                          XmNrightOffset, 10,
5160                                          XmNbackground, colors[0xff],
5161                                          XmNnavigationType, XmTAB_GROUP,
5162                                          XmNtraversalOn, TRUE,
5163                                          XmNfontList, fontlist1,
5164                                          NULL);
5165     XtAddCallback(rotate_90,XmNvalueChangedCallback,Rotate_90,"1");
5166 
5167 
5168     auto_scale = XtVaCreateManagedWidget(langcode("PRINT0005"),xmToggleButtonWidgetClass,form,
5169                                          XmNtopAttachment, XmATTACH_WIDGET,
5170                                          XmNtopWidget, auto_rotate,
5171                                          XmNtopOffset, 5,
5172                                          XmNbottomAttachment, XmATTACH_NONE,
5173                                          XmNleftAttachment, XmATTACH_FORM,
5174                                          XmNleftOffset,10,
5175                                          XmNrightAttachment, XmATTACH_NONE,
5176                                          XmNbackground, colors[0xff],
5177                                          XmNnavigationType, XmTAB_GROUP,
5178                                          XmNtraversalOn, TRUE,
5179                                          XmNfontList, fontlist1,
5180                                          NULL);
5181     XtAddCallback(auto_scale,XmNvalueChangedCallback,Auto_scale,"1");
5182 
5183 
5184     /*
5185             scale = XtVaCreateManagedWidget(langcode("PRINT0006"),xmLabelWidgetClass, form,
5186                                           XmNtopAttachment, XmATTACH_WIDGET,
5187                                           XmNtopWidget, auto_rotate,
5188                                           XmNtopOffset, 10,
5189                                           XmNbottomAttachment, XmATTACH_NONE,
5190                                           XmNleftAttachment, XmATTACH_WIDGET,
5191                                           XmNleftWidget, auto_scale,
5192                                           XmNleftOffset, 10,
5193                                           XmNrightAttachment, XmATTACH_NONE,
5194                                           XmNbackground, colors[0xff],
5195                                           XmNfontList, fontlist1,
5196                                           NULL);
5197     XtSetSensitive(scale,FALSE);
5198 
5199 
5200             scale_data = XtVaCreateManagedWidget("Print_properties scale_data", xmTextFieldWidgetClass, form,
5201                                           XmNeditable,   TRUE,
5202                                           XmNcursorPositionVisible, TRUE,
5203                                           XmNsensitive, TRUE,
5204                                           XmNshadowThickness,    1,
5205                                           XmNcolumns, 15,
5206                                           XmNwidth, ((15*7)+2),
5207                                           XmNmaxLength, 15,
5208                                           XmNbackground, colors[0x0f],
5209                                           XmNtopAttachment,XmATTACH_WIDGET,
5210                                           XmNtopWidget, auto_rotate,
5211                                           XmNtopOffset, 5,
5212                                           XmNbottomAttachment,XmATTACH_NONE,
5213                                           XmNleftAttachment, XmATTACH_WIDGET,
5214                                           XmNleftWidget, scale,
5215                                           XmNleftOffset, 10,
5216                                           XmNrightAttachment,XmATTACH_FORM,
5217                                           XmNrightOffset, 10,
5218                                           XmNnavigationType, XmTAB_GROUP,
5219                                           XmNtraversalOn, TRUE,
5220                                           XmNfontList, fontlist1,
5221                                           NULL);
5222     XtSetSensitive(scale_data,FALSE);
5223     */
5224 
5225 
5226     /*
5227             blank_background = XtVaCreateManagedWidget(langcode("PRINT0007"),xmToggleButtonWidgetClass,form,
5228                                           XmNtopAttachment, XmATTACH_WIDGET,
5229                                           XmNtopWidget, scale_data,
5230                                           XmNtopWidget, auto_rotate,
5231                                           XmNtopOffset, 5,
5232                                           XmNbottomAttachment, XmATTACH_NONE,
5233                                           XmNleftAttachment, XmATTACH_FORM,
5234                                           XmNleftOffset ,10,
5235                                           XmNrightAttachment, XmATTACH_NONE,
5236                                           XmNbackground, colors[0xff],
5237                                           XmNnavigationType, XmTAB_GROUP,
5238                                           XmNtraversalOn, TRUE,
5239                                           XmNfontList, fontlist1,
5240                                           NULL);
5241     XtSetSensitive(blank_background,FALSE);
5242     */
5243 
5244 
5245     monochrome = XtVaCreateManagedWidget(langcode("PRINT0008"),xmToggleButtonWidgetClass,form,
5246                                          XmNtopAttachment, XmATTACH_WIDGET,
5247 //                                      XmNtopWidget, blank_background,
5248                                          XmNtopWidget, auto_scale,
5249                                          XmNtopOffset, 5,
5250                                          XmNbottomAttachment, XmATTACH_NONE,
5251                                          XmNleftAttachment, XmATTACH_FORM,
5252                                          XmNleftOffset,10,
5253                                          XmNrightAttachment, XmATTACH_NONE,
5254                                          XmNbackground, colors[0xff],
5255                                          XmNnavigationType, XmTAB_GROUP,
5256                                          XmNtraversalOn, TRUE,
5257                                          XmNfontList, fontlist1,
5258                                          NULL);
5259     XtAddCallback(monochrome,XmNvalueChangedCallback,Monochrome,"1");
5260 
5261 
5262     invert = XtVaCreateManagedWidget(langcode("PRINT0016"),xmToggleButtonWidgetClass,form,
5263                                      XmNtopAttachment, XmATTACH_WIDGET,
5264                                      XmNtopWidget, monochrome,
5265                                      XmNtopOffset, 5,
5266                                      XmNbottomAttachment, XmATTACH_NONE,
5267                                      XmNleftAttachment, XmATTACH_FORM,
5268                                      XmNleftOffset,10,
5269                                      XmNrightAttachment, XmATTACH_NONE,
5270                                      XmNbackground, colors[0xff],
5271                                      XmNnavigationType, XmTAB_GROUP,
5272                                      XmNtraversalOn, TRUE,
5273                                      XmNfontList, fontlist1,
5274                                      NULL);
5275     XtAddCallback(invert,XmNvalueChangedCallback,Invert,"1");
5276 
5277 
5278     /*
5279             res_label1 = XtVaCreateManagedWidget(langcode("PRINT0009"),xmLabelWidgetClass, form,
5280                                           XmNtopAttachment, XmATTACH_WIDGET,
5281                                           XmNtopWidget, invert,
5282                                           XmNtopOffset, 10,
5283                                           XmNbottomAttachment, XmATTACH_NONE,
5284                                           XmNleftAttachment, XmATTACH_FORM,
5285                                           XmNleftOffset, 10,
5286                                           XmNrightAttachment, XmATTACH_NONE,
5287                                           XmNbackground, colors[0xff],
5288                                           XmNfontList, fontlist1,
5289                                           NULL);
5290     XtSetSensitive(res_label1,FALSE);
5291 
5292 
5293             res_x = XtVaCreateManagedWidget("Print_properties resx_data", xmTextFieldWidgetClass, form,
5294                                           XmNeditable,   TRUE,
5295                                           XmNcursorPositionVisible, TRUE,
5296                                           XmNsensitive, TRUE,
5297                                           XmNshadowThickness,    1,
5298                                           XmNcolumns, 15,
5299                                           XmNwidth, ((15*7)+2),
5300                                           XmNmaxLength, 15,
5301                                           XmNbackground, colors[0x0f],
5302                                           XmNtopAttachment,XmATTACH_WIDGET,
5303                                           XmNtopWidget, invert,
5304                                           XmNtopOffset, 5,
5305                                           XmNbottomAttachment,XmATTACH_NONE,
5306                                           XmNleftAttachment, XmATTACH_WIDGET,
5307                                           XmNleftWidget, res_label1,
5308                                           XmNleftOffset, 10,
5309                                           XmNrightAttachment,XmATTACH_NONE,
5310                                           XmNnavigationType, XmTAB_GROUP,
5311                                           XmNtraversalOn, TRUE,
5312                                           XmNfontList, fontlist1,
5313                                           NULL);
5314     XtSetSensitive(res_x,FALSE);
5315 
5316 
5317             res_label2 = XtVaCreateManagedWidget("X",xmLabelWidgetClass, form,
5318                                           XmNtopAttachment, XmATTACH_WIDGET,
5319                                           XmNtopWidget, invert,
5320                                           XmNtopOffset, 10,
5321                                           XmNbottomAttachment, XmATTACH_NONE,
5322                                           XmNleftAttachment, XmATTACH_WIDGET,
5323                                           XmNleftWidget, res_x,
5324                                           XmNleftOffset, 10,
5325                                           XmNrightAttachment, XmATTACH_NONE,
5326                                           XmNbackground, colors[0xff],
5327                                           XmNfontList, fontlist1,
5328                                           NULL);
5329     XtSetSensitive(res_label2,FALSE);
5330 
5331 
5332             res_y = XtVaCreateManagedWidget("Print_properties res_y_data", xmTextFieldWidgetClass, form,
5333                                           XmNeditable,   TRUE,
5334                                           XmNcursorPositionVisible, TRUE,
5335                                           XmNsensitive, TRUE,
5336                                           XmNshadowThickness,    1,
5337                                           XmNcolumns, 15,
5338                                           XmNwidth, ((15*7)+2),
5339                                           XmNmaxLength, 15,
5340                                           XmNbackground, colors[0x0f],
5341                                           XmNtopAttachment,XmATTACH_WIDGET,
5342                                           XmNtopWidget, invert,
5343                                           XmNtopOffset, 5,
5344                                           XmNbottomAttachment,XmATTACH_NONE,
5345                                           XmNleftAttachment, XmATTACH_WIDGET,
5346                                           XmNleftWidget, res_label2,
5347                                           XmNleftOffset, 10,
5348                                           XmNrightAttachment,XmATTACH_FORM,
5349                                           XmNrightOffset, 10,
5350                                           XmNnavigationType, XmTAB_GROUP,
5351                                           XmNtraversalOn, TRUE,
5352                                           XmNfontList, fontlist1,
5353                                           NULL);
5354     XtSetSensitive(res_y,FALSE);
5355     */
5356 
5357 
5358     sep = XtVaCreateManagedWidget("Print_properties sep", xmSeparatorGadgetClass,form,
5359                                   XmNorientation, XmHORIZONTAL,
5360                                   XmNtopAttachment,XmATTACH_WIDGET,
5361 //                                      XmNtopWidget, res_y,
5362                                   XmNtopWidget, invert,
5363                                   XmNtopOffset, 10,
5364                                   XmNbottomAttachment,XmATTACH_NONE,
5365                                   XmNleftAttachment, XmATTACH_FORM,
5366                                   XmNrightAttachment,XmATTACH_FORM,
5367                                   XmNbackground, colors[0xff],
5368                                   XmNfontList, fontlist1,
5369                                   NULL);
5370 
5371 
5372 //        button_ok = XtVaCreateManagedWidget(langcode("PRINT0011"),xmPushButtonGadgetClass, form,
5373     button_ok = XtVaCreateManagedWidget(langcode("PRINT0010"),xmPushButtonGadgetClass, form,
5374                                         XmNtopAttachment, XmATTACH_WIDGET,
5375                                         XmNtopWidget, sep,
5376                                         XmNtopOffset, 5,
5377                                         XmNbottomAttachment, XmATTACH_FORM,
5378                                         XmNbottomOffset, 5,
5379                                         XmNleftAttachment, XmATTACH_POSITION,
5380                                         XmNleftPosition, 0,
5381                                         XmNleftOffset, 3,
5382                                         XmNrightAttachment, XmATTACH_POSITION,
5383                                         XmNrightPosition, 1,
5384                                         XmNrightOffset, 2,
5385                                         XmNbackground, colors[0xff],
5386                                         XmNnavigationType, XmTAB_GROUP,
5387                                         XmNtraversalOn, TRUE,
5388                                         XmNfontList, fontlist1,
5389                                         NULL);
5390 
5391 
5392     button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form,
5393                                             XmNtopAttachment, XmATTACH_WIDGET,
5394                                             XmNtopWidget, sep,
5395                                             XmNtopOffset, 5,
5396                                             XmNbottomAttachment, XmATTACH_FORM,
5397                                             XmNbottomOffset, 5,
5398                                             XmNleftAttachment, XmATTACH_POSITION,
5399                                             XmNleftPosition, 1,
5400                                             XmNleftOffset, 3,
5401                                             XmNrightAttachment, XmATTACH_POSITION,
5402                                             XmNrightPosition, 2,
5403                                             XmNrightOffset, 5,
5404                                             XmNbackground, colors[0xff],
5405                                             XmNnavigationType, XmTAB_GROUP,
5406                                             XmNtraversalOn, TRUE,
5407                                             XmNfontList, fontlist1,
5408                                             NULL);
5409 
5410 
5411     XtAddCallback(button_ok, XmNactivateCallback, Print_preview, NULL );
5412     XtAddCallback(button_cancel, XmNactivateCallback, Print_properties_destroy_shell, print_properties_dialog);
5413 
5414 
5415     XmToggleButtonSetState(rotate_90,FALSE,FALSE);
5416     XmToggleButtonSetState(auto_rotate,TRUE,FALSE);
5417 
5418 
5419     if (print_auto_rotation)
5420     {
5421       XmToggleButtonSetState(auto_rotate, TRUE, TRUE);
5422     }
5423     else
5424     {
5425       XmToggleButtonSetState(auto_rotate, FALSE, TRUE);
5426     }
5427 
5428 
5429     if (print_rotated)
5430     {
5431       XmToggleButtonSetState(rotate_90, TRUE, TRUE);
5432     }
5433     else
5434     {
5435       XmToggleButtonSetState(rotate_90, FALSE, TRUE);
5436     }
5437 
5438 
5439     if (print_in_monochrome)
5440     {
5441       XmToggleButtonSetState(monochrome, TRUE, FALSE);
5442     }
5443     else
5444     {
5445       XmToggleButtonSetState(monochrome, FALSE, FALSE);
5446     }
5447 
5448 
5449     if (print_invert)
5450     {
5451       XmToggleButtonSetState(invert, TRUE, FALSE);
5452     }
5453     else
5454     {
5455       XmToggleButtonSetState(invert, FALSE, FALSE);
5456     }
5457 
5458 
5459     if (print_auto_scale)
5460     {
5461       XmToggleButtonSetState(auto_scale, TRUE, TRUE);
5462     }
5463     else
5464     {
5465       XmToggleButtonSetState(auto_scale, FALSE, TRUE);
5466     }
5467 
5468 
5469 //        XmTextFieldSetString(paper_size_data,print_paper_size);
5470 
5471 
5472     end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" );
5473 
5474 
5475     pos_dialog(print_properties_dialog);
5476 
5477 
5478     delw = XmInternAtom(XtDisplay(print_properties_dialog),"WM_DELETE_WINDOW", FALSE);
5479     XmAddWMProtocolCallback(print_properties_dialog, delw, Print_properties_destroy_shell, (XtPointer)print_properties_dialog);
5480 
5481 
5482     XtManageChild(form);
5483     XtManageChild(pane);
5484 
5485     resize_dialog(form, print_properties_dialog);
5486 
5487     XtPopup(print_properties_dialog,XtGrabNone);
5488 
5489 
5490     // Move focus to the Cancel button.  This appears to highlight the
5491     // button fine, but we're not able to hit the <Enter> key to
5492     // have that default function happen.  Note:  We _can_ hit the
5493     // <SPACE> key, and that activates the option.
5494 //        XmUpdateDisplay(print_properties_dialog);
5495     XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT);
5496 
5497 
5498   }
5499   else
5500   {
5501     (void)XRaiseWindow(XtDisplay(print_properties_dialog), XtWindow(print_properties_dialog));
5502   }
5503 }
5504 
5505 
5506 
5507 
5508 
5509 // General print dialog.  From here we can either print Postscript
5510 // files to the device selected in this dialog, or head off to a
5511 // print preview program that might allow us a variety of print
5512 // options.  From here we should be able to set the print device
5513 // and the print preview program & path.
5514 //
Print_Postscript(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))5515 void Print_Postscript( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
5516 {
5517   static Widget pane, scrollwindow, form, button_print, button_cancel,
5518          sep, button_preview;
5519   Atom delw;
5520 
5521   if (!print_postscript_dialog)
5522   {
5523 
5524 
5525     begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" );
5526 
5527 
5528     print_postscript_dialog = XtVaCreatePopupShell(langcode("PULDNFI015"),
5529                               xmDialogShellWidgetClass, appshell,
5530                               XmNdeleteResponse, XmDESTROY,
5531                               XmNdefaultPosition, FALSE,
5532                               XmNfontList, fontlist1,
5533                               NULL);
5534 
5535     pane = XtVaCreateWidget("Print_postscript pane",xmPanedWindowWidgetClass, print_postscript_dialog,
5536                             XmNbackground, colors[0xff],
5537                             NULL);
5538 
5539     scrollwindow = XtVaCreateManagedWidget("scrollwindow",
5540                                            xmScrolledWindowWidgetClass,
5541                                            pane,
5542                                            XmNscrollingPolicy, XmAUTOMATIC,
5543                                            NULL);
5544 
5545     form =  XtVaCreateWidget("Print_postscript form",
5546                              xmFormWidgetClass,
5547                              scrollwindow,
5548                              XmNfractionBase, 3,
5549                              XmNbackground, colors[0xff],
5550                              XmNautoUnmanage, FALSE,
5551                              XmNshadowThickness, 1,
5552                              NULL);
5553 
5554     // "Direct to:"
5555     button_print = XtVaCreateManagedWidget(langcode("PRINT1001"),xmPushButtonGadgetClass, form,
5556                                            XmNtopAttachment, XmATTACH_FORM,
5557                                            XmNtopOffset, 5,
5558                                            XmNbottomAttachment, XmATTACH_NONE,
5559                                            XmNleftAttachment, XmATTACH_FORM,
5560                                            XmNleftOffset, 5,
5561                                            XmNrightAttachment, XmATTACH_NONE,
5562                                            XmNbackground, colors[0xff],
5563                                            XmNnavigationType, XmTAB_GROUP,
5564                                            XmNtraversalOn, TRUE,
5565                                            XmNfontList, fontlist1,
5566                                            NULL);
5567 
5568 
5569     printer_data = XtVaCreateManagedWidget("Print_Postscript printer_data", xmTextFieldWidgetClass, form,
5570                                            XmNeditable,   TRUE,
5571                                            XmNcursorPositionVisible, TRUE,
5572                                            XmNsensitive, TRUE,
5573                                            XmNshadowThickness,    1,
5574                                            XmNcolumns, 40,
5575                                            XmNwidth, ((40*7)+2),
5576                                            XmNmaxLength, MAX_FILENAME,
5577                                            XmNbackground, colors[0x0f],
5578                                            XmNtopAttachment,XmATTACH_FORM,
5579                                            XmNtopOffset, 5,
5580                                            XmNbottomAttachment,XmATTACH_NONE,
5581                                            XmNleftAttachment, XmATTACH_WIDGET,
5582                                            XmNleftWidget, button_print,
5583                                            XmNleftOffset, 10,
5584                                            XmNrightAttachment,XmATTACH_FORM,
5585                                            XmNrightOffset, 5,
5586                                            XmNnavigationType, XmTAB_GROUP,
5587                                            XmNtraversalOn, TRUE,
5588                                            XmNfontList, fontlist1,
5589                                            NULL);
5590 
5591 
5592     // "Via Previewer:"
5593     button_preview = XtVaCreateManagedWidget(langcode("PRINT1002"),xmPushButtonGadgetClass, form,
5594                      XmNtopAttachment, XmATTACH_WIDGET,
5595                      XmNtopWidget, button_print,
5596                      XmNtopOffset, 5,
5597                      XmNbottomAttachment, XmATTACH_NONE,
5598                      XmNleftAttachment, XmATTACH_FORM,
5599                      XmNleftOffset, 5,
5600                      XmNrightAttachment, XmATTACH_NONE,
5601                      XmNbackground, colors[0xff],
5602                      XmNnavigationType, XmTAB_GROUP,
5603                      XmNtraversalOn, TRUE,
5604                      XmNfontList, fontlist1,
5605                      NULL);
5606 
5607 
5608     previewer_data = XtVaCreateManagedWidget("Print_Postscript previewer_data", xmTextFieldWidgetClass, form,
5609                      XmNeditable,   TRUE,
5610                      XmNcursorPositionVisible, TRUE,
5611                      XmNsensitive, TRUE,
5612                      XmNshadowThickness,    1,
5613                      XmNcolumns, 40,
5614                      XmNwidth, ((40*7)+2),
5615                      XmNmaxLength, MAX_FILENAME,
5616                      XmNbackground, colors[0x0f],
5617                      XmNtopAttachment,XmATTACH_WIDGET,
5618                      XmNtopWidget, button_print,
5619                      XmNtopOffset, 5,
5620                      XmNbottomAttachment,XmATTACH_NONE,
5621                      XmNleftAttachment, XmATTACH_WIDGET,
5622                      XmNleftWidget, button_preview,
5623                      XmNleftOffset, 10,
5624                      XmNrightAttachment,XmATTACH_FORM,
5625                      XmNrightOffset, 5,
5626                      XmNnavigationType, XmTAB_GROUP,
5627                      XmNtraversalOn, TRUE,
5628                      XmNfontList, fontlist1,
5629                      NULL);
5630 
5631 
5632     sep = XtVaCreateManagedWidget("Print_postscript sep", xmSeparatorGadgetClass,form,
5633                                   XmNorientation, XmHORIZONTAL,
5634                                   XmNtopAttachment,XmATTACH_WIDGET,
5635                                   XmNtopWidget, button_preview,
5636                                   XmNtopOffset, 10,
5637                                   XmNbottomAttachment,XmATTACH_NONE,
5638                                   XmNleftAttachment, XmATTACH_FORM,
5639                                   XmNrightAttachment,XmATTACH_FORM,
5640                                   XmNbackground, colors[0xff],
5641                                   XmNfontList, fontlist1,
5642                                   NULL);
5643 
5644 
5645     button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form,
5646                                             XmNtopAttachment, XmATTACH_WIDGET,
5647                                             XmNtopWidget, sep,
5648                                             XmNtopOffset, 5,
5649                                             XmNbottomAttachment, XmATTACH_FORM,
5650                                             XmNbottomOffset, 5,
5651                                             XmNleftAttachment, XmATTACH_FORM,
5652                                             XmNleftOffset, 5,
5653                                             XmNrightAttachment, XmATTACH_FORM,
5654                                             XmNrightOffset, 5,
5655                                             XmNbackground, colors[0xff],
5656                                             XmNnavigationType, XmTAB_GROUP,
5657                                             XmNtraversalOn, TRUE,
5658                                             XmNfontList, fontlist1,
5659                                             NULL);
5660 
5661 
5662     XtAddCallback(button_preview, XmNactivateCallback, Print_properties, NULL );
5663     XtAddCallback(button_print, XmNactivateCallback, Print_window, NULL );
5664     XtAddCallback(button_cancel, XmNactivateCallback, Print_postscript_destroy_shell, print_postscript_dialog);
5665 
5666     // Fill in the text fields from persistent variables out of the config file.
5667     XmTextFieldSetString(printer_data, printer_program);
5668     XmTextFieldSetString(previewer_data, previewer_program);
5669 
5670     end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" );
5671 
5672 
5673     pos_dialog(print_postscript_dialog);
5674 
5675 
5676     delw = XmInternAtom(XtDisplay(print_postscript_dialog),"WM_DELETE_WINDOW", FALSE);
5677     XmAddWMProtocolCallback(print_postscript_dialog, delw, Print_postscript_destroy_shell, (XtPointer)print_postscript_dialog);
5678 
5679 
5680     XtManageChild(form);
5681     XtManageChild(pane);
5682 
5683     resize_dialog(form, print_postscript_dialog);
5684 
5685     XtPopup(print_postscript_dialog,XtGrabNone);
5686 
5687     // Move focus to the Cancel button.  This appears to highlight the
5688     // button fine, but we're not able to hit the <Enter> key to
5689     // have that default function happen.  Note:  We _can_ hit the
5690     // <SPACE> key, and that activates the option.
5691 //        XmUpdateDisplay(print_postscript_dialog);
5692     XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT);
5693 
5694 
5695   }
5696   else
5697   {
5698     (void)XRaiseWindow(XtDisplay(print_postscript_dialog), XtWindow(print_postscript_dialog));
5699   }
5700 }
5701 
5702 
5703 
5704 
5705 
5706 // Create png image (for use in web browsers??).  Requires that "convert"
5707 // from the ImageMagick package be installed on the system.  At the
5708 // point this thread is started, the XPM file has already been
5709 // created.  We now create a .geo file to go with the .png file.
5710 //
5711 #ifndef NO_XPM
snapshot_thread(void * UNUSED (arg))5712 static void* snapshot_thread(void * UNUSED(arg) )
5713 {
5714   char xpm_filename[MAX_FILENAME];
5715   char png_filename[MAX_FILENAME];
5716   char geo_filename[MAX_FILENAME];
5717   char kml_filename[MAX_FILENAME];   // filename for kml file that describes the png file in keyhole markup language
5718   char timestring[101];  // string representation of the time heard or the current time
5719   FILE *f;
5720   FILE *fk;  // file handle for kml file
5721   time_t expire_time;
5722 #ifdef HAVE_CONVERT
5723   char command[MAX_FILENAME*2];
5724 #endif  // HAVE_CONVERT
5725   char temp_base_dir[MAX_VALUE];
5726 
5727   get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir));
5728 
5729 
5730   // The pthread_detach() call means we don't care about the
5731   // return code and won't use pthread_join() later.  Makes
5732   // threading more efficient.
5733   (void)pthread_detach(pthread_self());
5734 
5735   xastir_snprintf(xpm_filename,
5736                   sizeof(xpm_filename),
5737                   "%s/snapshot.xpm",
5738                   temp_base_dir);
5739 
5740   xastir_snprintf(png_filename,
5741                   sizeof(png_filename),
5742                   "%s/snapshot.png",
5743                   temp_base_dir);
5744 
5745   // Same for the .geo filename
5746   xastir_snprintf(geo_filename,
5747                   sizeof(geo_filename),
5748                   "%s/snapshot.geo",
5749                   temp_base_dir);
5750 
5751   // Same for the .kml filename
5752   xastir_snprintf(kml_filename,
5753                   sizeof(kml_filename),
5754                   "%s/snapshot.kml",
5755                   temp_base_dir);
5756 
5757 
5758   // Create a .geo file to match the new png image
5759   // Likewise for a matching .kml file
5760   f = fopen(geo_filename,"w");    // Overwrite whatever file
5761   // is there.
5762   fk = fopen(kml_filename,"w");
5763 
5764   if (f == NULL || fk == NULL)
5765   {
5766     if (f==NULL)
5767     {
5768       fprintf(stderr,"Couldn't open %s\n",geo_filename);
5769     }
5770     if (fk==NULL)
5771     {
5772       fprintf(stderr,"Couldn't open %s\n",kml_filename);
5773     }
5774   }
5775   else
5776   {
5777     float lat1, long1, lat2, long2;
5778 
5779 
5780     long1 = f_NW_corner_longitude;
5781     lat1 = f_NW_corner_latitude;
5782     long2 = f_SE_corner_longitude;
5783     lat2 = f_SE_corner_latitude;
5784 
5785     // FILENAME   world1.xpm
5786     // #          x          y        lon         lat
5787     // TIEPOINT   0          0        -180        90
5788     // TIEPOINT   639        319      180         -90
5789     // IMAGESIZE  640        320
5790     // REFRESH    250
5791 
5792     fprintf(f,"FILENAME     snapshot.png\n");
5793     fprintf(f,"#            x       y        lon           lat\n");
5794     fprintf(f,"TIEPOINT     0       0       %8.5f     %8.5f\n",
5795             long1, lat1);
5796     fprintf(f,"TIEPOINT     %-4d    %-4d    %8.5f     %8.5f\n",
5797             (int)screen_width-1, (int)screen_height-1, long2, lat2);
5798 
5799     fprintf(f,"IMAGESIZE    %-4d    %-4d\n",
5800             (int)screen_width, (int)screen_height);
5801     fprintf(f,"REFRESH      250\n");
5802     fclose(f);
5803 
5804     // Write a matching kml file that describes the location of the snapshot on
5805     // the Earth's surface.
5806     // Another kml file pointing to the location of this file with a networklinkcontrol element
5807     // and an update element loaded into a kml application should be able to reload this file
5808     // at regular intervals.
5809     // See kml documentation of:
5810     // <kml><NetworkLinkControl><linkName/><refreshMode/>
5811     //
5812     // <?xml version="1.0" encoding="UTF-8"?>
5813     // <kml xmlns="http://earth.google.com/kml/2.1">
5814     // <Document>
5815     //   <NetworkLink>
5816     //      <Link>
5817     //        <href>http://www.example.com/cgi-bin/screenshot.kml</href>
5818     //        <refreshMode>onExpire</refreshMode>
5819     //      </Link>
5820     //  </NetworkLink>
5821     // </Document>
5822     // </kml>
5823     //
5824     // TODO: Calculate a suitable range and tilt for viewing the snapshot draped on the
5825     // underlying terrain.
5826 
5827     fprintf(fk,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
5828     fprintf(fk,"<kml xmlns=\"http://earth.google.com/kml/2.2\">\n");
5829     // Add an expire time matching the time when the next snapshot should
5830     // be produced, so that a network link with an onExpire refresh mode
5831     // will check for the next snapshot.
5832     expire_time = sec_now() + (time_t)(snapshot_interval * 60);
5833     if (get_w3cdtf_datetime(expire_time, timestring, False, False))
5834     {
5835       if (strlen(timestring) > 0)
5836       {
5837         fprintf(fk,"  <NetworkLinkControl>\n");
5838         fprintf(fk,"     <expires>%s</expires>\n",timestring);
5839         fprintf(fk,"  </NetworkLinkControl>\n");
5840       }
5841     }
5842     fprintf(fk,"  <Document>\n");
5843     fprintf(fk,"    <name>XASTIR Snapshot from %s</name>\n",my_callsign);
5844     fprintf(fk,"    <open>1</open>\n");
5845     fprintf(fk,"    <GroundOverlay>\n");
5846     fprintf(fk,"      <name>Xastir snapshot</name>\n");
5847     fprintf(fk,"      <visibility>1</visibility>\n");
5848     // timestamp the overlay with the current time
5849     if (get_w3cdtf_datetime(sec_now(), timestring, True, True))
5850     {
5851       if (strlen(timestring) > 0)
5852       {
5853         fprintf(fk,"      <TimeStamp><when>%s</when></TimeStamp>\n",timestring);
5854         fprintf(fk,"      <description>Overlay shows screen visible for %s in Xastir at %s.</description>\n",my_callsign,timestring);
5855       }
5856     }
5857     else
5858     {
5859       fprintf(fk,"      <description>Overlay shows screen visible for %s in Xastir.</description>\n",my_callsign);
5860     }
5861     fprintf(fk,"      <LookAt>\n");
5862     fprintf(fk,"        <longitude>%8.5f</longitude>\n",f_center_longitude);
5863     fprintf(fk,"        <latitude>%8.5f</latitude>\n",f_center_latitude);
5864     fprintf(fk,"        <altitude>0</altitude>\n");
5865     fprintf(fk,"        <range>30350.36838438907</range>\n");  // range in meters from viewer to lookat point
5866     fprintf(fk,"        <tilt>0</tilt>\n");  // 0 is looking straight down
5867     fprintf(fk,"        <altitudeMode>clampToGround</altitudeMode>\n");
5868     fprintf(fk,"        <heading>0</heading>\n");  // 0 is north at top, 90 east at top
5869     fprintf(fk,"      </LookAt>\n");
5870     fprintf(fk,"      <Icon>\n");
5871     fprintf(fk,"        <href>snapshot.png</href>\n");
5872     fprintf(fk,"      </Icon>\n");
5873     fprintf(fk,"      <LatLonBox>\n");
5874     fprintf(fk,"        <north>%8.5f</north>\n",lat1);
5875     fprintf(fk,"        <south>%8.5f</south>\n",lat2);
5876     fprintf(fk,"        <east>%8.5f</east>\n",long2);
5877     fprintf(fk,"        <west>%8.5f</west>\n",long1);
5878     fprintf(fk,"        <rotation>0</rotation>\n");
5879     fprintf(fk,"      </LatLonBox>\n");
5880     fprintf(fk,"    </GroundOverlay>\n");
5881     fprintf(fk,"  </Document>\n");
5882     fprintf(fk,"</kml>\n");
5883 
5884     fclose(fk);
5885 
5886     chmod( geo_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
5887     chmod( kml_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
5888   }
5889 
5890 
5891   if ( debug_level & 512 )
5892   {
5893     fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, png_filename );
5894   }
5895 
5896 
5897 #ifdef HAVE_CONVERT
5898   // Convert it to a png file.  This depends upon having the
5899   // ImageMagick command "convert" installed.
5900   strcpy(command, CONVERT_PATH);
5901   command[sizeof(command)-1] = '\0';  // Terminate string
5902   strcat(command, " -quality 100 -colors 256 ");
5903   command[sizeof(command)-1] = '\0';  // Terminate string
5904   strcat(command, xpm_filename);
5905   command[sizeof(command)-1] = '\0';  // Terminate string
5906   strcat(command, " ");
5907   command[sizeof(command)-1] = '\0';  // Terminate string
5908   strcat(command, png_filename);
5909   command[sizeof(command)-1] = '\0';  // Terminate string
5910 
5911   if ( system( command ) != 0 )
5912   {
5913     // We _may_ have had an error.  Check errno to make
5914     // sure.
5915     if (errno)
5916     {
5917       fprintf(stderr, "%s\n", strerror(errno));
5918       fprintf(stderr,
5919               "Failed to convert snapshot: %s -> %s\n",
5920               xpm_filename,
5921               png_filename);
5922     }
5923     else
5924     {
5925       fprintf(stderr,
5926               "System call return error: convert: %s -> %s\n",
5927               xpm_filename,
5928               png_filename);
5929     }
5930   }
5931   else
5932   {
5933     chmod( png_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
5934 
5935 //        // Delete temporary xpm file
5936 //        unlink( xpm_filename );
5937 
5938     if ( debug_level & 512 )
5939     {
5940       fprintf(stderr,"  Done creating png.\n");
5941     }
5942   }
5943 
5944 #endif  // HAVE_CONVERT
5945 
5946   // Signify that we're all done and that another snapshot can
5947   // occur.
5948   doing_snapshot = 0;
5949 
5950   return(NULL);
5951 }
5952 #endif  // NO_XPM
5953 
5954 
5955 
5956 
5957 
5958 // Starts a separate thread that creates a png image from the
5959 // current displayed image.
5960 //
Snapshot(void)5961 void Snapshot(void)
5962 {
5963 #ifndef NO_XPM
5964   pthread_t snapshot_thread_id;
5965   char xpm_filename[MAX_FILENAME];
5966   int xpmretval;
5967 #endif  // NO_XPM
5968   char temp_base_dir[MAX_VALUE];
5969 
5970   get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir));
5971 
5972 
5973   // Check whether we're already doing a snapshot
5974   if (doing_snapshot)
5975   {
5976     return;
5977   }
5978 
5979   // Time to take another snapshot?
5980   // New snapshot interval based on slider in Configure Timing
5981   // dialog (in minutes)
5982   if (sec_now() < (last_snapshot + (snapshot_interval * 60)) )
5983   {
5984     return;
5985   }
5986 
5987   last_snapshot = sec_now(); // Set up timer for next time
5988 
5989 
5990 #ifndef NO_XPM
5991 
5992   if (debug_level & 512)
5993   {
5994     fprintf(stderr,"Taking Snapshot\n");
5995   }
5996 
5997   doing_snapshot++;
5998 
5999   // Set up the XPM filename that we'll use
6000   xastir_snprintf(xpm_filename,
6001                   sizeof(xpm_filename),
6002                   "%s/snapshot.xpm",
6003                   temp_base_dir);
6004 
6005 
6006   if ( debug_level & 512 )
6007   {
6008     fprintf(stderr,"Creating %s\n", xpm_filename );
6009   }
6010 
6011   // Create an XPM file from pixmap_final.
6012   if (chdir(temp_base_dir) != 0)
6013   {
6014     fprintf(stderr,"Couldn't chdir to %s directory for snapshot\n", temp_base_dir);
6015     return;
6016   }
6017 
6018   xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),   // Display *display
6019                                    "snapshot.xpm",                             // char *filename
6020                                    pixmap_final,                               // Pixmap pixmap
6021                                    (Pixmap)NULL,                               // Pixmap shapemask
6022                                    NULL );
6023 
6024   if (xpmretval != XpmSuccess)
6025   {
6026     fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename,
6027             XpmGetErrorString(xpmretval));
6028     return;
6029   }
6030 
6031   chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
6032 
6033 
6034 //----- Start New Thread -----
6035 
6036   //
6037   // Here we start a new thread.  We'll communicate with the main
6038   // thread via global variables.  Use mutex locks if there might
6039   // be a conflict as to when/how we're updating those variables.
6040   //
6041 
6042   if (pthread_create(&snapshot_thread_id, NULL, snapshot_thread, NULL))
6043   {
6044     fprintf(stderr,"Error creating snapshot thread\n");
6045   }
6046   else
6047   {
6048     // We're off and running with the new thread!
6049   }
6050 #endif  // NO_XPM
6051 }
6052 
6053 
6054 
6055 
6056 
6057 // Function to remove double-quote characters and spaces that occur
6058 // outside of the double-quote characters.
clean_string(char * input)6059 void clean_string(char *input)
6060 {
6061   char *i;
6062   char *j;
6063 
6064 
6065   //fprintf(stderr,"|%s|\t",input);
6066 
6067   // Remove any double quote characters
6068   i = index(input,'"');   // Find first quote character, if any
6069 
6070   if (i != NULL)
6071   {
6072     j = index(i+1,'"'); // Find second quote character, if any
6073 
6074     if (j != NULL)      // Found two quote characters
6075     {
6076       j[0] = '\0';    // Terminate the string at the 2nd quote
6077       // Can't use strcpy here because it can't work with
6078       // overlapping strings.  strcpy is a dangerous function
6079       // anyway and shouldn't be used.
6080       memmove(input, i+1, j-i);
6081     }
6082     else    // We only found one quote character.  What to do?
6083     {
6084 //            fprintf(stderr,"clean_string: Only one quote found!\n");
6085     }
6086   }
6087   //fprintf(stderr,"|%s|\n",input);
6088 
6089   // Remove leading/trailing spaces?
6090 }
6091 
6092 
6093 
6094 
6095 
6096 
6097 
6098 // Test map visibility (on screen)
6099 //
6100 // Input parameters are in Xastir coordinate system (fastest for us)
6101 // check_percentage:
6102 //      0 = don't check
6103 //      1 = check map size versus viewport scale.  Return 0 if map
6104 //      is too large/small (percentage-wise) to be displayed.
6105 //
6106 // Returns: MAP_NOT_VIS if map is _not_ visible
6107 //          MAP_IS_VIS if map _is_ visible
6108 //
6109 // Xastir Coordinate System:
6110 //
6111 //              0 (90 deg. or 90N)
6112 //
6113 // 0 (-180 deg. or 180W)      129,600,000 (180 deg. or 180E)
6114 //
6115 //          64,800,000 (-90 deg. or 90S)
6116 //
6117 // Note that we already have map_visible() and map_visible_lat_lon()
6118 // routines.
6119 //
map_onscreen(long left,long right,long top,long bottom,int UNUSED (check_percentage))6120 enum map_onscreen_enum map_onscreen(long left,
6121                                     long right,
6122                                     long top,
6123                                     long bottom,
6124                                     int UNUSED(check_percentage) )
6125 {
6126 
6127   enum map_onscreen_enum in_window = MAP_NOT_VIS;
6128 
6129 
6130   if (map_visible((unsigned long)bottom,
6131                   (unsigned long)top,
6132                   (unsigned long)left,
6133                   (unsigned long)right))
6134   {
6135     in_window = MAP_IS_VIS;
6136     //fprintf(stderr,"map_onscreen:Map is visible\n");
6137   }
6138 
6139 
6140 #ifdef MAP_SCALE_CHECK
6141   // Check whether map is too large/small for our current scale?
6142   // Check whether the map extents are < XX% of viewscreen size
6143   // (both directions), or viewscreen is > XX% of map extents
6144   // (either direction).  This will knock out maps that are too
6145   // large/small to be displayed at this zoom level.
6146 //WE7U
6147   if (in_window && check_percentage)
6148   {
6149     long map_x, map_y, view_x, view_y;
6150     float percentage = 0.04;
6151 
6152 
6153     map_x  = right - left;
6154     if (map_x < 0)
6155     {
6156       map_x = 0;
6157     }
6158 
6159     map_y  = bottom - top;
6160     if (map_y < 0)
6161     {
6162       map_y = 0;
6163     }
6164 
6165     view_x = max_NW_corner_longitude - NW_corner_longitude;
6166     if (view_x < 0)
6167     {
6168       view_x = 0;
6169     }
6170 
6171     view_y = max_NW_corner_latitude - NW_corner_latitude;
6172     if (view_y < 0)
6173     {
6174       view_y = 0;
6175     }
6176 
6177 //fprintf(stderr,"\n map_x: %d\n", map_x);
6178 //fprintf(stderr," map_y: %d\n", map_y);
6179 //fprintf(stderr,"view_x: %d\n", view_x);
6180 //fprintf(stderr,"view_y: %d\n", view_y);
6181 
6182     if ((map_x < (view_x * percentage )) && (map_y < (view_x * percentage)))
6183     {
6184       in_window = 0;  // Send back "not-visible" flag
6185       fprintf(stderr,"map too small for view: %d%%\n",(int)(percentage * 100));
6186     }
6187 
6188 //        if ((view_x < (map_x * percentage)) && (view_y < (map_x * percentage))) {
6189 //            in_window = 0;  // Send back "not-visible" flag
6190 //fprintf(stderr,"view too small for map: %d%%\n",(int)(percentage * 100));
6191 //        }
6192 
6193   }
6194 #endif  // MAP_SCALE_CHECK
6195 
6196   //fprintf(stderr,"map_onscreen returning %d\n", in_window);
6197   return (in_window);
6198 }
6199 
6200 
6201 
6202 
6203 
6204 // Function which checks whether a map is onscreen, but does so by
6205 // finding the map boundaries from the map index.  The only input
6206 // parameter is the complete path/filename.
6207 //
6208 // Returns: MAP_NOT_VIS if map is _not_ visible
6209 //          MAP_IS_VIS if map _is_ visible
6210 //          MAP_NOT_INDEXED if the map is not in the index
6211 //
map_onscreen_index(char * filename)6212 enum map_onscreen_enum map_onscreen_index(char *filename)
6213 {
6214   unsigned long top, bottom, left, right;
6215   enum map_onscreen_enum onscreen = MAP_NOT_INDEXED;
6216   int max_zoom, min_zoom;
6217   int map_layer, draw_filled, usgs_drg, auto_maps; // Unused in this function
6218 
6219 
6220   if (index_retrieve(filename, &bottom, &top, &left, &right,
6221                      &max_zoom, &min_zoom, &map_layer,
6222                      &draw_filled, &usgs_drg, &auto_maps) )
6223   {
6224 
6225     //fprintf(stderr, "Map found in index: %s\n", filename);
6226 
6227     // Map was in the index, check for visibility and scale
6228     // Check whether the map extents are < XX% of viewscreen
6229     // size (both directions), or viewscreen is > XX% of map
6230     // extents (either direction).  This will knock out maps
6231     // that are too large/small to be displayed at this zoom
6232     // level.
6233     if (map_onscreen(left, right, top, bottom, 1))
6234     {
6235 
6236       //fprintf(stderr, "Map found in index and onscreen: %s\n", filename);
6237 
6238       if (((max_zoom == 0) ||
6239            ((max_zoom != 0) && (scale_y <= max_zoom))) &&
6240           ((min_zoom == 0) ||
6241            ((min_zoom != 0) && (scale_y >= min_zoom))))
6242       {
6243 
6244         onscreen = MAP_IS_VIS;
6245         //fprintf(stderr,"Map in the zoom zone: %s\n",filename);
6246       }
6247       else
6248       {
6249         onscreen = MAP_NOT_VIS;
6250         //fprintf(stderr,"Map not in the zoom zone: %s\n",filename);
6251       }
6252 
6253 // Check whether the map extents are < XX% of viewscreen size (both
6254 // directions), or viewscreen is > XX% of map extents (either
6255 // direction).  This will knock out maps that are too large/small to
6256 // be displayed at this zoom level.
6257 
6258 
6259     }
6260     else    // Map is not visible
6261     {
6262       onscreen = MAP_NOT_VIS;
6263       //fprintf(stderr,"Map found in index but not onscreen: %s\n",filename);
6264     }
6265   }
6266   else    // Map is not in the index
6267   {
6268     onscreen = MAP_NOT_INDEXED;
6269     //fprintf(stderr,"Map not found in index: %s\n",filename);
6270   }
6271   return(onscreen);
6272 }
6273 
6274 
6275 
6276 
6277 
6278 /**********************************************************
6279  * draw_map()
6280  *
6281  * Function which tries to figure out what type of map or
6282  * image file we're dealing with, and takes care of getting
6283  * it onto the screen.  Calls other functions to deal with
6284  * .geo/.tif/.shp maps.
6285  *
6286  * If destination_pixmap == DRAW_NOT, then we'll not draw
6287  * the map anywhere, but we'll determine the map extents
6288  * and write them to the map index file.
6289  **********************************************************/
6290 /* table of map drivers, selected by filename extension */
6291 extern void draw_dos_map(Widget w,
6292                          char *dir,
6293                          char *filenm,
6294                          alert_entry *alert,
6295                          u_char alert_color,
6296                          int destination_pixmap,
6297                          map_draw_flags *draw_flags);
6298 
6299 extern void draw_palm_image_map(Widget w,
6300                                 char *dir,
6301                                 char *filenm,
6302                                 alert_entry *alert,
6303                                 u_char alert_color,
6304                                 int destination_pixmap,
6305                                 map_draw_flags *draw_flags);
6306 
6307 #ifdef HAVE_LIBSHP
6308 extern void draw_shapefile_map (Widget w,
6309                                 char *dir,
6310                                 char *filenm,
6311                                 alert_entry *alert,
6312                                 u_char alert_color,
6313                                 int destination_pixmap,
6314                                 map_draw_flags *draw_flags);
6315   extern void clear_dbfawk_sigs(void);
6316 #endif /* HAVE_LIBSHP */
6317 #ifdef HAVE_LIBGEOTIFF
6318 extern void draw_geotiff_image_map(Widget w,
6319                                    char *dir,
6320                                    char *filenm,
6321                                    alert_entry *alert,
6322                                    u_char alert_color,
6323                                    int destination_pixmap,
6324                                    map_draw_flags *draw_flags);
6325 #endif /* HAVE_LIBGEOTIFF */
6326 extern void draw_geo_image_map(Widget w,
6327                                char *dir,
6328                                char *filenm,
6329                                alert_entry *alert,
6330                                u_char alert_color,
6331                                int destination_pixmap,
6332                                map_draw_flags *draw_flags);
6333 
6334 extern void draw_gnis_map(Widget w,
6335                           char *dir,
6336                           char *filenm,
6337                           alert_entry *alert,
6338                           u_char alert_color,
6339                           int destination_pixmap,
6340                           map_draw_flags *draw_flags);
6341 
6342 extern void draw_pop_map(Widget w,
6343                          char *dir,
6344                          char *filenm,
6345                          alert_entry *alert,
6346                          u_char alert_color,
6347                          int destination_pixmap,
6348                          map_draw_flags *draw_flags);
6349 
6350 struct
6351 {
6352   char *ext;
6353   enum {none=0, map, tif, geo, gnis, shp, pop} type;
6354   void (*func)(Widget w,
6355                char *dir,
6356                char *filenm,
6357                alert_entry *alert,
6358                u_char alert_color,
6359                int destination_pixmap,
6360                map_draw_flags *draw_flags);
6361 } map_driver[] =
6362 {
6363   {"map",map,draw_dos_map},
6364 
6365 #ifdef HAVE_LIBGEOTIFF
6366   {"tif",tif,draw_geotiff_image_map},
6367 #endif /* HAVE_LIBGEOTIFF */
6368 
6369   {"geo",geo,draw_geo_image_map},
6370   {"gnis",gnis,draw_gnis_map},
6371   {"pop",pop,draw_pop_map},
6372 
6373 #ifdef HAVE_LIBSHP
6374   {"shp",shp,draw_shapefile_map},
6375 #endif /* HAVE_LIBSHP */
6376 
6377   {NULL,none,NULL}
6378 }, *map_driver_ptr;
6379 
6380 
6381 
6382 
6383 
draw_map(Widget w,char * dir,char * filenm,alert_entry * alert,u_char alert_color,int destination_pixmap,map_draw_flags * draw_flags)6384 void draw_map (Widget w, char *dir, char *filenm, alert_entry *alert,
6385                u_char alert_color, int destination_pixmap,
6386                map_draw_flags *draw_flags)
6387 {
6388   enum map_onscreen_enum onscreen;
6389   char *ext;
6390   char file[MAX_FILENAME];
6391 
6392   if ((ext = get_map_ext(filenm)) == NULL)
6393   {
6394     return;
6395   }
6396 
6397   if (debug_level & 16)
6398   {
6399     fprintf(stderr,"draw_map: Searching for map driver\n");
6400   }
6401 
6402   for (map_driver_ptr = map_driver; map_driver_ptr->ext; map_driver_ptr++)
6403   {
6404     if (strcasecmp(ext,map_driver_ptr->ext) == 0)
6405     {
6406       if (debug_level & 16)
6407         fprintf(stderr,
6408                 "draw_map: Found map driver: %s: %d\n",
6409                 ext,
6410                 map_driver_ptr->type);
6411       break;            /* found our map_driver */
6412     }
6413   }
6414   if (map_driver_ptr->type == none)      /* fall thru: unknown map driver */
6415   {
6416     // Check whether we're indexing or drawing the map
6417     if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS)
6418          && (destination_pixmap != INDEX_NO_TIMESTAMPS) )
6419     {
6420       // We're drawing, not indexing.  Output a warning
6421       // message.
6422       fprintf(stderr,"*** draw_map: Unknown map type: %s ***\n", filenm);
6423     }
6424     else    // We're indexing
6425     {
6426       if (debug_level & 16)
6427       {
6428         fprintf(stderr,"draw_map: No map driver found\n");
6429       }
6430     }
6431     return;
6432   }
6433 
6434   onscreen = map_onscreen_index(filenm); // Check map index
6435 
6436   // Check whether we're indexing or drawing the map
6437   if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
6438        || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
6439   {
6440 
6441     // We're indexing maps
6442     if (onscreen != MAP_NOT_INDEXED) // We already have an index entry for this map.
6443       // This is where we pick up a big speed increase:
6444       // Refusing to index a map that's already indexed.
6445     {
6446       return;  // Skip it.
6447     }
6448   }
6449   else    // We're drawing maps
6450   {
6451     // See if map is visible.  If not, skip it.
6452     if (onscreen == MAP_NOT_VIS)    // Map is not visible, skip it.
6453     {
6454       //fprintf(stderr,"map not visible\n");
6455       if (alert)
6456       {
6457         alert->flags[on_screen] = 'N';
6458       }
6459       return;
6460     }
6461   }
6462 
6463 
6464   xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm);
6465 
6466   // Used for debugging.  If we get a segfault on a map, this is
6467   // often the only way of finding out which map file we can't
6468   // handle.
6469   if (debug_level & 16)
6470   {
6471     fprintf(stderr,"draw_map: %s\n",file);
6472   }
6473 
6474   /* XXX - aren't alerts just shp maps?  Why was there special case code? */
6475 
6476   if (map_driver_ptr->func)
6477   {
6478     map_driver_ptr->func(w,
6479                          dir,
6480                          filenm,
6481                          alert,
6482                          alert_color,
6483                          destination_pixmap,
6484                          draw_flags);
6485   }
6486 
6487   XmUpdateDisplay (XtParent (da));
6488 }  // End of draw_map()
6489 
6490 
6491 
6492 
6493 
6494 static void index_update_directory(char *directory);
6495 static void index_update_accessed(char *filename);
6496 
6497 
6498 
6499 
6500 
6501 /////////////////////////////////////////////////////////////////////
6502 // map_search()
6503 //
6504 // Function which recurses through map directories, finding map
6505 // files.  It's called from load_auto_maps and load_alert_maps.  If
6506 // a map file is found, it is drawn.  We can also call this function
6507 // in indexing mode rather than draw mode, specified by the
6508 // destination_pixmap parameter.
6509 //
6510 // If alert == NULL, we looking for a regular map file to draw.
6511 // If alert != NULL, we have a weather alert to draw.
6512 //
6513 // For alert maps, we need to do things a bit differently, as there
6514 // should be only a few maps that contain all of the alert maps, and we
6515 // can compute which map some of them might be in.  We need to fill in
6516 // the alert structure with the filename that alert is found in.
6517 // For alerts we're not drawing the maps, we're just computing the
6518 // full filename for the alert and filling that struct field in.
6519 //
6520 // The "warn" parameter specifies whether to warn the operator about
6521 // the alert on the console as well.  If it was received locally or
6522 // via local RF, then the answer is yes.  The severe weather may be
6523 // nearby.
6524 //
6525 // We have the timestamp of the map_index.sys file stored away in
6526 // the global:  time_t map_index_timestamp;
6527 // Use that timestamp to compare the map file or GEO file timestamps
6528 // to.  Re-index the map if map_index_timestamp is older.
6529 //
6530 /////////////////////////////////////////////////////////////////////
map_search(Widget w,char * dir,alert_entry * alert,int * alert_count,int warn,int destination_pixmap)6531 static void map_search (Widget w, char *dir, alert_entry * alert, int *alert_count,int warn, int destination_pixmap)
6532 {
6533   struct dirent *dl = NULL;
6534   DIR *dm;
6535   char fullpath[MAX_FILENAME];
6536   struct stat nfile;
6537 //    const time_t *ftime;
6538 //    char this_time[40];
6539   char *ptr;
6540   char *map_dir;
6541   int map_dir_length;
6542   map_draw_flags mdf;
6543 
6544   // We'll use the weather alert directory if it's an alert
6545   map_dir = alert ? ALERT_MAP_DIR : SELECTED_MAP_DIR;
6546 
6547   map_dir_length = (int)strlen (map_dir);
6548 
6549   if (alert)      // We're doing weather alerts
6550   {
6551     // First check whether the alert->filename variable is filled
6552     // in.  If so, we've already found the file and can just display
6553     // that shape in the file
6554     if (alert->filename[0] == '\0')     // No filename in struct, so will have
6555     {
6556       // to search for the shape in the files.
6557       switch (alert->title[3])
6558       {
6559         case 'F':   // 'F' in 4th char means fire alert
6560           // Use fire alert file fz_??????
6561           //fprintf(stderr,"%c:Fire Alert file\n",alert->title[3]);
6562           xastir_snprintf(alert->filename,
6563                           sizeof(alert->filename),
6564                           "fz");
6565           break;
6566 
6567         case 'C':   // 'C' in 4th char means county
6568           // Use County file c_??????
6569           //fprintf(stderr,"%c:County file\n",alert->title[3]);
6570           xastir_snprintf(alert->filename,
6571                           sizeof(alert->filename),
6572                           "c_");
6573           break;
6574         case 'A':   // 'A' in 4th char means county warning area
6575           // Use County warning area w_?????
6576           //fprintf(stderr,"%c:County warning area file\n",alert->title[3]);
6577           xastir_snprintf(alert->filename,
6578                           sizeof(alert->filename),
6579                           "w_");
6580           break;
6581         case 'Z':
6582           // Zone, coastal or offshore marine zone file z_????? or mz?????? or oz??????
6583           // oz: ANZ081-086,088,PZZ081-085
6584           // mz: AM,AN,GM,LC,LE,LH,LM,LO,LS,PH,PK,PM,PS,PZ,SL
6585           // z_: All others
6586           if (strncasecmp(alert->title,"AM",2) == 0)
6587           {
6588             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6589             xastir_snprintf(alert->filename,
6590                             sizeof(alert->filename),
6591                             "mz");
6592           }
6593           else if (strncasecmp(alert->title,"AN",2) == 0)
6594           {
6595             // Need to check for Z081-Z086, Z088, if so use
6596             // oz??????, else use mz??????
6597             if (       (strncasecmp(&alert->title[3],"Z081",4) == 0)
6598                        || (strncasecmp(&alert->title[3],"Z082",4) == 0)
6599                        || (strncasecmp(&alert->title[3],"Z083",4) == 0)
6600                        || (strncasecmp(&alert->title[3],"Z084",4) == 0)
6601                        || (strncasecmp(&alert->title[3],"Z085",4) == 0)
6602                        || (strncasecmp(&alert->title[3],"Z086",4) == 0)
6603                        || (strncasecmp(&alert->title[3],"Z088",4) == 0) )
6604             {
6605               //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]);
6606               xastir_snprintf(alert->filename,
6607                               sizeof(alert->filename),
6608                               "oz");
6609             }
6610             else
6611             {
6612               //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6613               xastir_snprintf(alert->filename,
6614                               sizeof(alert->filename),
6615                               "mz");
6616             }
6617           }
6618           else if (strncasecmp(alert->title,"GM",2) == 0)
6619           {
6620             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6621             xastir_snprintf(alert->filename,
6622                             sizeof(alert->filename),
6623                             "mz");
6624           }
6625           else if (strncasecmp(alert->title,"LC",2) == 0)
6626           {
6627             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6628             xastir_snprintf(alert->filename,
6629                             sizeof(alert->filename),
6630                             "mz");
6631           }
6632           else if (strncasecmp(alert->title,"LE",2) == 0)
6633           {
6634             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6635             xastir_snprintf(alert->filename,
6636                             sizeof(alert->filename),
6637                             "mz");
6638           }
6639           else if (strncasecmp(alert->title,"LH",2) == 0)
6640           {
6641             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6642             xastir_snprintf(alert->filename,
6643                             sizeof(alert->filename),
6644                             "mz");
6645           }
6646           else if (strncasecmp(alert->title,"LM",2) == 0)
6647           {
6648             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6649             xastir_snprintf(alert->filename,
6650                             sizeof(alert->filename),
6651                             "mz");
6652           }
6653           else if (strncasecmp(alert->title,"LO",2) == 0)
6654           {
6655             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6656             xastir_snprintf(alert->filename,
6657                             sizeof(alert->filename),
6658                             "mz");
6659           }
6660           else if (strncasecmp(alert->title,"LS",2) == 0)
6661           {
6662             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6663             xastir_snprintf(alert->filename,
6664                             sizeof(alert->filename),
6665                             "mz");
6666           }
6667           else if (strncasecmp(alert->title,"PH",2) == 0)
6668           {
6669             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6670             xastir_snprintf(alert->filename,
6671                             sizeof(alert->filename),
6672                             "mz");
6673           }
6674           else if (strncasecmp(alert->title,"PK",2) == 0)
6675           {
6676             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6677             xastir_snprintf(alert->filename,
6678                             sizeof(alert->filename),
6679                             "mz");
6680           }
6681           else if (strncasecmp(alert->title,"PM",2) == 0)
6682           {
6683             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6684             xastir_snprintf(alert->filename,
6685                             sizeof(alert->filename),
6686                             "mz");
6687           }
6688           else if (strncasecmp(alert->title,"PS",2) == 0)
6689           {
6690             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6691             xastir_snprintf(alert->filename,
6692                             sizeof(alert->filename),
6693                             "mz");
6694           }
6695           else if (strncasecmp(alert->title,"PZ",2) == 0)
6696           {
6697 // Need to check for PZZ081-085, if so use oz??????, else use mz??????
6698             if (       (strncasecmp(&alert->title[3],"Z081",4) == 0)
6699                        || (strncasecmp(&alert->title[3],"Z082",4) == 0)
6700                        || (strncasecmp(&alert->title[3],"Z083",4) == 0)
6701                        || (strncasecmp(&alert->title[3],"Z084",4) == 0)
6702                        || (strncasecmp(&alert->title[3],"Z085",4) == 0) )
6703             {
6704               //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]);
6705               xastir_snprintf(alert->filename,
6706                               sizeof(alert->filename),
6707                               "oz");
6708             }
6709             else
6710             {
6711               //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6712               xastir_snprintf(alert->filename,
6713                               sizeof(alert->filename),
6714                               "mz");
6715             }
6716           }
6717           else if (strncasecmp(alert->title,"SL",2) == 0)
6718           {
6719             //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]);
6720             xastir_snprintf(alert->filename,
6721                             sizeof(alert->filename),
6722                             "mz");
6723           }
6724           else
6725           {
6726             // Must be regular zone file instead of coastal
6727             // marine zone or offshore marine zone.
6728             //fprintf(stderr,"%c:Zone file\n",alert->title[3]);
6729             xastir_snprintf(alert->filename,
6730                             sizeof(alert->filename),
6731                             "z_");
6732           }
6733           break;
6734 
6735         default:
6736 // VK2XJG
6737 // This section could most likely be moved so that it's not called as part of the default, but in order
6738 // to get the shapefiles for BOM working this was the best spot at the time...
6739           // Australian BOM alerts use the following shapefiles:
6740           // PW = Public Warning = gfe_public_weather
6741           // MW = Coastal Waters = gfe_coastal_waters
6742           // CW = Coastal Waters Warnings = gfe_coastal_waters_warnings
6743           // FW = Fire Weather = gfe_fire_weather
6744           // ME = Metro Effects = gfe_metro_areas
6745           // Note - Need to cater for both 2 and 3 character state designators
6746           // Shapefile filenames are static - there is no datestamp in the filename.
6747           if ((strncasecmp(&alert->title[4],"MW",2) == 0) || (strncasecmp(&alert->title[3],"MW",2) == 0))
6748           {
6749             //fprintf(stderr,"%c:BOM Coastal Waters file\n",alert->title[4]);
6750             xastir_snprintf(alert->filename,
6751                             sizeof(alert->filename),
6752                             "gfe_coastal_waters.shp");
6753           }
6754           else if ((strncasecmp(&alert->title[4],"CW",2) == 0) || (strncasecmp(&alert->title[3],"CW",2) == 0))
6755           {
6756             //fprintf(stderr,"%c:BOM Coastal waters warning file\n",alert->title[3]);
6757             xastir_snprintf(alert->filename,
6758                             sizeof(alert->filename),
6759                             "gfe_coastal_waters_warnings.shp");
6760           }
6761           else if ((strncasecmp(&alert->title[4],"PW",2) == 0) || (strncasecmp(&alert->title[3],"PW",2) == 0))
6762           {
6763             //fprintf(stderr,"%c:BOM Public Weather file\n",alert->title[3]);
6764             xastir_snprintf(alert->filename,
6765                             sizeof(alert->filename),
6766                             "gfe_public_weather.shp");
6767           }
6768           else if ((strncasecmp(&alert->title[4],"FW",2) == 0) || (strncasecmp(&alert->title[3],"FW",2) == 0))
6769           {
6770             //fprintf(stderr,"%c:BOM Fire Weather file\n",alert->title[3]);
6771             xastir_snprintf(alert->filename,
6772                             sizeof(alert->filename),
6773                             "gfe_fire_weather.shp");
6774           }
6775           else if ((strncasecmp(&alert->title[4],"ME",2) == 0) || (strncasecmp(&alert->title[3],"ME",2) == 0))
6776           {
6777             //fprintf(stderr,"%c:BOM Metro Areas file\n",alert->title[3]);
6778             xastir_snprintf(alert->filename,
6779                             sizeof(alert->filename),
6780                             "gfe_metro_areas.shp");
6781           }
6782 
6783 
6784 
6785           // Unknown type
6786 //fprintf(stderr,"%c:Can't match weather warning to a Shapefile:%s\n",alert->title[3],alert->title);
6787           break;
6788       }
6789 //            fprintf(stderr,"%s\t%s\t%s\n",alert->activity,alert->alert_status,alert->title);
6790       //fprintf(stderr,"File: %s\n",alert->filename);
6791     }
6792 
6793 // NOTE:  Need to skip this part if we have a full filename.
6794 
6795     if (alert->filename[0])     // We have at least a partial filename
6796     {
6797       int done = 0;
6798 
6799       if (strlen(alert->filename) > 3)
6800       {
6801         done++;  // We already have a filename
6802       }
6803 
6804       if (!done)      // We don't have a filename yet
6805       {
6806 
6807         // Look through the warning directory to find a match for
6808         // the first few characters that we already figured out.
6809         // This is designed so that we don't need to know the exact
6810         // filename, but only the lead three characters in order to
6811         // figure out which shapefile to use.
6812         dm = opendir (dir);
6813         if (!dm)    // Couldn't open directory
6814         {
6815           xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir);
6816           // If local alert, warn the operator via the
6817           // console as well.
6818           if (warn)
6819           {
6820             perror (fullpath);
6821           }
6822         }
6823         else      // We could open the directory just fine
6824         {
6825           while ( (dl = readdir(dm)) && !done )
6826           {
6827             int i;
6828 
6829             // Check the file/directory name for control
6830             // characters
6831             for (i = 0; i < (int)strlen(dl->d_name); i++)
6832             {
6833               // Dump out a warning if control
6834               // characters other than LF or CR are
6835               // found.
6836               if ( (dl->d_name[i] != '\n')
6837                    && (dl->d_name[i] != '\r')
6838                    && (dl->d_name[i] < 0x20) )
6839               {
6840 
6841                 fprintf(stderr,"\nmap_search: Found control char 0x%02x in alert file/alert directory name.  Line was:\n",
6842                         dl->d_name[i]);
6843                 fprintf(stderr,"%s\n",dl->d_name);
6844               }
6845               /*
6846               // This part might not work 'cuz we'd be changing a memory area that
6847               // we might have only read access to.  Check this.
6848                                           if (dl->d_name[i] < 0x20) {
6849                                               // Terminate string at any control character
6850                                               dl->d_name[i] = '\0';
6851                                           }
6852               */
6853             }
6854 
6855             xastir_snprintf(fullpath, sizeof(fullpath), "%s%s", dir, dl->d_name);
6856             /*fprintf(stderr,"FULL PATH %s\n",fullpath); */
6857             if (stat (fullpath, &nfile) == 0)
6858             {
6859 //                            ftime = (time_t *)&nfile.st_ctime;
6860               switch (nfile.st_mode & S_IFMT)
6861               {
6862                 case (S_IFDIR):     // It's a directory, skip it
6863                   break;
6864 
6865                 case (S_IFREG):     // It's a file, check it
6866                   /*fprintf(stderr,"FILE %s\n",dl->d_name); */
6867                   // Here we look for a match for the
6868                   // first 2 characters of the filename.
6869                   //
6870                   if (strncasecmp(alert->filename,dl->d_name,2) == 0)
6871                   {
6872                     // We have a match for the
6873                     // first few characters.
6874                     // Check that last three are
6875                     // "shp"
6876 
6877                     //fprintf(stderr,"%s\n",fullpath);
6878 
6879                     if ( (dl->d_name[strlen(dl->d_name)-3] == 's'
6880                           || dl->d_name[strlen(dl->d_name)-3] == 'S')
6881                          && (dl->d_name[strlen(dl->d_name)-2] == 'h'
6882                              || dl->d_name[strlen(dl->d_name)-2] == 'H')
6883                          && (dl->d_name[strlen(dl->d_name)-1] == 'p'
6884                              || dl->d_name[strlen(dl->d_name)-1] == 'P') )
6885                     {
6886                       // We have an exact match.
6887                       // Save the filename in the alert
6888                       memcpy(alert->filename,
6889                              dl->d_name,
6890                              sizeof(alert->filename));
6891                       // Terminate string
6892                       alert->filename[sizeof(alert->filename)-1] = '\0';
6893                       done++;
6894                       //fprintf(stderr,"%s\n",dl->d_name);
6895                     }
6896                   }
6897                   break;
6898 
6899                 default:    // Not dir or file, skip it
6900                   break;
6901               }
6902             }
6903           }
6904         }
6905         (void)closedir (dm);
6906       }
6907 
6908       if (done)      // We found a filename match for the alert
6909       {
6910         // Go draw the weather alert (kind'a)
6911 //WE7U
6912         mdf.draw_filled=1;
6913         mdf.usgs_drg=0;
6914 
6915         if (debug_level & 16)
6916         {
6917           fprintf(stderr,"map_search: calling draw_map for an alert\n");
6918         }
6919 
6920         draw_map (w,
6921                   dir,                // Alert directory
6922                   alert->filename,    // Shapefile filename
6923                   alert,
6924                   -1,                 // Signifies "DON'T DRAW THE SHAPE"
6925                   destination_pixmap,
6926                   &mdf );
6927 
6928         if (debug_level & 16)
6929         {
6930           fprintf(stderr,"map_search: returned from draw_map\n");
6931         }
6932 
6933       }
6934       else        // No filename found that matches the first two
6935       {
6936         // characters that we already computed.
6937 
6938         //
6939         // Need code here
6940         //
6941 
6942       }
6943     }
6944     else    // Still no filename for the weather alert.
6945     {
6946       // Output an error message?
6947       //
6948       // Need code here
6949       //
6950 
6951     }
6952   }
6953 
6954 
6955 // MAPS, not alerts
6956 
6957   else    // We're doing regular maps, not weather alerts
6958   {
6959     time_t map_timestamp;
6960 
6961 
6962     dm = opendir (dir);
6963     if (!dm)    // Couldn't open directory
6964     {
6965       xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir);
6966       if (warn)
6967       {
6968         perror (fullpath);
6969       }
6970     }
6971     else
6972     {
6973       int count = 0;
6974       while ((dl = readdir (dm)))
6975       {
6976         int i;
6977 
6978         // Check the file/directory name for control
6979         // characters
6980         for (i = 0; i < (int)strlen(dl->d_name); i++)
6981         {
6982           // Dump out a warning if control characters
6983           // other than LF or CR are found.
6984           if ( (dl->d_name[i] != '\n')
6985                && (dl->d_name[i] != '\r')
6986                && (dl->d_name[i] < 0x20) )
6987           {
6988 
6989             fprintf(stderr,"\nmap_search: Found control char 0x%02x in map file/map directory name.  Line was:\n",
6990                     dl->d_name[i]);
6991             fprintf(stderr,"%s\n",dl->d_name);
6992           }
6993           /*
6994           // This part might not work 'cuz we'd be changing a memory area that
6995           // we might have only read access to.  Check this.
6996                               if (dl->d_name[i] < 0x20) {
6997                                   // Terminate string at any control character
6998                                   dl->d_name[i] = '\0';
6999                               }
7000           */
7001         }
7002 
7003         xastir_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, dl->d_name);
7004         //fprintf(stderr,"FULL PATH %s\n",fullpath);
7005         if (stat (fullpath, &nfile) == 0)
7006         {
7007 //                    ftime = (time_t *)&nfile.st_ctime;
7008           switch (nfile.st_mode & S_IFMT)
7009           {
7010             case (S_IFDIR):     // It's a directory, recurse
7011               //fprintf(stderr,"file %c letter %c\n",dl->d_name[0],letter);
7012               if ((strcmp (dl->d_name, ".") != 0) && (strcmp (dl->d_name, "..") != 0))
7013               {
7014 
7015                 //fprintf(stderr,"FULL PATH %s\n",fullpath);
7016 
7017                 // If we're indexing, throw the
7018                 // directory into the map index as
7019                 // well.
7020                 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
7021                      || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
7022                 {
7023                   char temp_dir[MAX_FILENAME];
7024 
7025                   // Drop off the base part of the
7026                   // path for the indexing,
7027                   // usually
7028                   // "/usr/local/share/xastir/maps".
7029                   // Add a '/' to the end.
7030                   xastir_snprintf(temp_dir,
7031                                   sizeof(temp_dir),
7032                                   "%s/",
7033                                   &fullpath[map_dir_length+1]);
7034 
7035                   // Add the directory to the
7036                   // in-memory map index.
7037                   index_update_directory(temp_dir);
7038                 }
7039 
7040 //                                xastir_snprintf(this_time,
7041 //                                    sizeof(this_time),
7042 //                                    "%s",
7043 //                                    ctime(ftime));
7044                 map_search(w, fullpath, alert, alert_count, warn, destination_pixmap);
7045               }
7046               break;
7047 
7048             case (S_IFREG):     // It's a file, draw the map
7049               /*fprintf(stderr,"FILE %s\n",dl->d_name); */
7050 
7051               // Get the last-modified timestamp for the map file
7052               //map_timestamp = (time_t)nfile.st_mtime;
7053               map_timestamp =
7054                 (time_t)( (nfile.st_mtime>nfile.st_ctime) ? nfile.st_mtime : nfile.st_ctime );
7055 
7056 
7057               // Check whether we're doing indexing or
7058               // map drawing.  If indexing, we only
7059               // want to index if the map timestamp is
7060               // newer than the index timestamp.
7061               if (destination_pixmap == INDEX_CHECK_TIMESTAMPS
7062                   || destination_pixmap == INDEX_NO_TIMESTAMPS)
7063               {
7064                 // We're doing indexing, not map drawing
7065                 char temp_dir[MAX_FILENAME];
7066 
7067                 // Drop off the base part of the
7068                 // path for the indexing, usually
7069                 // "/usr/local/share/xastir/maps".
7070                 xastir_snprintf(temp_dir,
7071                                 sizeof(temp_dir),
7072                                 "%s",
7073                                 &fullpath[map_dir_length+1]);
7074 
7075                 // Update the "accessed"
7076                 // variable in the record
7077                 index_update_accessed(temp_dir);
7078 
7079 // Note:  This is not as efficient as it should be, as we're looking
7080 // through the in-memory map index here just to update the
7081 // "accessed" variable, then in some cases looking through it again
7082 // in the next section for updated maps, or if we're ignoring
7083 // timestamps while indexing.  Looking through a linear linked list
7084 // too many times overall.
7085 
7086                 if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
7087                      && (map_timestamp < map_index_timestamp) )
7088                 {
7089                   // Map is older than index _and_
7090                   // we're supposed to check
7091                   // timestamps.
7092                   count++;
7093                   break;  // Skip indexing this file
7094                 }
7095                 else    // Map is newer or we're ignoring timestamps.
7096                 {
7097                   // We'll index the map
7098                   if (debug_level & 16)
7099                   {
7100                     fprintf(stderr,"Indexing map: %s\n",fullpath);
7101                   }
7102                 }
7103               }
7104 
7105               // Check whether the file is in a subdirectory
7106               if (strncmp (fullpath, map_dir, (size_t)map_dir_length) != 0)
7107               {
7108 
7109                 if (debug_level & 16)
7110                 {
7111                   fprintf(stderr,"Calling draw_map\n");
7112                 }
7113                 mdf.draw_filled=1;
7114                 mdf.usgs_drg=0;
7115 
7116                 draw_map (w,
7117                           dir,
7118                           dl->d_name,
7119                           alert ? &alert[*alert_count] : NULL,
7120                           '\0',
7121                           destination_pixmap,
7122                           &mdf );
7123 
7124                 if (debug_level & 16)
7125                 {
7126                   fprintf(stderr,"Returned from draw_map\n");
7127                 }
7128                 if (alert_count && *alert_count)
7129                 {
7130                   (*alert_count)--;
7131                 }
7132               }
7133               else
7134               {
7135                 // File is in the main map directory
7136                 // Find the '/' character
7137                 for (ptr = &fullpath[map_dir_length]; *ptr == '/'; ptr++) ;
7138                 mdf.draw_filled=1;
7139                 mdf.usgs_drg=0;
7140 
7141                 if (debug_level & 16)
7142                 {
7143                   fprintf(stderr,"Calling draw_map\n");
7144                 }
7145 
7146                 draw_map (w,
7147                           map_dir,
7148                           ptr,
7149                           alert ? &alert[*alert_count] : NULL,
7150                           '\0',
7151                           destination_pixmap,
7152                           &mdf );
7153 
7154                 if (alert_count && *alert_count)
7155                 {
7156                   (*alert_count)--;
7157                 }
7158               }
7159               count++;
7160               break;
7161 
7162             default:
7163               break;
7164           }
7165         }
7166       }
7167       if (debug_level & 16)
7168       {
7169         fprintf(stderr,"Number of maps queried: %d\n", count);
7170       }
7171 
7172       (void)closedir (dm);
7173     }
7174   }
7175 }
7176 
7177 
7178 
7179 
7180 
7181 // List pointer for the map index linked list.
7182 map_index_record *map_index_head = NULL;
7183 
7184 // Might wish to have another variable in the index which is used to
7185 // record that a file has been indexed recently.  This could be used
7186 // to prune old entries out of the index if a full indexing didn't
7187 // touch a file entry.  Could also delete an entry from the index
7188 // if/when a file can't be opened?
7189 
7190 
7191 
7192 
7193 
7194 // Function to dissect and free all of the records in a map index
7195 // linked list, leaving it totally empty.
7196 //
free_map_index(map_index_record * index_list_head)7197 static void free_map_index(map_index_record *index_list_head)
7198 {
7199   map_index_record *current;
7200   map_index_record *temp;
7201 
7202 
7203   current = index_list_head;
7204 
7205   while (current != NULL)
7206   {
7207     temp = current;
7208     if (current->XmStringPtr != NULL)
7209     {
7210       XmStringFree(current->XmStringPtr);
7211     }
7212     current = current->next;
7213     free(temp);
7214   }
7215 
7216   index_list_head = NULL;
7217 }
7218 
7219 
7220 
7221 
7222 
7223 // Function to copy just the properties fields from the backup map
7224 // index to the primary index.  Must match each record before
7225 // copying.  Once it's done, it frees the backup map index.
7226 //
map_index_copy_properties(map_index_record * primary_index_head,map_index_record * backup_index_head)7227 static void map_index_copy_properties(map_index_record *primary_index_head,
7228                                       map_index_record *backup_index_head)
7229 {
7230   map_index_record *primary;
7231   map_index_record *backup;
7232 
7233 
7234   backup = backup_index_head;
7235 
7236   // Walk the backup list, comparing the filename field with the
7237   // primary list.  When a match is found, copy just the
7238   // Properties fields (map_layer/draw_filled/auto_maps/selected)
7239   // across to the primary record.
7240   //
7241   while (backup != NULL)
7242   {
7243     int done = 0;
7244 
7245     primary = primary_index_head;
7246 
7247     while (!done && primary != NULL)
7248     {
7249 
7250       if (strcmp(primary->filename, backup->filename) == 0)   // If match
7251       {
7252 
7253         if (debug_level & 16)
7254         {
7255           fprintf(stderr,"Match: %s\t%s\n",
7256                   primary->filename,
7257                   backup->filename);
7258         }
7259 
7260         // Copy the Properties across
7261         primary->max_zoom    = backup->max_zoom;
7262         primary->min_zoom    = backup->min_zoom;
7263         primary->map_layer   = backup->map_layer;
7264         primary->draw_filled = backup->draw_filled;
7265         primary->usgs_drg    = backup->usgs_drg;
7266         primary->auto_maps   = backup->auto_maps;
7267         primary->selected    = backup->selected;
7268 
7269         // Done copying this backup record.  Go on to the
7270         // next.  Skip the rest of the primary list for this
7271         // iteration.
7272         done++;
7273       }
7274       else    // No match, walk the primary list looking for one.
7275       {
7276         primary = primary->next;
7277       }
7278     }
7279 
7280     // Walk the backup list
7281     backup = backup->next;
7282   }
7283 
7284   // We're done copying.  Free the backup list.
7285   free_map_index(backup_index_head);
7286 }
7287 
7288 
7289 
7290 
7291 
7292 // Function used to add map directories to the in-memory map index.
7293 // Causes an update of the index list in memory.  Input Records are
7294 // inserted in alphanumerical order.  We mark directories in the
7295 // index with a '/' on the end of the name, and zero entries for
7296 // top/bottom/left/right.
7297 // The input directory to this routine MUST have a '/' character on
7298 // the end of it.  This is how we differentiate directories from
7299 // files in the list.
index_update_directory(char * directory)7300 static void index_update_directory(char *directory)
7301 {
7302 
7303   map_index_record *current = map_index_head;
7304   map_index_record *previous = map_index_head;
7305   map_index_record *temp_record = NULL;
7306   int done = 0;
7307   int i;
7308 
7309 
7310   //fprintf(stderr,"index_update_directory: %s\n", directory );
7311 
7312   // Check for initial bad input
7313   if ( (directory == NULL)
7314        || (directory[0] == '\0')
7315        || (directory[strlen(directory) - 1] != '/')
7316        || ( (directory[1] == '/') && (strlen(directory) == 1)) )
7317   {
7318     fprintf(stderr,"index_update_directory: Bad input: %s\n",directory);
7319     return;
7320   }
7321   // Make sure there aren't any weird characters in the directory
7322   // that might cause problems later.  Look for control characters
7323   // and convert them to string-end characters.
7324   for ( i = 0; i < (int)strlen(directory); i++ )
7325   {
7326     // Change any control characters to '\0' chars
7327     if (directory[i] < 0x20)
7328     {
7329 
7330       fprintf(stderr,"\nindex_update_directory: Found control char 0x%02x in map file/map directory name:\n%s\n",
7331               directory[i],
7332               directory);
7333 
7334       directory[i] = '\0';    // Terminate it here
7335     }
7336   }
7337   // Check if the string is _now_ bogus
7338   if ( (directory[0] == '\0')
7339        || (directory[strlen(directory) - 1] != '/')
7340        || ( (directory[1] == '/') && (strlen(directory) == 1)))
7341   {
7342     fprintf(stderr,"index_update_directory: Bad input: %s\n",directory);
7343     return;
7344   }
7345 
7346   //if (map_index_head == NULL)
7347   //    fprintf(stderr,"Empty list\n");
7348 
7349   // Search for a matching directory name in the linked list
7350   while ((current != NULL) && !done)
7351   {
7352     int test;
7353 
7354     //fprintf(stderr,"Comparing %s to\n          %s\n",
7355     //    current->filename, directory);
7356 
7357     test = strcmp(current->filename, directory);
7358     if (test == 0)
7359     {
7360       // Found a match!
7361       //fprintf(stderr,"Found: Updating entry for %s\n",directory);
7362       temp_record = current;
7363       done++; // Exit loop, "current" points to found record
7364     }
7365     else if (test > 0)      // Found a string past us in the
7366     {
7367       // alphabet.  Insert ahead of this
7368       // last record.
7369 
7370       //fprintf(stderr,"\n%s\n%s\n",current->filename,directory);
7371 
7372       //fprintf(stderr,"Not Found: Inserting an index record for %s\n",directory);
7373       temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7374       CHECKMALLOC(temp_record);
7375 
7376       if (current == map_index_head)    // Start of list!
7377       {
7378         // Insert new record at head of list
7379         temp_record->next = map_index_head;
7380         map_index_head = temp_record;
7381         //fprintf(stderr,"Inserting at head of list\n");
7382       }
7383       else    // Insert between "previous" and "current"
7384       {
7385         // Insert new record before "current"
7386         previous->next = temp_record;
7387         temp_record->next = current;
7388         //fprintf(stderr,"Inserting before current\n");
7389       }
7390 
7391       //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory);
7392 
7393       // Fill in some default values for the new record.
7394       temp_record->selected = 0;
7395       temp_record->auto_maps = 0;
7396       temp_record->XmStringPtr = NULL;
7397 
7398       //current = current->next;
7399       done++;
7400     }
7401     else    // Haven't gotten to the correct insertion point yet
7402     {
7403       previous = current; // Save ptr to last record
7404       current = current->next;
7405     }
7406   }
7407 
7408   if (!done)      // Matching record not found, add a record to
7409   {
7410     // the end of the list.  "previous" points to
7411     // the last record in the list or NULL (empty
7412     // list).
7413     //fprintf(stderr,"Not Found: Adding an index record for %s\n",directory);
7414     temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7415     CHECKMALLOC(temp_record);
7416 
7417     temp_record->next = NULL;
7418 
7419     if (previous == NULL)   // Empty list
7420     {
7421       map_index_head = temp_record;
7422       //fprintf(stderr,"First record in new list\n");
7423     }
7424     else    // Else at end of list
7425     {
7426       previous->next = temp_record;
7427       //fprintf(stderr,"Adding to end of list: %s\n",directory);
7428     }
7429 
7430     //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory);
7431 
7432     // Fill in some default values for the new record.
7433     temp_record->selected = 0;
7434     temp_record->auto_maps = 0;
7435     temp_record->XmStringPtr = NULL;
7436   }
7437 
7438   // Update the values.  By this point we have a struct to fill
7439   // in, whether it's a new or old struct doesn't matter.  Convert
7440   // the values from lat/long to Xastir coordinate system.
7441   xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",directory);
7442 
7443   temp_record->bottom = 0;
7444   temp_record->top = 0;
7445   temp_record->left = 0;
7446   temp_record->right = 0;
7447   temp_record->accessed = 1;
7448   temp_record->max_zoom = 0;
7449   temp_record->min_zoom = 0;
7450   temp_record->map_layer = 0;
7451   temp_record->draw_filled = 0;
7452   temp_record->usgs_drg = 2;
7453 }
7454 
7455 
7456 
7457 
7458 
7459 // Function called by the various draw_* functions when in indexing
7460 // mode.  Causes an update of the index list in memory.  Input
7461 // parameters are in the Xastir coordinate system due to speed
7462 // considerations.  Records are inserted in alphanumerical order.
index_update_xastir(char * filename,unsigned long bottom,unsigned long top,unsigned long left,unsigned long right,int default_map_layer)7463 void index_update_xastir(char *filename,
7464                          unsigned long bottom,
7465                          unsigned long top,
7466                          unsigned long left,
7467                          unsigned long right,
7468                          int default_map_layer)
7469 {
7470 
7471   map_index_record *current = map_index_head;
7472   map_index_record *previous = map_index_head;
7473   map_index_record *temp_record = NULL;
7474   int done = 0;
7475   int i;
7476 
7477 
7478   // Check for initial bad input
7479   if ( (filename == NULL)
7480        || (filename[0] == '\0')
7481        || (filename[strlen(filename) - 1] == '/') )
7482   {
7483     fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename);
7484     return;
7485   }
7486   // Make sure there aren't any weird characters in the filename
7487   // that might cause problems later.  Look for control characters
7488   // and convert them to string-end characters.
7489   for ( i = 0; i < (int)strlen(filename); i++ )
7490   {
7491     // Change any control characters to '\0' chars
7492     if (filename[i] < 0x20)
7493     {
7494 
7495       fprintf(stderr,"\nindex_update_xastir: Found control char 0x%02x in map file/map directory name:\n%s\n",
7496               filename[i],
7497               filename);
7498 
7499       filename[i] = '\0';    // Terminate it here
7500     }
7501   }
7502   // Check if the string is _now_ bogus
7503   if (filename[0] == '\0')
7504   {
7505     fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename);
7506     return;
7507   }
7508 
7509   //fprintf(stderr,"index_update_xastir: (%lu,%lu)\t(%lu,%lu)\t%s\n",
7510   //    bottom, top, left, right, filename );
7511 
7512   //if (map_index_head == NULL)
7513   //    fprintf(stderr,"Empty list\n");
7514 
7515   // Skip dbf and shx map extensions.  Really should make this
7516   // case-independent...
7517   if (       strstr(filename,"shx")
7518              || strstr(filename,"dbf")
7519              || strstr(filename,"SHX")
7520              || strstr(filename,"DBF") )
7521   {
7522     return;
7523   }
7524 
7525   // Search for a matching filename in the linked list
7526   while ((current != NULL) && !done)
7527   {
7528     int test;
7529 
7530     //fprintf(stderr,"Comparing %s to\n          %s\n",current->filename,filename);
7531 
7532     test = strcmp(current->filename,filename);
7533     if (test == 0)
7534     {
7535       // Found a match!
7536       //fprintf(stderr,"Found: Updating entry for %s\n",filename);
7537       temp_record = current;
7538       done++; // Exit the while loop
7539     }
7540     else if (test > 0)      // Found a string past us in the
7541     {
7542       // alphabet.  Insert ahead of this
7543       // last record.
7544 
7545       //fprintf(stderr,"\n%s\n%s\n",current->filename,filename);
7546 
7547       //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename);
7548       temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7549       CHECKMALLOC(temp_record);
7550 
7551       if (current == map_index_head)    // Start of list!
7552       {
7553         // Insert new record at head of list
7554         temp_record->next = map_index_head;
7555         map_index_head = temp_record;
7556         //fprintf(stderr,"Inserting at head of list\n");
7557       }
7558       else
7559       {
7560         // Insert new record before "current"
7561         previous->next = temp_record;
7562         temp_record->next = current;
7563         //fprintf(stderr,"Inserting before current\n");
7564       }
7565 
7566       //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename);
7567 
7568       // Fill in some default values for the new record
7569 //WE7U
7570 // Here's where we might look at the file extension and assign
7571 // default map_layer fields based on that.
7572       temp_record->max_zoom = 0;
7573       temp_record->min_zoom = 0;
7574       temp_record->map_layer = default_map_layer;
7575       temp_record->selected = 0;
7576       temp_record->XmStringPtr = NULL;
7577 
7578       if (       strstr(filename,".geo")
7579                  || strstr(filename,".GEO")
7580                  || strstr(filename,".Geo"))
7581       {
7582         temp_record->auto_maps = 0;
7583       }
7584       else
7585       {
7586         temp_record->auto_maps = 1;
7587       }
7588 
7589       if (       strstr(filename,".shp")
7590                  || strstr(filename,".SHP")
7591                  || strstr(filename,".Shp") )
7592       {
7593         temp_record->draw_filled = 2; // Auto
7594       }
7595       else
7596       {
7597         temp_record->draw_filled = 0; // No-Fill
7598       }
7599 
7600       if (       strstr(filename,".tif")
7601                  || strstr(filename,".TIF")
7602                  || strstr(filename,".Tif") )
7603       {
7604         temp_record->usgs_drg = 2; // Auto
7605       }
7606       else
7607       {
7608         temp_record->usgs_drg = 0; // No
7609       }
7610 
7611       //current = current->next;
7612       done++;
7613     }
7614     else    // Haven't gotten to the correct insertion point yet
7615     {
7616       previous = current; // Save ptr to last record
7617       current = current->next;
7618     }
7619   }
7620 
7621   if (!done)    // Matching record not found, add a
7622   {
7623     // record to the end of the list
7624     //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename);
7625     temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7626     CHECKMALLOC(temp_record);
7627 
7628     temp_record->next = NULL;
7629 
7630     if (previous == NULL)   // Empty list
7631     {
7632       map_index_head = temp_record;
7633       //fprintf(stderr,"First record in new list\n");
7634     }
7635     else    // Else at end of list
7636     {
7637       previous->next = temp_record;
7638       //fprintf(stderr,"Adding to end of list: %s\n",filename);
7639     }
7640 
7641     //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename);
7642 
7643     // Fill in some default values for the new record
7644 //WE7U
7645 // Here's where we might look at the file extension and assign
7646 // default map_layer fields based on that.
7647     temp_record->max_zoom = 0;
7648     temp_record->min_zoom = 0;
7649     temp_record->map_layer = default_map_layer;
7650     temp_record->selected = 0;
7651     temp_record->XmStringPtr = NULL;
7652 
7653     if (       strstr(filename,".geo")
7654                || strstr(filename,".GEO")
7655                || strstr(filename,".Geo"))
7656     {
7657       temp_record->auto_maps = 0;
7658     }
7659     else
7660     {
7661       temp_record->auto_maps = 1;
7662     }
7663 
7664     if (       strstr(filename,".shp")
7665                || strstr(filename,".SHP")
7666                || strstr(filename,".Shp") )
7667     {
7668       temp_record->draw_filled = 2; // Auto
7669     }
7670     else
7671     {
7672       temp_record->draw_filled = 0; // No-Fill
7673     }
7674 
7675     if (       strstr(filename,".tif")
7676                || strstr(filename,".TIF")
7677                || strstr(filename,".Tif") )
7678     {
7679       temp_record->usgs_drg = 2; // Auto
7680     }
7681     else
7682     {
7683       temp_record->usgs_drg = 0; // No
7684     }
7685 
7686   }
7687 
7688   // Update the values.  By this point we have a struct to fill
7689   // in, whether it's a new or old struct doesn't matter.  Convert
7690   // the values from lat/long to Xastir coordinate system.
7691   xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename);
7692 
7693   temp_record->bottom = bottom;
7694   temp_record->top = top;
7695   temp_record->left = left;
7696   temp_record->right = right;
7697   temp_record->accessed = 1;
7698 }
7699 
7700 
7701 
7702 
7703 
7704 // Function called by the various draw_* functions when in indexing
7705 // mode.  Causes an update of the index list in memory.  Input
7706 // parameters are in lat/long, which are converted to Xastir
7707 // coordinates for storage due to speed considerations.  Records are
7708 // inserted in alphanumerical order.
index_update_ll(char * filename,double bottom,double top,double left,double right,int default_map_layer)7709 void index_update_ll(char *filename,
7710                      double bottom,
7711                      double top,
7712                      double left,
7713                      double right,
7714                      int default_map_layer)
7715 {
7716 
7717   map_index_record *current = map_index_head;
7718   map_index_record *previous = map_index_head;
7719   map_index_record *temp_record = NULL;
7720   int done = 0;
7721   unsigned long temp_left, temp_right, temp_top, temp_bottom;
7722   int ok;
7723   int i;
7724 
7725 
7726   // Check for initial bad input
7727   if ( (filename == NULL)
7728        || (filename[0] == '\0')
7729        || (filename[strlen(filename) - 1] == '/') )
7730   {
7731     fprintf(stderr,"index_update_ll: Bad input: %s\n",filename);
7732     return;
7733   }
7734   // Make sure there aren't any weird characters in the filename
7735   // that might cause problems later.  Look for control characters
7736   // and convert them to string-end characters.
7737   for ( i = 0; i < (int)strlen(filename); i++ )
7738   {
7739     // Change any control characters to '\0' chars
7740     if (filename[i] < 0x20)
7741     {
7742 
7743       fprintf(stderr,"\nindex_update_ll: Found control char 0x%02x in map file/map directory name:\n%s\n",
7744               filename[i],
7745               filename);
7746 
7747       filename[i] = '\0';    // Terminate it here
7748     }
7749   }
7750   // Check if the string is _now_ bogus
7751   if (filename[0] == '\0')
7752   {
7753     fprintf(stderr,"index_update_ll: Bad input: %s\n",filename);
7754     return;
7755   }
7756 
7757   //fprintf(stderr,"index_update_ll: (%15.10g,%15.10g)\t(%15.10g,%15.10g)\t%s\n",
7758   //    bottom, top, left, right, filename );
7759 
7760   //if (map_index_head == NULL)
7761   //    fprintf(stderr,"Empty list\n");
7762 
7763   // Skip dbf and shx map extensions.  Really should make this
7764   // case-independent...
7765   if (       strstr(filename,"shx")
7766              || strstr(filename,"dbf")
7767              || strstr(filename,"SHX")
7768              || strstr(filename,"DBF") )
7769   {
7770     return;
7771   }
7772 
7773   // Search for a matching filename in the linked list
7774   while ((current != NULL) && !done)
7775   {
7776     int test;
7777 
7778     //fprintf(stderr,"Comparing %s to\n          %s\n",current->filename,filename);
7779 
7780     test = strcmp(current->filename,filename);
7781 
7782     if (test == 0)
7783     {
7784       // Found a match!
7785       //fprintf(stderr,"Found: Updating entry for %s\n",filename);
7786       temp_record = current;
7787       done++; // Exit the while loop
7788     }
7789 
7790     else if (test > 0)
7791     {
7792       // Found a string past us in the alphabet.  Insert ahead
7793       // of this last record.
7794 
7795       //fprintf(stderr,"\n%s\n%s\n",current->filename,filename);
7796 
7797       //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename);
7798       temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7799       CHECKMALLOC(temp_record);
7800 
7801       if (current == map_index_head)    // Start of list!
7802       {
7803         // Insert new record at head of list
7804         temp_record->next = map_index_head;
7805         map_index_head = temp_record;
7806         //fprintf(stderr,"Inserting at head of list\n");
7807       }
7808       else
7809       {
7810         // Insert new record before "current"
7811         previous->next = temp_record;
7812         temp_record->next = current;
7813         //fprintf(stderr,"Inserting before current\n");
7814       }
7815 
7816       //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename);
7817 
7818       // Fill in some default values for the new record
7819 //WE7U
7820 // Here's where we might look at the file extension and assign
7821 // default map_layer fields based on that.
7822       temp_record->max_zoom = 0;
7823       temp_record->min_zoom = 0;
7824       temp_record->map_layer = default_map_layer;
7825       temp_record->selected = 0;
7826       temp_record->XmStringPtr = NULL;
7827 
7828       if (       strstr(filename,".geo")
7829                  || strstr(filename,".GEO")
7830                  || strstr(filename,".Geo"))
7831       {
7832         temp_record->auto_maps = 0;
7833       }
7834       else
7835       {
7836         temp_record->auto_maps = 1;
7837       }
7838 
7839       if (       strstr(filename,".shp")
7840                  || strstr(filename,".SHP")
7841                  || strstr(filename,".Shp") )
7842       {
7843         temp_record->draw_filled = 2; // Auto
7844       }
7845       else
7846       {
7847         temp_record->draw_filled = 0; // No-Fill
7848       }
7849 
7850       if (       strstr(filename,".tif")
7851                  || strstr(filename,".TIF")
7852                  || strstr(filename,".Tif") )
7853       {
7854         temp_record->usgs_drg = 2; // Auto
7855       }
7856       else
7857       {
7858         temp_record->usgs_drg = 0; // No
7859       }
7860 
7861       //current = current->next;
7862       done++;
7863     }
7864     else    // Haven't gotten to the correct insertion point yet
7865     {
7866       previous = current; // Save ptr to last record
7867       current = current->next;
7868     }
7869   }
7870 
7871   if (!done)      // Matching record not found, didn't find alpha
7872   {
7873     // chars after our string either, add record to
7874     // the end of the list.
7875 
7876     //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename);
7877     temp_record = (map_index_record *)malloc(sizeof(map_index_record));
7878     CHECKMALLOC(temp_record);
7879 
7880     temp_record->next = NULL;
7881 
7882     if (previous == NULL)   // Empty list
7883     {
7884       map_index_head = temp_record;
7885       //fprintf(stderr,"First record in new list\n");
7886     }
7887     else    // Else at end of list
7888     {
7889       previous->next = temp_record;
7890       //fprintf(stderr,"Adding to end of list: %s\n",filename);
7891     }
7892 
7893     //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename);
7894 
7895     // Fill in some default values for the new record
7896 //WE7U
7897 // Here's where we might look at the file extension and assign
7898 // default map_layer fields based on that.
7899     temp_record->max_zoom = 0;
7900     temp_record->min_zoom = 0;
7901     temp_record->map_layer = default_map_layer;
7902     temp_record->selected = 0;
7903     temp_record->XmStringPtr = NULL;
7904 
7905     if (       strstr(filename,".geo")
7906                || strstr(filename,".GEO")
7907                || strstr(filename,".Geo"))
7908     {
7909       temp_record->auto_maps = 0;
7910     }
7911     else
7912     {
7913       temp_record->auto_maps = 1;
7914     }
7915 
7916     if (       strstr(filename,".shp")
7917                || strstr(filename,".SHP")
7918                || strstr(filename,".Shp") )
7919     {
7920       temp_record->draw_filled = 2; // Auto
7921     }
7922     else
7923     {
7924       temp_record->draw_filled = 0; // No-Fill
7925     }
7926 
7927     if (       strstr(filename,".tif")
7928                || strstr(filename,".TIF")
7929                || strstr(filename,".Tif") )
7930     {
7931       temp_record->usgs_drg = 2; // Auto
7932     }
7933     else
7934     {
7935       temp_record->usgs_drg = 0; // No
7936     }
7937 
7938   }
7939 
7940   // Update the values.  By this point we have a struct to fill
7941   // in, whether it's a new or old struct doesn't matter.  Convert
7942   // the values from lat/long to Xastir coordinate system.
7943 
7944   // In this case the struct uses MAX_FILENAME for the length of
7945   // the field, so the below statement is ok.
7946   xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename);
7947 
7948   ok = convert_to_xastir_coordinates( &temp_left,
7949                                       &temp_top,
7950                                       (float)left,
7951                                       (float)top);
7952   if (!ok)
7953   {
7954     fprintf(stderr,"%s\n\n",filename);
7955   }
7956 
7957   ok = convert_to_xastir_coordinates( &temp_right,
7958                                       &temp_bottom,
7959                                       (float)right,
7960                                       (float)bottom);
7961   if (!ok)
7962   {
7963     fprintf(stderr,"%s\n\n",filename);
7964   }
7965 
7966   temp_record->bottom = temp_bottom;
7967   temp_record->top = temp_top;
7968   temp_record->left = temp_left;
7969   temp_record->right = temp_right;
7970   temp_record->accessed = 1;
7971 }
7972 
7973 
7974 
7975 
7976 
7977 // Function which will update the "accessed" variable on either a
7978 // directory or a filename in the map index.
index_update_accessed(char * filename)7979 static void index_update_accessed(char *filename)
7980 {
7981   map_index_record *current = map_index_head;
7982   int done = 0;
7983   int i;
7984 
7985 
7986   // Check for initial bad input
7987   if ( (filename == NULL) || (filename[0] == '\0') )
7988   {
7989     fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename);
7990     return;
7991   }
7992 
7993   // Make sure there aren't any weird characters in the filename
7994   // that might cause problems later.  Look for control characters
7995   // and convert them to string-end characters.
7996   for ( i = 0; i < (int)strlen(filename); i++ )
7997   {
7998     // Change any control characters to '\0' chars
7999     if (filename[i] < 0x20)
8000     {
8001 
8002       fprintf(stderr,"\nindex_update_accessed: Found control char 0x%02x in map file/map directory name:\n%s\n",
8003               filename[i],
8004               filename);
8005 
8006       filename[i] = '\0';    // Terminate it here
8007     }
8008   }
8009   // Check if the string is _now_ bogus
8010   if (filename[0] == '\0')
8011   {
8012     fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename);
8013     return;
8014   }
8015 
8016   // Skip dbf and shx map extensions.  Really should make this
8017   // case-independent...
8018   if (       strstr(filename,"shx")
8019              || strstr(filename,"dbf")
8020              || strstr(filename,"SHX")
8021              || strstr(filename,"DBF") )
8022   {
8023     return;
8024   }
8025 
8026   // Search for a matching filename in the linked list
8027   while ((current != NULL) && !done)
8028   {
8029     int test;
8030 
8031 //fprintf(stderr,"Comparing %s to\n          %s\n",current->filename,filename);
8032 
8033     test = strcmp(current->filename,filename);
8034 
8035     if (test == 0)
8036     {
8037       // Found a match!
8038 //fprintf(stderr,"Found: Updating entry for %s\n\n",filename);
8039       current->accessed = 1;
8040       done++; // Exit the while loop
8041     }
8042 
8043     else    // Haven't gotten to the correct insertion point yet
8044     {
8045       current = current->next;
8046     }
8047   }
8048 }
8049 
8050 
8051 
8052 
8053 
8054 // Function called by map_onscreen_index()
8055 //
8056 // This function returns:
8057 //      0 if the map isn't in the index
8058 //      1 if the map is listed in the index
8059 //      Four parameters listing the extents of the map
8060 //
8061 // The updated parameters are in the Xastir coordinate system for
8062 // speed reasons.
8063 //
8064 // Note that the index retrieval could be made much faster by
8065 // storing the data in a hash instead of a linked list.  This is
8066 // just an initial implementation to see what speedups are possible.
8067 // Hashing might be next.  --we7u
8068 //
8069 // Note that since we've alphanumerically ordered the list, we can
8070 // stop when we hit something after this filename in the alphabet.
8071 // It speeds things up quite a bit.
8072 //
8073 // In order to speed this up slightly for the general case, we'll
8074 // assume that we'll be fetching indexes in alphabetical order, as
8075 // that's how we store them everywhere.  We'll save the last map
8076 // index pointer away and start searching there each time.  That
8077 // should make all but the _first_ lookup much faster.
8078 //
8079 map_index_record *last_index_lookup = NULL;
8080 
index_retrieve(char * filename,unsigned long * bottom,unsigned long * top,unsigned long * left,unsigned long * right,int * max_zoom,int * min_zoom,int * map_layer,int * draw_filled,int * usgs_drg,int * auto_maps)8081 int index_retrieve(char *filename,
8082                    unsigned long *bottom,
8083                    unsigned long *top,
8084                    unsigned long *left,
8085                    unsigned long *right,
8086                    int *max_zoom,
8087                    int *min_zoom,
8088                    int *map_layer,
8089                    int *draw_filled,
8090                    int *usgs_drg,
8091                    int *auto_maps)
8092 {
8093 
8094   map_index_record *current;
8095   int status = 0;
8096 
8097 
8098   if ( (filename == NULL)
8099        || (strlen(filename) >= MAX_FILENAME) )
8100   {
8101     return(status);
8102   }
8103 
8104   // Attempt to start where we left off last time
8105   if (last_index_lookup != NULL)
8106   {
8107     current = last_index_lookup;
8108   }
8109   else
8110   {
8111     current = map_index_head;
8112 //fprintf(stderr,"Start at beginning:%s\t", filename);
8113   }
8114 
8115   // Check to see if we're past the correct area.  If so, start at
8116   // the beginning of the index instead.
8117   //
8118   if (current
8119       && ((current->filename[0] > filename[0])
8120           || (strcmp(current->filename, filename) > 0)))
8121   {
8122     //
8123     // We're past the correct point.  Start at the beginning of
8124     // the list unless we're already there.
8125     //
8126     if (current != map_index_head)
8127     {
8128       current = map_index_head;
8129     }
8130 //fprintf(stderr,"Start at beginning:%s\t", filename);
8131   }
8132 
8133   //
8134   // Search for a matching filename in the linked list.
8135   //
8136 
8137   // Check the first char only.  Loop until they match or go past.
8138   // This is our high-speed method to get to the correct search
8139   // area.
8140   //
8141   while (current && (current->filename[0] < filename[0]))
8142   {
8143     // Save the pointer away for next time.  There's a reason we
8144     // save it before we increment the counter:  For "z" weather
8145     // alerts, it's nice to have it scan just the very last of
8146     // the list before it fails, instead of scanning the entire
8147     // list each time and then failing.  Need to find out why
8148     // weather alerts always fail, and therefore why this
8149     // routine gets called every time for them.
8150     //
8151     last_index_lookup = current;
8152     current = current->next;
8153 //fprintf(stderr,"1");
8154   }
8155 
8156   // Stay in this loop while the first char matches.  This is our
8157   // active search area.
8158   //
8159   while (current && (current->filename[0] == filename[0]))
8160   {
8161     int result;
8162 
8163     // Check the entire string
8164     result = strcmp(current->filename, filename);
8165 
8166     if (result == 0)
8167     {
8168       // Found a match!
8169       status = 1;
8170       *bottom = current->bottom;
8171       *top = current->top;
8172       *left = current->left;
8173       *right = current->right;
8174       *max_zoom = current->max_zoom;
8175       *min_zoom = current->min_zoom;
8176       *map_layer = current->map_layer;
8177       *draw_filled = current->draw_filled;
8178       *usgs_drg = current->usgs_drg;
8179       *auto_maps = current->auto_maps;
8180 //fprintf(stderr," Found it\n");
8181       return(status);
8182     }
8183     else if (result > 0)
8184     {
8185       // We're past it in the index.  We didn't find it in the
8186       // index.
8187 //fprintf(stderr," Did not find1\n");
8188       return(status);
8189     }
8190     else    // Not found yet, look at the next
8191     {
8192       // Save the pointer away for next time.  There's a
8193       // reason we save it before we increment the counter:
8194       // For "z" weather alerts, it's nice to have it scan
8195       // just the very last of the list before it fails,
8196       // instead of scanning the entire list each time and
8197       // then failing.  Need to find out why weather alerts
8198       // always fail, and therefore why this routine gets
8199       // called every time for them.
8200       //
8201       last_index_lookup = current;
8202       current = current->next;
8203 //fprintf(stderr,"2");
8204     }
8205   }
8206 
8207   // We're past the correct search area and didn't find it.
8208 //fprintf(stderr," Did not find2\n");
8209 
8210   return(status);
8211 }
8212 
8213 
8214 
8215 
8216 
8217 // Saves the linked list pointed to by map_index_head to a file.
8218 // Keeps the same order as the memory linked list.  Delete records
8219 // in the in-memory linked list for which the "accessed" variable is
8220 // 0 or filename is empty.
8221 //
index_save_to_file(void)8222 void index_save_to_file(void)
8223 {
8224   FILE *f;
8225   map_index_record *current;
8226 //  map_index_record *last;
8227   char out_string[MAX_FILENAME*2];
8228   char map_index_path[MAX_VALUE];
8229 
8230   get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path));
8231 
8232 
8233 //fprintf(stderr,"Saving map index to file\n");
8234 
8235   f = fopen( map_index_path, "w" );
8236 
8237   if (f == NULL)
8238   {
8239     fprintf(stderr,"Couldn't create/update map index file: %s\n",
8240             map_index_path );
8241     return;
8242   }
8243 
8244   current = map_index_head;
8245 //  last = current;
8246 
8247   while (current != NULL)
8248   {
8249     int i;
8250 
8251     // Make sure there aren't any weird characters in the
8252     // filename that might cause problems later.  Look for
8253     // control characters and convert them to string-end
8254     // characters.
8255     for ( i = 0; i < (int)strlen(current->filename); i++ )
8256     {
8257       // Change any control characters to '\0' chars
8258       if (current->filename[i] < 0x20)
8259       {
8260 
8261         fprintf(stderr,"\nindex_save_to_file: Found control char 0x%02x in map name:\n%s\n",
8262                 current->filename[i],
8263                 current->filename);
8264 
8265         current->filename[i] = '\0';    // Terminate it here
8266       }
8267     }
8268 
8269     // Save to file if filename non-blank and record has the
8270     // accessed field set.
8271     if ( (current->filename[0] != '\0')
8272          && (current->accessed != 0) )
8273     {
8274 
8275       // Write each object out to the file as one
8276       // comma-delimited line
8277       xastir_snprintf(out_string,
8278                       sizeof(out_string),
8279                       "%010lu,%010lu,%010lu,%010lu,%05d,%01d,%01d,%01d,%05d,%05d,%s\n",
8280                       current->bottom,
8281                       current->top,
8282                       current->left,
8283                       current->right,
8284                       current->map_layer,
8285                       current->draw_filled,
8286                       current->usgs_drg,
8287                       current->auto_maps,
8288                       current->max_zoom,
8289                       current->min_zoom,
8290                       current->filename);
8291 
8292       if (fprintf(f,"%s",out_string) < (int)strlen(out_string))
8293       {
8294         // Failed to write
8295         fprintf(stderr,"Couldn't write objects to map index file: %s\n",
8296                 map_index_path );
8297         current = NULL; // All done
8298       }
8299       // Set up pointers for next loop iteration
8300 //          last = current;
8301 
8302       if (current != NULL)
8303       {
8304         current = current->next;
8305       }
8306     }
8307 
8308 
8309     else
8310     {
8311 //          last = current;
8312       current = current->next;
8313     }
8314     /*
8315     //WE7U
8316             else {  // Delete this record from our list!  It's a record
8317                     // for a map file that doesn't exist in the
8318                     // filesystem anymore.
8319                 if (last == current) {   // We're at the head of the list
8320                     map_index_head = current->next;
8321 
8322     // Remember to free the XmStringPtr if we use this bit of code
8323     // again.
8324 
8325                     free(current);
8326 
8327                     // Set up pointers for next loop iteration
8328                     current = map_index_head;
8329                     last = current;
8330                 }
8331                 else {  // Not the first record in the list
8332                     map_index_record *gone;
8333 
8334                     gone = current; // Save ptr to record we wish to delete
8335                     last->next = current->next; // Unlink from list
8336 
8337     // Remember to free the XmStringPtr if we use this bit of code
8338     // again.
8339 
8340                     free(gone);
8341 
8342                     // Set up pointers for next loop iteration
8343                     // "last" is still ok
8344                     current = last->next;
8345                 }
8346             }
8347     */
8348   }
8349   (void)fclose(f);
8350 }
8351 
8352 
8353 
8354 
8355 
8356 // This function is currently not used.
8357 //
8358 // Function used to add map directories/files to the in-memory map
8359 // index.  Causes an update of the index list in memory.  Input
8360 // records are inserted in alphanumerical order.  This function is
8361 // called from the index_restore_from_file() function below.  When
8362 // this function is called the new record has all of the needed
8363 // information in it.
8364 //
8365 /*
8366 static void index_insert_sorted(map_index_record *new_record) {
8367 
8368     map_index_record *current = map_index_head;
8369     map_index_record *previous = map_index_head;
8370     int done = 0;
8371     int i;
8372 
8373 
8374     //fprintf(stderr,"index_insert_sorted: %s\n", new_record->filename );
8375 
8376     // Check for bad input.
8377     if (new_record == NULL) {
8378         fprintf(stderr,"index_insert_sorted: Bad input.\n");
8379         return;
8380     }
8381     // Make sure there aren't any weird characters in the filename
8382     // that might cause problems later.  Look for any control
8383     // characters and convert them to string-end characters.
8384     for ( i = 0; i < (int)strlen(new_record->filename); i++ ) {
8385         if (new_record->filename[i] < 0x20) {
8386 
8387             fprintf(stderr,"\nindex_insert_sorted: Found control char 0x%02x in map name:\n%s\n",
8388                 new_record->filename[i],
8389                 new_record->filename);
8390 
8391             new_record->filename[i] = '\0';    // Terminate it here
8392         }
8393     }
8394     // Check if the string is _now_ bogus
8395     if (new_record->filename[0] == '\0') {
8396         fprintf(stderr,"index_insert_sorted: Bad input.\n");
8397         return;
8398     }
8399 
8400     //if (map_index_head == NULL)
8401     //    fprintf(stderr,"Empty list\n");
8402 
8403     // Search for a matching filename in the linked list
8404     while ((current != NULL) && !done) {
8405         int test;
8406 
8407         //fprintf(stderr,"Comparing %s to\n          %s\n",
8408         //    current->filename, new_record->filename);
8409 
8410         test = strcmp(current->filename, new_record->filename);
8411 
8412         if (test == 0) {    // Found a match!
8413             int selected;
8414 
8415 //fprintf(stderr,"Found a match: Updating entry for %s\n",new_record->filename);
8416 
8417             // Save this away temporarily.
8418             selected = current->selected;
8419 
8420             // Copy the fields across and then free new_record.  We
8421             // overwrite the contents of the existing record.
8422             xastir_snprintf(current->filename,
8423                 MAX_FILENAME,
8424                 "%s",
8425                 new_record->filename);
8426             current->bottom = new_record->bottom;
8427             current->top = new_record->top;
8428             current->left = new_record->left;
8429             current->right = new_record->right;
8430             current->accessed = 1;
8431             current->max_zoom = new_record->max_zoom;
8432             current->min_zoom = new_record->min_zoom;
8433             current->map_layer = new_record->map_layer;
8434             current->draw_filled = new_record->draw_filled;
8435             current->usgs_drg = new_record->usgs_drg;
8436             current->selected = selected;   // Restore it
8437             current->auto_maps = new_record->auto_maps;
8438 
8439 // Remember to free the XmStringPtr if we use this bit of code
8440 // again.
8441 
8442             free(new_record);   // Don't need it anymore
8443 
8444             done++; // Exit loop, "current" points to found record
8445         }
8446         else if (test > 0) {    // Found a string past us in the
8447                                 // alphabet.  Insert ahead of this
8448                                 // last record.
8449 
8450 //fprintf(stderr,"Not Found, inserting: %s\n", new_record->filename);
8451 //fprintf(stderr,"       Before record: %s\n", current->filename);
8452 
8453             if (current == map_index_head) {  // Start of list!
8454                 // Insert new record at head of list
8455                 new_record->next = map_index_head;
8456                 map_index_head = new_record;
8457                 //fprintf(stderr,"Inserting at head of list\n");
8458             }
8459             else {  // Insert between "previous" and "current"
8460                 // Insert new record before "current"
8461                 previous->next = new_record;
8462                 new_record->next = current;
8463                 //fprintf(stderr,"Inserting before current\n");
8464             }
8465 
8466             //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename);
8467 
8468             // Fill in some default values for the new record that
8469             // don't exist in the map_index.sys file.
8470             new_record->selected = 0;
8471 
8472             if (       strstr(new_record->filename,".geo")
8473                     || strstr(new_record->filename,".GEO")
8474                     || strstr(new_record->filename,".Geo") ) {
8475                 new_record->auto_maps = 0;
8476             }
8477             else {
8478                 new_record->auto_maps = 1;
8479             }
8480 
8481             //current = current->next;
8482             done++;
8483         }
8484         else {  // Haven't gotten to the correct insertion point yet
8485             previous = current; // Save ptr to last record
8486             current = current->next;
8487         }
8488     }
8489 
8490     if (!done) {    // Matching record not found, add the record to
8491         // the end of the list.  "previous" points to the last
8492         // record in the list or NULL (empty list).
8493 
8494 //fprintf(stderr,"Not Found: Adding to end: %s\n",new_record->filename);
8495 
8496         new_record->next = NULL;
8497 
8498         if (previous == NULL) { // Empty list
8499             map_index_head = new_record;
8500             //fprintf(stderr,"First record in new list\n");
8501         }
8502         else {  // Else at end of list
8503             previous->next = new_record;
8504             //fprintf(stderr,"Adding to end of list: %s\n",new_record->filename);
8505         }
8506 
8507         //fprintf(stderr,"Adding:%d:%s\n",strlen(new_record->filename),new_record->filename);
8508 
8509         // Fill in some default values for the new record.
8510         new_record->selected = 0;
8511 
8512         if (       strstr(new_record->filename,".geo")
8513                 || strstr(new_record->filename,".GEO")
8514                 || strstr(new_record->filename,".Geo") ) {
8515             new_record->auto_maps = 0;
8516         }
8517         else {
8518             new_record->auto_maps = 1;
8519         }
8520     }
8521 }
8522 */
8523 
8524 
8525 
8526 
8527 
8528 // sort map index
8529 // simple bubble sort, since we should be sorted already
8530 //
index_sort(void)8531 static void index_sort(void)
8532 {
8533   map_index_record *current, *previous, *next;
8534   int changed = 1;
8535   int loops = 0; // for debug stats
8536 
8537   previous = map_index_head;
8538   next = NULL;
8539   //  fprintf(stderr, "index_sort: start.\n");
8540   // check if we have any records at all, and at least two
8541   if ( (previous != NULL) && (previous->next != NULL) )
8542   {
8543     current = previous->next;
8544     while ( changed == 1)
8545     {
8546       changed = 0;
8547       if (current->next != NULL)
8548       {
8549         next = current->next;
8550       }
8551       if ( strcmp( previous->filename, current->filename) >= 0 )
8552       {
8553         // out of order - swap them
8554         current->next = previous;
8555         previous->next = next;
8556         map_index_head = current;
8557         current = previous;
8558         previous = map_index_head;
8559         changed = 1;
8560       }
8561 
8562       while ( next != NULL )
8563       {
8564         if ( strcmp( current->filename, next->filename) >= 0 )
8565         {
8566           // out of order - swap them
8567           current->next = next->next;
8568           previous->next = next;
8569           next->next = current;
8570           // get ready for the next iteration
8571           previous = next;  // current already moved ahead from the swap
8572           next = current->next;
8573           changed = 1;
8574         }
8575         else
8576         {
8577           previous = current;
8578           current = next;
8579           next = current->next;
8580         }
8581       }
8582       previous = map_index_head;
8583       current = previous->next;
8584       next = current->next;
8585       loops++;
8586     }
8587   }
8588   // debug stats
8589   // fprintf(stderr, "index_sort: ran %d loops.\n", loops);
8590 }
8591 
8592 
8593 
8594 
8595 
8596 // Snags the file and creates the linked list pointed to by the
8597 // map_index_head pointer.  The memory linked list keeps the same
8598 // order as the entries in the file.
8599 //
8600 // NOTE:  If we're converting from the old format to the new, we
8601 // need to call index_save_to_file() in order to write out the new
8602 // format once we're done.
8603 //
index_restore_from_file(void)8604 void index_restore_from_file(void)
8605 {
8606   FILE *f;
8607   map_index_record *temp_record;
8608   map_index_record *last_record;
8609   char in_string[MAX_FILENAME*2];
8610   int doing_migration = 0;
8611   char map_index_path[MAX_VALUE];
8612 
8613   get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path));
8614 
8615 
8616 //fprintf(stderr,"\nRestoring map index from file\n");
8617 
8618   if (map_index_head != NULL)
8619   {
8620     fprintf(stderr,"Warning: index_restore_from_file(): map_index_head was non-null!\n");
8621   }
8622 
8623   map_index_head = NULL;  // Starting with empty list
8624   last_record = NULL;
8625 
8626   f = fopen( map_index_path, "r" );
8627   if (f == NULL)  // No map_index file yet
8628   {
8629     return;
8630   }
8631 
8632   while (!feof (f))   // Loop through entire map_index file
8633   {
8634 
8635     // Read one line from the file
8636     if ( get_line (f, in_string, MAX_FILENAME*2) )
8637     {
8638 
8639       if (strlen(in_string) >= 15)     // We have some data.
8640       {
8641         // Try to process the
8642         // line.
8643         char scanf_format[50];
8644         char old_scanf_format[50];
8645         char older_scanf_format[50];
8646         int processed;
8647         int i, jj;
8648 
8649 //fprintf(stderr,"%s\n",in_string);
8650 
8651         // Tweaked the string below so that it will track
8652         // along with MAX_FILENAME-1.  We're constructing
8653         // the string "%lu,%lu,%lu,%lu,%d,%d,%2000c", where
8654         // the 2000 example number is from MAX_FILENAME.
8655         xastir_snprintf(scanf_format,
8656                         sizeof(scanf_format),
8657                         "%s%d%s",
8658                         "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%d,%",
8659                         MAX_FILENAME,
8660                         "c");
8661         //fprintf(stderr,"%s\n",scanf_format);
8662 
8663         // index predates addition of usgs_drg flag (26 Jul 2005)
8664         xastir_snprintf(old_scanf_format,
8665                         sizeof(old_scanf_format),
8666                         "%s%d%s",
8667                         "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%",
8668                         MAX_FILENAME,
8669                         "c");
8670 
8671         // index predates addition of min/max zoom (29 Oct 2003)
8672         xastir_snprintf(older_scanf_format,
8673                         sizeof(older_scanf_format),
8674                         "%s%d%s",
8675                         "%lu,%lu,%lu,%lu,%d,%d,%d,%",
8676                         MAX_FILENAME,
8677                         "c");
8678 
8679         // Malloc an index record.  We'll add it to the list
8680         // only if the data looks reasonable.
8681         temp_record = (map_index_record *)malloc(sizeof(map_index_record));
8682         CHECKMALLOC(temp_record);
8683 
8684         memset(temp_record->filename, 0, sizeof(temp_record->filename));
8685         temp_record->next = NULL;
8686         temp_record->bottom = 64800001l;// Too high
8687         temp_record->top = 64800001l;   // Too high
8688         temp_record->left = 129600001l; // Too high
8689         temp_record->right = 129600001l;// Too high
8690         temp_record->map_layer = -1;    // Too low
8691         temp_record->draw_filled = -1;  // Too low
8692         temp_record->usgs_drg = -1;     // Too low
8693         temp_record->auto_maps = -1;    // Too low
8694         temp_record->max_zoom = -1;     // Too low
8695         temp_record->min_zoom = -1;     // Too low
8696         temp_record->filename[0] = '\0';// Empty
8697 
8698         processed = sscanf(in_string,
8699                            scanf_format,
8700                            &temp_record->bottom,
8701                            &temp_record->top,
8702                            &temp_record->left,
8703                            &temp_record->right,
8704                            &temp_record->map_layer,
8705                            &temp_record->draw_filled,
8706                            &temp_record->usgs_drg,
8707                            &temp_record->auto_maps,
8708                            &temp_record->max_zoom,
8709                            &temp_record->min_zoom,
8710                            temp_record->filename);
8711 
8712         if (processed < 11)
8713         {
8714           // We're upgrading from an old format index file
8715           // that doesn't have usgs_drg.  Try the
8716           // old_scanf_format string instead.
8717 
8718           doing_migration = 1;
8719 
8720           processed = sscanf(in_string,
8721                              old_scanf_format,
8722                              &temp_record->bottom,
8723                              &temp_record->top,
8724                              &temp_record->left,
8725                              &temp_record->right,
8726                              &temp_record->map_layer,
8727                              &temp_record->draw_filled,
8728                              &temp_record->auto_maps,
8729                              &temp_record->max_zoom,
8730                              &temp_record->min_zoom,
8731                              temp_record->filename);
8732           if (processed < 10)
8733           {
8734             // It's really old, doesn't have min/max zoom either
8735             temp_record->max_zoom = -1;     // Too low
8736             temp_record->min_zoom = -1;     // Too low
8737 
8738             processed = sscanf(in_string,
8739                                older_scanf_format,
8740                                &temp_record->bottom,
8741                                &temp_record->top,
8742                                &temp_record->left,
8743                                &temp_record->right,
8744                                &temp_record->map_layer,
8745                                &temp_record->draw_filled,
8746                                &temp_record->auto_maps,
8747                                temp_record->filename);
8748           }
8749           // either way, it doesn't have usgs_drg, so add one
8750           // defaulting to Auto if it's a tif file, no if not
8751           if (       strstr(temp_record->filename,".tif")
8752                      || strstr(temp_record->filename,".TIF")
8753                      || strstr(temp_record->filename,".Tif") )
8754           {
8755             temp_record->usgs_drg = 2; // Auto
8756           }
8757           else
8758           {
8759             temp_record->usgs_drg = 0; // No
8760           }
8761         }
8762 
8763         temp_record->XmStringPtr = NULL;
8764 
8765         // Do some reasonableness checking on the parameters
8766         // we just parsed.
8767 //WE7U: First comparison here is always false
8768 //                if ( (temp_record->bottom < 0l)
8769 //                        || (temp_record->bottom > 64800000l) ) {
8770         if (temp_record->bottom > 64800000l)
8771         {
8772 
8773           processed = 0;  // Reject this record
8774           fprintf(stderr,"\nindex_restore_from_file: bottom extent incorrect %lu in map name:\n%s\n",
8775                   temp_record->bottom,
8776                   temp_record->filename);
8777         }
8778 
8779 
8780 //WE7U: First comparison here is always false
8781 //               if ( (temp_record->top < 0l)
8782 //                        || (temp_record->top > 64800000l) ) {
8783         if (temp_record->top > 64800000l)
8784         {
8785 
8786           processed = 0;  // Reject this record
8787           fprintf(stderr,"\nindex_restore_from_file: top extent incorrect %lu in map name:\n%s\n",
8788                   temp_record->top,
8789                   temp_record->filename);
8790         }
8791 
8792 //WE7U: First comparison here is always false
8793 //                if ( (temp_record->left < 0l)
8794 //                        || (temp_record->left > 129600000l) ) {
8795         if (temp_record->left > 129600000l)
8796         {
8797 
8798           processed = 0;  // Reject this record
8799           fprintf(stderr,"\nindex_restore_from_file: left extent incorrect %lu in map name:\n%s\n",
8800                   temp_record->left,
8801                   temp_record->filename);
8802         }
8803 
8804 //WE7U: First comparison here is always false
8805 //                if ( (temp_record->right < 0l)
8806 //                        || (temp_record->right > 129600000l) ) {
8807         if (temp_record->right > 129600000l)
8808         {
8809 
8810           processed = 0;  // Reject this record
8811           fprintf(stderr,"\nindex_restore_from_file: right extent incorrect %lu in map name:\n%s\n",
8812                   temp_record->right,
8813                   temp_record->filename);
8814         }
8815 
8816         if ( (temp_record->max_zoom < 0)
8817              || (temp_record->max_zoom > 99999) )
8818         {
8819 //                    processed = 0;  // Reject this record
8820 //                    fprintf(stderr,"\nindex_restore_from_file: max_zoom field incorrect %d in map name:\n%s\n",
8821 //                            temp_record->max_zoom,
8822 //                            temp_record->filename);
8823           // Assign a reasonable value
8824           temp_record->max_zoom = 0;
8825           //fprintf(stderr,"Assigning max_zoom of 0\n");
8826         }
8827 
8828         if ( (temp_record->min_zoom < 0)
8829              || (temp_record->min_zoom > 99999) )
8830         {
8831 //                    processed = 0;  // Reject this record
8832 //                    fprintf(stderr,"\nindex_restore_from_file: min_zoom field incorrect %d in map name:\n%s\n",
8833 //                            temp_record->min_zoom,
8834 //                            temp_record->filename);
8835           // Assign a reasonable value
8836           temp_record->min_zoom = 0;
8837           //fprintf(stderr,"Assigning min_zoom of 0\n");
8838         }
8839 
8840         if ( (temp_record->map_layer < -99999)
8841              || (temp_record->map_layer > 99999) )
8842         {
8843           processed = 0;  // Reject this record
8844           fprintf(stderr,"\nindex_restore_from_file: map_layer field incorrect %d in map name:\n%s\n",
8845                   temp_record->map_layer,
8846                   temp_record->filename);
8847         }
8848 
8849         if ( (temp_record->draw_filled < 0)
8850              || (temp_record->draw_filled > 2) )
8851         {
8852           processed = 0;  // Reject this record
8853           fprintf(stderr,"\nindex_restore_from_file: draw_filled field incorrect %d in map name:\n%s\n",
8854                   temp_record->draw_filled,
8855                   temp_record->filename);
8856         }
8857 
8858         if ( (temp_record->usgs_drg < 0)
8859              || (temp_record->usgs_drg > 2) )
8860         {
8861           processed = 0;  // Reject this record
8862           fprintf(stderr,"\nindex_restore_from_file: usgs_drg field incorrect %d in map name:\n%s\n",
8863                   temp_record->usgs_drg,
8864                   temp_record->filename);
8865         }
8866 
8867         if ( (temp_record->auto_maps < 0)
8868              || (temp_record->auto_maps > 1) )
8869         {
8870           processed = 0;  // Reject this record
8871           fprintf(stderr,"\nindex_restore_from_file: auto_maps field incorrect %d in map name:\n%s\n",
8872                   temp_record->auto_maps,
8873                   temp_record->filename);
8874         }
8875 
8876         // Check whether the filename is empty
8877         if (strlen(temp_record->filename) == 0)
8878         {
8879           processed = 0;  // Reject this record
8880         }
8881 
8882         // Check for control characters in the filename.
8883         // Reject any that have them.
8884         jj = (int)strlen(temp_record->filename);
8885         for (i = 0; i < jj; i++)
8886         {
8887           if (temp_record->filename[i] < 0x20)
8888           {
8889 
8890             processed = 0;  // Reject this record
8891             fprintf(stderr,"\nindex_restore_from_file: Found control char 0x%02x in map name:\n%s\n",
8892                     temp_record->filename[i],
8893                     temp_record->filename);
8894           }
8895         }
8896 
8897 
8898         // Mark the record as accessed at this point.
8899         // At the stage where we're writing this list off to
8900         // disk, if the record hasn't been accessed by the
8901         // re-indexing, it doesn't get written.  This has
8902         // the effect of flushes deleted files from the
8903         // index quickly.
8904         temp_record->accessed = 1;
8905 
8906         // Default is not-selected.  Later we read in the
8907         // selected_maps.sys file and tweak some of these
8908         // fields.
8909         temp_record->selected = 0;
8910 
8911         temp_record->filename[MAX_FILENAME-1] = '\0';
8912 
8913         // If correct number of parameters for either old or
8914         // new format
8915         if (processed == 11 || processed == 10 || processed == 8)
8916         {
8917 
8918           //fprintf(stderr,"Restored: %s\n",temp_record->filename);
8919 
8920           // Insert the new record into the in-memory map
8921           // list in sorted order.
8922           // --slow for large lists
8923           // index_insert_sorted(temp_record);
8924           // -- so we just add it to the end of the list
8925           // and sort it at the end tp make sure nobody
8926           // messed us up by editting the file by hand
8927           if ( last_record == NULL )   // first record
8928           {
8929             map_index_head = temp_record;
8930           }
8931           else
8932           {
8933             last_record->next = temp_record;
8934           }
8935           last_record = temp_record;
8936 
8937 
8938           // Remember that we may just have attached the
8939           // record to our in-memory map list, or we may
8940           // have free'ed it in the above function call.
8941           // Set the pointer to NULL to make sure we don't
8942           // try to do anything else with the memory.
8943           temp_record = NULL;
8944         }
8945         else    // sscanf didn't parse the proper number of
8946         {
8947           // items.  Delete the record.
8948 
8949 // Remember to free the XmString pointer if necessary.
8950 
8951           free(temp_record);
8952 //                    fprintf(stderr,"index_restore_from_file:sscanf parsing error\n");
8953         }
8954       }
8955     }
8956   }
8957   (void)fclose(f);
8958   // now that we have read the whole file, make sure it is sorted
8959   index_sort();  // probably should check for dup records
8960 
8961   if (doing_migration)
8962   {
8963     // Save in new file format if we just did a migration from
8964     // old format to new.
8965     fprintf(stderr,"Migrating from old map_index.sys format to new format.\n");
8966     index_save_to_file();
8967   }
8968 }
8969 
8970 
8971 
8972 
8973 
8974 // map_indexer()
8975 //
8976 // Recurses through the map directories finding map extents
8977 // and recording them in the map index.  Once the indexing is
8978 // complete, write the current index out to a file.
8979 //
8980 // It'd be nice to call index_restore_from_file() from main.c:main()
8981 // so that an earlier copy of the index is restored before the map
8982 // display is created.
8983 //
8984 // If we set the "accessed" variable in the in-memory index to 0 for
8985 // each record and then run the indexer, the save-to-file function
8986 // will delete those with a value of 0 when writing to disk.  Those
8987 // maps no longer exist in the filesystem and should be deleted.  We
8988 // could either wipe them from the in-memory database at that time
8989 // as well, or wipe the whole list and re-read it from disk to get
8990 // the current list.
8991 //
8992 // If parameter is 0, we'll do the smart timestamp-checking
8993 // indexing.
8994 // If 1, we'll erase the in-memory index and do full indexing.
8995 //
map_indexer(int parameter)8996 void map_indexer(int parameter)
8997 {
8998   struct stat nfile;
8999   int check_times = 1;
9000   FILE *f;
9001   map_index_record *current;
9002   map_index_record *backup_list_head = NULL;
9003   char map_index_path[MAX_VALUE];
9004 
9005   get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path));
9006 
9007 
9008   if (debug_level & 16)
9009   {
9010     fprintf(stderr,"map_indexer() start\n");
9011   }
9012 
9013   fprintf(stderr,"Indexing maps...\n");
9014 
9015 #ifdef HAVE_LIBSHP
9016   // get rid of stored dbfawk signatures and force reload.
9017   clear_dbfawk_sigs();
9018 #endif
9019 
9020   // Find the timestamp on the index file first.  Save it away so
9021   // that the timestamp for each map file can be compared to it.
9022   if (stat ( map_index_path, &nfile) != 0)
9023   {
9024 
9025     // File doesn't exist yet.  Create it.
9026     f = fopen( map_index_path, "w" );
9027     if (f != NULL)
9028     {
9029       (void)fclose(f);
9030     }
9031     else
9032       fprintf(stderr,"Couldn't create map index file: %s\n",
9033               map_index_path );
9034 
9035     check_times = 0; // Don't check the timestamps.  Do them all.
9036   }
9037   else    // File exists
9038   {
9039     map_index_timestamp = (time_t)nfile.st_mtime;
9040     check_times = 1;
9041   }
9042 
9043 
9044   if (parameter == 1)     // Full indexing instead of timestamp-check indexing
9045   {
9046 
9047     // Move the in-memory index to a backup pointer
9048     backup_list_head = map_index_head;
9049     map_index_head = NULL;
9050 
9051 //        // Set the timestamp to 0 so that everything gets indexed
9052 //        map_index_timestamp = (time_t)0l;
9053 
9054     check_times = 0;
9055   }
9056 
9057 
9058   // Set the "accessed" field to zero for every record in the
9059   // index.  Note that the list could be empty at this point.
9060   current = map_index_head;
9061   while (current != NULL)
9062   {
9063     current->accessed = 0;
9064     current = current->next;
9065   }
9066 
9067 
9068   if (check_times)
9069   {
9070     if (debug_level & 16)
9071     {
9072       fprintf(stderr,"map_indexer: Calling map_search\n");
9073     }
9074 
9075     map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_CHECK_TIMESTAMPS);
9076 
9077     if (debug_level & 16)
9078     {
9079       fprintf(stderr,"map_indexer: Returned from map_search\n");
9080     }
9081   }
9082   else
9083   {
9084     if (debug_level & 16)
9085     {
9086       fprintf(stderr,"map_indexer: Calling map_search\n");
9087     }
9088 
9089     map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_NO_TIMESTAMPS);
9090 
9091     if (debug_level & 16)
9092     {
9093       fprintf(stderr,"map_indexer: Returned from map_search\n");
9094     }
9095   }
9096 
9097   if (debug_level & 16)
9098   {
9099     fprintf(stderr,"map_indexer() middle\n");
9100   }
9101 
9102 
9103   if (parameter == 1)     // Full indexing instead of timestamp-check indexing
9104   {
9105     // Copy the Properties from the backup list to the new list,
9106     // then free the backup list.
9107     map_index_copy_properties(map_index_head, backup_list_head);
9108   }
9109 
9110 
9111   // Save the updated index to the file
9112   index_save_to_file();
9113 
9114   fprintf(stderr,"Finished indexing maps\n");
9115 
9116   if (debug_level & 16)
9117   {
9118     fprintf(stderr,"map_indexer() end\n");
9119   }
9120 }
9121 
9122 
9123 
9124 
9125 
9126 /* moved these here and made them static so it will function on FREEBSD */
9127 #define MAX_ALERT 7000
9128 // If we comment this out, we link, but get a segfault at runtime.
9129 // Take out the "static" and we get a segfault when we zoom out too
9130 // far with the lakes or counties shapefile loaded.  No idea why
9131 // yet.  --we7u
9132 //static alert_entry alert[MAX_ALERT];
9133 static int alert_count;
9134 
9135 
9136 
9137 
9138 
9139 /*******************************************************************
9140  * fill_in_new_alert_entries()
9141  *
9142  * Fills in the index and filename portions of any alert entries
9143  * that are missing them.  This function should be called at the
9144  * point where we've just received a new weather alert.
9145  *
9146 
9147 //WE7U
9148 // Later we should change this so that it doesn't scan the entire
9149 // message list, but is passed the important info directly from the
9150 // decode routines in db.c, and the message should NOT be added to
9151 // the message list.
9152 //WE7U
9153 
9154  *
9155  * This function is designed to use ESRI Shapefile map files.  The
9156  * base directory where the Shapefiles are located is passed to us
9157  * in the "dir" variable.
9158  *
9159  * map_search() fills in the filename field of the alert struct.
9160  * draw_shapefile_map() fills in the index field.
9161  *******************************************************************/
fill_in_new_alert_entries()9162 void fill_in_new_alert_entries()
9163 {
9164 //  int ii;
9165   char alert_scan[MAX_FILENAME];
9166 //  char *dir_ptr;
9167   struct hashtable_itr *iterator = NULL;
9168   alert_entry *temp;
9169   char dir[MAX_FILENAME];
9170 
9171 
9172   if (debug_level & 2)
9173   {
9174     fprintf(stderr,"fill_in_new_alert_entries start\n");
9175   }
9176 
9177   xastir_snprintf(dir,
9178                   sizeof(dir),
9179                   "%s",
9180                   ALERT_MAP_DIR);
9181 
9182   alert_count = MAX_ALERT - 1;
9183 
9184   // Set up our path to the wx alert maps
9185   memset(alert_scan, 0, sizeof (alert_scan));    // Zero our alert_scan string
9186   xastir_snprintf(alert_scan, // Fetch the base directory
9187                   sizeof(alert_scan),
9188                   "%s",
9189                   dir);
9190   strncat(alert_scan, // Complete alert directory is now set up in the string
9191           "/",
9192           sizeof(alert_scan) - 1 - strlen(alert_scan));
9193 //  dir_ptr = &alert_scan[strlen (alert_scan)]; // Point to end of path
9194 
9195   // Iterate through the weather alerts.  It looks like we wish to
9196   // just fill in the alert struct and to determine whether the
9197   // alert is within our viewport here.  We don't wish to draw the
9198   // alerts at this stage, that happens in the load_alert_maps()
9199   // function below.
9200 
9201   iterator = create_wx_alert_iterator();
9202   temp = get_next_wx_alert(iterator);
9203   while (iterator != NULL && temp)
9204   {
9205 
9206     if (!temp->filename[0])   // Filename is
9207     {
9208       // empty, we need to fill it in.
9209 
9210 //            fprintf(stderr,"fill_in_new_alert_entries() Title: %s\n",temp->title);
9211 
9212       // The last parameter denotes loading into
9213       // pixmap_alerts instead of pixmap or pixmap_final.
9214       // Note that just calling map_search does not get
9215       // the alert areas drawn on the screen.  The
9216       // draw_map() function called by map_search just
9217       // fills in the filename field in the struct and
9218       // exits.
9219       //
9220       // The "warn" parameter (next to last) specifies whether
9221       // to dump warnings out to the console as well.  If the
9222       // warning was received on local RF or locally, warn the
9223       // operator (the weather must be near).
9224       map_search (da,
9225                   alert_scan,
9226                   temp,
9227                   &alert_count,
9228                   (int)temp->flags[source],
9229                   DRAW_TO_PIXMAP_ALERTS);
9230 
9231 //            fprintf(stderr,"fill_in_new_alert_entries() Title1:%s\n",temp->title);
9232     }
9233     temp = get_next_wx_alert(iterator);
9234   }
9235 #ifndef USING_LIBGC
9236 //fprintf(stderr,"free iterator 4\n");
9237   if (iterator)
9238   {
9239     free(iterator);
9240   }
9241 #endif  // USING_LIBGC
9242 
9243   if (debug_level & 2)
9244   {
9245     fprintf(stderr,"fill_in_new_alert_entries end\n");
9246   }
9247 }
9248 
9249 
9250 
9251 
9252 /*******************************************************************
9253  * load_alert_maps()
9254  *
9255  * Used to load weather alert maps, based on NWS weather alerts that
9256  * are received.  Called from create_image() and refresh_image().
9257  * This function is designed to use ESRI Shapefile map files.  The
9258  * base directory where the Shapefiles are located is passed to us
9259  * in the "dir" variable.
9260  *
9261  * map_search() fills in the filename field of the alert struct.
9262  * draw_shapefile_map() fills in the index field.
9263  *******************************************************************/
load_alert_maps(Widget w,char * dir)9264 void load_alert_maps (Widget w, char *dir)
9265 {
9266 //    int ii;
9267   int level;
9268   unsigned char fill_color[] = {  (unsigned char)0x69,    // gray86
9269                                   (unsigned char)0x4a,    // red2
9270                                   (unsigned char)0x63,    // yellow2
9271                                   (unsigned char)0x66,    // cyan2
9272                                   (unsigned char)0x61,    // RoyalBlue
9273                                   (unsigned char)0x64,    // ForestGreen
9274                                   (unsigned char)0x62
9275                                };  // orange3
9276 
9277   struct hashtable_itr *iterator = NULL;
9278   alert_entry *temp;
9279   map_draw_flags mdf;
9280 
9281 
9282 //fprintf(stderr,"load_alert_maps\n");
9283 
9284 // TODO:
9285 // Figure out how to pass a quantity of zones off to the map drawing
9286 // routines, then we can draw them all with one pass through each
9287 // map file.  Alphanumerically sort the zones to make it easier for
9288 // the map drawing functions?  Note that the indexing routines fill
9289 // in both the filename and the shapefile index for each record.
9290 //
9291 // Alternative:  Call map_draw for each filename listed and have the
9292 // draw_shapefile function iterate through the array looking for all
9293 // filename matches, pulling non-negative indexes out of each index
9294 // field for matches and drawing them.  That should be fast and
9295 // require no sorting of the array.  Downside:  The alerts won't be
9296 // layered based on alert level unless we modify the above:  Drawing
9297 // each file once for each alert-level in the proper layering order.
9298 // Perhaps we could keep a list of which filenames have been called,
9299 // and only call each one once per load_alert_maps() call.
9300 
9301 
9302 // Just for a test
9303 //draw_shapefile_map (w, dir, filenm, alert, alert_color, destination_pixmap);
9304 //draw_shapefile_map (w, dir, "c_16my01.shp", NULL, '\0', DRAW_TO_PIXMAP_ALERTS);
9305 
9306 
9307 // Are we drawing them in reverse order so that the important
9308 // alerts end up drawn on top of the less important alerts?
9309 // Actually, since the alert hash isn't ordered, perhaps we need to
9310 // order them by priority, then by map file, so that we can draw the
9311 // shapes from each map file in the correct order.  This might cause
9312 // each map file to be drawn up to three times (once for each
9313 // priority level), but that's better than calling each map for each
9314 // zone as is done now.
9315 
9316   iterator = create_wx_alert_iterator();
9317   temp = get_next_wx_alert(iterator);
9318   while (iterator != NULL && temp)
9319   {
9320 
9321     HandlePendingEvents(app_context);
9322     if (interrupt_drawing_now)
9323     {
9324 #ifndef USING_LIBGC
9325 //fprintf(stderr,"free iterator 5\n");
9326       if (iterator)
9327       {
9328         free(iterator);
9329       }
9330 #endif  // USING_LIBGC
9331       return;
9332     }
9333 
9334     if (disable_all_maps)
9335     {
9336 #ifndef USING_LIBGC
9337 //fprintf(stderr,"free iterator 6\n");
9338       if (iterator)
9339       {
9340         free(iterator);
9341       }
9342 #endif  // USING_LIBGC
9343       return;
9344     }
9345 
9346     //  Check whether the alert slot is filled/empty
9347     if (temp->title[0] == '\0')   // Empty slot
9348     {
9349       temp = get_next_wx_alert(iterator);
9350       continue;
9351     }
9352 
9353     if ( (level = alert_active(temp, ALERT_ALL) ) )
9354     {
9355       if (level >= (int)sizeof (fill_color))
9356       {
9357         level = 0;
9358       }
9359 
9360       // The last parameter denotes drawing into pixmap_alert
9361       // instead of pixmap or pixmap_final.
9362 
9363       if (debug_level & 16)
9364       {
9365         fprintf(stderr,"load_alert_maps() Drawing %s\n",temp->filename);
9366         fprintf(stderr,"load_alert_maps() Title4:%s\n",temp->title);
9367       }
9368 
9369       // Attempt to draw alert
9370       if ( temp->index != -1 )            // Shape found in shapefile
9371       {
9372 
9373         // Check whether we've ever tried to draw this alert
9374         // before.  If not, attempt it and get the boundary
9375         // limits filled in.
9376         //
9377         if (       temp->bottom_boundary == 0.0
9378                    && temp->top_boundary == 0.0
9379                    && temp->left_boundary == 0.0
9380                    && temp->right_boundary == 0.0)
9381         {
9382 
9383           if (temp->alert_level != 'C')
9384           {
9385             draw_map (w, dir, temp->filename, temp,
9386                       fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf);  // draw filled
9387           }
9388         }
9389 
9390         if (map_visible_lat_lon(temp->bottom_boundary, // Shape visible
9391                                 temp->top_boundary,
9392                                 temp->left_boundary,
9393                                 temp->right_boundary) )
9394         {
9395 
9396           if (temp->alert_level != 'C')       // Alert not cancelled
9397           {
9398             mdf.draw_filled=1;
9399             mdf.usgs_drg=0;
9400 
9401             if (debug_level & 16)
9402             {
9403               fprintf(stderr,"load_alert_maps: Calling draw_map\n");
9404             }
9405 
9406             draw_map (w, dir, temp->filename, temp,
9407                       fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf);  // draw filled
9408           }
9409           if (temp)
9410           {
9411             temp->flags[on_screen] = 'Y';
9412           }
9413         }
9414         else
9415         {
9416           // Not in our viewport, don't draw it!
9417           if (debug_level & 16)
9418           {
9419             fprintf(stderr,"load_alert_maps() Alert not visible\n");
9420           }
9421 //fprintf(stderr,"B:%f  T:%f  L:%f  R:%f\n", temp->bottom_boundary, temp->top_boundary, temp->left_boundary, temp->right_boundary);
9422           if (temp)
9423           {
9424             temp->flags[on_screen] = 'N';
9425           }
9426         }
9427       }
9428       else
9429       {
9430         // Can't find this shape in the shapefile.
9431         if (debug_level & 16)
9432         {
9433           fprintf(stderr,
9434                   "load_alert_maps() Shape %s, strlen=%d, not found in %s\n",
9435                   temp->title,
9436                   (int)strlen(temp->title),
9437                   temp->filename );
9438         }
9439       }
9440     }
9441     temp = get_next_wx_alert(iterator);
9442   }
9443 #ifndef USING_LIBGC
9444 //fprintf(stderr,"free iterator 7\n");
9445   if (iterator)
9446   {
9447     free(iterator);
9448   }
9449 #endif  // USING_LIBGC
9450 
9451   if (debug_level & 16)
9452   {
9453     fprintf(stderr,"load_alert_maps() Done drawing all active alerts\n");
9454   }
9455 
9456   if (alert_display_request())
9457   {
9458     alert_redraw_on_update = redraw_on_new_data = 2;
9459   }
9460 }
9461 
9462 
9463 
9464 
9465 
9466 // Here's the head of our sorted-by-layer maps list
9467 static map_index_record *map_sorted_list_head = NULL;
9468 
9469 
empty_map_sorted_list(void)9470 static void empty_map_sorted_list(void)
9471 {
9472   map_index_record *current = map_sorted_list_head;
9473 
9474   while (map_sorted_list_head != NULL)
9475   {
9476     current = map_sorted_list_head;
9477     map_sorted_list_head = current->next;
9478     if (current->XmStringPtr != NULL)
9479     {
9480       XmStringFree(current->XmStringPtr);
9481     }
9482     free(current);
9483   }
9484 }
9485 
9486 
9487 
9488 
9489 
9490 // Insert a map into the list at the end of the maps with the same
9491 // layer number.  We'll need to look up the parameters for it from
9492 // the master map_index list and then attach a new record to our new
9493 // sorted list in the proper place.
9494 //
9495 // This function should be called when we're first starting up
9496 // Xastir and anytime that selected_maps.sys is changed.
9497 //
insert_map_sorted(char * filename)9498 static void insert_map_sorted(char *filename)
9499 {
9500   map_index_record *current;
9501   map_index_record *last;
9502   map_index_record *temp_record;
9503   unsigned long bottom;
9504   unsigned long top;
9505   unsigned long left;
9506   unsigned long right;
9507   int max_zoom;
9508   int min_zoom;
9509   int map_layer;
9510   int draw_filled;
9511   int usgs_drg;
9512   int auto_maps;
9513   int done;
9514 
9515 
9516   if (index_retrieve(filename,
9517                      &bottom,
9518                      &top,
9519                      &left,
9520                      &right,
9521                      &max_zoom,
9522                      &min_zoom,
9523                      &map_layer,
9524                      &draw_filled,
9525                      &usgs_drg,
9526                      &auto_maps))      // Found a match
9527   {
9528 
9529     // Allocate a new record
9530     temp_record = (map_index_record *)malloc(sizeof(map_index_record));
9531     CHECKMALLOC(temp_record);
9532 
9533     // Fill in the values
9534     xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename);
9535     temp_record->bottom = bottom;
9536     temp_record->top = top;
9537     temp_record->left = left;
9538     temp_record->right = right;
9539     temp_record->max_zoom = max_zoom;
9540     temp_record->min_zoom = min_zoom;
9541     temp_record->map_layer = map_layer;
9542     temp_record->draw_filled = draw_filled;
9543     temp_record->usgs_drg = usgs_drg;
9544     temp_record->auto_maps = auto_maps;
9545     temp_record->selected = 1;  // Always, we already know this!
9546     temp_record->accessed = 0;
9547     temp_record->next = NULL;
9548     temp_record->XmStringPtr = NULL;
9549 
9550     // Now find the proper place for it and insert it in
9551     // layer-order into the list.
9552     current = map_sorted_list_head;
9553     last = map_sorted_list_head;
9554     done = 0;
9555 
9556     // Possible cases:
9557     // Empty list
9558     // insert at beginning of list
9559     // insert at end of list
9560     // insert between other entries
9561 
9562     if (map_sorted_list_head == NULL)
9563     {
9564       // Empty list.  Insert record.
9565       map_sorted_list_head = temp_record;
9566       done++;
9567     }
9568     else if (map_layer < current->map_layer)
9569     {
9570       // Insert at beginning of list
9571       temp_record->next = current;
9572       map_sorted_list_head = temp_record;
9573       done++;
9574     }
9575     else    // Need to insert between records or at end of list
9576     {
9577       while (!done && (current != NULL) )
9578       {
9579         if (map_layer >= current->map_layer)    // Not to our layer yet
9580         {
9581           last = current;
9582           current = current->next;    // May point to NULL now
9583         }
9584         else if (map_layer < current->map_layer)
9585         {
9586           temp_record->next = current;
9587           last->next = temp_record;
9588           done++;
9589         }
9590       }
9591     }
9592     // Handle running off the end of the list
9593     if (!done && (current == NULL) )
9594     {
9595       last->next = temp_record;
9596     }
9597   }
9598   else
9599   {
9600     // We failed to find it in the map index
9601   }
9602 }
9603 
9604 
9605 
9606 
9607 
9608 /**********************************************************
9609  * load_auto_maps()
9610  *
9611  * NEW:  Uses the in-memory map_index to scan through the
9612  * maps.
9613  *
9614  * OLD: Recurses through the map directories looking for
9615  * maps to load.
9616  **********************************************************/
load_auto_maps(Widget w,char * UNUSED (dir))9617 void load_auto_maps (Widget w, char * UNUSED(dir) )
9618 {
9619   map_index_record *current = map_index_head;
9620   map_draw_flags mdf;
9621 
9622   HandlePendingEvents(app_context);
9623   if (interrupt_drawing_now)
9624   {
9625     return;
9626   }
9627 
9628   // Skip the sorting of the maps if we don't need to do it
9629   if (re_sort_maps)
9630   {
9631 
9632     //fprintf(stderr,"*** Sorting the selected maps by layer...\n");
9633 
9634     // Empty the sorted list first.  We'll create a new one.
9635     empty_map_sorted_list();
9636 
9637     // Run through the entire map_index linked list
9638     while (current != NULL)
9639     {
9640       if (auto_maps_skip_raster
9641           && (   strstr(current->filename,".geo")
9642                  || strstr(current->filename,".GEO")
9643                  || strstr(current->filename,".Geo")
9644                  || strstr(current->filename,".tif")
9645                  || strstr(current->filename,".TIF")
9646                  || strstr(current->filename,".Tif")))
9647       {
9648         // Skip this map
9649       }
9650       else    // Draw this map
9651       {
9652 
9653         //fprintf(stderr,"Loading: %s/%s\n",SELECTED_MAP_DIR,current->filename);
9654 
9655         //WE7U
9656         insert_map_sorted(current->filename);
9657 
9658         /*
9659                         draw_map (w,
9660                             SELECTED_MAP_DIR,
9661                             current->filename,
9662                             NULL,
9663                             '\0',
9664                             DRAW_TO_PIXMAP);
9665         */
9666       }
9667       current = current->next;
9668     }
9669 
9670     // All done sorting until something is changed in the Map
9671     // Chooser.
9672     re_sort_maps = 0;
9673 
9674     //fprintf(stderr,"*** DONE sorting the selected maps.\n");
9675   }
9676 
9677   // We have the maps in sorted order.  Run through the list and
9678   // draw them.  Only include those that have the auto_maps field
9679   // set to 1.
9680   current = map_sorted_list_head;
9681   while  (current != NULL)
9682   {
9683 
9684     HandlePendingEvents(app_context);
9685     if (interrupt_drawing_now)
9686     {
9687       // Update to screen
9688       (void)XCopyArea(XtDisplay(da),
9689                       pixmap,
9690                       XtWindow(da),
9691                       gc,
9692                       0,
9693                       0,
9694                       (unsigned int)screen_width,
9695                       (unsigned int)screen_height,
9696                       0,
9697                       0);
9698       return;
9699     }
9700 
9701     if (disable_all_maps)
9702     {
9703       // Update to screen
9704       (void)XCopyArea(XtDisplay(da),
9705                       pixmap,
9706                       XtWindow(da),
9707                       gc,
9708                       0,
9709                       0,
9710                       (unsigned int)screen_width,
9711                       (unsigned int)screen_height,
9712                       0,
9713                       0);
9714       return;
9715     }
9716 
9717     // Debug
9718 //        fprintf(stderr,"Drawing level:%05d, file:%s\n",
9719 //            current->map_layer,
9720 //            current->filename);
9721 
9722     // Draw the maps in sorted-by-layer order
9723     if (current->auto_maps)
9724     {
9725 
9726       mdf.draw_filled = current->draw_filled;
9727       mdf.usgs_drg = current->usgs_drg;
9728 
9729       if (debug_level & 16)
9730       {
9731         fprintf(stderr,"load_auto_maps: Calling draw_map\n");
9732       }
9733 
9734       draw_map (w,
9735                 SELECTED_MAP_DIR,
9736                 current->filename,
9737                 NULL,
9738                 '\0',
9739                 DRAW_TO_PIXMAP,
9740                 &mdf);
9741     }
9742 
9743     current = current->next;
9744   }
9745 }
9746 
9747 
9748 
9749 
9750 
9751 /*******************************************************************
9752  * load_maps()
9753  *
9754  * Loads maps, draws grid, updates the display.
9755  *
9756  * We now create a linked list of maps in layer-order and use this
9757  * list to draw the maps.  This preserves the correct ordering in
9758  * all cases.  The layer to draw each map is specified in the
9759  * map_index.sys file (fifth parameter).  Eventually code will be
9760  * added to the Map Chooser in order to change the layer each map is
9761  * drawn at.
9762  *******************************************************************/
load_maps(Widget w)9763 void load_maps (Widget w)
9764 {
9765   FILE *f;
9766   char mapname[MAX_FILENAME];
9767   int i;
9768   char selected_dir[MAX_FILENAME];
9769   map_index_record *current;
9770   map_draw_flags mdf;
9771   char selected_map_path[MAX_VALUE];
9772 
9773   get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path));
9774 
9775 //    int dummy;
9776 
9777 
9778   if (debug_level & 16)
9779   {
9780     fprintf(stderr,"Load maps start\n");
9781   }
9782 
9783   HandlePendingEvents(app_context);
9784   if (interrupt_drawing_now)
9785   {
9786     // Update to screen
9787     (void)XCopyArea(XtDisplay(da),
9788                     pixmap,
9789                     XtWindow(da),
9790                     gc,
9791                     0,
9792                     0,
9793                     (unsigned int)screen_width,
9794                     (unsigned int)screen_height,
9795                     0,
9796                     0);
9797     return;
9798   }
9799 
9800   // Skip the sorting of the maps if we don't need to do it
9801   if (re_sort_maps)
9802   {
9803 
9804     //fprintf(stderr,"*** Sorting the selected maps by layer...\n");
9805 
9806     // Empty the sorted list first.  We'll create a new one.
9807     empty_map_sorted_list();
9808 
9809     // Make sure the string is empty before we start
9810     selected_dir[0] = '\0';
9811 
9812     // Create empty file if it doesn't exist
9813     (void)filecreate( selected_map_path );
9814 
9815     f = fopen ( selected_map_path, "r" );
9816     if (f != NULL)
9817     {
9818       if (debug_level & 16)
9819       {
9820         fprintf(stderr,"Load maps Open map file\n");
9821       }
9822 
9823       while (!feof (f))
9824       {
9825 
9826         // Grab one line from the file
9827         if ( fgets( mapname, MAX_FILENAME-1, f ) != NULL )
9828         {
9829 
9830           // Forced termination (just in case)
9831           mapname[MAX_FILENAME-1] = '\0';
9832 
9833           // Get rid of the newline at the end
9834           for (i = strlen(mapname); i > 0; i--)
9835           {
9836             if (mapname[i] == '\n')
9837             {
9838               mapname[i] = '\0';
9839             }
9840           }
9841 
9842           if (debug_level & 16)
9843           {
9844             fprintf(stderr,"Found mapname: %s\n", mapname);
9845           }
9846 
9847           // Test for comment
9848           if (mapname[0] != '#')
9849           {
9850 
9851 
9852             // Check whether it's a directory that was
9853             // selected.  If so, save it in a special
9854             // variable and use that to match all the files
9855             // inside the directory.  Note that with the way
9856             // we have things ordered in the list, the
9857             // directories appear before their member files.
9858             if (mapname[strlen(mapname)-1] == '/')
9859             {
9860               int len;
9861 
9862               // Found a directory.  Save the name.
9863               xastir_snprintf(selected_dir,
9864                               sizeof(selected_dir),
9865                               "%s",
9866                               mapname);
9867 
9868               len = strlen(mapname);
9869 
9870 //fprintf(stderr,"Selected %s directory\n",selected_dir);
9871 
9872               // Here we need to run through the map_index
9873               // list to find all maps that match the
9874               // currently selected directory.  Attempt to
9875               // load all of those maps as well.
9876 
9877 //fprintf(stderr,"Load all maps under this directory: %s\n",selected_dir);
9878 
9879               // Point to the start of the map_index list
9880               current = map_index_head;
9881 
9882               while (current != NULL)
9883               {
9884 
9885                 if (strncmp(current->filename,selected_dir,len) == 0)
9886                 {
9887 
9888                   if (current->filename[strlen(current->filename)-1] != '/')
9889                   {
9890 
9891 //fprintf(stderr,"Loading: %s\n",current->filename);
9892 
9893                     //WE7U
9894                     insert_map_sorted(current->filename);
9895 
9896                     /*
9897                                                             draw_map (w,
9898                                                                 SELECTED_MAP_DIR,
9899                                                                 current->filename,
9900                                                                 NULL,
9901                                                                 '\0',
9902                                                                 DRAW_TO_PIXMAP);
9903                     */
9904 
9905                   }
9906                 }
9907                 current = current->next;
9908               }
9909             }
9910             // Else must be a regular map file
9911             else
9912             {
9913 //fprintf(stderr,"%s\n",mapname);
9914 //start_timer();
9915 
9916               //WE7U
9917               insert_map_sorted(mapname);
9918 
9919               /*
9920                                           draw_map (w,
9921                                               SELECTED_MAP_DIR,
9922                                               mapname,
9923                                               NULL,
9924                                               '\0',
9925                                               DRAW_TO_PIXMAP);
9926               */
9927 
9928 //stop_timer();
9929 //print_timer_results();
9930 
9931               if (debug_level & 16)
9932               {
9933                 fprintf(stderr,"Load maps -%s\n", mapname);
9934               }
9935 
9936               XmUpdateDisplay (da);
9937             }
9938           }
9939         }
9940         else    // We've hit EOF
9941         {
9942           break;
9943         }
9944 
9945       }
9946       (void)fclose (f);
9947       statusline(" ",1);      // delete status line
9948     }
9949     else
9950     {
9951       fprintf(stderr,"Couldn't open file: %s\n", selected_map_path );
9952     }
9953 
9954     // All done sorting until something is changed in the Map
9955     // Chooser.
9956     re_sort_maps = 0;
9957 
9958     //fprintf(stderr,"*** DONE sorting the selected maps.\n");
9959   }
9960 
9961 
9962   // We have the maps in sorted order.  Run through the list and
9963   // draw them.
9964   current = map_sorted_list_head;
9965   while  (current != NULL)
9966   {
9967 
9968     HandlePendingEvents(app_context);
9969     if (interrupt_drawing_now)
9970     {
9971       statusline(" ",1);      // delete status line
9972       // Update to screen
9973       (void)XCopyArea(XtDisplay(da),
9974                       pixmap,
9975                       XtWindow(da),
9976                       gc,
9977                       0,
9978                       0,
9979                       (unsigned int)screen_width,
9980                       (unsigned int)screen_height,
9981                       0,
9982                       0);
9983       return;
9984     }
9985 
9986     if (disable_all_maps)
9987     {
9988       // Update to screen
9989       (void)XCopyArea(XtDisplay(da),
9990                       pixmap,
9991                       XtWindow(da),
9992                       gc,
9993                       0,
9994                       0,
9995                       (unsigned int)screen_width,
9996                       (unsigned int)screen_height,
9997                       0,
9998                       0);
9999       return;
10000     }
10001 
10002     // Debug
10003 //        fprintf(stderr,"Drawing level:%05d, file:%s\n",
10004 //            current->map_layer,
10005 //            current->filename);
10006 
10007     // Draw the maps in sorted-by-layer order
10008     mdf.draw_filled = current->draw_filled;
10009     mdf.usgs_drg = current->usgs_drg;
10010 
10011     if (debug_level & 16)
10012     {
10013       fprintf(stderr,"load_maps: Calling draw_map\n");
10014     }
10015 
10016 // Map profiling, set up for 800x600 window at "Map Profile Test
10017 // Site" bookmark.
10018 //
10019 // Loading "rd011802.shp" 500 times takes
10020 // 302->256->264->269->115->116 seconds.
10021 //
10022 // 100 times on PP200 takes 192->183 seconds.
10023 //
10024 //start_timer();
10025 //fprintf(stderr,"Calling draw_map() 500 times...\n");
10026 //for (dummy = 0; dummy < 500; dummy++) {
10027     draw_map (w,
10028               SELECTED_MAP_DIR,
10029               current->filename,
10030               NULL,
10031               '\0',
10032               DRAW_TO_PIXMAP,
10033               &mdf);
10034 //}
10035 //stop_timer(); print_timer_results();
10036 
10037     current = current->next;
10038   }
10039 
10040   if (debug_level & 16)
10041   {
10042     fprintf(stderr,"Load maps stop\n");
10043   }
10044 }
10045 
10046 
10047