]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/vikcoordlayer.c
Mapnik library needs full filename for the configuration file.
[andy/viking.git] / src / vikcoordlayer.c
... / ...
CommitLineData
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
33static VikCoordLayer *coord_layer_new ( VikViewport *vp );
34static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp );
35static void coord_layer_free ( VikCoordLayer *vcl );
36static VikCoordLayer *coord_layer_create ( VikViewport *vp );
37static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
38static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
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 );
41static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
42static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp );
43
44static VikLayerParamScale param_scales[] = {
45 { 0.05, 60.0, 0.25, 10 },
46 { 1, 10, 1, 0 },
47};
48
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
56static 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
62enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
63
64VikLayerInterface 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
124struct _VikCoordLayer {
125 VikLayer vl;
126 GdkGC *gc;
127 gdouble deg_inc;
128 guint8 line_thickness;
129 GdkColor color;
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
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{
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
170gboolean 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
182static 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
195static 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
204static 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
216static 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
390static void coord_layer_free ( VikCoordLayer *vcl )
391{
392 if ( vcl->gc != NULL )
393 g_object_unref ( G_OBJECT(vcl->gc) );
394}
395
396static 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
404static 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}