]> git.street.me.uk Git - andy/viking.git/blob - src/vikcoordlayer.c
Mapnik library needs full filename for the configuration file.
[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     default: break;
178   }
179   return TRUE;
180 }
181
182 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
183 {
184   VikLayerParamData rv;
185   switch ( id )
186   {
187     case PARAM_COLOR: rv.c = vcl->color; break;
188     case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
189     case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
190     default: break;
191   }
192   return rv;
193 }
194
195 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
196 {
197   VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
198   if ( vcl->gc )
199     g_object_unref ( G_OBJECT(vcl->gc) );
200
201   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
202 }
203
204 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
205 {
206   VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
207   vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
208
209   vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
210
211   vcl->gc = NULL;
212
213   return vcl;
214 }
215
216 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
217 {
218   if ( !vcl->gc ) {
219     return;
220   }
221
222   if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM ) 
223   {
224     VikCoord left, right, left2, right2;
225     gdouble l, r, i, j;
226     gint x1, y1, x2, y2, smod = 1, mmod = 1;
227     gboolean mins = FALSE, secs = FALSE;
228     GdkGC *dgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), vcl->line_thickness);
229     GdkGC *mgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/2, 1));
230     GdkGC *sgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/5, 1));
231
232     vik_viewport_screen_to_coord ( vp, 0, 0, &left );
233     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
234     vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
235     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
236
237 #define CLINE(gc, c1, c2) { \
238           vik_viewport_coord_to_screen(vp, (c1), &x1, &y1);  \
239           vik_viewport_coord_to_screen(vp, (c2), &x2, &y2);  \
240           vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
241         }
242
243     l = left.east_west;
244     r = right.east_west;
245     if (60*fabs(l-r) < 4) {
246       secs = TRUE;
247       smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
248     }
249     if (fabs(l-r) < 4) {
250       mins = TRUE;
251       mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
252     }
253     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
254       if (secs) {
255         for (j=i*60+1; j<(i+1)*60; j+=1.0) {
256           left.east_west = j/3600.0;
257           left2.east_west = j/3600.0;
258           if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
259         }
260       }
261       if (mins) {
262         left.east_west = i/60.0;
263         left2.east_west = i/60.0;
264         if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
265       }
266       if ((int)i % 60 == 0) {
267         left.east_west = i/60.0;
268         left2.east_west = i/60.0;
269         CLINE(dgc, &left, &left2);
270       }
271     }
272
273     vik_viewport_screen_to_coord ( vp, 0, 0, &left );
274     l = left2.north_south;
275     r = left.north_south;
276     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
277       if (secs) {
278         for (j=i*60+1; j<(i+1)*60; j+=1.0) {
279           left.north_south = j/3600.0;
280           right.north_south = j/3600.0;
281           if ((int)j % smod == 0) CLINE(sgc, &left, &right);
282         }
283       }
284       if (mins) {
285         left.north_south = i/60.0;
286         right.north_south = i/60.0;
287         if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
288       }
289       if ((int)i % 60 == 0) {
290         left.north_south = i/60.0;
291         right.north_south = i/60.0;
292         CLINE(dgc, &left, &right);
293       }
294     }
295 #undef CLINE
296     g_object_unref(dgc);
297     g_object_unref(sgc);
298     g_object_unref(mgc);
299     return;
300   }
301
302   if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM ) 
303   {
304     const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
305     gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
306     guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
307     struct LatLon ll, ll2, min, max;
308     double lon;
309     int x1, x2;
310     struct UTM utm;
311
312     utm = *center;
313     utm.northing = center->northing - ( ympp * height / 2 );
314
315     a_coords_utm_to_latlon ( &utm, &ll );
316
317     utm.northing = center->northing + ( ympp * height / 2 );
318
319     a_coords_utm_to_latlon ( &utm, &ll2 );
320
321     {
322       /* find corner coords in lat/lon.
323         start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
324       */
325       struct LatLon topleft, topright, bottomleft, bottomright;
326       struct UTM temp_utm;
327       temp_utm = *center;
328       temp_utm.easting -= (width/2)*xmpp;
329       temp_utm.northing += (height/2)*ympp;
330       a_coords_utm_to_latlon ( &temp_utm, &topleft );
331       temp_utm.easting += (width*xmpp);
332       a_coords_utm_to_latlon ( &temp_utm, &topright );
333       temp_utm.northing -= (height*ympp);
334       a_coords_utm_to_latlon ( &temp_utm, &bottomright );
335       temp_utm.easting -= (width*xmpp);
336       a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
337       min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
338       max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
339       min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
340       max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
341     }
342
343     /* Can zoom out more than whole world and so the above can give invalid positions */
344     /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
345     if ( min.lon < -180.0 )
346       min.lon = -180.0;
347     if ( max.lon > 180.0 )
348       max.lon = 180.0;
349     if ( min.lat < -90.0 )
350       min.lat = -90.0;
351     if ( max.lat > 90.0 )
352       max.lat = 90.0;
353
354     lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
355     ll.lon = ll2.lon = lon;
356
357     for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
358     {
359       a_coords_latlon_to_utm ( &ll, &utm );
360       x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
361       a_coords_latlon_to_utm ( &ll2, &utm );
362       x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
363       vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
364     }
365
366     utm = *center;
367     utm.easting = center->easting - ( xmpp * width / 2 );
368
369     a_coords_utm_to_latlon ( &utm, &ll );
370
371     utm.easting = center->easting + ( xmpp * width / 2 );
372
373     a_coords_utm_to_latlon ( &utm, &ll2 );
374
375     /* really lat, just reusing a variable */
376     lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
377     ll.lat = ll2.lat = lon;
378
379     for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
380     {
381       a_coords_latlon_to_utm ( &ll, &utm );
382       x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
383       a_coords_latlon_to_utm ( &ll2, &utm );
384       x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
385       vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
386     }
387   }
388 }
389
390 static void coord_layer_free ( VikCoordLayer *vcl )
391 {
392   if ( vcl->gc != NULL )
393     g_object_unref ( G_OBJECT(vcl->gc) );
394 }
395
396 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
397 {
398   if ( vcl->gc )
399     g_object_unref ( G_OBJECT(vcl->gc) );
400
401   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
402 }
403
404 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
405 {
406   VikCoordLayer *vcl = coord_layer_new ( vp );
407   if ( vp )
408     coord_layer_update_gc ( vcl, vp );
409   return vcl;
410 }