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, VikLayerSetParam *vlsp );
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 (VikLayerFuncGetTimestamp) NULL,
91 (VikLayerFuncSetMenuItemsSelection) NULL,
92 (VikLayerFuncGetMenuItemsSelection) NULL,
94 (VikLayerFuncAddMenuItems) NULL,
95 (VikLayerFuncSublayerAddMenuItems) NULL,
97 (VikLayerFuncSublayerRenameRequest) NULL,
98 (VikLayerFuncSublayerToggleVisible) NULL,
99 (VikLayerFuncSublayerTooltip) NULL,
100 (VikLayerFuncLayerTooltip) NULL,
101 (VikLayerFuncLayerSelected) NULL,
103 (VikLayerFuncMarshall) coord_layer_marshall,
104 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
106 (VikLayerFuncSetParam) coord_layer_set_param,
107 (VikLayerFuncGetParam) coord_layer_get_param,
108 (VikLayerFuncChangeParam) NULL,
110 (VikLayerFuncReadFileData) NULL,
111 (VikLayerFuncWriteFileData) NULL,
113 (VikLayerFuncDeleteItem) NULL,
114 (VikLayerFuncCutItem) NULL,
115 (VikLayerFuncCopyItem) NULL,
116 (VikLayerFuncPasteItem) NULL,
117 (VikLayerFuncFreeCopiedItem) NULL,
118 (VikLayerFuncDragDropRequest) NULL,
120 (VikLayerFuncSelectClick) NULL,
121 (VikLayerFuncSelectMove) NULL,
122 (VikLayerFuncSelectRelease) NULL,
123 (VikLayerFuncSelectedViewportMenu) NULL,
126 struct _VikCoordLayer {
130 guint8 line_thickness;
134 GType vik_coord_layer_get_type ()
136 static GType vcl_type = 0;
140 static const GTypeInfo vcl_info =
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),
150 NULL /* instance init */
152 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
158 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
160 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
163 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
165 VikCoordLayer *rv = coord_layer_new ( vvp );
166 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
167 coord_layer_update_gc ( rv, vvp );
171 // NB VikViewport can be null as it's not used ATM
172 gboolean coord_layer_set_param ( VikCoordLayer *vcl, VikLayerSetParam *vlsp )
176 case PARAM_COLOR: vcl->color = vlsp->data.c; break;
177 case PARAM_MIN_INC: vcl->deg_inc = vlsp->data.d / 60.0; break;
178 case PARAM_LINE_THICKNESS: if ( vlsp->data.u >= 1 && vlsp->data.u <= 15 ) vcl->line_thickness = vlsp->data.u; break;
184 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
186 VikLayerParamData rv;
189 case PARAM_COLOR: rv.c = vcl->color; break;
190 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
191 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
197 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
199 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
201 g_object_unref ( G_OBJECT(vcl->gc) );
203 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
206 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
208 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
209 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
211 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
218 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
224 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
226 VikCoord left, right, left2, right2;
228 gint x1, y1, x2, y2, smod = 1, mmod = 1;
229 gboolean mins = FALSE, secs = FALSE;
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));
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 );
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); \
247 if (60*fabs(l-r) < 4) {
249 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
253 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
255 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
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);
264 left.east_west = i/60.0;
265 left2.east_west = i/60.0;
266 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
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);
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) {
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);
287 left.north_south = i/60.0;
288 right.north_south = i/60.0;
289 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
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);
304 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
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;
315 utm.northing = center->northing - ( ympp * height / 2 );
317 a_coords_utm_to_latlon ( &utm, &ll );
319 utm.northing = center->northing + ( ympp * height / 2 );
321 a_coords_utm_to_latlon ( &utm, &ll2 );
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
327 struct LatLon topleft, topright, bottomleft, bottomright;
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;
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 )
349 if ( max.lon > 180.0 )
351 if ( min.lat < -90.0 )
353 if ( max.lat > 90.0 )
356 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
357 ll.lon = ll2.lon = lon;
359 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
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);
369 utm.easting = center->easting - ( xmpp * width / 2 );
371 a_coords_utm_to_latlon ( &utm, &ll );
373 utm.easting = center->easting + ( xmpp * width / 2 );
375 a_coords_utm_to_latlon ( &utm, &ll2 );
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;
381 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
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);
392 static void coord_layer_free ( VikCoordLayer *vcl )
394 if ( vcl->gc != NULL )
395 g_object_unref ( G_OBJECT(vcl->gc) );
398 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
401 g_object_unref ( G_OBJECT(vcl->gc) );
403 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
406 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
408 VikCoordLayer *vcl = coord_layer_new ( vp );
410 coord_layer_update_gc ( vcl, vp );