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 FUZZYRASTER
25 
26 #ifdef HAVE_CONFIG_H
27   #include "config.h"
28 #endif  // HAVE_CONFIG_H
29 
30 #include "snprintf.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <ctype.h>
37 #include <sys/types.h>
38 #include <pwd.h>
39 #include <errno.h>
40 
41 // Needed for Solaris
42 #ifdef HAVE_STRINGS_H
43   #include <strings.h>
44 #endif  // HAVE_STRINGS_H
45 
46 #include <dirent.h>
47 #include <netinet/in.h>
48 #include <Xm/XmAll.h>
49 
50 #ifdef HAVE_X11_XPM_H
51   #include <X11/xpm.h>
52   #ifdef HAVE_LIBXPM // if we have both, prefer the extra library
53     #undef HAVE_XM_XPMI_H
54   #endif // HAVE_LIBXPM
55 #endif // HAVE_X11_XPM_H
56 
57 #ifdef HAVE_XM_XPMI_H
58   #include <Xm/XpmI.h>
59 #endif // HAVE_XM_XPMI_H
60 
61 #include <X11/Xlib.h>
62 
63 #include <math.h>
64 
65 #include "xastir.h"
66 #include "maps.h"
67 #include "map_cache.h"
68 #include "alert.h"
69 #include "fetch_remote.h"
70 #include "util.h"
71 #include "main.h"
72 #include "datum.h"
73 #include "draw_symbols.h"
74 #include "rotated.h"
75 #include "color.h"
76 #include "xa_config.h"
77 
78 #include "map_OSM.h"
79 
80 #define CHECKMALLOC(m)  if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); }
81 
82 
83 // Check for XPM and/or ImageMagick.  We use "NO_GRAPHICS"
84 // to disable some routines below if the support for them
85 // is not compiled in.
86 #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK))
87   #define NO_GRAPHICS 1
88 #endif  // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK)
89 
90 #if defined(HAVE_MAGICK) || !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM))
91   #define NO_XPM 1
92 #endif  // HAVE_MAGICK ||  !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM)
93 
94 
95 #ifdef HAVE_MAGICK
96   #if TIME_WITH_SYS_TIME
97     #include <sys/time.h>
98     #include <time.h>
99   #else   // TIME_WITH_SYS_TIME
100     #if HAVE_SYS_TIME_H
101       #include <sys/time.h>
102     #else  // HAVE_SYS_TIME_H
103       #include <time.h>
104     #endif // HAVE_SYS_TIME_H
105   #endif  // TIME_WITH_SYS_TIME
106   #undef RETSIGTYPE
107   // TVR: "stupid ImageMagick"
108   // The problem is that magick/api.h includes Magick's config.h file, and that
109   // pulls in all the same autoconf-generated defines that we use.
110   // plays those games below, but I don't think in the end that they actually
111   // make usable macros with our own data in them.
112   // Fortunately, we don't need them, so I'll just undef the ones that are
113   // causing problems today.  See main.c for fixes that preserve our values.
114   #undef PACKAGE
115   #undef VERSION
116   /* JMT - stupid ImageMagick */
117   #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT
118   #undef PACKAGE_BUGREPORT
119   #define XASTIR_PACKAGE_NAME PACKAGE_NAME
120   #undef PACKAGE_NAME
121   #define XASTIR_PACKAGE_STRING PACKAGE_STRING
122   #undef PACKAGE_STRING
123   #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME
124   #undef PACKAGE_TARNAME
125   #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION
126   #undef PACKAGE_VERSION
127   #ifdef HAVE_MAGICK
128     #ifdef HAVE_MAGICKCORE_MAGICKCORE_H
129       #include <MagickCore/MagickCore.h>
130     #else
131       #ifdef HAVE_MAGICK_API_H
132         #include <magick/api.h>
133       #endif // HAVE_MAGICK_API_H
134     #endif //HAVE_MAGICKCORE_MAGICKCORE_H
135   #endif //HAVE_MAGICK
136   #undef PACKAGE_BUGREPORT
137   #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT
138   #undef XASTIR_PACKAGE_BUGREPORT
139   #undef PACKAGE_NAME
140   #define PACKAGE_NAME XASTIR_PACKAGE_NAME
141   #undef XASTIR_PACKAGE_NAME
142   #undef PACKAGE_STRING
143   #define PACKAGE_STRING XASTIR_PACKAGE_STRING
144   #undef XASTIR_PACKAGE_STRING
145   #undef PACKAGE_TARNAME
146   #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME
147   #undef XASTIR_PACKAGE_TARNAME
148   #undef PACKAGE_VERSION
149   #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION
150   #undef XASTIR_PACKAGE_VERSION
151 #endif // HAVE_MAGICK
152 
153 // Must be last include file
154 #include "leak_detection.h"
155 
156 
check_interrupt(Image * image,ImageInfo * image_info,ExceptionInfo * exception,Widget * da,Pixmap * pixmap,GC * gc,unsigned long screen_width,unsigned long screen_height)157 int check_interrupt(
158 #ifdef HAVE_MAGICK
159   Image *image, ImageInfo *image_info, ExceptionInfo *exception,
160 #else // HAVE_MAGICK
161   XImage *xi,
162 #endif // HAVE_MAGICK
163   Widget *da, Pixmap *pixmap,
164   GC *gc, unsigned long screen_width, unsigned long screen_height)
165 {
166   HandlePendingEvents(app_context);
167   if (interrupt_drawing_now)
168   {
169 #ifdef HAVE_MAGICK
170     if (image)
171     {
172       DestroyImage(image);
173     }
174     if (image_info)
175     {
176       DestroyImageInfo(image_info);
177     }
178 #else   // HAVE_MAGICK
179     if (xi)
180     {
181       XDestroyImage (xi);
182     }
183 #endif // HAVE_MAGICK
184     // Update to screen
185     (void)XCopyArea(XtDisplay(*da),
186                     *pixmap,
187                     XtWindow(*da),
188                     *gc,
189                     0,
190                     0,
191                     (unsigned int)screen_width,
192                     (unsigned int)screen_height,
193                     0,
194                     0);
195 #ifdef HAVE_MAGICK
196     DestroyExceptionInfo(exception);
197 #endif // HAVE_MAGICK
198     return(~0);
199   }
200   else
201   {
202     return(0);
203   }
204 }
205 
206 void draw_geo_image_map (Widget w, char *dir, char *filenm,
207                          alert_entry *alert, u_char alert_color, int destination_pixmap,
208                          map_draw_flags *mdf);
209 
210 
211 
212 
213 
214 /*  typedef struct _transparent_color_record{
215     unsigned long trans_color;
216     struct _transparent_color_record *next;
217     } transparent_color_record;
218 */
219 // Pointer to head of transparent color linked list.
220 transparent_color_record *trans_color_head = NULL;
221 
222 
223 
224 
225 
226 // Empty out the linked list containing transparent colors
empty_trans_color_list(void)227 void empty_trans_color_list(void)
228 {
229   transparent_color_record *p;
230 
231   while (trans_color_head != NULL)
232   {
233     p = trans_color_head;
234     trans_color_head = p->next;
235     free(p);
236   }
237 }
238 
239 
240 
241 
242 
243 // Add a new transparent color to the linked list
new_trans_color(unsigned long trans_color)244 void new_trans_color(unsigned long trans_color)
245 {
246   transparent_color_record *p;
247 
248   //fprintf(stderr,"New transparent color: %lx\n", trans_color);
249 
250   p = (transparent_color_record *)malloc( sizeof(transparent_color_record) );
251 
252   // Fill in value
253   p->trans_color = trans_color;
254 
255   // Link it to transparent color list
256   p->next = trans_color_head;
257   trans_color_head = p;
258 }
259 
260 
261 
262 
263 
264 /********************(**********************************************
265  * check_trans()
266  *
267  * See if this pixel's color should be transparent
268  *
269  * We only call this from blocks where ImageMagick is used, so we're
270  * ok to use IM calls.
271  ******************************************(************************/
272 
check_trans(XColor c,transparent_color_record * c_trans_color_head)273 int check_trans (XColor c, transparent_color_record *c_trans_color_head)
274 {
275   transparent_color_record *p = c_trans_color_head;
276 
277   //    fprintf (stderr, "pix = %li,%lx, chk = %li,%lx.\n",c.pixel,c.pixel,c_trans_color,c_trans_color);
278   // A linked list from the geo file of colors to zap.
279 
280   //    if ( c.pixel == (unsigned long) 0x000000 ) {
281   //    return 1; // black background
282   //}
283   while (p)
284   {
285     if ( c.pixel == p->trans_color )
286     {
287       return 1;
288     }
289     p = p->next;
290   }
291 
292   return 0; // everything else is OK to draw
293 }
294 
295 
296 
297 
298 
299 // Regarding MAP CACHING for toporama maps:  Here we are only
300 // snagging a .geo file for toporama from findu.com:  We send the
301 // parameters off to findu.com, it computes the .geo file, we
302 // download it, then we call draw_geo_image_map() with it.  We would
303 // have to cache the .geo files from findu, we'd have to modify them
304 // to point to our local cached map file (maybe), and we'd of course
305 // have to cache that map image as well.  The image filename on
306 // findu changes each time we call with the same parameters, so we'd
307 // have to give the image file our own name based on the parameters
308 // and write that same name into the cached .geo file.  A bit of
309 // work, but it _could_ be done.  Actually, we should be able to map
310 // between the original URL we use to request the .GEO file and the
311 // final image we received.  That way the name would stay the same
312 // each time we made the request.  There may be other things we need
313 // from the generated .GEO file though.
314 //
315 // For this particular case we need to snag a remote .geo file and
316 // then start the process all over again.  The URL we'll need to use
317 // looks something like this:
318 //
319 // http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1
320 //
321 // Where the lat/lon are the center of our view, and the
322 // width/height depend on our window size.  The "set" parameter
323 // decides whether we're fetching 50k or 250k maps.
324 //
draw_toporama_map(Widget w,char * UNUSED (dir),char * filenm,alert_entry * alert,u_char alert_color,int destination_pixmap,map_draw_flags * mdf,int toporama_flag)325 void draw_toporama_map (Widget w,
326                         char * UNUSED(dir),
327                         char *filenm,
328                         alert_entry *alert,
329                         u_char alert_color,
330                         int destination_pixmap,
331                         map_draw_flags *mdf,
332                         int toporama_flag)      // 50 or 250
333 {
334 
335 #ifdef HAVE_MAGICK
336 
337   char fileimg[MAX_FILENAME+1];   // Ascii name of image file, read from GEO file
338   char map_it[MAX_FILENAME];
339   char local_filename[MAX_FILENAME];
340   char file[MAX_FILENAME+1];      // Complete path/name of image file
341   char short_filenm[MAX_FILENAME+1];
342   FILE *f;                        // Filehandle of image file
343   double lat_center = 0;
344   double long_center = 0;
345   double left, right, top, bottom;
346   int my_screen_width, my_screen_height;
347   float my_zoom = 1.0;
348   char temp_file_path[MAX_VALUE];
349 
350   // Create a shorter filename for display (one that fits the
351   // status line more closely).  Subtract the length of the
352   // "Indexing " and/or "Loading " strings as well.
353   if (strlen(filenm) > (41 - 9))
354   {
355     int avail = 41 - 11;
356     int new_len = strlen(filenm) - avail;
357 
358     xastir_snprintf(short_filenm,
359                     sizeof(short_filenm),
360                     "..%s",
361                     &filenm[new_len]);
362   }
363   else
364   {
365     xastir_snprintf(short_filenm,
366                     sizeof(short_filenm),
367                     "%s",
368                     filenm);
369   }
370 
371 
372   //fprintf(stderr, "Found TOPORAMA in a .geo file, %dk scale\n", toporama_flag);
373 
374   // Check whether we're indexing or drawing the map
375   if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
376        || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
377   {
378 
379     // We're indexing only.  Save the extents in the index.
380     // Force the extents to the edges of the earth for the index
381     // file.
382     index_update_xastir(filenm, // Filename only
383                         64800000l,      // Bottom
384                         0l,             // Top
385                         0l,             // Left
386                         129600000l,     // Right
387                         0);             // Default Map Level
388 
389     // Update statusline
390     xastir_snprintf(map_it,
391                     sizeof(map_it),
392                     langcode ("BBARSTA039"),
393                     short_filenm);
394     statusline(map_it,0);       // Loading/Indexing ...
395 
396     return; // Done indexing this file
397   }
398 
399 
400   // Compute the parameters we'll need for the URL, fetch the .geo
401   // file at that address, then pass that .geo file off to
402   // draw_geo_image_map().  This will cause us to fetch the image
403   // file corresponding to the .geo file and display it.  We may
404   // also need to tweak the zoom parameter for our current zoom
405   // level so that things match up properly.
406 
407 
408   // Compute the center of our view in decimal lat/long.
409   left = (double)((NW_corner_longitude - 64800000l )/360000.0);   // Lat/long Coordinates
410   top = (double)(-((NW_corner_latitude - 32400000l )/360000.0));  // Lat/long Coordinates
411   right = (double)((SE_corner_longitude - 64800000l)/360000.0);//Lat/long Coordinates
412   bottom = (double)(-((SE_corner_latitude - 32400000l)/360000.0));//Lat/long Coordinates
413 
414   long_center = (left + right)/2.0l;
415   lat_center  = (top + bottom)/2.0l;
416 
417   // We now have the center in decimal lat/long.  We also have the
418   // screen width and height in pixels, which we can use in the
419   // URL as well (depending on the zoom parameter and how to make
420   // the finished display look nice).
421 
422 
423   // Compute the size of the image we want to snag.  It should be
424   // easy to get darn near anything to work, although the size and
425   // scale of the image will drastically affect how nicely the
426   // finished map display will look.
427 
428 
429   // Compute the zoom parameter for the URL.
430 
431 
432   // A test URL that works, just to get things going.  This URL
433   // requests 1:50k scale maps ("set=50").
434   //xastir_snprintf(fileimg, sizeof(fileimg),
435   //    "\"http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1\"");
436 
437   // Compute our custom URL based on our map view and the
438   // requested map scale.
439   //
440   my_screen_width = (int)screen_width;
441   my_screen_height = (int)screen_height;
442 
443   if (toporama_flag == 50)    // 1:50k
444   {
445 
446     my_zoom = 32.0 / scale_y;
447 
448     if (scale_y <= 16)
449     {
450       my_zoom = 2.0;
451     }
452   }
453   else    // toporama_flag == 250 (1:250k)
454   {
455 
456     my_zoom = 128.0 / scale_y;
457 
458     if (scale_y <= 64)
459     {
460       my_zoom = 2.0;
461     }
462   }
463 
464   // Set a max zoom limit so we don't tax the server too much.
465   if (my_zoom < 0.02)
466   {
467     my_zoom = 0.02;
468   }
469 
470   xastir_snprintf(fileimg, sizeof(fileimg),
471                   "http://mm.aprs.net/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f",
472                   //        "http://www2.findu.com/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f",
473                   toporama_flag,  // Scale, 50 or 250
474                   lat_center,
475                   long_center,
476                   my_screen_width,
477                   my_screen_height,
478                   my_zoom);
479 
480   //fprintf(stderr,"%s\n", fileimg);
481 
482   // Create a local filename that we'll save to.
483   xastir_snprintf(local_filename,
484                   sizeof(local_filename),
485                   "%s/map.geo",
486                   get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)));
487 
488   // Erase any previously existing local file by the same
489   // name.  This avoids the problem of having an old map image
490   // here and the code trying to display it when the download
491   // fails.
492   unlink( local_filename );
493 
494 
495   // Call wget or libcurl to fetch the .geo file.  Best would be
496   // to create a generic "fetch" routine which would fetch a
497   // remote file, then go back and rework all of the various map
498   // routines to use it.
499 
500   if (fetch_remote_file(fileimg, local_filename))
501   {
502     // Had trouble getting the file.  Abort.
503     return;
504   }
505 
506   // Set permissions on the file so that any user can overwrite it.
507   chmod(local_filename, 0666);
508 
509   // We now re-use the "file" variable.  It'll hold the
510   //name of the map file now instead of the .geo file.
511 
512   // Tell ImageMagick where to find it
513   xastir_snprintf(file,sizeof(file),"%s",local_filename);
514 
515 
516 
517   // Check whether we got a reasonable ~/.xastir/tmp/map.geo file from
518   // the fetch.  If so, pass it off to the routine which can draw it.
519 
520   // We also need to write a valid IMAGESIZE line into the .geo
521   // file.  We know these parameters because they should match
522   // screen_width/screen_height.
523   //
524   xastir_snprintf(map_it,
525                   sizeof(map_it),
526                   "IMAGESIZE\t%d\t%d\n",
527                   my_screen_width,
528                   my_screen_height);
529 
530   // Another thing we might need is a TRANSPARENT line, for the grey
531   // color we see crossing over the U.S. border and obscuring maps on
532   // this side of the border.
533 
534   f = fopen (local_filename, "a");
535   if (f != NULL)
536   {
537     fprintf(f, "%s", map_it);
538     (void)fclose (f);
539   }
540   else
541   {
542     fprintf(stderr,"Couldn't open file: %s to add IMAGESIZE tag\n", local_filename);
543     return;
544   }
545 
546 
547   // Call draw_geo_image_map() with our newly-fetched .geo file,
548   // passing it most of the parameters that we were originally
549   // passed in order to effect the map draw.
550   draw_geo_image_map (w,
551                       get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),
552                       "map.geo",
553                       alert,
554                       alert_color,
555                       destination_pixmap,
556                       mdf);
557 
558 #endif  // HAVE_MAGICK
559 }
560 
561 
562 
563 
564 
565 /**********************************************************
566  * draw_geo_image_map()
567  *
568  * If we have found a ".geo" file, we read it here and plot
569  * the graphic image into the current viewport.
570  * We check first to see whether the map should be plotted
571  * and skip it if it's not in our viewport.  These images
572  * are expected to be aligned in the lat/lon directions
573  * (not rotated) and rectangular.
574  **********************************************************/
575 
draw_geo_image_map(Widget w,char * dir,char * filenm,alert_entry * alert,u_char alert_color,int destination_pixmap,map_draw_flags * mdf)576 void draw_geo_image_map (Widget w,
577                          char *dir,
578                          char *filenm,
579                          alert_entry *alert,
580                          u_char alert_color,
581                          int destination_pixmap,
582                          map_draw_flags *mdf)
583 {
584 #ifdef NO_GRAPHICS
585   fprintf(stderr,"XPM and/or ImageMagick support have not been compiled in.\n");
586 #else   // NO_GRAPHICS
587   char file[MAX_FILENAME+1];      // Complete path/name of image file
588   char short_filenm[MAX_FILENAME+1];
589   FILE *f;                        // Filehandle of image file
590   char line[MAX_FILENAME];        // One line from GEO file
591   char fileimg[MAX_FILENAME+1];   // Ascii name of image file, read from GEO file
592   char tileCache[MAX_FILENAME+1]; // directory for the OSM tile cache, read from GEO file.
593   char OSMstyle[MAX_OSMSTYLE];
594   char OSMtileExt[MAX_OSMEXT];
595 
596   // Start with an empty fileimg[] string so that we can
597   // tell if a URL has been specified in the file. Same for OSMstyle.
598   fileimg[0] = '\0';
599   OSMstyle[0] = '\0';
600   tileCache[0] = '\0';
601   OSMtileExt[0] = '\0';
602 
603   int width,height;
604 #ifndef NO_XPM
605   XpmAttributes atb;              // Map attributes after map's read into an XImage
606 #endif  // NO_XPM
607 
608   tiepoint tp[2];                 // Calibration points for map, read in from .geo file
609   int n_tp;                       // Temp counter for number of tiepoints read
610   float temp_long, temp_lat;
611   long map_c_T, map_c_L;          // map delta NW edge coordinates, DNN: these should be signed
612   long tp_c_dx, tp_c_dy;          // tiepoint coordinate differences
613   // DK7IN--
614   //  int test;                       // temporary debugging
615 
616   unsigned long c_x_min,  c_y_min;// top left coordinates of map inside screen
617   //  unsigned long c_y_max;          // bottom right coordinates of map inside screen
618   double c_x;                     // Xastir coordinates 1/100 sec, 0 = 180�W
619   double c_y;                     // Xastir coordinates 1/100 sec, 0 =  90�N
620   double c_y_a;                   // coordinates correction for Transverse Mercator
621 
622   long map_y_0;                   // map pixel pointer prior to TM adjustment
623   long map_x, map_y;              // map pixel pointers, DNN: this was a float, chg to long
624   long map_x_min, map_x_max;      // map boundaries for in screen part of map
625   long map_y_min, map_y_max;      //
626   long map_x_ctr;                 // half map width in pixel
627   //  long map_y_ctr;                 // half map height in pixel
628   //  long x;
629   int map_seen, map_act, map_done;
630   double corrfact;
631 
632   long map_c_yc;                  // map center, vert coordinate
633   long map_c_xc;                  // map center, hor  coordinate
634   double map_c_dx, map_c_dy;      // map coordinates increment (pixel width)
635   double c_dx;                    // adjusted map pixel width
636 
637   long scr_x,  scr_y;             // screen pixel plot positions
638   long scr_xp, scr_yp;            // previous screen plot positions
639   int  scr_dx, scr_dy;            // increments in screen plot positions
640   //  long scr_x_mc;                  // map center in screen units
641 
642   long scr_c_xr;
643 
644   double dist;                    // distance from equator in nm
645   double ew_ofs;                  // distance from map center in nm
646 
647   long scale_xa;                  // adjusted for topo maps
648   double scale_x_nm;              // nm per Xastir coordinate unit
649   long scale_x0;                  // at widest map area
650 
651 #ifdef HAVE_MAGICK
652   char local_filename[MAX_FILENAME];
653   ExceptionInfo exception;
654   Image *image;
655   ImageInfo *image_info;
656   PixelPacket *pixel_pack;
657   PixelPacket temp_pack;
658   IndexPacket *index_pack;
659   int l;
660   XColor my_colors[256];
661   time_t query_start_time, query_end_time;
662   char gamma[16];
663   struct
664   {
665     float r_gamma;
666     float g_gamma;
667     float b_gamma;
668     int gamma_flag;
669     int contrast;
670     int negate;
671     int equalize;
672     int normalize;
673     char level[32];
674     char modulate[32];
675   } imagemagick_options = { 1.0, 1.0, 1.0, 0, 0, -1, 0, 0, "", "" };
676   double left, right, top, bottom;
677   //  double map_width, map_height;
678   //N0VH
679   //    double lat_center  = 0;
680   //    double long_center = 0;
681   // Terraserver variables
682   double top_n=0, left_e=0, bottom_n=0, right_e=0, map_top_n=0, map_left_e=0;
683   int z, url_n=0, url_e=0, t_zoom=16, t_scale=12800;
684   char zstr0[8];
685   char zstr1[8];
686 #else   // HAVE_MAGICK
687   XImage *xi;                 // Temp XImage used for reading in current image
688 #endif // HAVE_MAGICK
689 
690   int terraserver_flag = 0;   // U.S. satellite images/topo/reflectivity/urban
691   // areas via terraserver
692   int OSMserver_flag = 0;     // OpenStreetMaps server, 1 = static maps, 2 = tiled
693   unsigned tmp_zl = 0;
694 
695   int toporama_flag = 0;      // Canadian topo's from mm.aprs.net (originally from Toporama)
696   int WMSserver_flag = 0;     // WMS server
697   char map_it[MAX_FILENAME];
698   int geo_image_width = 0;    // Image width  from GEO file
699   int geo_image_height = 0;   // Image height from GEO file
700   char geo_datum[8+1];        // WGS-84 etc.
701   char geo_projection[256+1];   // TM, UTM, GK, LATLON etc.
702   int map_proj=0;
703   int map_refresh_interval_temp = 0;
704 #ifdef HAVE_MAGICK
705   int nocache = 0;            // Don't cache the file if non-zero
706 #endif  // HAVE_MAGICK
707 #ifdef FUZZYRASTER
708   int rasterfuzz = 3;    // ratio to skip
709 #endif //FUZZYRASTER
710   unsigned long temp_trans_color;    // what color to zap
711   int trans_skip = 0;  // skip transparent pixel
712   int crop_x1=0, crop_x2=0, crop_y1=0, crop_y2=0; // pixel crop box
713   int do_crop = 0;     // do we crop pixels
714   //#define TIMING_DEBUG
715 #ifdef TIMING_DEBUG
716   time_mark(1);
717 #endif  // TIMING_DEBUG
718 
719 #ifdef HAVE_MAGICK
720 #ifdef USE_MAP_CACHE
721   int map_cache_return;
722   char *cache_file_id;
723 #endif  // USE_MAP_CACHE
724 #endif  // HAVE_MAGICK
725 
726 #ifdef HAVE_MAGICK
727   char temp_file_path[MAX_VALUE];
728 #endif  // HAVE_MAGICK
729 
730   KeySym OSM_key = 0;
731 
732   xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm);
733 
734   // Create a shorter filename for display (one that fits the
735   // status line more closely).  Subtract the length of the
736   // "Indexing " and/or "Loading " strings as well.
737   if (strlen(filenm) > (41 - 9))
738   {
739     int avail = 41 - 11;
740     int new_len = strlen(filenm) - avail;
741 
742     xastir_snprintf(short_filenm,
743                     sizeof(short_filenm),
744                     "..%s",
745                     &filenm[new_len]);
746   }
747   else
748   {
749     xastir_snprintf(short_filenm,
750                     sizeof(short_filenm),
751                     "%s",
752                     filenm);
753   }
754 
755 
756   // Read the .geo file to find out map filename and tiepoint info
757 
758   // Empty the transparent color list before we start reading in a
759   // new .geo file.
760   empty_trans_color_list();
761 
762   n_tp = 0;
763   geo_datum[0]      = '\0';
764   geo_projection[0] = '\0';
765   f = fopen (file, "r");
766   if (f != NULL)
767   {
768     while (!feof (f))
769     {
770       (void)get_line (f, line, MAX_FILENAME);
771       if (strncasecmp (line, "FILENAME", 8) == 0)
772       {
773         if (1 != sscanf (line + 9, "%s", fileimg))
774         {
775           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
776         }
777         if (fileimg[0] != '/' )   // not absolute path
778         {
779           // make it relative to the .geo file
780           char temp[MAX_FILENAME];
781 
782           // grab .geo file name
783           strcpy(temp, file);
784           temp[sizeof(temp)-1] = '\0';  // Terminate line
785 
786           (void)get_map_dir(temp);           // leaves just the path and trailing /
787           if (strlen(temp) < (MAX_FILENAME - 1 - strlen(fileimg)))
788             strncat(temp,
789                     fileimg,
790                     sizeof(temp) - 1 - strlen(temp));
791           xastir_snprintf(fileimg,sizeof(fileimg),"%s",temp);
792         }
793       }
794       if (strncasecmp (line, "URL", 3) == 0)
795         if (1 != sscanf (line + 4, "%s", fileimg))
796         {
797           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
798         }
799 
800       if (n_tp < 2)       // Only take the first two tiepoints
801       {
802         if (strncasecmp (line, "TIEPOINT", 8) == 0)
803         {
804           if (4 != sscanf (line + 9, "%d %d %f %f",
805                            &tp[n_tp].img_x,
806                            &tp[n_tp].img_y,
807                            &temp_long,
808                            &temp_lat))
809           {
810             fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
811           }
812           // Convert tiepoints from lat/lon to Xastir coordinates
813           tp[n_tp].x_long = 64800000l + (360000.0 * temp_long);
814           tp[n_tp].y_lat  = 32400000l + (360000.0 * (-temp_lat));
815           n_tp++;
816         }
817       }
818 
819       if (strncasecmp (line, "IMAGESIZE", 9) == 0)
820         if (2 != sscanf (line + 10, "%d %d",&geo_image_width,&geo_image_height))
821         {
822           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
823         }
824 
825       if (strncasecmp (line, "DATUM", 5) == 0)
826         if (1 != sscanf (line + 6, "%8s",geo_datum))
827         {
828           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
829         }
830 
831       if (strncasecmp (line, "PROJECTION", 10) == 0)
832         // Ignores leading and trailing space (nice!)
833         if (1 != sscanf (line + 11, "%256s",geo_projection))
834         {
835           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
836         }
837 
838       if (strncasecmp (line, "TERRASERVER-URBAN", 17) == 0)
839       {
840         terraserver_flag = 4;
841       }
842 
843       if (strncasecmp (line, "TERRASERVER-REFLECTIVITY", 24) == 0)
844       {
845         terraserver_flag = 3;
846       }
847 
848       if (strncasecmp (line, "TERRASERVER-TOPO", 16) == 0)
849       {
850         // Set to max brightness as it looks weird when the
851         // intensity variable comes into play.
852 #ifdef HAVE_MAGICK
853         // This one causes problems now.  Not sure why.
854         //                xastir_snprintf(imagemagick_options.modulate,32,"100 100 100");
855 #endif  // HAVE_MAGICK
856         terraserver_flag = 2;
857       }
858 
859       if (strncasecmp (line, "TERRASERVER-SATELLITE", 21) == 0)
860       {
861         terraserver_flag = 1;
862       }
863 
864       if (strncasecmp (line, "OSMSTATICMAP", 12) == 0)
865       {
866         OSMserver_flag = 1;
867         if (strlen(line) > 13)
868         {
869           if (1 != sscanf (line + 13, "%s", OSMstyle))
870           {
871             fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n");
872           }
873         }
874       }
875 
876       if (strncasecmp (line, "OSM_TILED_MAP", 13) == 0)
877       {
878         OSMserver_flag = 2;
879         if (strlen(line) > 14)
880         {
881           if (1 != sscanf (line + 14, "%s", OSMstyle))
882           {
883             fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n");
884           }
885         }
886       }
887 
888       if (OSMserver_flag > 0)    // the following keywords are only valid for OSM maps
889       {
890         if (strncasecmp (line, "OSM_OPTIMIZE_KEY", 16) == 0)
891         {
892           if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS)
893               && (destination_pixmap != INDEX_NO_TIMESTAMPS))
894           {
895             if (strlen(line) > 17)
896             {
897               if (1 != sscanf (line + 17, "%lu", &OSM_key))
898               {
899                 fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n");
900               }
901               else
902               {
903                 set_OSM_optimize_key(OSM_key);
904               }
905             }
906           }
907         }
908 
909         if (strncasecmp (line, "OSM_REPORT_SCALE_KEY", 20) == 0)
910         {
911           if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS)
912               && (destination_pixmap != INDEX_NO_TIMESTAMPS))
913           {
914             if (strlen(line) > 21)
915             {
916               if (1 != sscanf (line + 21, "%lu", &OSM_key))
917               {
918                 fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n");
919               }
920               else
921               {
922                 set_OSM_report_scale_key(OSM_key);
923               }
924             }
925           }
926         }
927 
928         if (strncasecmp (line, "TILE_DIR", 8) == 0)
929         {
930           if (strlen(line) > 9)
931           {
932             if (1 != sscanf (line + 9, "%s", tileCache))
933             {
934               fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_DIR\n");
935             }
936           }
937         }
938 
939         if (strncasecmp (line, "TILE_EXT", 8) == 0)
940         {
941           if (strlen(line) > 9)
942           {
943             if (1 != sscanf (line + 9, "%s", OSMtileExt))
944             {
945               fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_EXT\n");
946             }
947           }
948         }
949 
950         if (strncasecmp(line, "ZOOM_LEVEL_MIN", 14) == 0)
951         {
952           if (strlen(line) > 15)
953           {
954             if (1 != sscanf(line + 15, "%u", &tmp_zl))
955             {
956               fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MIN\n");
957             }
958             else
959             {
960               if (!(osm_zoom_level(scale_x) >= tmp_zl))
961               {
962                 // skip this map because the zoom level
963                 // is not supported.
964                 if (debug_level & 512)
965                 {
966                   fprintf(stderr, "Skipping OSM map. zl = %u < %u\n", osm_zoom_level(scale_x), tmp_zl);
967                 }
968                 return;
969               }
970             }
971           }
972         }
973         if (strncasecmp(line, "ZOOM_LEVEL_MAX", 14) == 0)
974         {
975           if (strlen(line) > 15)
976           {
977             if (1 != sscanf(line + 15, "%u", &tmp_zl))
978             {
979               fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MAX\n");
980             }
981             else
982             {
983               if (!(tmp_zl >= osm_zoom_level(scale_x)))
984               {
985                 // skip this map because the zoom level
986                 // is not supported.
987                 if (debug_level & 512)
988                 {
989                   fprintf(stderr, "Skipping OSM map. zl = %u > %u\n", osm_zoom_level(scale_x), tmp_zl);
990                 }
991                 return;
992               }
993             }
994           }
995         }
996       }
997 
998       if (strncasecmp (line, "WMSSERVER", 9) == 0)
999       {
1000         WMSserver_flag = 1;
1001       }
1002 
1003       // Check for Canadian topo map request
1004       if (strncasecmp (line, "TOPORAMA-50k", 12) == 0)
1005       {
1006         toporama_flag = 50;
1007       }
1008       if (strncasecmp (line, "TOPORAMA-250k", 13) == 0)
1009       {
1010         toporama_flag = 250;
1011       }
1012 
1013 
1014       // Check whether we're indexing or drawing the map.
1015       // Exclude setting the map refresh interval from
1016       // indexing.
1017       if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS)
1018            && (destination_pixmap != INDEX_NO_TIMESTAMPS) )
1019       {
1020 
1021         if (strncasecmp (line, "REFRESH", 7) == 0)
1022         {
1023           if (1 != sscanf (line + 8, "%d", &map_refresh_interval_temp))
1024           {
1025             fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1026           }
1027           if ( map_refresh_interval_temp > 0 &&
1028                ( map_refresh_interval == 0 ||
1029                  map_refresh_interval_temp < map_refresh_interval) )
1030           {
1031             map_refresh_interval = (time_t) map_refresh_interval_temp;
1032             map_refresh_time = sec_now() + map_refresh_interval;
1033 
1034             if (debug_level & 512)
1035             {
1036               fprintf(stderr, "Map Refresh set to %d.\n", (int) map_refresh_interval);
1037             }
1038           }
1039 #ifdef HAVE_MAGICK
1040           nocache = map_refresh_interval_temp;
1041 #endif  // HAVE_MAGICK
1042         }
1043       }
1044 
1045       if (strncasecmp(line, "TRANSPARENT", 11) == 0)
1046       {
1047         // need to make this read a list of colors to zap
1048         // out.  Use 32-bit unsigned values, so we can
1049         // handle 32-bit color displays.
1050         if (1 != sscanf (line + 12, "%lx", &temp_trans_color))
1051         {
1052           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1053         }
1054 
1055         {
1056           unsigned short r,g,b;
1057           // We'll assume the temp_trans_color has been
1058           // specified as a 24-bit quantity
1059           r = (temp_trans_color&0xff0000) >> 16;
1060           g = (temp_trans_color&0x00ff00)>>8;
1061           b = temp_trans_color&0x0000ff;
1062           // Now this is an incredible kludge, but seems to be right
1063           // Apparently, if QuantumDepth is 16 bits, r, g, and b
1064           // values are duplicated in the high and low byte, which
1065           // is just bizarre
1066 #ifdef HAVE_MAGICK
1067           if (QuantumDepth == 16)
1068           {
1069             r=r|(r<<8);
1070             g=g|(g<<8);
1071             b=b|(b<<8);
1072           }
1073 #endif  // HAVE_MAGICK
1074           //fprintf(stderr,"Original Transparent %lx\n",temp_trans_color);
1075           //fprintf(stderr,"Transparent r,g,b=%x,%x,%x\n",r,g,b);
1076           if (visual_type == NOT_TRUE_NOR_DIRECT)
1077           {
1078             XColor junk;
1079 
1080 #ifdef HAVE_MAGICK
1081             if (QuantumDepth == 16)
1082             {
1083               junk.red=r;
1084               junk.green=g;
1085               junk.blue=b;
1086             }
1087             else
1088 #endif  // HAVE_MAGICK
1089             {
1090               junk.red= r<<8;
1091               junk.green = g<<8;
1092               junk.blue = b<<8;
1093             }
1094             XAllocColor(XtDisplay(w),cmap,&junk);
1095             temp_trans_color = junk.pixel;
1096           }
1097           else
1098           {
1099             pack_pixel_bits(r,g,b,&temp_trans_color);
1100           }
1101           //fprintf(stderr,"Packed Transparent %lx\n",temp_trans_color);
1102         }
1103 
1104         //fprintf(stderr,"New Transparent: %lx\n",temp_trans_color);
1105 
1106         // Link color to transparent color list
1107         new_trans_color(temp_trans_color);
1108       }
1109       if (strncasecmp(line, "CROP", 4) == 0)
1110       {
1111         if (4 != sscanf (line + 5, "%d %d %d %d",
1112                          &crop_x1,
1113                          &crop_y1,
1114                          &crop_x2,
1115                          &crop_y2 ))
1116         {
1117           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1118         }
1119         if (crop_x1 < 0 )
1120         {
1121           crop_x1 = 0;
1122         }
1123         if (crop_y1 < 0 )
1124         {
1125           crop_y1 = 0;
1126         }
1127         if (crop_x2 < 0 )
1128         {
1129           crop_x2 = 0;
1130         }
1131         if (crop_y2 < 0 )
1132         {
1133           crop_y2 = 0;
1134         }
1135         if (crop_x2 < crop_x1 )
1136         {
1137           // swap
1138           do_crop = crop_x1;
1139           crop_x1=crop_x2;
1140           crop_x2=do_crop;
1141         }
1142         if (crop_y2 < crop_y1 )
1143         {
1144           // swap
1145           do_crop = crop_y1;
1146           crop_y1=crop_y2;
1147           crop_y2=do_crop;
1148         }
1149         do_crop = 1;
1150       }
1151 #ifdef HAVE_MAGICK
1152       if (strncasecmp(line, "GAMMA", 5) == 0)
1153         imagemagick_options.gamma_flag = sscanf(line + 6, "%f,%f,%f",
1154                                                 &imagemagick_options.r_gamma,
1155                                                 &imagemagick_options.g_gamma,
1156                                                 &imagemagick_options.b_gamma);
1157       if (strncasecmp(line, "CONTRAST", 8) == 0)
1158       {
1159         if (1 != sscanf(line + 9, "%d", &imagemagick_options.contrast))
1160         {
1161           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1162         }
1163       }
1164       if (strncasecmp(line, "NEGATE", 6) == 0)
1165       {
1166         if (1 != sscanf(line + 7, "%d", &imagemagick_options.negate))
1167         {
1168           fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1169         }
1170       }
1171       if (strncasecmp(line, "EQUALIZE", 8) == 0)
1172       {
1173         imagemagick_options.equalize = 1;
1174       }
1175       if (strncasecmp(line, "NORMALIZE", 9) == 0)
1176       {
1177         imagemagick_options.normalize = 1;
1178       }
1179 #if (MagickLibVersion >= 0x0539)
1180       if (strncasecmp(line, "LEVEL", 5) == 0)
1181       {
1182         xastir_snprintf(imagemagick_options.level,
1183                         sizeof(imagemagick_options.level),
1184                         "%s",
1185                         line+6);
1186       }
1187 #endif  // MagickLibVersion >= 0x0539
1188       if (strncasecmp(line, "MODULATE", 8) == 0)
1189       {
1190         xastir_snprintf(imagemagick_options.modulate,
1191                         sizeof(imagemagick_options.modulate),
1192                         "%s",
1193                         line+9);
1194       }
1195 #endif  // HAVE_MAGICK
1196     }
1197     (void)fclose (f);
1198   }
1199   else
1200   {
1201     fprintf(stderr,"Couldn't open file: %s\n", file);
1202     return;
1203   }
1204 
1205   //
1206   // Check whether OpenStreetMap has been selected.  If so, run off to
1207   // another routine to service this request.
1208   //
1209   if (OSMserver_flag == 1)
1210   {
1211 
1212 #ifdef HAVE_MAGICK
1213 
1214     // We need to send the "nocache" parameter to this function
1215     // for those instances when the received map is bad.
1216     // Later the GUI can implement a method for refreshing the
1217     // latest map and replacing the bad map in the cache.
1218     //
1219     // fileimg is the server URL, if specified.
1220     draw_OSM_map(w, filenm, destination_pixmap, fileimg, OSMstyle, nocache);
1221 
1222 #endif  // HAVE_MAGICK
1223 
1224     return;
1225   }
1226   else if (OSMserver_flag == 2)
1227   {
1228 #ifdef HAVE_MAGICK
1229 
1230     // fileimg is the server URL, if specified.
1231     draw_OSM_tiles(w, filenm, destination_pixmap, fileimg, tileCache, OSMstyle, OSMtileExt);
1232 
1233 #endif  // HAVE_MAGICK
1234 
1235     return;
1236   }
1237 
1238 
1239 
1240   // Check whether a WMS server has been selected.  If so, run off
1241   // to another routine to service this request.
1242   //
1243   if (WMSserver_flag)
1244   {
1245 
1246 #ifdef HAVE_MAGICK
1247     // Pass the URL in "fileimg"
1248     draw_WMS_map(w,
1249                  filenm,
1250                  destination_pixmap,
1251                  fileimg,
1252                  trans_color_head,
1253                  nocache); // Don't use cached version if non-zero
1254 
1255 #endif  // HAVE_MAGICK
1256 
1257     return;
1258   }
1259 
1260 
1261   if (toporama_flag)
1262   {
1263 
1264 #ifdef HAVE_MAGICK
1265     // Pass all of the parameters to it.  We'll need to use them
1266     // to call draw_geo_image_map() again shortly, after we
1267     // fetch the remote .geo file.
1268     //
1269     draw_toporama_map(w,
1270                       dir,
1271                       filenm,
1272                       alert,
1273                       alert_color,
1274                       destination_pixmap,
1275                       mdf,
1276                       toporama_flag);
1277 #endif  // HAVE_MAGICK
1278 
1279     return;
1280   }
1281 
1282 
1283 
1284   // DK7IN: I'm experimenting with the adjustment of topo maps with
1285   // Transverse Mercator projection. Those maps have equal scaling
1286   // in distance while we use equal scaling in degrees.
1287 
1288   // For now I use the map center as central meridian (I think that
1289   // is ok for mapblast), that will change with UTM and Gauss-Krueger
1290 
1291   // I have introduced new entries in the geo file for that...
1292   // I first adjust the x scaling depending on the latitude
1293   // Then I move points in y direction depending on the offset from
1294   // the central meridian. I hope I get that right with those
1295   // approximations. I have the correct formulas, but that will
1296   // be very computing intensive and result in slow map loading...
1297 
1298   //    if (geo_datum[0] != '\0')
1299   //        fprintf(stderr,"Map Datum: %s\n",geo_datum);   // not used now...
1300 
1301   if (geo_projection[0] == '\0')
1302     // default
1303     xastir_snprintf(geo_projection,
1304                     sizeof(geo_projection),
1305                     "LatLon");
1306   //fprintf(stderr,"Map Projection: %s\n",geo_projection);
1307   //    (void)to_upper(geo_projection);
1308   if (strcasecmp(geo_projection,"TM") == 0)
1309   {
1310     map_proj = 1;  // Transverse Mercator
1311   }
1312   else
1313   {
1314     map_proj = 0;  // Lat/Lon, default
1315   }
1316 
1317 #ifdef HAVE_MAGICK
1318   if (terraserver_flag)
1319   {
1320     //http://terraservice.net/download.ashx?t=1&s=10&x=2742&y=26372&z=10&w=820&h=480
1321     if (scale_y <= 4)
1322     {
1323       t_zoom  = 10; // 1m/pixel
1324       t_scale = 200;
1325     }
1326     else if (scale_y <= 8)
1327     {
1328       t_zoom  = 11; // 2m/pixel
1329       t_scale = 400;
1330     }
1331     else if (scale_y <= 16)
1332     {
1333       t_zoom  = 12; // 4m/pixel
1334       t_scale = 800;
1335     }
1336     else if (scale_y <= 32)
1337     {
1338       t_zoom  = 13; // 8m/pixel
1339       t_scale = 1600;
1340     }
1341     else if (scale_y <= 64)
1342     {
1343       t_zoom  = 14; // 16m/pixel
1344       t_scale = 3200;
1345     }
1346     else if (scale_y <= 128)
1347     {
1348       t_zoom  = 15; // 32m/pixel
1349       t_scale = 6400;
1350     }
1351     else
1352     {
1353       t_zoom  = 16; // 64m/pixel
1354       t_scale = 12800;
1355     }
1356 
1357     top  = -((NW_corner_latitude - 32400000l) / 360000.0);
1358     left =  (NW_corner_longitude - 64800000l) / 360000.0;
1359     ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid,
1360                   top,
1361                   left,
1362                   &top_n,
1363                   &left_e,
1364                   zstr0,
1365                   sizeof(zstr0) );
1366     if (1 != sscanf(zstr0, "%d", &z))
1367     {
1368       fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n");
1369     }
1370 
1371     bottom = -((SE_corner_latitude - 32400000l) / 360000.0);
1372     right  =   (SE_corner_longitude - 64800000l) / 360000.0;
1373 
1374     ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid,
1375                   bottom,
1376                   right,
1377                   &bottom_n,
1378                   &right_e,
1379                   zstr1,
1380                   sizeof(zstr1) );
1381 
1382 
1383     //
1384     // NOTE:
1385     // POSSIBLE FUTURE ENHANCEMENT:
1386     // If zstr0 != zstr1, we have a viewscreen that crosses a UTM zone
1387     // boundary.  Terraserver/Toposerver will only feed us a map for one
1388     // side of it or the other.  It'd be VERY nice if some day we could
1389     // check for this condition and do two map loads instead of the one.
1390     // We'd need to stop drawing right at the boundary for each map
1391     // also, so that they'd tile together nicely.
1392     //
1393 
1394 
1395     map_top_n  = (int)((top_n  / t_scale) + 1) * t_scale;
1396     map_left_e = (int)((left_e / t_scale) + 0) * t_scale;
1397     utm_ups_to_ll(gDatum[D_NAD_83_CONUS].ellipsoid,
1398                   map_top_n,
1399                   map_left_e,
1400                   zstr0,
1401                   &top,
1402                   &left);
1403 
1404 
1405     // Below here things can get messed up.  We can end up with very
1406     // large and/or negative values for geo_image_width and/or
1407     // geo_image_height.  Usually happens around UTM zone boundaries.
1408     //
1409     // Terraserver uses UTM coordinates for specifying the maps instead
1410     // of lat/long.  Note that we're also not supposed to cross UTM
1411     // zones in our requests.
1412     //
1413     // t = 1 - 4, theme.  1=DOQ (aerial photo)
1414     //                    2=DRG (topo)
1415     //                    3=shaded relief
1416     //                    4=Color photos/Urban areas
1417     // s = 10 - 16, scale.  10=1 meter/pixel.  11=2 meters/pixel.
1418     // x = UTM easting, center of image
1419     // y = UTM northing, center of image
1420     // z = 1 - 60, UTM zone, center of image
1421     // w = 50 - 2000, width in pixels
1422     // h = 50 - 2000, height in pixels
1423     // logo = 0/1, USGS logo in image if 1
1424     //
1425 
1426     // This number gets messed up if we cross zones.  UTM lines
1427     // are slanted, so we _can_ cross zones vertically!
1428     geo_image_height = abs( (((int)map_top_n - (int)bottom_n) * 200 / t_scale) );
1429 
1430     // This number gets messed up if we cross zones
1431     geo_image_width  = abs( (((int)right_e - (int)map_left_e) * 200 / t_scale) );
1432 
1433 
1434     //fprintf(stderr,"\ngeo_image_height:%d\tmap_top_n:%0.1f\tbottom_n:%0.1f\tt_scale:%d\n",
1435     //geo_image_height,
1436     //map_top_n,
1437     //bottom_n,
1438     //t_scale);
1439     // map_top_n is the one that goes whacko, throwing off the height.
1440     // Check whether this is because we're crossing a UTM zone.  We
1441     // _can_ cross zones vertically because the UTM lines are slanted.
1442 
1443     //fprintf(stderr,"geo_image_width:%d\tright_e:%0.1f\tmap_left_e:%0.1f\tt_scale:%d\n",
1444     //geo_image_width,
1445     //right_e,
1446     //map_left_e,
1447     //t_scale);
1448     // right_e is the one that goes whacko, throwing off the width.
1449     // Check whether this is because we're crossing a UTM zone.
1450 
1451 
1452     if (geo_image_height < 50)
1453     {
1454       geo_image_height = 50;
1455     }
1456 
1457     if (geo_image_width < 50)
1458     {
1459       geo_image_width = 50;
1460     }
1461 
1462     if (geo_image_height > 2000)
1463     {
1464       geo_image_height = geo_image_width;
1465     }
1466 
1467     if (geo_image_width > 2000)
1468     {
1469       geo_image_width = geo_image_height;
1470     }
1471 
1472     if (geo_image_height > 2000)
1473     {
1474       geo_image_height = geo_image_width;
1475     }
1476     if (geo_image_width > 2000)
1477     {
1478       geo_image_width = geo_image_height;
1479     }
1480 
1481 
1482     //        map_width  = right - left;
1483     //        map_height = top - bottom;
1484 
1485     tp[0].img_x = 0;
1486     tp[0].img_y = 0;
1487     tp[0].x_long = 64800000l + (360000.0 * left);
1488     tp[0].y_lat  = 32400000l + (360000.0 * (-top));
1489 
1490     tp[1].img_x = geo_image_width  - 1;
1491     tp[1].img_y = geo_image_height - 1;
1492     tp[1].x_long = 64800000l + (360000.0 * right);
1493     tp[1].y_lat  = 32400000l + (360000.0 * (-bottom));
1494 
1495     url_n = (int)(top_n  / t_scale); // The request URL does not use the
1496     url_e = (int)(left_e / t_scale); // N/E of the map corner
1497 
1498 
1499     xastir_snprintf(fileimg, sizeof(fileimg),
1500                     "http://terraservice.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d",
1501                     //            "http://terraserver-usa.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d",
1502                     terraserver_flag,   // 1, 2, 3, or 4
1503                     t_zoom,
1504                     url_e,  // easting, center of map
1505                     url_n,  // northing, center of map
1506                     z,
1507                     geo_image_width,
1508                     geo_image_height);
1509     //http://terraservice.net/download.ashx?t=1&s=11&x=1384&y=13274&z=10&w=1215&h=560
1510     //fprintf(stderr,"%s\n",fileimg);
1511 
1512     if (debug_level & 16)
1513     {
1514       fprintf(stderr,"URL: %s\n", fileimg);
1515     }
1516   }
1517 #endif // HAVE_MAGICK
1518 
1519   //
1520   // DK7IN: we should check what we got from the geo file
1521   //   we use geo_image_width, but it might not be initialised...
1522   //   and it's wrong if the '\n' is missing at the end...
1523 
1524   /*
1525    * Here are the corners of our viewport, using the Xastir
1526    * coordinate system.  Notice that Y is upside down:
1527    *
1528    *   left edge of view = NW_corner_longitude
1529    *  right edge of view = SE_corner_longitude
1530    *    top edge of view =  NW_corner_latitude
1531    * bottom edge of view =  SE_corner_latitude
1532    *
1533    * The corners of our map will soon be (after translating the
1534    * tiepoints to the corners if they're not already there):
1535    *
1536    *   left edge of map = tp[0].x_long   in Xastir format
1537    *  right edge of map = tp[1].x_long
1538    *    top edge of map = tp[0].y_lat
1539    * bottom edge of map = tp[1].y_lat
1540    *
1541    */
1542   map_c_L = tp[0].x_long - NW_corner_longitude;     // map left coordinate
1543   map_c_T = tp[0].y_lat  - NW_corner_latitude;      // map top  coordinate
1544 
1545   tp_c_dx = (long)(tp[1].x_long - tp[0].x_long);//  Width between tiepoints
1546   tp_c_dy = (long)(tp[1].y_lat  - tp[0].y_lat); // Height between tiepoints
1547 
1548 
1549   // Check for tiepoints being in wrong relation to one another
1550   if (tp_c_dx < 0)
1551   {
1552     tp_c_dx = -tp_c_dx;  // New  width between tiepoints
1553   }
1554   if (tp_c_dy < 0)
1555   {
1556     tp_c_dy = -tp_c_dy;  // New height between tiepoints
1557   }
1558 
1559 
1560   if (debug_level & 512)
1561   {
1562     fprintf(stderr,"X tiepoint width: %ld\n", tp_c_dx);
1563     fprintf(stderr,"Y tiepoint width: %ld\n", tp_c_dy);
1564   }
1565 
1566   // Calculate step size per pixel
1567   map_c_dx = ((double) tp_c_dx / abs(tp[1].img_x - tp[0].img_x));
1568   map_c_dy = ((double) tp_c_dy / abs(tp[1].img_y - tp[0].img_y));
1569 
1570   // Scaled screen step size for use with XFillRectangle below
1571   scr_dx = (int) (map_c_dx / scale_x) + 1;
1572   scr_dy = (int) (map_c_dy / scale_y) + 1;
1573 
1574   if (debug_level & 512)
1575   {
1576     fprintf(stderr,"\nImage: %s\n", file);
1577     fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height);
1578     fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y));
1579   }
1580 
1581   // calculate top left map corner from tiepoints
1582   if (tp[0].img_x != 0)
1583   {
1584     tp[0].x_long -= (tp[0].img_x * map_c_dx);   // map left edge longitude
1585     map_c_L = tp[0].x_long - NW_corner_longitude;     // delta ??
1586     tp[0].img_x = 0;
1587     if (debug_level & 512)
1588     {
1589       fprintf(stderr,"Translated tiepoint_0 x: %d\t%lu\n", tp[0].img_x, tp[0].x_long);
1590     }
1591   }
1592   if (tp[0].img_y != 0)
1593   {
1594     tp[0].y_lat -= (tp[0].img_y * map_c_dy);    // map top edge latitude
1595     map_c_T = tp[0].y_lat - NW_corner_latitude;
1596     tp[0].img_y = 0;
1597     if (debug_level & 512)
1598     {
1599       fprintf(stderr,"Translated tiepoint_0 y: %d\t%lu\n", tp[0].img_y, tp[0].y_lat);
1600     }
1601   }
1602 
1603   // By this point, geo_image_width & geo_image_height have to
1604   // have been initialized to something.
1605 
1606   if ( (geo_image_width == 0) || (geo_image_height == 0) )
1607   {
1608 
1609     if ( (strncasecmp ("http", fileimg, 4) == 0)
1610          || (strncasecmp ("ftp", fileimg, 3) == 0))
1611     {
1612       // what to do for remote files... hmm... -cbell
1613     }
1614     else
1615     {
1616 
1617 #ifdef HAVE_MAGICK
1618       GetExceptionInfo(&exception);
1619       image_info=CloneImageInfo((ImageInfo *) NULL);
1620       xastir_snprintf(image_info->filename,
1621                       sizeof(image_info->filename),
1622                       "%s",
1623                       fileimg);
1624       if (debug_level & 16)
1625       {
1626         fprintf(stderr,"Copied %s into image info.\n", file);
1627         fprintf(stderr,"image_info got: %s\n", image_info->filename);
1628         fprintf(stderr,"Entered ImageMagick code.\n");
1629         fprintf(stderr,"Attempting to open: %s\n", image_info->filename);
1630       }
1631 
1632       // We do a test read first to see if the file exists, so we
1633       // don't kill Xastir in the ReadImage routine.
1634       f = fopen (image_info->filename, "r");
1635       if (f == NULL)
1636       {
1637         fprintf(stderr,"1 ");
1638         fprintf(stderr,"File %s could not be read\n",image_info->filename);
1639 
1640 #ifdef USE_MAP_CACHE
1641         // clear from cache if bad
1642         if (map_cache_del(fileimg))
1643         {
1644           if (debug_level & 512)
1645           {
1646             fprintf(stderr,"Couldn't delete map from cache\n");
1647           }
1648         }
1649 #endif
1650         if (image_info)
1651         {
1652           DestroyImageInfo(image_info);
1653         }
1654         DestroyExceptionInfo(&exception);
1655         return;
1656       }
1657       (void)fclose (f);
1658 
1659       image = PingImage(image_info, &exception);
1660 
1661       if (image == (Image *) NULL)
1662       {
1663         MagickWarning(exception.severity, exception.reason, exception.description);
1664         //fprintf(stderr,"MagickWarning\n");
1665 
1666 #ifdef USE_MAP_CACHE
1667         // clear from cache if bad
1668         if (map_cache_del(fileimg))
1669         {
1670           if (debug_level & 512)
1671           {
1672             fprintf(stderr,"Couldn't delete map from cache\n");
1673           }
1674         }
1675 #endif
1676 
1677         if (image_info)
1678         {
1679           DestroyImageInfo(image_info);
1680         }
1681         DestroyExceptionInfo(&exception);
1682         return;
1683       }
1684 
1685       if (debug_level & 16)
1686       {
1687         fprintf(stderr,"Color depth is %i \n", (int)image->depth);
1688       }
1689 
1690       geo_image_width = image->magick_columns;
1691       geo_image_height = image->magick_rows;
1692 
1693       // close and clean up imagemagick
1694 
1695       if (image)
1696       {
1697         DestroyImage(image);
1698       }
1699       if (image_info)
1700       {
1701         DestroyImageInfo(image_info);
1702       }
1703       DestroyExceptionInfo(&exception);
1704 #endif // HAVE_MAGICK
1705     }
1706   }
1707 
1708   //    fprintf(stderr, "Geo: %s: size %ux%u.\n",file, geo_image_width, geo_image_height);
1709   // if that did not generate a valid size, bail out...
1710   if ( (geo_image_width == 0) || (geo_image_height == 0) )
1711   {
1712     fprintf(stderr,"*** Skipping '%s', IMAGESIZE tag missing or incorrect. ***\n",file);
1713     fprintf(stderr,"Perhaps no XPM/ImageMagick/GraphicsMagick library support is installed?\n");
1714     return;
1715   }
1716   // calculate bottom right map corner from tiepoints
1717   // map size is geo_image_width / geo_image_height
1718   if (tp[1].img_x != (geo_image_width - 1) )
1719   {
1720     tp[1].img_x = geo_image_width - 1;
1721     tp[1].x_long = tp[0].x_long + (tp[1].img_x * map_c_dx); // right
1722     if (debug_level & 512)
1723     {
1724       fprintf(stderr,"Translated tiepoint_1 x: %d\t%lu\n", tp[1].img_x, tp[1].x_long);
1725     }
1726   }
1727   if (tp[1].img_y != (geo_image_height - 1) )
1728   {
1729     tp[1].img_y = geo_image_height - 1;
1730     tp[1].y_lat = tp[0].y_lat + (tp[1].img_y * map_c_dy);   // bottom
1731     if (debug_level & 512)
1732     {
1733       fprintf(stderr,"Translated tiepoint_1 y: %d\t%lu\n", tp[1].img_y, tp[1].y_lat);
1734     }
1735   }
1736 
1737 
1738   // Check whether we're indexing or drawing the map
1739   if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS)
1740        || (destination_pixmap == INDEX_NO_TIMESTAMPS) )
1741   {
1742 
1743     // We're indexing only.  Save the extents in the index.
1744     if (terraserver_flag)
1745     {
1746       // Force the extents to the edges of the earth for the
1747       // index file.
1748       index_update_xastir(filenm, // Filename only
1749                           64800000l,      // Bottom
1750                           0l,             // Top
1751                           0l,             // Left
1752                           129600000l,     // Right
1753                           0);             // Default Map Level
1754     }
1755     else
1756     {
1757       index_update_xastir(filenm, // Filename only
1758                           tp[1].y_lat,    // Bottom
1759                           tp[0].y_lat,    // Top
1760                           tp[0].x_long,   // Left
1761                           tp[1].x_long,   // Right
1762                           0);             // Default Map Level
1763     }
1764 
1765     // Update statusline
1766     xastir_snprintf(map_it,
1767                     sizeof(map_it),
1768                     langcode ("BBARSTA039"),
1769                     short_filenm);
1770     statusline(map_it,0);       // Loading/Indexing ...
1771 
1772     return; // Done indexing this file
1773   }
1774 
1775   HandlePendingEvents(app_context);
1776   if (interrupt_drawing_now)
1777   {
1778     // Update to screen
1779     (void)XCopyArea(XtDisplay(da),
1780                     pixmap,
1781                     XtWindow(da),
1782                     gc,
1783                     0,
1784                     0,
1785                     (unsigned int)screen_width,
1786                     (unsigned int)screen_height,
1787                     0,
1788                     0);
1789     return;
1790   }
1791 
1792   // Check whether map is inside our current view
1793   //                bottom        top    left        right
1794   if (!map_visible (tp[1].y_lat, tp[0].y_lat, tp[0].x_long, tp[1].x_long))
1795   {
1796     if (debug_level & 16)
1797     {
1798       fprintf(stderr,"Map not in current view, skipping: %s\n", file);
1799       fprintf(stderr,"\nImage: %s\n", file);
1800       fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height);
1801       fprintf(stderr,"   Map:  lat0:%ld\t lon0:%ld\t lat1:%ld\t lon1:%ld\n",
1802               tp[0].y_lat,
1803               tp[0].x_long,
1804               tp[1].y_lat,
1805               tp[1].x_long);
1806       fprintf(stderr,"Screen: NWlat:%ld\tNWlon:%ld\tSElat:%ld\tSElon:%ld\n",
1807               NW_corner_latitude,
1808               NW_corner_longitude,
1809               SE_corner_latitude,
1810               SE_corner_longitude);
1811       fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y));
1812     }
1813     return;            // Skip this map
1814 #ifdef FUZZYRASTER
1815   }
1816   else if (((float)(map_c_dx/scale_x) > rasterfuzz) ||
1817            ((float)(scale_x/map_c_dx) > rasterfuzz) ||
1818            ((float)(map_c_dy/scale_y) > rasterfuzz) ||
1819            ((float)(scale_y/map_c_dy) > rasterfuzz))
1820   {
1821     fprintf(stderr,"Skipping fuzzy map %s with sx=%f,sy=%f.\n", file,
1822             (float)(map_c_dx/scale_x),(float)(map_c_dy/scale_y));
1823     return;
1824 #endif //FUZZYRASTER
1825   }
1826   else if (debug_level & 16)
1827   {
1828     fprintf(stderr,"Loading imagemap: %s\n", file);
1829     fprintf(stderr,"\nImage: %s\n", file);
1830     fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height);
1831     fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y));
1832   }
1833 
1834   // Update statusline
1835   xastir_snprintf(map_it,
1836                   sizeof(map_it),
1837                   langcode ("BBARSTA028"),
1838                   short_filenm);
1839   statusline(map_it,0);       // Loading/Indexing ...
1840 
1841 #ifndef NO_XPM
1842   atb.valuemask = 0;
1843 #endif  // NO_XPM
1844 
1845   HandlePendingEvents(app_context);
1846   if (interrupt_drawing_now)
1847   {
1848     // Update to screen
1849     (void)XCopyArea(XtDisplay(da),
1850                     pixmap,
1851                     XtWindow(da),
1852                     gc,
1853                     0,
1854                     0,
1855                     (unsigned int)screen_width,
1856                     (unsigned int)screen_height,
1857                     0,
1858                     0);
1859     return;
1860   }
1861 
1862   // Best here would be to add the process ID or user ID to the filename
1863   // (to keep the filename distinct for different users), and to check
1864   // the timestamp on the map file.  If it's older than xx minutes, go
1865   // get another one.  Make sure to delete the temp files when closing
1866   // Xastir.  It'd probably be good to check for old files and delete
1867   // them when starting Xastir as well.
1868 
1869   // Check to see if we have to use "wget" to go get an internet map
1870   if ( (strncasecmp ("http", fileimg, 4) == 0)
1871        || (strncasecmp ("ftp", fileimg, 3) == 0)
1872        || (terraserver_flag) )
1873   {
1874 #ifdef HAVE_MAGICK
1875     char *ext;
1876 
1877     if (debug_level & 16)
1878     {
1879       fprintf(stderr,"ftp or http file: %s\n", fileimg);
1880     }
1881 
1882     if (terraserver_flag)
1883     {
1884       ext = "jpg";
1885     }
1886     else
1887     {
1888       ext = get_map_ext(fileimg);  // Use extension to determine image type
1889     }
1890 
1891     if (debug_level & 512)
1892     {
1893       query_start_time=time(&query_start_time);
1894     }
1895 
1896 #ifdef USE_MAP_CACHE
1897 
1898     if (nocache || map_cache_fetch_disable)
1899     {
1900 
1901       // Delete old copy from the cache
1902       if (map_cache_fetch_disable && fileimg[0] != '\0')
1903       {
1904         if (map_cache_del(fileimg))
1905         {
1906           if (debug_level & 512)
1907           {
1908             fprintf(stderr,"Couldn't delete old map from cache\n");
1909           }
1910         }
1911       }
1912 
1913       // Simulate a cache miss
1914       map_cache_return = 1;
1915     }
1916     else
1917     {
1918       // Look for the file in the cache
1919       map_cache_return = map_cache_get(fileimg,local_filename);
1920     }
1921 
1922     if (debug_level & 512)
1923     {
1924       fprintf(stderr,"map_cache_return: %d\n", map_cache_return);
1925     }
1926 
1927     // If nocache is non-zero, we're supposed to refresh the map
1928     // at intervals.  Don't use a cached version of the map in
1929     // that case.
1930     //
1931     if (nocache || map_cache_return != 0 )
1932     {
1933 
1934       // Caching not requested or cached file not found.  We
1935       // must snag the remote file via libcurl or wget.
1936 
1937       if (nocache)
1938       {
1939         xastir_snprintf(local_filename,
1940                         sizeof(local_filename),
1941                         "%s/map.%s",
1942                         get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext);
1943       }
1944       else
1945       {
1946         cache_file_id = map_cache_fileid();
1947         xastir_snprintf(local_filename,
1948                         sizeof(local_filename),
1949                         "%s/map_%s.%s",
1950                         get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)),
1951                         cache_file_id,
1952                         ext);
1953         free(cache_file_id);
1954       }
1955 
1956 #else   // USE_MAP_CACHE
1957 
1958     xastir_snprintf(local_filename,
1959                     sizeof(local_filename),
1960                     "%s/map.%s",
1961                     get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext);
1962 
1963 #endif  // USE_MAP_CACHE
1964 
1965 
1966       // Erase any previously existing local file by the same
1967       // name.  This avoids the problem of having an old map image
1968       // here and the code trying to display it when the download
1969       // fails.
1970       unlink( local_filename );
1971 
1972       if (fetch_remote_file(fileimg, local_filename))
1973       {
1974         // Had trouble getting the file.  Abort.
1975         return;
1976       }
1977 
1978 #ifdef USE_MAP_CACHE
1979 
1980       // Cache the map only if map_refresh_interval_temp is zero
1981       if (!map_refresh_interval_temp)
1982       {
1983         map_cache_put(fileimg,local_filename);
1984       }
1985 
1986     } // end if is cached
1987 #endif // MAP_CACHE
1988 
1989     if (debug_level & 512)
1990     {
1991       fprintf (stderr, "Fetch or query took %d seconds\n",
1992                (int) (time(&query_end_time) - query_start_time));
1993     }
1994 
1995     // Set permissions on the file so that any user can overwrite it.
1996     chmod(local_filename, 0666);
1997 
1998     // We now re-use the "file" variable.  It'll hold the
1999     //name of the map file now instead of the .geo file.
2000     // Tell ImageMagick where to find it
2001     xastir_snprintf(file, sizeof(file), "%s", local_filename);
2002 #endif  // HAVE_MAGICK
2003 
2004   }
2005   else
2006   {
2007     //fprintf(stderr,"Not ftp or http file\n");
2008 
2009     // We now re-use the "file" variable.  It'll hold the
2010     //name of the map file now instead of the .geo file.
2011     xastir_snprintf(file, sizeof(file), "%s", fileimg);
2012   }
2013 
2014   //fprintf(stderr,"File = %s\n",file);
2015 
2016   HandlePendingEvents(app_context);
2017   if (interrupt_drawing_now)
2018   {
2019     // Update to screen
2020     (void)XCopyArea(XtDisplay(da),
2021                     pixmap,
2022                     XtWindow(da),
2023                     gc,
2024                     0,
2025                     0,
2026                     (unsigned int)screen_width,
2027                     (unsigned int)screen_height,
2028                     0,
2029                     0);
2030     return;
2031   }
2032 
2033   // The status line is not updated yet, probably 'cuz we're too busy
2034   // getting the map in this thread and aren't redrawing?
2035 
2036 #ifdef HAVE_MAGICK
2037   GetExceptionInfo(&exception);
2038   image_info=CloneImageInfo((ImageInfo *) NULL);
2039   xastir_snprintf(image_info->filename,
2040                   sizeof(image_info->filename),
2041                   "%s",
2042                   file);
2043   if (debug_level & 16)
2044   {
2045     fprintf(stderr,"Copied %s into image info.\n", file);
2046     fprintf(stderr,"image_info got: %s\n", image_info->filename);
2047     fprintf(stderr,"Entered ImageMagick code.\n");
2048     fprintf(stderr,"Attempting to open: %s\n", image_info->filename);
2049   }
2050 
2051   // We do a test read first to see if the file exists, so we
2052   // don't kill Xastir in the ReadImage routine.
2053   f = fopen (image_info->filename, "r");
2054   if (f == NULL)
2055   {
2056     fprintf(stderr,"2 ");
2057     fprintf(stderr,"File %s could not be read\n",image_info->filename);
2058     if (image_info)
2059     {
2060       DestroyImageInfo(image_info);
2061     }
2062     DestroyExceptionInfo(&exception);
2063     return;
2064   }
2065   (void)fclose (f);
2066 
2067   HandlePendingEvents(app_context);
2068   if (interrupt_drawing_now)
2069   {
2070     // Update to screen
2071     (void)XCopyArea(XtDisplay(da),
2072                     pixmap,
2073                     XtWindow(da),
2074                     gc,
2075                     0,
2076                     0,
2077                     (unsigned int)screen_width,
2078                     (unsigned int)screen_height,
2079                     0,
2080                     0);
2081     if (image_info)
2082     {
2083       DestroyImageInfo(image_info);
2084     }
2085     DestroyExceptionInfo(&exception);
2086     return;
2087   }
2088 
2089   image = ReadImage(image_info, &exception);
2090 
2091   if (image == (Image *) NULL)
2092   {
2093     MagickWarning(exception.severity, exception.reason, exception.description);
2094     //fprintf(stderr,"MagickWarning\n");
2095     if (image_info)
2096     {
2097       DestroyImageInfo(image_info);
2098     }
2099     DestroyExceptionInfo(&exception);
2100     return;
2101   }
2102 
2103   if (debug_level & 16)
2104   {
2105     fprintf(stderr,"Color depth is %i \n", (int)image->depth);
2106   }
2107 
2108   /*
2109     if (image->colorspace != RGBColorspace) {
2110     fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB");
2111     if (image)
2112     DestroyImage(image);
2113     if (image_info)
2114     DestroyImageInfo(image_info);
2115     DestroyExceptionInfo(&exception);
2116     return;
2117     }
2118   */
2119 
2120   width = image->columns;
2121   height = image->rows;
2122 
2123   if (check_interrupt(image, image_info,
2124                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2125   {
2126     return;
2127   }
2128 
2129   // gamma setup
2130   if (imagemagick_options.gamma_flag == 0 ||
2131       imagemagick_options.gamma_flag == 1)
2132   {
2133     if (imagemagick_options.gamma_flag == 0) // if not set in file, set to 1.0
2134     {
2135       imagemagick_options.r_gamma = 1.0;
2136     }
2137 
2138     imagemagick_options.gamma_flag = 1; // set flag to do gamma
2139 
2140     imagemagick_options.r_gamma += imagemagick_gamma_adjust;
2141 
2142     if (imagemagick_options.r_gamma > 0.95 && imagemagick_options.r_gamma < 1.05)
2143     {
2144       imagemagick_options.gamma_flag = 0;  // don't bother if near 1.0
2145     }
2146     else if (imagemagick_options.r_gamma < 0.1)
2147     {
2148       imagemagick_options.r_gamma = 0.1;  // 0.0 is black and negative is really wacky
2149     }
2150 
2151     xastir_snprintf(gamma, sizeof(gamma), "%.1f", imagemagick_options.r_gamma);
2152   }
2153   else if (imagemagick_options.gamma_flag == 3)
2154   {
2155     // No checking if you specify 3 channel gamma correction, so you can try negative
2156     // numbers, etc. if you wish.
2157     imagemagick_options.gamma_flag = 1; // set flag to do gamma
2158     imagemagick_options.r_gamma += imagemagick_gamma_adjust;
2159     imagemagick_options.g_gamma += imagemagick_gamma_adjust;
2160     imagemagick_options.b_gamma += imagemagick_gamma_adjust;
2161     xastir_snprintf(gamma, sizeof(gamma), "%.1f,%.1f,%.1f",
2162                     imagemagick_options.r_gamma,
2163                     imagemagick_options.g_gamma,
2164                     imagemagick_options.b_gamma);
2165   }
2166   else
2167   {
2168     imagemagick_options.gamma_flag = 0;
2169   }
2170 
2171   if (check_interrupt(image, image_info,
2172                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2173   {
2174     return;
2175   }
2176 
2177   if (imagemagick_options.gamma_flag)
2178   {
2179     if (debug_level & 16)
2180     {
2181       fprintf(stderr,"gamma=%s\n", gamma);
2182     }
2183     GammaImage(image, gamma);
2184   }
2185 
2186   if (check_interrupt(image, image_info,
2187                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2188   {
2189     return;
2190   }
2191 
2192   if (imagemagick_options.contrast != 0)
2193   {
2194     if (debug_level & 16)
2195     {
2196       fprintf(stderr,"contrast=%d\n", imagemagick_options.contrast);
2197     }
2198     ContrastImage(image, imagemagick_options.contrast);
2199   }
2200 
2201   if (check_interrupt(image, image_info,
2202                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2203   {
2204     return;
2205   }
2206 
2207   if (imagemagick_options.negate != -1)
2208   {
2209     if (debug_level & 16)
2210     {
2211       fprintf(stderr,"negate=%d\n", imagemagick_options.negate);
2212     }
2213     NegateImage(image, imagemagick_options.negate);
2214   }
2215 
2216   if (check_interrupt(image, image_info,
2217                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2218   {
2219     return;
2220   }
2221 
2222   if (imagemagick_options.equalize)
2223   {
2224     if (debug_level & 16)
2225     {
2226       fprintf(stderr,"equalize");
2227     }
2228     EqualizeImage(image);
2229   }
2230 
2231   if (check_interrupt(image, image_info,
2232                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2233   {
2234     return;
2235   }
2236 
2237   if (imagemagick_options.normalize)
2238   {
2239     if (debug_level & 16)
2240     {
2241       fprintf(stderr,"normalize");
2242     }
2243     NormalizeImage(image);
2244   }
2245 
2246   if (check_interrupt(image, image_info,
2247                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2248   {
2249     return;
2250   }
2251 
2252 #if (MagickLibVersion >= 0x0539)
2253   if (imagemagick_options.level[0] != '\0')
2254   {
2255     if (debug_level & 16)
2256     {
2257       fprintf(stderr,"level=%s\n", imagemagick_options.level);
2258     }
2259     LevelImage(image, imagemagick_options.level);
2260   }
2261 #endif  // MagickLibVersion >= 0x0539
2262 
2263   if (check_interrupt(image, image_info,
2264                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2265   {
2266     return;
2267   }
2268 
2269   if (imagemagick_options.modulate[0] != '\0')
2270   {
2271     if (debug_level & 16)
2272     {
2273       fprintf(stderr,"modulate=%s\n", imagemagick_options.modulate);
2274     }
2275     ModulateImage(image, imagemagick_options.modulate);
2276   }
2277   /*
2278   // Else check the menu option for raster intensity
2279   else if (raster_map_intensity < 1.0) {
2280   char tempstr[30];
2281   int temp_i;
2282 
2283   temp_i = (int)(raster_map_intensity * 100.0);
2284 
2285   xastir_snprintf(tempstr,
2286   sizeof(tempstr),
2287   "%d, 100, 100",
2288   temp_i);
2289 
2290   //fprintf(stderr,"Modulate: %s\n", tempstr);
2291 
2292   ModulateImage(image, tempstr);
2293   }
2294   */
2295 
2296   if (check_interrupt(image, image_info,
2297                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2298   {
2299     return;
2300   }
2301 
2302   // crop image: if we just use CropImage(), then the tiepoints will be off
2303   // make border pixels transparent.
2304   // cbell - this is a first attempt, it will be integrated into the
2305   //         lower loops to speed them up...
2306   if ( do_crop)
2307   {
2308     int x, y;
2309     //PixelPacket target;
2310     PixelPacket *q;
2311 
2312     //        target=GetOnePixel(image,0,0);
2313     for (y=0; y < (long) image->rows; y++)
2314     {
2315 #if defined(HAVE_GRAPHICSMAGICK) || (MagickLibVersion < 0x0669)
2316       q=GetImagePixels(image,0,y,image->columns,1);
2317 #else
2318       q=GetAuthenticPixels(image,0,y,image->columns,1,&exception);
2319 #endif
2320       if (q == (PixelPacket *) NULL)
2321       {
2322         fprintf(stderr, "GetImagePixels Failed....\n");
2323       }
2324       for (x=0; x < (int) image->columns; x++)
2325       {
2326         if ( (x < crop_x1) || (x > crop_x2) ||
2327              (y < crop_y1) || (y > crop_y2))
2328         {
2329           q->opacity=(Quantum) 1;
2330         }
2331         q++;
2332       }
2333 #if defined(HAVE_GRAPHICSMAGICK) || (MagickLibVersion < 0x0669)
2334       if (!SyncImagePixels(image))
2335       {
2336         fprintf(stderr, "SyncImagePixels Failed....\n");
2337       }
2338 #else
2339       if (!SyncAuthenticPixels(image,&exception))
2340       {
2341         fprintf(stderr, "SyncImagePixels Failed....\n");
2342       }
2343 #endif
2344     }
2345   }
2346 
2347   // If were are drawing to a low bpp display (typically < 8bpp)
2348   // try to reduce the number of colors in an image.
2349   // This may take some time, so it would be best to do ahead of
2350   // time if it is a static image.
2351 #if (MagickLibVersion < 0x0540)
2352   if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL) > 128)
2353   {
2354 #else   // MagickLib >= 540
2355   if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, &exception) > 128)
2356   {
2357 #endif  // MagickLib Version
2358 
2359     if (image->storage_class == PseudoClass)
2360     {
2361 #if (MagickLibVersion < 0x0549)
2362       CompressColormap(image); // Remove duplicate colors
2363 #else // MagickLib >= 0x0549
2364       CompressImageColormap(image); // Remove duplicate colors
2365 #endif  // MagickLibVersion < 0x0549
2366     }
2367 
2368     // Quantize down to 128 will go here...
2369   }
2370 
2371   if (check_interrupt(image, image_info,
2372                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2373   {
2374     return;
2375   }
2376 
2377 #if defined(HAVE_GRAPHICSMAGICK) || (MagickLibVersion < 0x0669)
2378   pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows);
2379 #else
2380   pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows,&exception);
2381 #endif
2382   if (!pixel_pack)
2383   {
2384     fprintf(stderr,"pixel_pack == NULL!!!");
2385     if (image)
2386     {
2387       DestroyImage(image);
2388     }
2389     if (image_info)
2390     {
2391       DestroyImageInfo(image_info);
2392     }
2393     DestroyExceptionInfo(&exception);
2394     return;
2395   }
2396 
2397   if (check_interrupt(image, image_info,
2398                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2399   {
2400     return;
2401   }
2402 
2403 #if defined(HAVE_GRAPHICSMAGICK)
2404   #if (MagickLibVersion < 0x201702)
2405     index_pack = GetIndexes(image);
2406   #else
2407     index_pack = AccessMutableIndexes(image);
2408   #endif
2409 #else
2410   #if (MagickLibVersion < 0x0669)
2411     index_pack = GetIndexes(image);
2412   #else
2413     index_pack = GetAuthenticIndexQueue(image);
2414   #endif
2415 #endif
2416   if (image->storage_class == PseudoClass && !index_pack)
2417   {
2418     fprintf(stderr,"PseudoClass && index_pack == NULL!!!");
2419     if (image)
2420     {
2421       DestroyImage(image);
2422     }
2423     if (image_info)
2424     {
2425       DestroyImageInfo(image_info);
2426     }
2427     DestroyExceptionInfo(&exception);
2428     return;
2429   }
2430 
2431   if (check_interrupt(image, image_info,
2432                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2433   {
2434     return;
2435   }
2436 
2437   if (debug_level & 16)
2438 #ifdef HAVE_GRAPHICSMAGICK
2439   fprintf(stderr,"Colors = %d\n", (int)image->colors);
2440 #else   // HAVE_GRAPHICSMAGICK
2441   fprintf(stderr,"Colors = %ld\n", image->colors);
2442 #endif  // HAVE_GRAPHICSMAGICK
2443 
2444     // Set up our own version of the color map.
2445     if (image->storage_class == PseudoClass && image->colors <= 256)
2446     {
2447       for (l = 0; l < (int)image->colors; l++)
2448       {
2449         int leave_unchanged = 0;
2450 
2451         // Need to check how to do this for ANY image, as ImageMagick can read in all sorts
2452         // of image files
2453         temp_pack = image->colormap[l];
2454         if (debug_level & 16)
2455           fprintf(stderr,"Colormap color is %1.2f  %1.2f  %1.2f \n",
2456                   (float)temp_pack.red, (float)temp_pack.green, (float)temp_pack.blue);
2457 
2458         // Here's a tricky bit:  PixelPacket entries are defined as Quantum's.  Quantum
2459         // is defined in /usr/include/magick/image.h as either an unsigned short or an
2460         // unsigned char, depending on what "configure" decided when ImageMagick was installed.
2461         // We can determine which by looking at MaxRGB or QuantumDepth.
2462         //
2463 
2464         if (QuantumDepth == 16)     // Defined in /usr/include/magick/magick_config.h
2465         {
2466           if (debug_level & 16)
2467           {
2468             fprintf(stderr,"Color quantum is [0..65535]\n");
2469           }
2470 
2471           my_colors[l].red   = temp_pack.red;
2472           my_colors[l].green = temp_pack.green;
2473           my_colors[l].blue  = temp_pack.blue;
2474         }
2475         else    // QuantumDepth = 8
2476         {
2477           if (debug_level & 16)
2478           {
2479             fprintf(stderr,"Color quantum is [0..255]\n");
2480           }
2481 
2482           my_colors[l].red   = temp_pack.red * 256;
2483           my_colors[l].green = temp_pack.green * 256;
2484           my_colors[l].blue  = temp_pack.blue * 256;
2485         }
2486 
2487         // Take care not to screw up the transparency value by
2488         // the raster_map_intensity multiplication factor.
2489         if ( trans_color_head )
2490         {
2491           //fprintf(stderr,"Checking for transparency\n");
2492 
2493           // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel
2494           if (visual_type == NOT_TRUE_NOR_DIRECT)
2495           {
2496             //                    XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0);
2497             XAllocColor(XtDisplay(w), cmap, &my_colors[l]);
2498           }
2499           else
2500           {
2501             pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue,
2502                             &my_colors[l].pixel);
2503           }
2504 
2505           if (check_trans(my_colors[l],trans_color_head) )
2506           {
2507 
2508             // Found a transparent color.  Leave it alone.
2509             leave_unchanged++;
2510             //fprintf(stderr,"Found transparency\n");
2511             // We never get here!
2512           }
2513         }
2514 
2515         // Use the map_intensity value if it's not a transparent
2516         // color we're dealing with.
2517         if (!leave_unchanged)
2518         {
2519           my_colors[l].red   = my_colors[l].red   * raster_map_intensity;
2520           my_colors[l].green = my_colors[l].green * raster_map_intensity;
2521           my_colors[l].blue  = my_colors[l].blue  * raster_map_intensity;
2522         }
2523 
2524 
2525         // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel
2526         if (visual_type == NOT_TRUE_NOR_DIRECT)
2527         {
2528           //                XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0);
2529           XAllocColor(XtDisplay(w), cmap, &my_colors[l]);
2530         }
2531         else
2532         {
2533           pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue,
2534                           &my_colors[l].pixel);
2535         }
2536 
2537         if (debug_level & 16)
2538           fprintf(stderr,"Color allocated is %li  %i  %i  %i \n", my_colors[l].pixel,
2539                   my_colors[l].red, my_colors[l].blue, my_colors[l].green);
2540       }
2541     }
2542 
2543   if (check_interrupt(image, image_info,
2544                       &exception, &da, &pixmap, &gc, screen_width, screen_height))
2545   {
2546     return;
2547   }
2548 
2549 #ifdef TIMING_DEBUG
2550   time_mark(0);
2551 #endif  // TIMING_DEBUG
2552 
2553   if (debug_level & 16)
2554   {
2555     fprintf(stderr,"Image size %d %d\n", width, height);
2556 #if (MagickLibVersion < 0x0540)
2557     fprintf(stderr,"Unique colors = %d\n", GetNumberColors(image, NULL));
2558 #else   // MagickLibVersion < 0x0540
2559     fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception));
2560 #endif  // MagickLibVersion < 0x0540
2561     fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T,
2562             map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y));
2563 
2564 #if (MagickLibVersion < 0x0540)
2565     fprintf(stderr,"is Gray Image = %i\n", IsGrayImage(image));
2566     fprintf(stderr,"is Monochrome Image = %i\n", IsMonochromeImage(image));
2567     //fprintf(stderr,"is Opaque Image = %i\n", IsOpaqueImage(image));
2568     //fprintf(stderr,"is PseudoClass = %i\n", image->storage_class == PseudoClass);
2569 #else    // MagickLibVersion < 0x0540
2570     fprintf(stderr,"is Gray Image = %i\n", IsGrayImage( image, &exception ));
2571     fprintf(stderr,"is Monochrome Image = %i\n", IsMonochromeImage( image, &exception ));
2572     //fprintf(stderr,"is Opaque Image = %i\n", IsOpaqueImage( image, &exception ));
2573     //fprintf(stderr,"is PseudoClass = %i\n", image->storage_class == PseudoClass);
2574 #endif   // MagickLibVersion < 0x0540
2575 
2576     fprintf(stderr,"image matte is %i\n", image->matte);
2577     fprintf(stderr,"Colorspace = %i\n", image->colorspace);
2578     if (image->colorspace == UndefinedColorspace)
2579     {
2580       fprintf(stderr,"Class Type = Undefined\n");
2581     }
2582     else if (image->colorspace == RGBColorspace)
2583     {
2584       fprintf(stderr,"Class Type = RGBColorspace\n");
2585     }
2586     else if (image->colorspace == GRAYColorspace)
2587     {
2588       fprintf(stderr,"Class Type = GRAYColorspace\n");
2589     }
2590     else if (image->colorspace == sRGBColorspace)
2591     {
2592       fprintf(stderr,"Class Type = sRGBColorspace\n");
2593     }
2594   }
2595 
2596 #else   // HAVE_MAGICK
2597 
2598   // We don't have ImageMagick libs compiled in, so use the
2599   // XPM library instead, but only if we HAVE XPM.
2600 
2601 #ifndef NO_XPM
2602   HandlePendingEvents(app_context);
2603   if (interrupt_drawing_now)
2604   {
2605     // Update to screen
2606     (void)XCopyArea(XtDisplay(da),
2607                     pixmap,
2608                     XtWindow(da),
2609                     gc,
2610                     0,
2611                     0,
2612                     (unsigned int)screen_width,
2613                     (unsigned int)screen_height,
2614                     0,
2615                     0);
2616     return;
2617   }
2618 
2619   // Check whether file has .xpm or .xpm.Z or .xpm.gz at the end.
2620   // If not, don't use the XpmReadFileToImage call below.
2621 
2622   if (       !strstr(filenm,"xpm")
2623              && !strstr(filenm,"XPM")
2624              && !strstr(filenm,"Xpm") )
2625   {
2626     fprintf(stderr,
2627             "Error: File format not supported by XPM library: %s\n",
2628             filenm);
2629     return;
2630   }
2631 
2632   /*  XpmReadFileToImage is the call we wish to avoid if at all
2633    *  possible.  On large images this can take quite a while.  We
2634    *  check above to see whether the image is inside our viewport,
2635    *  and if not we skip loading the image.
2636    */
2637   if (! XpmReadFileToImage (XtDisplay (w), file, &xi, NULL, &atb) == XpmSuccess)
2638   {
2639     fprintf(stderr,"ERROR loading %s\n", file);
2640     if (xi)
2641     {
2642       XDestroyImage (xi);
2643     }
2644     return;
2645   }
2646 
2647   if (debug_level & 16)
2648   {
2649     fprintf(stderr,"Image size %d %d\n", (int)atb.width, (int)atb.height);
2650     fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n",
2651             map_c_L,
2652             map_c_T,
2653             map_c_dx,
2654             (int) (map_c_dx / scale_x),
2655             map_c_dy,
2656             (int) (map_c_dy / scale_y));
2657   }
2658 
2659   HandlePendingEvents(app_context);
2660   if (interrupt_drawing_now)
2661   {
2662     if (xi)
2663     {
2664       XDestroyImage (xi);
2665     }
2666     // Update to screen
2667     (void)XCopyArea(XtDisplay(da),
2668                     pixmap,
2669                     XtWindow(da),
2670                     gc,
2671                     0,
2672                     0,
2673                     (unsigned int)screen_width,
2674                     (unsigned int)screen_height,
2675                     0,
2676                     0);
2677     return;
2678   }
2679 
2680   width  = atb.width;
2681   height = atb.height;
2682 #else // NO_XPM
2683   fprintf(stderr,"Xastir was configured with neither XPM library nor (Image/Graphics)Magick, cannot display map %s\n",filenm);
2684 #endif // NO_XPM
2685 #endif  // HAVE_MAGICK
2686 
2687   // draw the image from the file out to the map screen
2688 
2689   // Get the border values for the X and Y for loops used
2690   // for the XFillRectangle call later.
2691 
2692   map_c_yc = (tp[0].y_lat + tp[1].y_lat) / 2;     // vert center of map as reference
2693   //  map_y_ctr = (long)(height / 2 +0.499);
2694   scale_x0 = get_x_scale(0,map_c_yc,scale_y);     // reference scaling at vert map center
2695 
2696   map_c_xc  = (tp[0].x_long + tp[1].x_long) / 2;  // hor center of map as reference
2697   map_x_ctr = (long)(width  / 2 +0.499);
2698   //  scr_x_mc  = (map_c_xc - NW_corner_longitude) / scale_x; // screen coordinates of map center
2699 
2700   // calculate map pixel range in y direction that falls into screen area
2701   //  c_y_max = 0ul;
2702   map_y_min = map_y_max = 0l;
2703   for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy)
2704   {
2705     scr_y = (c_y - NW_corner_latitude) / scale_y;   // current screen position
2706     if (scr_y > 0)
2707     {
2708       if (scr_y < screen_height)
2709       {
2710         map_y_max = map_y_0;          // update last map pixel in y
2711         //              c_y_max = (unsigned long)c_y;// bottom map inside screen coordinate
2712       }
2713       else
2714       {
2715         break;  // done, reached bottom screen border
2716       }
2717     }
2718     else                                // pixel is above screen
2719     {
2720       map_y_min = map_y_0;              // update first map pixel in y
2721     }
2722   }
2723   //    fprintf(stderr,"map top: %ld bottom: %ld\n",tp[0].y_lat,tp[1].y_lat);
2724   c_y_min = (unsigned long)(tp[0].y_lat + map_y_min * map_c_dy);   // top map inside screen coordinate
2725 
2726   //    // find the y coordinate nearest to the equator
2727   //    c_y = 90*60*60*100;         // Equator
2728   //    if ((c_y_min>c_y && c_y_max>c_y) || (c_y_min<c_y && c_y_max<c_y)) {
2729   //        if (abs(c_y_min-c_y) > abs(c_y_max-c_y))
2730   //            c_y = c_y_max;      // north
2731   //        else
2732   //            c_y = c_y_min;      // south
2733   //    }
2734   //    scale_x0 = get_x_scale(0,(long)c_y,scale_y); // calc widest map area in x
2735 
2736   //    if (map_proj != 1) {
2737   // calculate map pixel range in x direction that falls into screen area
2738   map_x_min = map_x_max = 0l;
2739   for (map_x = 0, c_x = tp[0].x_long; map_x < (long)width; map_x++, c_x += map_c_dx)
2740   {
2741     scr_x = (c_x - NW_corner_longitude)/ scale_x;  // current screen position
2742     if (scr_x > 0)
2743     {
2744       if (scr_x < screen_width)
2745       {
2746         map_x_max = map_x;  // update last map pixel in x
2747       }
2748       else
2749       {
2750         break;  // done, reached right screen border
2751       }
2752     }
2753     else                                // pixel is left from screen
2754     {
2755       map_x_min = map_x;              // update first map pixel in x
2756     }
2757   }
2758   c_x_min = (unsigned long)(tp[0].x_long + map_x_min * map_c_dx);   // left map inside screen coordinate
2759   //    }
2760   //    for (scr_y = scr_y_min; scr_y <= scr_y_max;scr_y++) {       // screen lines
2761   //    }
2762 
2763   //  test = 1;           // DK7IN: debuging
2764   scr_yp = -1;
2765   scr_c_xr = SE_corner_longitude;
2766   c_dx = map_c_dx;                            // map pixel width
2767   scale_xa = scale_x0;                        // the compiler likes it ;-)
2768 
2769   //    for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) {
2770   //        scr_y = (c_y - NW_corner_latitude) / scale_y;   // current screen position
2771 
2772   map_done = 0;
2773   map_act  = 0;
2774   map_seen = 0;
2775   scr_y = screen_height - 1;
2776 
2777 #ifdef TIMING_DEBUG
2778   time_mark(0);
2779 #endif  // TIMING_DEBUG
2780 
2781 
2782   if (check_interrupt(
2783 #ifdef HAVE_MAGICK
2784   image, image_info, &exception,
2785 #else  // HAVE_MAGICK
2786   xi,
2787 #endif // HAVE_MAGICK
2788         &da, &pixmap, &gc, screen_width, screen_height))
2789   {
2790     return;
2791   }
2792 
2793 
2794   // loop over map pixel rows
2795   for (map_y_0 = map_y_min, c_y = (double)c_y_min;
2796        (map_y_0 <= map_y_max) || (map_proj == 1 && !map_done && scr_y < screen_height);
2797        map_y_0++, c_y += map_c_dy)
2798   {
2799 
2800     if (check_interrupt(
2801 #ifdef HAVE_MAGICK
2802           image, image_info, &exception,
2803 #else  // HAVE_MAGICK
2804           xi,
2805 #endif // HAVE_MAGICK
2806           &da, &pixmap, &gc, screen_width, screen_height))
2807     {
2808       return;
2809     }
2810 
2811     scr_y = (c_y - NW_corner_latitude) / scale_y;
2812     if (scr_y != scr_yp)                    // don't do a row twice
2813     {
2814       scr_yp = scr_y;                     // remember as previous y
2815       if (map_proj == 1)                  // Transverse Mercator correction in x
2816       {
2817         scale_xa = get_x_scale(0,(long)c_y,scale_y); // recalc scale_x for current y
2818         c_dx = map_c_dx * scale_xa / scale_x0;       // adjusted map pixel width
2819 
2820         map_x_min = map_x_ctr - (map_c_xc - NW_corner_longitude) / c_dx;
2821         if (map_x_min < 0)
2822         {
2823           map_x_min = 0;
2824         }
2825         c_x_min = map_c_xc - (map_x_ctr - map_x_min) * c_dx;
2826         map_x_max = map_x_ctr - (map_c_xc - scr_c_xr) / c_dx;
2827         if (map_x_max > (long)width)
2828         {
2829           map_x_max = width;
2830         }
2831         scr_dx = (int) (c_dx / scale_x) + 1;    // at least 1 pixel wide
2832       }
2833 
2834       //            if (c_y == (double)c_y_min) {  // first call
2835       //                fprintf(stderr,"map: min %ld ctr %ld max %ld, c_dx %ld, c_x_min %ld, c_y_min %ld\n",map_x_min,map_x_ctr,map_x_max,(long)c_dx,c_x_min,c_y_min);
2836       //            }
2837       scr_xp = -1;
2838       // loop over map pixel columns
2839       map_act = 0;
2840       scale_x_nm = calc_dscale_x(0,(long)c_y) / 1852.0;  // nm per Xastir coordinate
2841       for (map_x = map_x_min, c_x = (double)c_x_min; map_x <= map_x_max; map_x++, c_x += c_dx)
2842       {
2843         scr_x = (c_x - NW_corner_longitude) / scale_x;
2844         if (scr_x != scr_xp)        // don't do a pixel twice
2845         {
2846           scr_xp = scr_x;         // remember as previous x
2847           if (map_proj == 1)      // Transverse Mercator correction in y
2848           {
2849             // DK7IN--
2850             dist = (90*60 - (c_y / 6000.0));   // equator distance in nm
2851             // ?? 180W discontinuity!  not done yet
2852             ew_ofs = (c_x - (double)map_c_xc) * scale_x_nm;  // EW offset from center in nm
2853             //corrfact = (map_y_0 - map_y_ctr)/(2*map_y_ctr);  // 0..50%
2854             //corrfact = fabs(ew_ofs/dist)*3.0;
2855             //corrfact = 1.0-1.0*(0.5*map_y_0 / map_y_ctr);
2856             corrfact = 1.0;
2857             c_y_a = (fabs(dist) - sqrt((double)(dist*dist - ew_ofs*ew_ofs)))*6000.0; // in Xastir units
2858             if (dist < 0)           // S
2859             {
2860               map_y = map_y_0 + (long)(corrfact*c_y_a / map_c_dy);  // coord per pixel
2861             }
2862             else                    // N
2863             {
2864               map_y = map_y_0 - (long)(corrfact*c_y_a / map_c_dy);
2865             }
2866             //                        if (test < 10) {
2867             //                            fprintf(stderr,"dist: %ldkm, ew_ofs: %ldkm, dy: %ldkm\n",(long)(1.852*dist),(long)(1.852*ew_ofs),(long)(1.852*c_y_a/6000.0));
2868             //                            fprintf(stderr,"  corrfact: %f, mapy0: %ld, mapy: %ld\n",corrfact,map_y_0,map_y);
2869             //                            test++;
2870             //                        }
2871           }
2872           else
2873           {
2874             map_y = map_y_0;
2875           }
2876 
2877           if (map_y >= 0 && map_y <= tp[1].img_y)   // check map boundaries in y direction
2878           {
2879             map_seen = 1;
2880             map_act = 1;    // detects blank screen rows (end of map)
2881 
2882             // DK7IN--
2883 
2884             //----- copy pixel from map to screen ---------------------
2885             //            if (c_y == (double)c_y_min && (scr_x < 5 || (c_x == (double)c_x_min))) {  // first call
2886             //                fprintf(stderr,"map: x %ld y %ld scr: x %ld y %ld dx %d, dy %d\n",map_x,map_y,scr_x,scr_y,scr_dx,scr_dy);
2887             //                fprintf(stderr,"color: %ld\n",XGetPixel (xi, map_x, map_y));
2888             //                // 65529
2889             //            }
2890 
2891             // now copy a pixel from the map image to the screen
2892 #ifdef HAVE_MAGICK
2893             l = map_x + map_y * image->columns;
2894             trans_skip = 1; // possibly transparent
2895             if (image->storage_class == PseudoClass)
2896             {
2897               if ( trans_color_head &&
2898                    check_trans(my_colors[(int)index_pack[l]],trans_color_head) )
2899               {
2900                 trans_skip = 1; // skip it
2901               }
2902               else
2903               {
2904                 XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel);
2905                 trans_skip = 0; // draw it
2906               }
2907             }
2908             else
2909             {
2910               // It is not safe to assume that the red/green/blue
2911               // elements of pixel_pack of type Quantum are the
2912               // same as the red/green/blue of an XColor!
2913               if (QuantumDepth==16)
2914               {
2915                 my_colors[0].red=pixel_pack[l].red;
2916                 my_colors[0].green=pixel_pack[l].green;
2917                 my_colors[0].blue=pixel_pack[l].blue;
2918               }
2919               else   // QuantumDepth=8
2920               {
2921                 // shift the bits of the 8-bit quantity so that
2922                 // they become the high bigs of my_colors.*
2923                 my_colors[0].red=pixel_pack[l].red*256;
2924                 my_colors[0].green=pixel_pack[l].green*256;
2925                 my_colors[0].blue=pixel_pack[l].blue*256;
2926               }
2927               // NOW my_colors has the right r,g,b range for
2928               // pack_pixel_bits
2929               pack_pixel_bits(my_colors[0].red * raster_map_intensity,
2930                               my_colors[0].green * raster_map_intensity,
2931                               my_colors[0].blue * raster_map_intensity,
2932                               &my_colors[0].pixel);
2933               if ( trans_color_head &&
2934                    check_trans(my_colors[0],trans_color_head) )
2935               {
2936                 trans_skip = 1; // skip it
2937               }
2938               else
2939               {
2940                 XSetForeground(XtDisplay(w), gc, my_colors[0].pixel);
2941                 trans_skip = 0; // draw it
2942               }
2943             }
2944 #else   // HAVE_MAGICK
2945             (void)XSetForeground (XtDisplay (w), gc, XGetPixel (xi, map_x, map_y));
2946 #endif  // HAVE_MAGICK
2947 
2948 
2949             // Skip drawing if a transparent pixel
2950 #ifdef HAVE_MAGICK
2951             if ( pixel_pack[l].opacity == 0 && !trans_skip  ) // skip transparent
2952 #else   // HAVE_MAGICK
2953             if (!trans_skip)    // skip transparent
2954 #endif  // HAVE_MAGICK
2955 
2956               (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy);
2957           } // check map boundaries in y direction
2958         }
2959       } // loop over map pixel columns
2960       if (map_seen && !map_act)
2961       {
2962         map_done = 1;
2963       }
2964     }
2965   } // loop over map pixel rows
2966 
2967 #ifdef HAVE_MAGICK
2968   if (image)
2969   {
2970   DestroyImage(image);
2971   }
2972   if (image_info)
2973   {
2974   DestroyImageInfo(image_info);
2975   }
2976   DestroyExceptionInfo(&exception);
2977 #else   // HAVE_MAGICK
2978   if (xi)
2979   {
2980   XDestroyImage (xi);
2981   }
2982 #endif // HAVE_MAGICK
2983 
2984 #ifdef TIMING_DEBUG
2985   time_mark(0);
2986 #endif  // TIMING_DEBUG
2987 #endif  // NO_GRAPHICS
2988 }
2989 
2990 
2991