2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
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.
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.
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
28 #include <glib/gi18n.h>
31 #include "icons/icons.h"
33 static VikCoordLayer *coord_layer_new ( VikViewport *vp );
34 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp );
35 static void coord_layer_free ( VikCoordLayer *vcl );
36 static VikCoordLayer *coord_layer_create ( VikViewport *vp );
37 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
38 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
39 static gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
40 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation );
41 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
42 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp );
44 static VikLayerParamScale param_scales[] = {
45 { 0.05, 60.0, 0.25, 10 },
49 static 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 );
53 static VikLayerParamData min_inc_default ( void ) { return VIK_LPD_DOUBLE ( 1.0 ); }
54 static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 3 ); }
56 static 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, ¶m_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, ¶m_scales[1], NULL, NULL, line_thickness_default, NULL, NULL },
62 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
64 VikLayerInterface vik_coord_layer_interface = {
68 &vikcoordlayer_pixbuf,
80 (VikLayerFuncCreate) coord_layer_create,
81 (VikLayerFuncRealize) NULL,
82 (VikLayerFuncPostRead) coord_layer_post_read,
83 (VikLayerFuncFree) coord_layer_free,
85 (VikLayerFuncProperties) NULL,
86 (VikLayerFuncDraw) coord_layer_draw,
87 (VikLayerFuncChangeCoordMode) NULL,
89 (VikLayerFuncSetMenuItemsSelection) NULL,
90 (VikLayerFuncGetMenuItemsSelection) NULL,
92 (VikLayerFuncAddMenuItems) NULL,
93 (VikLayerFuncSublayerAddMenuItems) NULL,
95 (VikLayerFuncSublayerRenameRequest) NULL,
96 (VikLayerFuncSublayerToggleVisible) NULL,
97 (VikLayerFuncSublayerTooltip) NULL,
98 (VikLayerFuncLayerTooltip) NULL,
99 (VikLayerFuncLayerSelected) NULL,
101 (VikLayerFuncMarshall) coord_layer_marshall,
102 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
104 (VikLayerFuncSetParam) coord_layer_set_param,
105 (VikLayerFuncGetParam) coord_layer_get_param,
106 (VikLayerFuncChangeParam) NULL,
108 (VikLayerFuncReadFileData) NULL,
109 (VikLayerFuncWriteFileData) NULL,
111 (VikLayerFuncDeleteItem) NULL,
112 (VikLayerFuncCutItem) NULL,
113 (VikLayerFuncCopyItem) NULL,
114 (VikLayerFuncPasteItem) NULL,
115 (VikLayerFuncFreeCopiedItem) NULL,
116 (VikLayerFuncDragDropRequest) NULL,
118 (VikLayerFuncSelectClick) NULL,
119 (VikLayerFuncSelectMove) NULL,
120 (VikLayerFuncSelectRelease) NULL,
121 (VikLayerFuncSelectedViewportMenu) NULL,
124 struct _VikCoordLayer {
128 guint8 line_thickness;
132 GType vik_coord_layer_get_type ()
134 static GType vcl_type = 0;
138 static const GTypeInfo vcl_info =
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),
148 NULL /* instance init */
150 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
156 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
158 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
161 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
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 );
169 // NB VikViewport can be null as it's not used ATM
170 gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
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;
182 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
184 VikLayerParamData rv;
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;
195 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
197 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
199 g_object_unref ( G_OBJECT(vcl->gc) );
201 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
204 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
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 );
209 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
216 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
222 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
224 VikCoord left, right, left2, right2;
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));
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 );
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); \
245 if (60*fabs(l-r) < 4) {
247 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
251 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
253 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
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);
262 left.east_west = i/60.0;
263 left2.east_west = i/60.0;
264 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
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);
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) {
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);
285 left.north_south = i/60.0;
286 right.north_south = i/60.0;
287 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
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);
302 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
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;
313 utm.northing = center->northing - ( ympp * height / 2 );
315 a_coords_utm_to_latlon ( &utm, &ll );
317 utm.northing = center->northing + ( ympp * height / 2 );
319 a_coords_utm_to_latlon ( &utm, &ll2 );
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
325 struct LatLon topleft, topright, bottomleft, bottomright;
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;
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 )
347 if ( max.lon > 180.0 )
349 if ( min.lat < -90.0 )
351 if ( max.lat > 90.0 )
354 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
355 ll.lon = ll2.lon = lon;
357 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
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);
367 utm.easting = center->easting - ( xmpp * width / 2 );
369 a_coords_utm_to_latlon ( &utm, &ll );
371 utm.easting = center->easting + ( xmpp * width / 2 );
373 a_coords_utm_to_latlon ( &utm, &ll2 );
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;
379 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
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);
390 static void coord_layer_free ( VikCoordLayer *vcl )
392 if ( vcl->gc != NULL )
393 g_object_unref ( G_OBJECT(vcl->gc) );
396 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
399 g_object_unref ( G_OBJECT(vcl->gc) );
401 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
404 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
406 VikCoordLayer *vcl = coord_layer_new ( vp );
408 coord_layer_update_gc ( vcl, vp );