]> git.street.me.uk Git - andy/viking.git/blame - src/vikviewport.c
trying to get g_dtostr to work
[andy/viking.git] / src / vikviewport.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * Lat/Lon plotting functions calcxy* are from GPSDrive
7 * GPSDrive Copyright (C) 2001-2004 Fritz Ganter <ganter@ganter.at>
8 *
9 * Multiple UTM zone patch by Kit Transue <notlostyet@didactek.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#define DEFAULT_BACKGROUND_COLOR "#CCCCCC"
28
29#include <gtk/gtk.h>
30#include <math.h>
31
32#include "coords.h"
33#include "vikcoord.h"
34#include "vikviewport.h"
35
36#include "mapcoord.h"
37
38/* for ALTI_TO_MPP */
39#include "globals.h"
40#include "googlemaps.h"
41#include "khmaps.h"
42
43static gdouble EASTING_OFFSET = 500000.0;
44
45static void viewport_class_init ( VikViewportClass *klass );
46static void viewport_init ( VikViewport *vvp );
47static void viewport_finalize ( GObject *gob );
48static void viewport_utm_zone_check ( VikViewport *vvp );
49
50static gboolean calcxy(double *x, double *y, double lg, double lt, double zero_long, double zero_lat, double pixelfact_x, double pixelfact_y, gint mapSizeX2, gint mapSizeY2 );
51static gboolean calcxy_rev(double *lg, double *lt, gint x, gint y, double zero_long, double zero_lat, double pixelfact_x, double pixelfact_y, gint mapSizeX2, gint mapSizeY2 );
52double calcR (double lat);
53
54static double Radius[181];
55static void viewport_init_ra();
56
57static GObjectClass *parent_class;
58
59static void viewport_google_rezoom ( VikViewport *vvp );
60
61
62struct _VikViewport {
63 GtkDrawingArea drawing_area;
64 GdkPixmap *scr_buffer;
65 gint width, height;
66 VikCoord center;
67 VikCoordMode coord_mode;
68 gdouble xmpp, ympp;
69
70 GdkPixbuf *alpha_pixbuf;
71 guint8 alpha_pixbuf_width;
72 guint8 alpha_pixbuf_height;
73
74 gdouble utm_zone_width;
75 gboolean one_utm_zone;
76
77 GdkGC *background_gc;
78 GdkColor background_color;
79
80 /* subset of coord types. lat lon can be plotted in 2 ways, google or exp. */
81 VikViewportDrawMode drawmode;
82
83 /* handy conversion factors which make google plotting extremely fast */
84 gdouble google_calcx_fact;
85 gdouble google_calcy_fact;
86 gdouble google_calcx_rev_fact;
87 gdouble google_calcy_rev_fact;
88};
89
90static gdouble
91viewport_utm_zone_width ( VikViewport *vvp )
92{
93 if ( vvp->coord_mode == VIK_COORD_UTM ) {
94 struct LatLon ll;
95
96 /* get latitude of screen bottom */
97 struct UTM utm = *((struct UTM *)(vik_viewport_get_center ( vvp )));
98 utm.northing -= vvp -> height * vvp -> ympp / 2;
99 a_coords_utm_to_latlon ( &utm, &ll );
100
101 /* boundary */
102 ll.lon = (utm.zone - 1) * 6 - 180 ;
103 a_coords_latlon_to_utm ( &ll, &utm);
104 return fabs ( utm.easting - EASTING_OFFSET ) * 2;
105 } else
106 return 0.0;
107}
108
109
110GType vik_viewport_get_type (void)
111{
112 static GType vvp_type = 0;
113
114 if (!vvp_type)
115 {
116 static const GTypeInfo vvp_info =
117 {
118 sizeof (VikViewportClass),
119 NULL, /* base_init */
120 NULL, /* base_finalize */
121 (GClassInitFunc) viewport_class_init,
122 NULL, /* class_finalize */
123 NULL, /* class_data */
124 sizeof (VikViewport),
125 0,
126 (GInstanceInitFunc) viewport_init,
127 };
128 vvp_type = g_type_register_static ( GTK_TYPE_DRAWING_AREA, "VikViewport", &vvp_info, 0 );
129 }
130 return vvp_type;
131}
132
133static void viewport_class_init ( VikViewportClass *klass )
134{
135 /* Destructor */
136 GObjectClass *object_class;
137
138 object_class = G_OBJECT_CLASS (klass);
139
140 object_class->finalize = viewport_finalize;
141
142 parent_class = g_type_class_peek_parent (klass);
143}
144
145VikViewport *vik_viewport_new ()
146{
147 return VIK_VIEWPORT ( g_object_new ( VIK_VIEWPORT_TYPE, NULL ) );
148}
149
150static void viewport_init ( VikViewport *vvp )
151{
152 viewport_init_ra();
153
154 /* TODO: not static */
155 vvp->xmpp = 4.0;
156 vvp->ympp = 4.0;
157 vvp->coord_mode = VIK_COORD_UTM;
158 vvp->drawmode = VIK_VIEWPORT_DRAWMODE_UTM;
159 vvp->center.north_south = 0;
160 vvp->center.east_west = -166021;
161 vvp->center.utm_zone = 31;
162 vvp->center.utm_letter = 'N';
163 vvp->scr_buffer = NULL;
164 vvp->alpha_pixbuf = NULL;
165 vvp->alpha_pixbuf_width = vvp->alpha_pixbuf_height = 0;
166 vvp->utm_zone_width = 0.0;
167 vvp->background_gc = NULL;
168 g_signal_connect (G_OBJECT(vvp), "configure_event", G_CALLBACK(vik_viewport_configure), NULL);
169}
170
171GdkColor *vik_viewport_get_background_gdkcolor ( VikViewport *vvp )
172{
173 GdkColor *rv = g_malloc ( sizeof ( GdkColor ) );
174 *rv = vvp->background_color;
175 return rv;
176}
177
178/* returns pointer to internal static storage, changes next time function called, use quickly */
179const gchar *vik_viewport_get_background_color ( VikViewport *vvp )
180{
181 static gchar color[8];
182 g_snprintf(color, sizeof(color), "#%.2x%.2x%.2x", (int)(vvp->background_color.red/256),(int)(vvp->background_color.green/256),(int)(vvp->background_color.blue/256));
183 return color;
184}
185
186void vik_viewport_set_background_color ( VikViewport *vvp, const gchar *colorname )
187{
188 g_assert ( vvp->background_gc );
189 gdk_color_parse ( colorname, &(vvp->background_color) );
190 gdk_gc_set_rgb_fg_color ( vvp->background_gc, &(vvp->background_color) );
191}
192
193void vik_viewport_set_background_gdkcolor ( VikViewport *vvp, GdkColor *color )
194{
195 g_assert ( vvp->background_gc );
196 vvp->background_color = *color;
197 gdk_gc_set_rgb_fg_color ( vvp->background_gc, color );
198}
199
200
201GdkGC *vik_viewport_new_gc ( VikViewport *vvp, const gchar *colorname, gint thickness )
202{
203 GdkGC *rv;
204 GdkColor color;
205
206 rv = gdk_gc_new ( GTK_WIDGET(vvp)->window );
207 gdk_color_parse ( colorname, &color );
208 gdk_gc_set_rgb_fg_color ( rv, &color );
209 gdk_gc_set_line_attributes ( rv, thickness, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
210 return rv;
211}
212
213GdkGC *vik_viewport_new_gc_from_color ( VikViewport *vvp, GdkColor *color, gint thickness )
214{
215 GdkGC *rv;
216
217 rv = gdk_gc_new ( GTK_WIDGET(vvp)->window );
218 gdk_gc_set_rgb_fg_color ( rv, color );
219 gdk_gc_set_line_attributes ( rv, thickness, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
220 return rv;
221}
222
223void vik_viewport_configure_manually ( VikViewport *vvp, gint width, guint height )
224{
225 vvp->width = width;
226 vvp->height = height;
227 if ( vvp->scr_buffer )
228 g_object_unref ( G_OBJECT ( vvp->scr_buffer ) );
229 vvp->scr_buffer = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, vvp->width, vvp->height, -1 );
230}
231
232
233GdkPixmap *vik_viewport_get_pixmap ( VikViewport *vvp )
234{
235 return vvp->scr_buffer;
236}
237
238gboolean vik_viewport_configure ( VikViewport *vvp )
239{
240 g_return_val_if_fail ( vvp != NULL, TRUE );
241
242 vvp->width = GTK_WIDGET(vvp)->allocation.width;
243 vvp->height = GTK_WIDGET(vvp)->allocation.height;
244
245 if ( vvp->scr_buffer )
246 g_object_unref ( G_OBJECT ( vvp->scr_buffer ) );
247
248 vvp->scr_buffer = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, vvp->width, vvp->height, -1 );
249
250 /* this is down here so it can get a GC (necessary?) */
251 if ( ! vvp->background_gc )
252 {
253 vvp->background_gc = vik_viewport_new_gc ( vvp, "", 1 );
254 vik_viewport_set_background_color ( vvp, DEFAULT_BACKGROUND_COLOR ); /* set to "backup" color in vvp->background_color */
255 }
256
257 return FALSE;
258}
259
260static void viewport_finalize ( GObject *gob )
261{
262 VikViewport *vvp = VIK_VIEWPORT(gob);
263
264 g_return_if_fail ( vvp != NULL );
265
266 if ( vvp->scr_buffer )
267 g_object_unref ( G_OBJECT ( vvp->scr_buffer ) );
268
269 if ( vvp->alpha_pixbuf )
270 g_object_unref ( G_OBJECT ( vvp->alpha_pixbuf ) );
271
272 if ( vvp->background_gc )
273 g_object_unref ( G_OBJECT ( vvp->background_gc ) );
274
275 G_OBJECT_CLASS(parent_class)->finalize(gob);
276}
277
278void vik_viewport_clear ( VikViewport *vvp )
279{
280 g_return_if_fail ( vvp != NULL );
281 gdk_draw_rectangle(GDK_DRAWABLE(vvp->scr_buffer), vvp->background_gc, TRUE, 0, 0, vvp->width, vvp->height);
282}
283
284void vik_viewport_sync ( VikViewport *vvp )
285{
286 g_return_if_fail ( vvp != NULL );
287 gdk_draw_drawable(GTK_WIDGET(vvp)->window, GTK_WIDGET(vvp)->style->bg_gc[0], GDK_DRAWABLE(vvp->scr_buffer), 0, 0, 0, 0, vvp->width, vvp->height);
288}
289
290void vik_viewport_pan_sync ( VikViewport *vvp, gint x_off, gint y_off )
291{
292 g_return_if_fail ( vvp != NULL );
293 gdk_draw_drawable(GTK_WIDGET(vvp)->window, GTK_WIDGET(vvp)->style->bg_gc[0], GDK_DRAWABLE(vvp->scr_buffer), 0, 0, x_off, y_off, vvp->width, vvp->height);
294}
295
296void vik_viewport_set_zoom ( VikViewport *vvp, gdouble xympp )
297{
298 g_return_if_fail ( vvp != NULL );
299 if ( xympp >= VIK_VIEWPORT_MIN_ZOOM && xympp <= VIK_VIEWPORT_MAX_ZOOM )
300 vvp->xmpp = vvp->ympp = xympp;
301
302 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_UTM )
303 viewport_utm_zone_check(vvp);
304 else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
305 viewport_google_rezoom ( vvp );
306}
307
308/* or could do factor */
309void vik_viewport_zoom_in ( VikViewport *vvp )
310{
311 g_return_if_fail ( vvp != NULL );
312 if ( vvp->xmpp >= (VIK_VIEWPORT_MIN_ZOOM*2) && vvp->ympp >= (VIK_VIEWPORT_MIN_ZOOM*2) )
313 {
314 vvp->xmpp /= 2;
315 vvp->ympp /= 2;
316
317 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
318 viewport_google_rezoom ( vvp );
319
320 viewport_utm_zone_check(vvp);
321 }
322}
323
324void vik_viewport_zoom_out ( VikViewport *vvp )
325{
326 g_return_if_fail ( vvp != NULL );
327 if ( vvp->xmpp <= (VIK_VIEWPORT_MAX_ZOOM/2) && vvp->ympp <= (VIK_VIEWPORT_MAX_ZOOM/2) )
328 {
329 vvp->xmpp *= 2;
330 vvp->ympp *= 2;
331
332 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
333 viewport_google_rezoom ( vvp );
334
335 viewport_utm_zone_check(vvp);
336 }
337}
338
339gdouble vik_viewport_get_zoom ( VikViewport *vvp )
340{
341 if ( vvp->xmpp == vvp->ympp )
342 return vvp->xmpp;
343 return 0.0;
344}
345
346gdouble vik_viewport_get_xmpp ( VikViewport *vvp )
347{
348 return vvp->xmpp;
349}
350
351gdouble vik_viewport_get_ympp ( VikViewport *vvp )
352{
353 return vvp->ympp;
354}
355
356void vik_viewport_set_xmpp ( VikViewport *vvp, gdouble xmpp )
357{
358 if ( xmpp >= VIK_VIEWPORT_MIN_ZOOM && xmpp <= VIK_VIEWPORT_MAX_ZOOM ) {
359 vvp->xmpp = xmpp;
360 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_UTM )
361 viewport_utm_zone_check(vvp);
362 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
363 viewport_google_rezoom ( vvp );
364 }
365}
366
367void vik_viewport_set_ympp ( VikViewport *vvp, gdouble ympp )
368{
369 if ( ympp >= VIK_VIEWPORT_MIN_ZOOM && ympp <= VIK_VIEWPORT_MAX_ZOOM ) {
370 vvp->ympp = ympp;
371 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_UTM )
372 viewport_utm_zone_check(vvp);
373 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
374 viewport_google_rezoom ( vvp );
375 }
376}
377
378
379const VikCoord *vik_viewport_get_center ( VikViewport *vvp )
380{
381 g_return_val_if_fail ( vvp != NULL, NULL );
382 return &(vvp->center);
383}
384
385/* called every time we update coordinates/zoom */
386static void viewport_utm_zone_check ( VikViewport *vvp )
387{
388 if ( vvp->coord_mode == VIK_COORD_UTM )
389 {
390 struct UTM utm;
391 struct LatLon ll;
392 a_coords_utm_to_latlon ( (struct UTM *) &(vvp->center), &ll );
393 a_coords_latlon_to_utm ( &ll, &utm );
394 if ( utm.zone != vvp->center.utm_zone )
395 *((struct UTM *)(&vvp->center)) = utm;
396
397 /* misc. stuff so we don't have to check later */
398 vvp->utm_zone_width = viewport_utm_zone_width ( vvp );
399 vvp->one_utm_zone = ( vik_viewport_rightmost_zone(vvp) == vik_viewport_leftmost_zone(vvp) );
400 }
401}
402
403void vik_viewport_set_center_latlon ( VikViewport *vvp, const struct LatLon *ll )
404{
405 vik_coord_load_from_latlon ( &(vvp->center), vvp->coord_mode, ll );
406 if ( vvp->coord_mode == VIK_COORD_UTM )
407 viewport_utm_zone_check ( vvp );
408}
409
410void vik_viewport_set_center_utm ( VikViewport *vvp, const struct UTM *utm )
411{
412 vik_coord_load_from_utm ( &(vvp->center), vvp->coord_mode, utm );
413 if ( vvp->coord_mode == VIK_COORD_UTM )
414 viewport_utm_zone_check ( vvp );
415}
416
417void vik_viewport_set_center_coord ( VikViewport *vvp, const VikCoord *coord )
418{
419 vvp->center = *coord;
420 if ( vvp->coord_mode == VIK_COORD_UTM )
421 viewport_utm_zone_check ( vvp );
422}
423
424void vik_viewport_corners_for_zonen ( VikViewport *vvp, int zone, VikCoord *ul, VikCoord *br )
425{
426 g_return_if_fail ( vvp->coord_mode == VIK_COORD_UTM );
427
428 /* get center, then just offset */
429 vik_viewport_center_for_zonen ( vvp, VIK_UTM(ul), zone );
430 ul->mode = VIK_COORD_UTM;
431 *br = *ul;
432
433 ul->north_south += (vvp->ympp * vvp->height / 2);
434 ul->east_west -= (vvp->xmpp * vvp->width / 2);
435 br->north_south -= (vvp->ympp * vvp->height / 2);
436 br->east_west += (vvp->xmpp * vvp->width / 2);
437}
438
439void vik_viewport_center_for_zonen ( VikViewport *vvp, struct UTM *center, int zone)
440{
441 if ( vvp->coord_mode == VIK_COORD_UTM ) {
442 *center = *((struct UTM *)(vik_viewport_get_center ( vvp )));
443 center->easting -= ( zone - center->zone ) * vvp->utm_zone_width;
444 center->zone = zone;
445 }
446}
447
448gchar vik_viewport_leftmost_zone ( VikViewport *vvp )
449{
450 if ( vvp->coord_mode == VIK_COORD_UTM ) {
451 VikCoord coord;
452 g_assert ( vvp != NULL );
453 vik_viewport_screen_to_coord ( vvp, 0, 0, &coord );
454 return coord.utm_zone;
455 }
456 return '\0';
457}
458
459gchar vik_viewport_rightmost_zone ( VikViewport *vvp )
460{
461 if ( vvp->coord_mode == VIK_COORD_UTM ) {
462 VikCoord coord;
463 g_assert ( vvp != NULL );
464 vik_viewport_screen_to_coord ( vvp, vvp->width, 0, &coord );
465 return coord.utm_zone;
466 }
467 return '\0';
468}
469
470
471void vik_viewport_set_center_screen ( VikViewport *vvp, int x, int y )
472{
473 g_return_if_fail ( vvp != NULL );
474 if ( vvp->coord_mode == VIK_COORD_UTM ) {
475 /* slightly optimized */
476 vvp->center.east_west += vvp->xmpp * (x - (vvp->width/2));
477 vvp->center.north_south += vvp->ympp * ((vvp->height/2) - y);
478 viewport_utm_zone_check ( vvp );
479 } else {
480 VikCoord tmp;
481 vik_viewport_screen_to_coord ( vvp, x, y, &tmp );
482 vik_viewport_set_center_coord ( vvp, &tmp );
483 }
484}
485
486gint vik_viewport_get_width( VikViewport *vvp )
487{
488 g_return_val_if_fail ( vvp != NULL, 0 );
489 return vvp->width;
490}
491
492gint vik_viewport_get_height( VikViewport *vvp )
493{
494 g_return_val_if_fail ( vvp != NULL, 0 );
495 return vvp->height;
496}
497
498void vik_viewport_screen_to_coord ( VikViewport *vvp, int x, int y, VikCoord *coord )
499{
500 if ( vvp->coord_mode == VIK_COORD_UTM ) {
501 int zone_delta;
502 struct UTM *utm = (struct UTM *) coord;
503 coord->mode = VIK_COORD_UTM;
504
505 g_return_if_fail ( vvp != NULL );
506
507 utm->zone = vvp->center.utm_zone;
508 utm->letter = vvp->center.utm_letter;
509 utm->easting = ( ( x - ( vvp->width / 2) ) * vvp->xmpp ) + vvp->center.east_west;
510 zone_delta = floor( (utm->easting - EASTING_OFFSET ) / vvp->utm_zone_width + 0.5 );
511 utm->zone += zone_delta;
512 utm->easting -= zone_delta * vvp->utm_zone_width;
513 utm->northing = ( ( ( vvp->height / 2) - y ) * vvp->ympp ) + vvp->center.north_south;
514 } else if ( vvp->coord_mode == VIK_COORD_LATLON ) {
515 coord->mode = VIK_COORD_LATLON;
516 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_EXPEDIA )
517 calcxy_rev(&(coord->east_west), &(coord->north_south), x, y, vvp->center.east_west, vvp->center.north_south, vvp->xmpp * ALTI_TO_MPP, vvp->ympp * ALTI_TO_MPP, vvp->width/2, vvp->height/2);
518 else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE ) {
519 /* google */
520 coord->east_west = (x - (vvp->width/2)) * vvp->google_calcx_rev_fact + vvp->center.east_west;
521 coord->north_south = ((vvp->height/2) - y) * vvp->google_calcy_rev_fact + vvp->center.north_south;
522 } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_KH ) {
523 coord->east_west = vvp->center.east_west + (180.0 * vvp->xmpp / 65536 / 256 * (x - vvp->width/2));
524 coord->north_south = vvp->center.north_south + (180.0 * vvp->ympp / 65536 / 256 * (vvp->height/2 - y));
525 } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_MERCATOR ) {
526 /* FIXMERCATOR */
527 coord->east_west = vvp->center.east_west + (180.0 * vvp->xmpp / 65536 / 256 * (x - vvp->width/2));
528 coord->north_south = DEMERCLAT ( MERCLAT(vvp->center.north_south) + (180.0 * vvp->ympp / 65536 / 256 * (vvp->height/2 - y)) );
529
530#if 0
531--> THIS IS JUNK HERE.
532 *y = vvp->height/2 + (65536.0 / 180 / vvp->ympp * (MERCLAT(center->lat) - MERCLAT(ll->lat)))*256.0;
533
534 (*y - vvp->height/2) / 256 / 65536 * 180 * vvp->ympp = (MERCLAT(center->lat) - MERCLAT(ll->lat);
535 DML((180.0 * vvp->ympp / 65536 / 256 * (vvp->height/2 - y)) + ML(cl)) = ll
536#endif
537 }
538 }
539}
540
541void vik_viewport_coord_to_screen ( VikViewport *vvp, const VikCoord *coord, int *x, int *y )
542{
543 static VikCoord tmp;
544 g_return_if_fail ( vvp != NULL );
545
546 if ( coord->mode != vvp->coord_mode )
547 {
548 g_warning ( "Have to convert in vik_viewport_coord_to_screen! This should never happen!");
549 vik_coord_copy_convert ( coord, vvp->coord_mode, &tmp );
550 coord = &tmp;
551 }
552
553 if ( vvp->coord_mode == VIK_COORD_UTM ) {
554 struct UTM *center = (struct UTM *) &(vvp->center);
555 struct UTM *utm = (struct UTM *) coord;
556 if ( center->zone != utm->zone && vvp->one_utm_zone )
557 {
558 *x = *y = VIK_VIEWPORT_UTM_WRONG_ZONE;
559 return;
560 }
561
562 *x = ( (utm->easting - center->easting) / vvp->xmpp ) + (vvp->width / 2) -
563 (center->zone - utm->zone ) * vvp->utm_zone_width / vvp->xmpp;
564 *y = (vvp->height / 2) - ( (utm->northing - center->northing) / vvp->ympp );
565 } else if ( vvp->coord_mode == VIK_COORD_LATLON ) {
566 struct LatLon *center = (struct LatLon *) &(vvp->center);
567 struct LatLon *ll = (struct LatLon *) coord;
568 double xx,yy;
569 if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_EXPEDIA ) {
570 calcxy ( &xx, &yy, center->lon, center->lat, ll->lon, ll->lat, vvp->xmpp * ALTI_TO_MPP, vvp->ympp * ALTI_TO_MPP, vvp->width / 2, vvp->height / 2 );
571 *x = xx; *y = yy;
572 } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE ) {
573 /* google */
574 *x = vvp->google_calcx_fact * (ll->lon - center->lon) + (vvp->width/2);
575 *y = vvp->google_calcy_fact * (center->lat - ll->lat) + (vvp->height/2);
576 } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_KH ) {
577 /* subtract, convert to KH coords; blow it up by 256 */
578 *x = vvp->width/2 + (65536.0 / 180 / vvp->xmpp * (ll->lon - center->lon))*256.0;
579 *y = vvp->height/2 + (65536.0 / 180 / vvp->ympp * (center->lat - ll->lat))*256.0;
580 } else if ( vvp->drawmode == VIK_VIEWPORT_DRAWMODE_MERCATOR ) {
581 /* FIXMERCATOR: Optimize */
582 *x = vvp->width/2 + (65536.0 / 180 / vvp->xmpp * (ll->lon - center->lon))*256.0;
583 *y = vvp->height/2 + (65536.0 / 180 / vvp->ympp * (MERCLAT(center->lat) - MERCLAT(ll->lat)))*256.0;
584 }
585 }
586}
587
588void vik_viewport_draw_line ( VikViewport *vvp, GdkGC *gc, gint x1, gint y1, gint x2, gint y2 )
589{
590 if ( ! ( ( x1 < 0 && x2 < 0 ) || ( y1 < 0 && y2 < 0 ) ||
591 ( x1 > vvp->width && x2 > vvp->width ) || ( y1 > vvp->height && y2 > vvp->height ) ) )
592 gdk_draw_line ( vvp->scr_buffer, gc, x1, y1, x2, y2);
593}
594
595void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 )
596{
597 if ( x1 > -10 && x1 < vvp->width + 10 && y1 > -10 && y1 < vvp->height + 10 )
598 gdk_draw_rectangle ( vvp->scr_buffer, gc, filled, x1, y1, x2, y2);
599}
600
601void vik_viewport_draw_string ( VikViewport *vvp, GdkFont *font, GdkGC *gc, gint x1, gint y1, const gchar *string )
602{
603 if ( x1 > -100 && x1 < vvp->width + 100 && y1 > -100 && y1 < vvp->height + 100 )
604 gdk_draw_string ( vvp->scr_buffer, font, gc, x1, y1, string );
605}
606
607/* shouldn't use this -- slow -- change the alpha channel instead. */
608void vik_viewport_draw_pixbuf_with_alpha ( VikViewport *vvp, GdkPixbuf *pixbuf, gint alpha,
609 gint src_x, gint src_y, gint dest_x, gint dest_y, gint w, gint h )
610{
611 gint real_dest_x = MAX(dest_x,0);
612 gint real_dest_y = MAX(dest_y,0);
613
614 if ( alpha == 0 )
615 return; /* don't waste your time */
616
617 if ( w > vvp->alpha_pixbuf_width || h > vvp->alpha_pixbuf_height )
618 {
619 if ( vvp->alpha_pixbuf )
620 g_object_unref ( G_OBJECT ( vvp->alpha_pixbuf ) );
621 vvp->alpha_pixbuf_width = MAX(w,vvp->alpha_pixbuf_width);
622 vvp->alpha_pixbuf_height = MAX(h,vvp->alpha_pixbuf_height);
623 vvp->alpha_pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, vvp->alpha_pixbuf_width, vvp->alpha_pixbuf_height );
624 }
625
626 w = MIN(w,vvp->width - dest_x);
627 h = MIN(h,vvp->height - dest_y);
628
629 /* check that we are drawing within boundaries. */
630 src_x += (real_dest_x - dest_x);
631 src_y += (real_dest_y - dest_y);
632 w -= (real_dest_x - dest_x);
633 h -= (real_dest_y - dest_y);
634
635 gdk_pixbuf_get_from_drawable ( vvp->alpha_pixbuf, vvp->scr_buffer, NULL,
636 real_dest_x, real_dest_y, 0, 0, w, h );
637
638 /* do a composite */
639 gdk_pixbuf_composite ( pixbuf, vvp->alpha_pixbuf, 0, 0, w, h, -src_x, -src_y, 1, 1, 0, alpha );
640
641 /* draw pixbuf_tmp */
642 vik_viewport_draw_pixbuf ( vvp, vvp->alpha_pixbuf, 0, 0, real_dest_x, real_dest_y, w, h );
643}
644
645void vik_viewport_draw_pixbuf ( VikViewport *vvp, GdkPixbuf *pixbuf, gint src_x, gint src_y,
646 gint dest_x, gint dest_y, gint w, gint h )
647{
648 gdk_draw_pixbuf ( vvp->scr_buffer,
649// GTK_WIDGET(vvp)->style->black_gc,
650NULL,
651 pixbuf,
652 src_x, src_y, dest_x, dest_y, w, h,
653 GDK_RGB_DITHER_NONE, 0, 0 );
654}
655
656void vik_viewport_draw_arc ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2 )
657{
658 gdk_draw_arc ( vvp->scr_buffer, gc, filled, x, y, width, height, angle1, angle2 );
659}
660
661
662void vik_viewport_draw_polygon ( VikViewport *vvp, GdkGC *gc, gboolean filled, GdkPoint *points, gint npoints )
663{
664 gdk_draw_polygon ( vvp->scr_buffer, gc, filled, points, npoints );
665}
666
667VikCoordMode vik_viewport_get_coord_mode ( const VikViewport *vvp )
668{
669 g_assert ( vvp );
670 return vvp->coord_mode;
671}
672
673static void viewport_set_coord_mode ( VikViewport *vvp, VikCoordMode mode )
674{
675 g_return_if_fail ( vvp != NULL );
676 vvp->coord_mode = mode;
677 vik_coord_convert ( &(vvp->center), mode );
678}
679
680/* Thanks GPSDrive */
681static gboolean calcxy_rev(double *lg, double *lt, gint x, gint y, double zero_long, double zero_lat, double pixelfact_x, double pixelfact_y, gint mapSizeX2, gint mapSizeY2 )
682{
683 int px, py;
684 gdouble dif, lat, lon;
685 double Ra = Radius[90+(gint)zero_lat];
686
687 px = (mapSizeX2 - x) * pixelfact_x;
688 py = (-mapSizeY2 + y) * pixelfact_y;
689
690 lat = zero_lat - py / Ra;
691 lat = zero_lat - py / Ra;
692 lon =
693 zero_long -
694 px / (Ra *
695 cos (lat * DEG2RAD));
696
697 dif = lat * (1 - (cos ((fabs (lon - zero_long)) * DEG2RAD)));
698 lat = lat - dif / 1.5;
699 lon =
700 zero_long -
701 px / (Ra *
702 cos (lat * DEG2RAD));
703
704 *lt = lat;
705 *lg = lon;
706 return (TRUE);
707}
708
709/* Thanks GPSDrive */
710static gboolean calcxy(double *x, double *y, double lg, double lt, double zero_long, double zero_lat, double pixelfact_x, double pixelfact_y, gint mapSizeX2, gint mapSizeY2 )
711{
712 double dif;
713 double Ra;
714 gint mapSizeX = 2 * mapSizeX2;
715 gint mapSizeY = 2 * mapSizeY2;
716
717 g_assert ( lt >= -90.0 && lt <= 90.0 );
718// lg *= rad2deg; // FIXME, optimize equations
719// lt *= rad2deg;
720 Ra = Radius[90+(gint)lt];
721 *x = Ra *
722 cos (lt*DEG2RAD) * (lg - zero_long);
723 *y = Ra * (lt - zero_lat);
724 dif = Ra * RAD2DEG * (1 - (cos ((DEG2RAD * (lg - zero_long)))));
725 *y = *y + dif / 1.85;
726 *x = *x / pixelfact_x;
727 *y = *y / pixelfact_y;
728 *x = mapSizeX2 - *x;
729 *y += mapSizeY2;
730 if ((*x < 0)||(*x >= mapSizeX)||(*y < 0)||(*y >= mapSizeY))
731 return (FALSE);
732 return (TRUE);
733}
734
735static void viewport_init_ra()
736{
737 static gboolean done_before = FALSE;
738 if ( !done_before )
739 {
740 gint i;
741 for ( i = -90; i <= 90; i++)
742 Radius[i+90] = calcR ( (double)i ) * DEG2RAD;
743 done_before = TRUE;
744 }
745}
746
747double calcR (double lat)
748{
749 double a = 6378.137, r, sc, x, y, z;
750 double e2 = 0.081082 * 0.081082;
751 /*
752 * the radius of curvature of an ellipsoidal Earth in the plane of the
753 * meridian is given by
754 *
755 * R' = a * (1 - e^2) / (1 - e^2 * (sin(lat))^2)^(3/2)
756 *
757 *
758 * where a is the equatorial radius, b is the polar radius, and e is
759 * the eccentricity of the ellipsoid = sqrt(1 - b^2/a^2)
760 *
761 * a = 6378 km (3963 mi) Equatorial radius (surface to center distance)
762 * b = 6356.752 km (3950 mi) Polar radius (surface to center distance) e
763 * = 0.081082 Eccentricity
764 */
765
766 lat = lat * DEG2RAD;
767 sc = sin (lat);
768 x = a * (1.0 - e2);
769 z = 1.0 - e2 * sc * sc;
770 y = pow (z, 1.5);
771 r = x / y;
772 r = r * 1000.0;
773 return r;
774}
775
776gboolean vik_viewport_is_one_zone ( VikViewport *vvp )
777{
778 return vvp->coord_mode == VIK_COORD_UTM && vvp->one_utm_zone;
779}
780
781void vik_viewport_draw_layout ( VikViewport *vvp, GdkGC *gc, gint x, gint y, PangoLayout *layout )
782{
783 if ( x > -100 && x < vvp->width + 100 && y > -100 && y < vvp->height + 100 )
784 gdk_draw_layout ( vvp->scr_buffer, gc, x, y, layout );
785}
786
787void vik_gc_get_fg_color ( GdkGC *gc, GdkColor *dest )
788{
789 static GdkGCValues values;
790 gdk_gc_get_values ( gc, &values );
791 gdk_colormap_query_color ( gdk_colormap_get_system(), values.foreground.pixel, dest );
792}
793
794GdkFunction vik_gc_get_function ( GdkGC *gc )
795{
796 static GdkGCValues values;
797 gdk_gc_get_values ( gc, &values );
798 return values.function;
799}
800
801void vik_viewport_set_drawmode ( VikViewport *vvp, VikViewportDrawMode drawmode )
802{
803 vvp->drawmode = drawmode;
804 if ( drawmode == VIK_VIEWPORT_DRAWMODE_UTM )
805 viewport_set_coord_mode ( vvp, VIK_COORD_UTM );
806 else {
807 viewport_set_coord_mode ( vvp, VIK_COORD_LATLON );
808 if ( drawmode == VIK_VIEWPORT_DRAWMODE_GOOGLE )
809 viewport_google_rezoom ( vvp );
810 }
811}
812
813VikViewportDrawMode vik_viewport_get_drawmode ( VikViewport *vvp )
814{
815 return vvp->drawmode;
816}
817
818static void viewport_google_rezoom ( VikViewport *vvp )
819{
820 vvp->google_calcx_fact = (GOOGLEMAPS_ZOOM_ONE_MPP * 65536.0 * 0.7716245833877 / vvp->xmpp);
821 vvp->google_calcy_fact = (GOOGLEMAPS_ZOOM_ONE_MPP * 65536.0 / vvp->ympp);
822 vvp->google_calcx_rev_fact = 1 / vvp->google_calcx_fact;
823 vvp->google_calcy_rev_fact = 1 / vvp->google_calcy_fact;
824}