]> git.street.me.uk Git - andy/viking.git/blame - src/vikcoordlayer.c
Fix mislabelled distance markers when using Nautical Miles.
[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
03c97bc3
RN
89 (VikLayerFuncGetTimestamp) NULL,
90
20c7a3a0
QT
91 (VikLayerFuncSetMenuItemsSelection) NULL,
92 (VikLayerFuncGetMenuItemsSelection) NULL,
93
50a14534
EB
94 (VikLayerFuncAddMenuItems) NULL,
95 (VikLayerFuncSublayerAddMenuItems) NULL,
96
97 (VikLayerFuncSublayerRenameRequest) NULL,
98 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 99 (VikLayerFuncSublayerTooltip) NULL,
1e8b7f57 100 (VikLayerFuncLayerTooltip) NULL,
a5dcfdb7 101 (VikLayerFuncLayerSelected) NULL,
50a14534 102
0a6cab71
AF
103 (VikLayerFuncMarshall) coord_layer_marshall,
104 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
50a14534
EB
105
106 (VikLayerFuncSetParam) coord_layer_set_param,
107 (VikLayerFuncGetParam) coord_layer_get_param,
db43cfa4 108 (VikLayerFuncChangeParam) NULL,
50a14534
EB
109
110 (VikLayerFuncReadFileData) NULL,
111 (VikLayerFuncWriteFileData) NULL,
112
33534cd8 113 (VikLayerFuncDeleteItem) NULL,
d5874ef9 114 (VikLayerFuncCutItem) NULL,
50a14534
EB
115 (VikLayerFuncCopyItem) NULL,
116 (VikLayerFuncPasteItem) NULL,
117 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 118 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
119
120 (VikLayerFuncSelectClick) NULL,
08f14055
RN
121 (VikLayerFuncSelectMove) NULL,
122 (VikLayerFuncSelectRelease) NULL,
e46f259a 123 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
124};
125
126struct _VikCoordLayer {
127 VikLayer vl;
128 GdkGC *gc;
129 gdouble deg_inc;
130 guint8 line_thickness;
280e71ab 131 GdkColor color;
50a14534
EB
132};
133
134GType vik_coord_layer_get_type ()
135{
136 static GType vcl_type = 0;
137
138 if (!vcl_type)
139 {
140 static const GTypeInfo vcl_info =
141 {
142 sizeof (VikCoordLayerClass),
143 NULL, /* base_init */
144 NULL, /* base_finalize */
145 NULL, /* class init */
146 NULL, /* class_finalize */
147 NULL, /* class_data */
148 sizeof (VikCoordLayer),
149 0,
150 NULL /* instance init */
151 };
152 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
153 }
154
155 return vcl_type;
156}
157
0a6cab71
AF
158static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
159{
160 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
161}
162
163static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
164{
1809b8f7 165 VikCoordLayer *rv = coord_layer_new ( vvp );
0a6cab71 166 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
1809b8f7 167 coord_layer_update_gc ( rv, vvp );
0a6cab71
AF
168 return rv;
169}
170
280e71ab 171// NB VikViewport can be null as it's not used ATM
158b3642 172gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
173{
174 switch ( id )
175 {
280e71ab 176 case PARAM_COLOR: vcl->color = data.c; break;
50a14534
EB
177 case PARAM_MIN_INC: vcl->deg_inc = data.d / 60.0; break;
178 case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vcl->line_thickness = data.u; break;
9351abc4 179 default: break;
50a14534
EB
180 }
181 return TRUE;
182}
183
158b3642 184static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
50a14534
EB
185{
186 VikLayerParamData rv;
187 switch ( id )
188 {
280e71ab 189 case PARAM_COLOR: rv.c = vcl->color; break;
50a14534
EB
190 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
191 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
9351abc4 192 default: break;
50a14534
EB
193 }
194 return rv;
195}
196
07059501 197static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
50a14534 198{
94933cb8 199 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
50a14534
EB
200 if ( vcl->gc )
201 g_object_unref ( G_OBJECT(vcl->gc) );
202
280e71ab 203 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
204}
205
a7023a1b 206static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
50a14534
EB
207{
208 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
a0c65899 209 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
50a14534 210
a7023a1b 211 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
ac68cea3 212
50a14534 213 vcl->gc = NULL;
a7023a1b 214
50a14534
EB
215 return vcl;
216}
217
8997679e 218static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 219{
80e450c0 220 if ( !vcl->gc ) {
50a14534 221 return;
80e450c0
AF
222 }
223
224 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
225 {
226 VikCoord left, right, left2, right2;
227 gdouble l, r, i, j;
228 gint x1, y1, x2, y2, smod = 1, mmod = 1;
229 gboolean mins = FALSE, secs = FALSE;
280e71ab
RN
230 GdkGC *dgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), vcl->line_thickness);
231 GdkGC *mgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/2, 1));
232 GdkGC *sgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/5, 1));
80e450c0
AF
233
234 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
235 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
236 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
237 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
238
239#define CLINE(gc, c1, c2) { \
240 vik_viewport_coord_to_screen(vp, (c1), &x1, &y1); \
241 vik_viewport_coord_to_screen(vp, (c2), &x2, &y2); \
242 vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
243 }
244
245 l = left.east_west;
246 r = right.east_west;
247 if (60*fabs(l-r) < 4) {
248 secs = TRUE;
249 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
250 }
251 if (fabs(l-r) < 4) {
252 mins = TRUE;
253 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
254 }
255 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
256 if (secs) {
257 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
258 left.east_west = j/3600.0;
259 left2.east_west = j/3600.0;
260 if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
261 }
262 }
263 if (mins) {
264 left.east_west = i/60.0;
265 left2.east_west = i/60.0;
266 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
267 }
268 if ((int)i % 60 == 0) {
269 left.east_west = i/60.0;
270 left2.east_west = i/60.0;
271 CLINE(dgc, &left, &left2);
272 }
273 }
274
275 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
276 l = left2.north_south;
277 r = left.north_south;
278 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
279 if (secs) {
280 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
281 left.north_south = j/3600.0;
282 right.north_south = j/3600.0;
283 if ((int)j % smod == 0) CLINE(sgc, &left, &right);
284 }
285 }
286 if (mins) {
287 left.north_south = i/60.0;
288 right.north_south = i/60.0;
289 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
290 }
291 if ((int)i % 60 == 0) {
292 left.north_south = i/60.0;
293 right.north_south = i/60.0;
294 CLINE(dgc, &left, &right);
295 }
296 }
297#undef CLINE
298 g_object_unref(dgc);
299 g_object_unref(sgc);
300 g_object_unref(mgc);
301 return;
302 }
303
304 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
50a14534
EB
305 {
306 const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
307 gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
308 guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
309 struct LatLon ll, ll2, min, max;
310 double lon;
311 int x1, x2;
312 struct UTM utm;
313
314 utm = *center;
315 utm.northing = center->northing - ( ympp * height / 2 );
316
317 a_coords_utm_to_latlon ( &utm, &ll );
318
319 utm.northing = center->northing + ( ympp * height / 2 );
320
321 a_coords_utm_to_latlon ( &utm, &ll2 );
322
323 {
324 /* find corner coords in lat/lon.
325 start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
326 */
327 struct LatLon topleft, topright, bottomleft, bottomright;
328 struct UTM temp_utm;
329 temp_utm = *center;
330 temp_utm.easting -= (width/2)*xmpp;
331 temp_utm.northing += (height/2)*ympp;
332 a_coords_utm_to_latlon ( &temp_utm, &topleft );
333 temp_utm.easting += (width*xmpp);
334 a_coords_utm_to_latlon ( &temp_utm, &topright );
335 temp_utm.northing -= (height*ympp);
336 a_coords_utm_to_latlon ( &temp_utm, &bottomright );
337 temp_utm.easting -= (width*xmpp);
338 a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
339 min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
340 max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
341 min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
342 max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
343 }
344
5b1d90a5
RN
345 /* Can zoom out more than whole world and so the above can give invalid positions */
346 /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
347 if ( min.lon < -180.0 )
348 min.lon = -180.0;
349 if ( max.lon > 180.0 )
350 max.lon = 180.0;
351 if ( min.lat < -90.0 )
352 min.lat = -90.0;
353 if ( max.lat > 90.0 )
354 max.lat = 90.0;
355
50a14534
EB
356 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
357 ll.lon = ll2.lon = lon;
358
359 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
360 {
361 a_coords_latlon_to_utm ( &ll, &utm );
362 x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
363 a_coords_latlon_to_utm ( &ll2, &utm );
364 x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
365 vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
366 }
367
368 utm = *center;
369 utm.easting = center->easting - ( xmpp * width / 2 );
370
371 a_coords_utm_to_latlon ( &utm, &ll );
372
373 utm.easting = center->easting + ( xmpp * width / 2 );
374
375 a_coords_utm_to_latlon ( &utm, &ll2 );
376
377 /* really lat, just reusing a variable */
378 lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
379 ll.lat = ll2.lat = lon;
380
381 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
382 {
383 a_coords_latlon_to_utm ( &ll, &utm );
384 x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
385 a_coords_latlon_to_utm ( &ll2, &utm );
386 x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
387 vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
388 }
389 }
390}
391
8997679e 392static void coord_layer_free ( VikCoordLayer *vcl )
50a14534
EB
393{
394 if ( vcl->gc != NULL )
395 g_object_unref ( G_OBJECT(vcl->gc) );
50a14534
EB
396}
397
280e71ab 398static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
50a14534 399{
50a14534
EB
400 if ( vcl->gc )
401 g_object_unref ( G_OBJECT(vcl->gc) );
402
280e71ab 403 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
50a14534
EB
404}
405
8997679e 406static VikCoordLayer *coord_layer_create ( VikViewport *vp )
50a14534 407{
a7023a1b 408 VikCoordLayer *vcl = coord_layer_new ( vp );
8aff54f2 409 if ( vp )
a7023a1b 410 coord_layer_update_gc ( vcl, vp );
50a14534
EB
411 return vcl;
412}