]> git.street.me.uk Git - andy/viking.git/blame - src/vikcoordlayer.c
[QA] Simplify vik_track_steal_and_append_trackpoints()
[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
0a6cab71
AF
33static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
34static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
35static gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
36static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation );
50a14534 37static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color );
07059501 38static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
50a14534 39
ad0a8c2d 40static VikLayerParamScale param_scales[] = {
50a14534
EB
41 { 0.05, 60.0, 0.25, 10 },
42 { 1, 10, 1, 0 },
43};
44
ad0a8c2d 45static VikLayerParam coord_layer_params[] = {
e6994d8d
RN
46 { "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL },
47 { "min_inc", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Minutes Width:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[0], NULL, NULL },
48 { "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Line Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[1], NULL, NULL },
50a14534
EB
49};
50
51
52enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
53
54VikLayerInterface vik_coord_layer_interface = {
db386630 55 "Coord",
affcc0f2 56 N_("Coordinate"),
75078768 57 NULL,
5bfafde9 58 &vikcoordlayer_pixbuf,
50a14534
EB
59
60 NULL,
61 0,
62
63 coord_layer_params,
64 NUM_PARAMS,
65 NULL,
66 0,
67
5a4a28bf
QT
68 VIK_MENU_ITEM_ALL,
69
50a14534
EB
70 (VikLayerFuncCreate) vik_coord_layer_create,
71 (VikLayerFuncRealize) NULL,
b112cbf5 72 (VikLayerFuncPostRead) coord_layer_post_read,
50a14534
EB
73 (VikLayerFuncFree) vik_coord_layer_free,
74
75 (VikLayerFuncProperties) NULL,
76 (VikLayerFuncDraw) vik_coord_layer_draw,
77 (VikLayerFuncChangeCoordMode) NULL,
78
20c7a3a0
QT
79 (VikLayerFuncSetMenuItemsSelection) NULL,
80 (VikLayerFuncGetMenuItemsSelection) NULL,
81
50a14534
EB
82 (VikLayerFuncAddMenuItems) NULL,
83 (VikLayerFuncSublayerAddMenuItems) NULL,
84
85 (VikLayerFuncSublayerRenameRequest) NULL,
86 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 87 (VikLayerFuncSublayerTooltip) NULL,
1e8b7f57 88 (VikLayerFuncLayerTooltip) NULL,
a5dcfdb7 89 (VikLayerFuncLayerSelected) NULL,
50a14534 90
0a6cab71
AF
91 (VikLayerFuncMarshall) coord_layer_marshall,
92 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
50a14534
EB
93
94 (VikLayerFuncSetParam) coord_layer_set_param,
95 (VikLayerFuncGetParam) coord_layer_get_param,
96
97 (VikLayerFuncReadFileData) NULL,
98 (VikLayerFuncWriteFileData) NULL,
99
33534cd8 100 (VikLayerFuncDeleteItem) NULL,
d5874ef9 101 (VikLayerFuncCutItem) NULL,
50a14534
EB
102 (VikLayerFuncCopyItem) NULL,
103 (VikLayerFuncPasteItem) NULL,
104 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 105 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
106
107 (VikLayerFuncSelectClick) NULL,
08f14055
RN
108 (VikLayerFuncSelectMove) NULL,
109 (VikLayerFuncSelectRelease) NULL,
e46f259a 110 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
111};
112
113struct _VikCoordLayer {
114 VikLayer vl;
115 GdkGC *gc;
116 gdouble deg_inc;
117 guint8 line_thickness;
ac68cea3 118 GdkColor *color;
50a14534
EB
119};
120
121GType vik_coord_layer_get_type ()
122{
123 static GType vcl_type = 0;
124
125 if (!vcl_type)
126 {
127 static const GTypeInfo vcl_info =
128 {
129 sizeof (VikCoordLayerClass),
130 NULL, /* base_init */
131 NULL, /* base_finalize */
132 NULL, /* class init */
133 NULL, /* class_finalize */
134 NULL, /* class_data */
135 sizeof (VikCoordLayer),
136 0,
137 NULL /* instance init */
138 };
139 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
140 }
141
142 return vcl_type;
143}
144
0a6cab71
AF
145static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
146{
147 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
148}
149
150static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
151{
c8430548 152 VikCoordLayer *rv = vik_coord_layer_new ();
0a6cab71
AF
153 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
154 return rv;
155}
156
158b3642 157gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
158{
159 switch ( id )
160 {
ac68cea3 161 case PARAM_COLOR: if ( vcl->color ) gdk_color_free ( vcl->color ); vcl->color = gdk_color_copy( &(data.c)); break;
50a14534
EB
162 case PARAM_MIN_INC: vcl->deg_inc = data.d / 60.0; break;
163 case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vcl->line_thickness = data.u; break;
164 }
165 return TRUE;
166}
167
158b3642 168static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
50a14534
EB
169{
170 VikLayerParamData rv;
171 switch ( id )
172 {
ac68cea3
MA
173 case PARAM_COLOR:
174 if (vcl->color)
175 {
176 rv.c.pixel = vcl->color->pixel;
177 rv.c.red = vcl->color->red;
178 rv.c.green = vcl->color->green;
179 rv.c.blue = vcl->color->blue;
180 }
181 break;
50a14534
EB
182 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
183 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
184 }
185 return rv;
186}
187
07059501 188static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
50a14534 189{
94933cb8 190 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
50a14534
EB
191 if ( vcl->gc )
192 g_object_unref ( G_OBJECT(vcl->gc) );
193
ac68cea3
MA
194 vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
195
50a14534
EB
196}
197
198VikCoordLayer *vik_coord_layer_new ( )
199{
ac68cea3
MA
200 GdkColor InitColor;
201
50a14534 202 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
a0c65899 203 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
50a14534 204
ac68cea3 205 InitColor.pixel = 0;
3750ef3e
GB
206 InitColor.red = 65535;
207 InitColor.green = 65535;
208 InitColor.blue = 65535;
ac68cea3 209
50a14534
EB
210 vcl->gc = NULL;
211 vcl->deg_inc = 1.0/60.0;
212 vcl->line_thickness = 3;
ac68cea3 213 vcl->color = gdk_color_copy (&InitColor);
50a14534
EB
214 return vcl;
215}
216
217void vik_coord_layer_draw ( VikCoordLayer *vcl, gpointer data )
218{
219 VikViewport *vp = (VikViewport *) data;
80e450c0
AF
220
221 if ( !vcl->gc ) {
50a14534 222 return;
80e450c0
AF
223 }
224
225 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
226 {
227 VikCoord left, right, left2, right2;
228 gdouble l, r, i, j;
229 gint x1, y1, x2, y2, smod = 1, mmod = 1;
230 gboolean mins = FALSE, secs = FALSE;
ac68cea3
MA
231 GdkGC *dgc = vik_viewport_new_gc_from_color(vp, vcl->color, vcl->line_thickness);
232 GdkGC *mgc = vik_viewport_new_gc_from_color(vp, vcl->color, MAX(vcl->line_thickness/2, 1));
233 GdkGC *sgc = vik_viewport_new_gc_from_color(vp, vcl->color, MAX(vcl->line_thickness/5, 1));
80e450c0
AF
234
235 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
236 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
237 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
238 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
239
240#define CLINE(gc, c1, c2) { \
241 vik_viewport_coord_to_screen(vp, (c1), &x1, &y1); \
242 vik_viewport_coord_to_screen(vp, (c2), &x2, &y2); \
243 vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
244 }
245
246 l = left.east_west;
247 r = right.east_west;
248 if (60*fabs(l-r) < 4) {
249 secs = TRUE;
250 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
251 }
252 if (fabs(l-r) < 4) {
253 mins = TRUE;
254 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
255 }
256 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
257 if (secs) {
258 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
259 left.east_west = j/3600.0;
260 left2.east_west = j/3600.0;
261 if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
262 }
263 }
264 if (mins) {
265 left.east_west = i/60.0;
266 left2.east_west = i/60.0;
267 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
268 }
269 if ((int)i % 60 == 0) {
270 left.east_west = i/60.0;
271 left2.east_west = i/60.0;
272 CLINE(dgc, &left, &left2);
273 }
274 }
275
276 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
277 l = left2.north_south;
278 r = left.north_south;
279 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
280 if (secs) {
281 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
282 left.north_south = j/3600.0;
283 right.north_south = j/3600.0;
284 if ((int)j % smod == 0) CLINE(sgc, &left, &right);
285 }
286 }
287 if (mins) {
288 left.north_south = i/60.0;
289 right.north_south = i/60.0;
290 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
291 }
292 if ((int)i % 60 == 0) {
293 left.north_south = i/60.0;
294 right.north_south = i/60.0;
295 CLINE(dgc, &left, &right);
296 }
297 }
298#undef CLINE
299 g_object_unref(dgc);
300 g_object_unref(sgc);
301 g_object_unref(mgc);
302 return;
303 }
304
305 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
50a14534
EB
306 {
307 const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
308 gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
309 guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
310 struct LatLon ll, ll2, min, max;
311 double lon;
312 int x1, x2;
313 struct UTM utm;
314
315 utm = *center;
316 utm.northing = center->northing - ( ympp * height / 2 );
317
318 a_coords_utm_to_latlon ( &utm, &ll );
319
320 utm.northing = center->northing + ( ympp * height / 2 );
321
322 a_coords_utm_to_latlon ( &utm, &ll2 );
323
324 {
325 /* find corner coords in lat/lon.
326 start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
327 */
328 struct LatLon topleft, topright, bottomleft, bottomright;
329 struct UTM temp_utm;
330 temp_utm = *center;
331 temp_utm.easting -= (width/2)*xmpp;
332 temp_utm.northing += (height/2)*ympp;
333 a_coords_utm_to_latlon ( &temp_utm, &topleft );
334 temp_utm.easting += (width*xmpp);
335 a_coords_utm_to_latlon ( &temp_utm, &topright );
336 temp_utm.northing -= (height*ympp);
337 a_coords_utm_to_latlon ( &temp_utm, &bottomright );
338 temp_utm.easting -= (width*xmpp);
339 a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
340 min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
341 max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
342 min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
343 max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
344 }
345
5b1d90a5
RN
346 /* Can zoom out more than whole world and so the above can give invalid positions */
347 /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
348 if ( min.lon < -180.0 )
349 min.lon = -180.0;
350 if ( max.lon > 180.0 )
351 max.lon = 180.0;
352 if ( min.lat < -90.0 )
353 min.lat = -90.0;
354 if ( max.lat > 90.0 )
355 max.lat = 90.0;
356
50a14534
EB
357 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
358 ll.lon = ll2.lon = lon;
359
360 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
361 {
362 a_coords_latlon_to_utm ( &ll, &utm );
363 x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
364 a_coords_latlon_to_utm ( &ll2, &utm );
365 x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
366 vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
367 }
368
369 utm = *center;
370 utm.easting = center->easting - ( xmpp * width / 2 );
371
372 a_coords_utm_to_latlon ( &utm, &ll );
373
374 utm.easting = center->easting + ( xmpp * width / 2 );
375
376 a_coords_utm_to_latlon ( &utm, &ll2 );
377
378 /* really lat, just reusing a variable */
379 lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
380 ll.lat = ll2.lat = lon;
381
382 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
383 {
384 a_coords_latlon_to_utm ( &ll, &utm );
385 x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
386 a_coords_latlon_to_utm ( &ll2, &utm );
387 x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
388 vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
389 }
390 }
391}
392
393void vik_coord_layer_free ( VikCoordLayer *vcl )
394{
395 if ( vcl->gc != NULL )
396 g_object_unref ( G_OBJECT(vcl->gc) );
397
398 if ( vcl->color != NULL )
ac68cea3 399 gdk_color_free ( vcl->color );
50a14534
EB
400}
401
402static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color )
403{
ac68cea3
MA
404 GdkColor InitColor;
405
50a14534 406 if ( vcl->color )
ac68cea3 407 gdk_color_free ( vcl->color );
50a14534 408
ac68cea3
MA
409 gdk_color_parse( color, &InitColor);
410 vcl->color = gdk_color_copy( &InitColor );
50a14534
EB
411
412 if ( vcl->gc )
413 g_object_unref ( G_OBJECT(vcl->gc) );
414
ac68cea3 415 vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
50a14534
EB
416}
417
418VikCoordLayer *vik_coord_layer_create ( VikViewport *vp )
419{
420 VikCoordLayer *vcl = vik_coord_layer_new ();
421 coord_layer_update_gc ( vcl, vp, "red" );
422 return vcl;
423}
424