]> git.street.me.uk Git - andy/viking.git/blob - src/vikcoordlayer.c
Fix translatable string with variable argument
[andy/viking.git] / src / vikcoordlayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #include <glib/gi18n.h>
29
30 #include "viking.h"
31 #include "icons/icons.h"
32
33 static VikCoordLayer *coord_layer_new ( VikViewport *vp );
34 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp );
35 static void coord_layer_free ( VikCoordLayer *vcl );
36 static VikCoordLayer *coord_layer_create ( VikViewport *vp );
37 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
38 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
39 static gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
40 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation );
41 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
42 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp );
43
44 static VikLayerParamScale param_scales[] = {
45   { 0.05, 60.0, 0.25, 10 },
46   { 1, 10, 1, 0 },
47 };
48
49 static VikLayerParamData color_default ( void ) {
50   VikLayerParamData data; gdk_color_parse ( "red", &data.c ); return data;
51   // or: return VIK_LPD_COLOR ( 0, 65535, 0, 0 );
52 }
53 static VikLayerParamData min_inc_default ( void ) { return VIK_LPD_DOUBLE ( 1.0 ); }
54 static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 3 ); }
55
56 static VikLayerParam coord_layer_params[] = {
57   { VIK_LAYER_COORD, "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, color_default, NULL, NULL },
58   { VIK_LAYER_COORD, "min_inc", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Minutes Width:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[0], NULL, NULL, min_inc_default, NULL, NULL },
59   { VIK_LAYER_COORD, "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Line Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[1], NULL, NULL, line_thickness_default, NULL, NULL },
60 };
61
62 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
63
64 VikLayerInterface vik_coord_layer_interface = {
65   "Coord",
66   N_("Coordinate"),
67   NULL,
68   &vikcoordlayer_pixbuf,
69
70   NULL,
71   0,
72
73   coord_layer_params,
74   NUM_PARAMS,
75   NULL,
76   0,
77
78   VIK_MENU_ITEM_ALL,
79
80   (VikLayerFuncCreate)                  coord_layer_create,
81   (VikLayerFuncRealize)                 NULL,
82   (VikLayerFuncPostRead)                coord_layer_post_read,
83   (VikLayerFuncFree)                    coord_layer_free,
84
85   (VikLayerFuncProperties)              NULL,
86   (VikLayerFuncDraw)                    coord_layer_draw,
87   (VikLayerFuncChangeCoordMode)         NULL,
88
89   (VikLayerFuncSetMenuItemsSelection)   NULL,
90   (VikLayerFuncGetMenuItemsSelection)   NULL,
91
92   (VikLayerFuncAddMenuItems)            NULL,
93   (VikLayerFuncSublayerAddMenuItems)    NULL,
94
95   (VikLayerFuncSublayerRenameRequest)   NULL,
96   (VikLayerFuncSublayerToggleVisible)   NULL,
97   (VikLayerFuncSublayerTooltip)         NULL,
98   (VikLayerFuncLayerTooltip)            NULL,
99   (VikLayerFuncLayerSelected)           NULL,
100
101   (VikLayerFuncMarshall)                coord_layer_marshall,
102   (VikLayerFuncUnmarshall)              coord_layer_unmarshall,
103
104   (VikLayerFuncSetParam)                coord_layer_set_param,
105   (VikLayerFuncGetParam)                coord_layer_get_param,
106   (VikLayerFuncChangeParam)             NULL,
107
108   (VikLayerFuncReadFileData)            NULL,
109   (VikLayerFuncWriteFileData)           NULL,
110
111   (VikLayerFuncDeleteItem)              NULL,
112   (VikLayerFuncCutItem)                 NULL,
113   (VikLayerFuncCopyItem)                NULL,
114   (VikLayerFuncPasteItem)               NULL,
115   (VikLayerFuncFreeCopiedItem)          NULL,
116   (VikLayerFuncDragDropRequest)         NULL,
117
118   (VikLayerFuncSelectClick)             NULL,
119   (VikLayerFuncSelectMove)              NULL,
120   (VikLayerFuncSelectRelease)           NULL,
121   (VikLayerFuncSelectedViewportMenu)    NULL,
122 };
123
124 struct _VikCoordLayer {
125   VikLayer vl;
126   GdkGC *gc;
127   gdouble deg_inc;
128   guint8 line_thickness;
129   GdkColor color;
130 };
131
132 GType vik_coord_layer_get_type ()
133 {
134   static GType vcl_type = 0;
135
136   if (!vcl_type)
137   {
138     static const GTypeInfo vcl_info =
139     {
140       sizeof (VikCoordLayerClass),
141       NULL, /* base_init */
142       NULL, /* base_finalize */
143       NULL, /* class init */
144       NULL, /* class_finalize */
145       NULL, /* class_data */
146       sizeof (VikCoordLayer),
147       0,
148       NULL /* instance init */
149     };
150     vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
151   }
152
153   return vcl_type;
154 }
155
156 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
157 {
158   vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
159 }
160
161 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
162 {
163   VikCoordLayer *rv = coord_layer_new ( vvp );
164   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
165   coord_layer_update_gc ( rv, vvp );
166   return rv;
167 }
168
169 // NB VikViewport can be null as it's not used ATM
170 gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
171 {
172   switch ( id )
173   {
174     case PARAM_COLOR: vcl->color = data.c; break;
175     case PARAM_MIN_INC: vcl->deg_inc = data.d / 60.0; break;
176     case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vcl->line_thickness = data.u; break;
177   }
178   return TRUE;
179 }
180
181 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
182 {
183   VikLayerParamData rv;
184   switch ( id )
185   {
186     case PARAM_COLOR: rv.c = vcl->color; break;
187     case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
188     case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
189   }
190   return rv;
191 }
192
193 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
194 {
195   VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
196   if ( vcl->gc )
197     g_object_unref ( G_OBJECT(vcl->gc) );
198
199   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
200 }
201
202 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
203 {
204   VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
205   vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
206
207   vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
208
209   vcl->gc = NULL;
210
211   return vcl;
212 }
213
214 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
215 {
216   if ( !vcl->gc ) {
217     return;
218   }
219
220   if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM ) 
221   {
222     VikCoord left, right, left2, right2;
223     gdouble l, r, i, j;
224     gint x1, y1, x2, y2, smod = 1, mmod = 1;
225     gboolean mins = FALSE, secs = FALSE;
226     GdkGC *dgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), vcl->line_thickness);
227     GdkGC *mgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/2, 1));
228     GdkGC *sgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/5, 1));
229
230     vik_viewport_screen_to_coord ( vp, 0, 0, &left );
231     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
232     vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
233     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
234
235 #define CLINE(gc, c1, c2) { \
236           vik_viewport_coord_to_screen(vp, (c1), &x1, &y1);  \
237           vik_viewport_coord_to_screen(vp, (c2), &x2, &y2);  \
238           vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
239         }
240
241     l = left.east_west;
242     r = right.east_west;
243     if (60*fabs(l-r) < 4) {
244       secs = TRUE;
245       smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
246     }
247     if (fabs(l-r) < 4) {
248       mins = TRUE;
249       mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
250     }
251     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
252       if (secs) {
253         for (j=i*60+1; j<(i+1)*60; j+=1.0) {
254           left.east_west = j/3600.0;
255           left2.east_west = j/3600.0;
256           if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
257         }
258       }
259       if (mins) {
260         left.east_west = i/60.0;
261         left2.east_west = i/60.0;
262         if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
263       }
264       if ((int)i % 60 == 0) {
265         left.east_west = i/60.0;
266         left2.east_west = i/60.0;
267         CLINE(dgc, &left, &left2);
268       }
269     }
270
271     vik_viewport_screen_to_coord ( vp, 0, 0, &left );
272     l = left2.north_south;
273     r = left.north_south;
274     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
275       if (secs) {
276         for (j=i*60+1; j<(i+1)*60; j+=1.0) {
277           left.north_south = j/3600.0;
278           right.north_south = j/3600.0;
279           if ((int)j % smod == 0) CLINE(sgc, &left, &right);
280         }
281       }
282       if (mins) {
283         left.north_south = i/60.0;
284         right.north_south = i/60.0;
285         if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
286       }
287       if ((int)i % 60 == 0) {
288         left.north_south = i/60.0;
289         right.north_south = i/60.0;
290         CLINE(dgc, &left, &right);
291       }
292     }
293 #undef CLINE
294     g_object_unref(dgc);
295     g_object_unref(sgc);
296     g_object_unref(mgc);
297     return;
298   }
299
300   if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM ) 
301   {
302     const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
303     gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
304     guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
305     struct LatLon ll, ll2, min, max;
306     double lon;
307     int x1, x2;
308     struct UTM utm;
309
310     utm = *center;
311     utm.northing = center->northing - ( ympp * height / 2 );
312
313     a_coords_utm_to_latlon ( &utm, &ll );
314
315     utm.northing = center->northing + ( ympp * height / 2 );
316
317     a_coords_utm_to_latlon ( &utm, &ll2 );
318
319     {
320       /* find corner coords in lat/lon.
321         start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
322       */
323       struct LatLon topleft, topright, bottomleft, bottomright;
324       struct UTM temp_utm;
325       temp_utm = *center;
326       temp_utm.easting -= (width/2)*xmpp;
327       temp_utm.northing += (height/2)*ympp;
328       a_coords_utm_to_latlon ( &temp_utm, &topleft );
329       temp_utm.easting += (width*xmpp);
330       a_coords_utm_to_latlon ( &temp_utm, &topright );
331       temp_utm.northing -= (height*ympp);
332       a_coords_utm_to_latlon ( &temp_utm, &bottomright );
333       temp_utm.easting -= (width*xmpp);
334       a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
335       min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
336       max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
337       min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
338       max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
339     }
340
341     /* Can zoom out more than whole world and so the above can give invalid positions */
342     /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
343     if ( min.lon < -180.0 )
344       min.lon = -180.0;
345     if ( max.lon > 180.0 )
346       max.lon = 180.0;
347     if ( min.lat < -90.0 )
348       min.lat = -90.0;
349     if ( max.lat > 90.0 )
350       max.lat = 90.0;
351
352     lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
353     ll.lon = ll2.lon = lon;
354
355     for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
356     {
357       a_coords_latlon_to_utm ( &ll, &utm );
358       x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
359       a_coords_latlon_to_utm ( &ll2, &utm );
360       x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
361       vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
362     }
363
364     utm = *center;
365     utm.easting = center->easting - ( xmpp * width / 2 );
366
367     a_coords_utm_to_latlon ( &utm, &ll );
368
369     utm.easting = center->easting + ( xmpp * width / 2 );
370
371     a_coords_utm_to_latlon ( &utm, &ll2 );
372
373     /* really lat, just reusing a variable */
374     lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
375     ll.lat = ll2.lat = lon;
376
377     for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
378     {
379       a_coords_latlon_to_utm ( &ll, &utm );
380       x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
381       a_coords_latlon_to_utm ( &ll2, &utm );
382       x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
383       vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
384     }
385   }
386 }
387
388 static void coord_layer_free ( VikCoordLayer *vcl )
389 {
390   if ( vcl->gc != NULL )
391     g_object_unref ( G_OBJECT(vcl->gc) );
392 }
393
394 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
395 {
396   if ( vcl->gc )
397     g_object_unref ( G_OBJECT(vcl->gc) );
398
399   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
400 }
401
402 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
403 {
404   VikCoordLayer *vcl = coord_layer_new ( vp );
405   if ( vp )
406     coord_layer_update_gc ( vcl, vp );
407   return vcl;
408 }