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