]> git.street.me.uk Git - andy/viking.git/blame - src/vikcoordlayer.c
Fix crashing on invoking the Customize Toolbar from the preferences dialog.
[andy/viking.git] / src / vikcoordlayer.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 * 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 */
4c77d5e0
GB
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
8c00358d
GB
24
25#ifdef HAVE_MATH_H
80e450c0 26#include <math.h>
8c00358d 27#endif
4c77d5e0 28#include <glib/gi18n.h>
50a14534
EB
29
30#include "viking.h"
5bfafde9 31#include "icons/icons.h"
50a14534 32
1809b8f7 33static VikCoordLayer *coord_layer_new ( VikViewport *vp );
8997679e
RN
34static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp );
35static void coord_layer_free ( VikCoordLayer *vcl );
36static VikCoordLayer *coord_layer_create ( VikViewport *vp );
0a6cab71
AF
37static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
38static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
39static gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
40static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation );
07059501 41static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
1809b8f7 42static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp );
50a14534 43
ad0a8c2d 44static VikLayerParamScale param_scales[] = {
50a14534
EB
45 { 0.05, 60.0, 0.25, 10 },
46 { 1, 10, 1, 0 },
47};
48
a7023a1b
RN
49static 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}
53static VikLayerParamData min_inc_default ( void ) { return VIK_LPD_DOUBLE ( 1.0 ); }
54static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 3 ); }
55
ad0a8c2d 56static VikLayerParam coord_layer_params[] = {
a87f8fa1
RN
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 },
50a14534
EB
60};
61
50a14534
EB
62enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
63
64VikLayerInterface vik_coord_layer_interface = {
db386630 65 "Coord",
affcc0f2 66 N_("Coordinate"),
75078768 67 NULL,
5bfafde9 68 &vikcoordlayer_pixbuf,
50a14534
EB
69
70 NULL,
71 0,
72
73 coord_layer_params,
74 NUM_PARAMS,
75 NULL,
76 0,
77
5a4a28bf
QT
78 VIK_MENU_ITEM_ALL,
79
8997679e 80 (VikLayerFuncCreate) coord_layer_create,
50a14534 81 (VikLayerFuncRealize) NULL,
b112cbf5 82 (VikLayerFuncPostRead) coord_layer_post_read,
8997679e 83 (VikLayerFuncFree) coord_layer_free,
50a14534
EB
84
85 (VikLayerFuncProperties) NULL,
8997679e 86 (VikLayerFuncDraw) coord_layer_draw,
50a14534
EB
87 (VikLayerFuncChangeCoordMode) NULL,
88
20c7a3a0
QT
89 (VikLayerFuncSetMenuItemsSelection) NULL,
90 (VikLayerFuncGetMenuItemsSelection) NULL,
91
50a14534
EB
92 (VikLayerFuncAddMenuItems) NULL,
93 (VikLayerFuncSublayerAddMenuItems) NULL,
94
95 (VikLayerFuncSublayerRenameRequest) NULL,
96 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 97 (VikLayerFuncSublayerTooltip) NULL,
1e8b7f57 98 (VikLayerFuncLayerTooltip) NULL,
a5dcfdb7 99 (VikLayerFuncLayerSelected) NULL,
50a14534 100
0a6cab71
AF
101 (VikLayerFuncMarshall) coord_layer_marshall,
102 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
50a14534
EB
103
104 (VikLayerFuncSetParam) coord_layer_set_param,
105 (VikLayerFuncGetParam) coord_layer_get_param,
db43cfa4 106 (VikLayerFuncChangeParam) NULL,
50a14534
EB
107
108 (VikLayerFuncReadFileData) NULL,
109 (VikLayerFuncWriteFileData) NULL,
110
33534cd8 111 (VikLayerFuncDeleteItem) NULL,
d5874ef9 112 (VikLayerFuncCutItem) NULL,
50a14534
EB
113 (VikLayerFuncCopyItem) NULL,
114 (VikLayerFuncPasteItem) NULL,
115 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 116 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
117
118 (VikLayerFuncSelectClick) NULL,
08f14055
RN
119 (VikLayerFuncSelectMove) NULL,
120 (VikLayerFuncSelectRelease) NULL,
e46f259a 121 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
122};
123
124struct _VikCoordLayer {
125 VikLayer vl;
126 GdkGC *gc;
127 gdouble deg_inc;
128 guint8 line_thickness;
280e71ab 129 GdkColor color;
50a14534
EB
130};
131
132GType 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
0a6cab71
AF
156static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
157{
158 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
159}
160
161static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
162{
1809b8f7 163 VikCoordLayer *rv = coord_layer_new ( vvp );
0a6cab71 164 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
1809b8f7 165 coord_layer_update_gc ( rv, vvp );
0a6cab71
AF
166 return rv;
167}
168
280e71ab 169// NB VikViewport can be null as it's not used ATM
158b3642 170gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
171{
172 switch ( id )
173 {
280e71ab 174 case PARAM_COLOR: vcl->color = data.c; break;
50a14534
EB
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;
9351abc4 177 default: break;
50a14534
EB
178 }
179 return TRUE;
180}
181
158b3642 182static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
50a14534
EB
183{
184 VikLayerParamData rv;
185 switch ( id )
186 {
280e71ab 187 case PARAM_COLOR: rv.c = vcl->color; break;
50a14534
EB
188 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
189 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
9351abc4 190 default: break;
50a14534
EB
191 }
192 return rv;
193}
194
07059501 195static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
50a14534 196{
94933cb8 197 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
50a14534
EB
198 if ( vcl->gc )
199 g_object_unref ( G_OBJECT(vcl->gc) );
200
280e71ab 201 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
202}
203
a7023a1b 204static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
50a14534
EB
205{
206 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
a0c65899 207 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
50a14534 208
a7023a1b 209 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
ac68cea3 210
50a14534 211 vcl->gc = NULL;
a7023a1b 212
50a14534
EB
213 return vcl;
214}
215
8997679e 216static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 217{
80e450c0 218 if ( !vcl->gc ) {
50a14534 219 return;
80e450c0
AF
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;
280e71ab
RN
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));
80e450c0
AF
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 )
50a14534
EB
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
5b1d90a5
RN
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
50a14534
EB
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
8997679e 390static void coord_layer_free ( VikCoordLayer *vcl )
50a14534
EB
391{
392 if ( vcl->gc != NULL )
393 g_object_unref ( G_OBJECT(vcl->gc) );
50a14534
EB
394}
395
280e71ab 396static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 397{
50a14534
EB
398 if ( vcl->gc )
399 g_object_unref ( G_OBJECT(vcl->gc) );
400
280e71ab 401 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
402}
403
8997679e 404static VikCoordLayer *coord_layer_create ( VikViewport *vp )
50a14534 405{
a7023a1b 406 VikCoordLayer *vcl = coord_layer_new ( vp );
8aff54f2 407 if ( vp )
a7023a1b 408 coord_layer_update_gc ( vcl, vp );
50a14534
EB
409 return vcl;
410}