]> git.street.me.uk Git - andy/viking.git/blame - src/vikcoordlayer.c
Extract a UI module for babel
[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;
177 }
178 return TRUE;
179}
180
158b3642 181static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
50a14534
EB
182{
183 VikLayerParamData rv;
184 switch ( id )
185 {
280e71ab 186 case PARAM_COLOR: rv.c = vcl->color; break;
50a14534
EB
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
07059501 193static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
50a14534 194{
94933cb8 195 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
50a14534
EB
196 if ( vcl->gc )
197 g_object_unref ( G_OBJECT(vcl->gc) );
198
280e71ab 199 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
200}
201
a7023a1b 202static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
50a14534
EB
203{
204 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
a0c65899 205 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
50a14534 206
a7023a1b 207 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
ac68cea3 208
50a14534 209 vcl->gc = NULL;
a7023a1b 210
50a14534
EB
211 return vcl;
212}
213
8997679e 214static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 215{
80e450c0 216 if ( !vcl->gc ) {
50a14534 217 return;
80e450c0
AF
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;
280e71ab
RN
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));
80e450c0
AF
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 )
50a14534
EB
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
5b1d90a5
RN
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
50a14534
EB
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
8997679e 388static void coord_layer_free ( VikCoordLayer *vcl )
50a14534
EB
389{
390 if ( vcl->gc != NULL )
391 g_object_unref ( G_OBJECT(vcl->gc) );
50a14534
EB
392}
393
280e71ab 394static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 395{
50a14534
EB
396 if ( vcl->gc )
397 g_object_unref ( G_OBJECT(vcl->gc) );
398
280e71ab 399 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
400}
401
8997679e 402static VikCoordLayer *coord_layer_create ( VikViewport *vp )
50a14534 403{
a7023a1b 404 VikCoordLayer *vcl = coord_layer_new ( vp );
8aff54f2 405 if ( vp )
a7023a1b 406 coord_layer_update_gc ( vcl, vp );
50a14534
EB
407 return vcl;
408}