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;
181 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
183 VikLayerParamData rv;
186 case PARAM_COLOR: rv.c = vcl->color; break;
187 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
188 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
193 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
195 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
197 g_object_unref ( G_OBJECT(vcl->gc) );
199 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
202 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
204 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
205 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
207 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
214 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
220 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
222 VikCoord left, right, left2, right2;
224 gint x1, y1, x2, y2, smod = 1, mmod = 1;
225 gboolean mins = FALSE, secs = FALSE;
226 GdkGC *dgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), vcl->line_thickness);
227 GdkGC *mgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/2, 1));
228 GdkGC *sgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/5, 1));
230 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
231 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
232 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
233 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
235 #define CLINE(gc, c1, c2) { \
236 vik_viewport_coord_to_screen(vp, (c1), &x1, &y1); \
237 vik_viewport_coord_to_screen(vp, (c2), &x2, &y2); \
238 vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
243 if (60*fabs(l-r) < 4) {
245 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
249 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
251 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
253 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
254 left.east_west = j/3600.0;
255 left2.east_west = j/3600.0;
256 if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
260 left.east_west = i/60.0;
261 left2.east_west = i/60.0;
262 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
264 if ((int)i % 60 == 0) {
265 left.east_west = i/60.0;
266 left2.east_west = i/60.0;
267 CLINE(dgc, &left, &left2);
271 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
272 l = left2.north_south;
273 r = left.north_south;
274 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
276 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
277 left.north_south = j/3600.0;
278 right.north_south = j/3600.0;
279 if ((int)j % smod == 0) CLINE(sgc, &left, &right);
283 left.north_south = i/60.0;
284 right.north_south = i/60.0;
285 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
287 if ((int)i % 60 == 0) {
288 left.north_south = i/60.0;
289 right.north_south = i/60.0;
290 CLINE(dgc, &left, &right);
300 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
302 const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
303 gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
304 guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
305 struct LatLon ll, ll2, min, max;
311 utm.northing = center->northing - ( ympp * height / 2 );
313 a_coords_utm_to_latlon ( &utm, &ll );
315 utm.northing = center->northing + ( ympp * height / 2 );
317 a_coords_utm_to_latlon ( &utm, &ll2 );
320 /* find corner coords in lat/lon.
321 start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
323 struct LatLon topleft, topright, bottomleft, bottomright;
326 temp_utm.easting -= (width/2)*xmpp;
327 temp_utm.northing += (height/2)*ympp;
328 a_coords_utm_to_latlon ( &temp_utm, &topleft );
329 temp_utm.easting += (width*xmpp);
330 a_coords_utm_to_latlon ( &temp_utm, &topright );
331 temp_utm.northing -= (height*ympp);
332 a_coords_utm_to_latlon ( &temp_utm, &bottomright );
333 temp_utm.easting -= (width*xmpp);
334 a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
335 min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
336 max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
337 min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
338 max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
341 /* Can zoom out more than whole world and so the above can give invalid positions */
342 /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
343 if ( min.lon < -180.0 )
345 if ( max.lon > 180.0 )
347 if ( min.lat < -90.0 )
349 if ( max.lat > 90.0 )
352 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
353 ll.lon = ll2.lon = lon;
355 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
357 a_coords_latlon_to_utm ( &ll, &utm );
358 x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
359 a_coords_latlon_to_utm ( &ll2, &utm );
360 x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
361 vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
365 utm.easting = center->easting - ( xmpp * width / 2 );
367 a_coords_utm_to_latlon ( &utm, &ll );
369 utm.easting = center->easting + ( xmpp * width / 2 );
371 a_coords_utm_to_latlon ( &utm, &ll2 );
373 /* really lat, just reusing a variable */
374 lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
375 ll.lat = ll2.lat = lon;
377 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
379 a_coords_latlon_to_utm ( &ll, &utm );
380 x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
381 a_coords_latlon_to_utm ( &ll2, &utm );
382 x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
383 vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
388 static void coord_layer_free ( VikCoordLayer *vcl )
390 if ( vcl->gc != NULL )
391 g_object_unref ( G_OBJECT(vcl->gc) );
394 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
397 g_object_unref ( G_OBJECT(vcl->gc) );
399 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
402 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
404 VikCoordLayer *vcl = coord_layer_new ( vp );
406 coord_layer_update_gc ( vcl, vp );