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 ( );
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 );
43 static VikLayerParamScale param_scales[] = {
44 { 0.05, 60.0, 0.25, 10 },
48 static VikLayerParamData color_default ( void ) {
49 VikLayerParamData data; gdk_color_parse ( "red", &data.c ); return data;
50 // or: return VIK_LPD_COLOR ( 0, 65535, 0, 0 );
52 static VikLayerParamData min_inc_default ( void ) { return VIK_LPD_DOUBLE ( 1.0 ); }
53 static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 3 ); }
55 static VikLayerParam coord_layer_params[] = {
56 { 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 },
57 { 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 },
58 { 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 },
61 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
63 VikLayerInterface vik_coord_layer_interface = {
67 &vikcoordlayer_pixbuf,
79 (VikLayerFuncCreate) coord_layer_create,
80 (VikLayerFuncRealize) NULL,
81 (VikLayerFuncPostRead) coord_layer_post_read,
82 (VikLayerFuncFree) coord_layer_free,
84 (VikLayerFuncProperties) NULL,
85 (VikLayerFuncDraw) coord_layer_draw,
86 (VikLayerFuncChangeCoordMode) NULL,
88 (VikLayerFuncSetMenuItemsSelection) NULL,
89 (VikLayerFuncGetMenuItemsSelection) NULL,
91 (VikLayerFuncAddMenuItems) NULL,
92 (VikLayerFuncSublayerAddMenuItems) NULL,
94 (VikLayerFuncSublayerRenameRequest) NULL,
95 (VikLayerFuncSublayerToggleVisible) NULL,
96 (VikLayerFuncSublayerTooltip) NULL,
97 (VikLayerFuncLayerTooltip) NULL,
98 (VikLayerFuncLayerSelected) NULL,
100 (VikLayerFuncMarshall) coord_layer_marshall,
101 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
103 (VikLayerFuncSetParam) coord_layer_set_param,
104 (VikLayerFuncGetParam) coord_layer_get_param,
106 (VikLayerFuncReadFileData) NULL,
107 (VikLayerFuncWriteFileData) NULL,
109 (VikLayerFuncDeleteItem) NULL,
110 (VikLayerFuncCutItem) NULL,
111 (VikLayerFuncCopyItem) NULL,
112 (VikLayerFuncPasteItem) NULL,
113 (VikLayerFuncFreeCopiedItem) NULL,
114 (VikLayerFuncDragDropRequest) NULL,
116 (VikLayerFuncSelectClick) NULL,
117 (VikLayerFuncSelectMove) NULL,
118 (VikLayerFuncSelectRelease) NULL,
119 (VikLayerFuncSelectedViewportMenu) NULL,
122 struct _VikCoordLayer {
126 guint8 line_thickness;
130 GType vik_coord_layer_get_type ()
132 static GType vcl_type = 0;
136 static const GTypeInfo vcl_info =
138 sizeof (VikCoordLayerClass),
139 NULL, /* base_init */
140 NULL, /* base_finalize */
141 NULL, /* class init */
142 NULL, /* class_finalize */
143 NULL, /* class_data */
144 sizeof (VikCoordLayer),
146 NULL /* instance init */
148 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
154 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
156 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
159 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
161 VikCoordLayer *rv = coord_layer_new ();
162 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
166 // NB VikViewport can be null as it's not used ATM
167 gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
171 case PARAM_COLOR: vcl->color = data.c; break;
172 case PARAM_MIN_INC: vcl->deg_inc = data.d / 60.0; break;
173 case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vcl->line_thickness = data.u; break;
178 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
180 VikLayerParamData rv;
183 case PARAM_COLOR: rv.c = vcl->color; break;
184 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
185 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
190 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
192 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
194 g_object_unref ( G_OBJECT(vcl->gc) );
196 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
199 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
201 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
202 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
204 vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
211 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
217 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
219 VikCoord left, right, left2, right2;
221 gint x1, y1, x2, y2, smod = 1, mmod = 1;
222 gboolean mins = FALSE, secs = FALSE;
223 GdkGC *dgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), vcl->line_thickness);
224 GdkGC *mgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/2, 1));
225 GdkGC *sgc = vik_viewport_new_gc_from_color(vp, &(vcl->color), MAX(vcl->line_thickness/5, 1));
227 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
228 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
229 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
230 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
232 #define CLINE(gc, c1, c2) { \
233 vik_viewport_coord_to_screen(vp, (c1), &x1, &y1); \
234 vik_viewport_coord_to_screen(vp, (c2), &x2, &y2); \
235 vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
240 if (60*fabs(l-r) < 4) {
242 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
246 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
248 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
250 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
251 left.east_west = j/3600.0;
252 left2.east_west = j/3600.0;
253 if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
257 left.east_west = i/60.0;
258 left2.east_west = i/60.0;
259 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
261 if ((int)i % 60 == 0) {
262 left.east_west = i/60.0;
263 left2.east_west = i/60.0;
264 CLINE(dgc, &left, &left2);
268 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
269 l = left2.north_south;
270 r = left.north_south;
271 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
273 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
274 left.north_south = j/3600.0;
275 right.north_south = j/3600.0;
276 if ((int)j % smod == 0) CLINE(sgc, &left, &right);
280 left.north_south = i/60.0;
281 right.north_south = i/60.0;
282 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
284 if ((int)i % 60 == 0) {
285 left.north_south = i/60.0;
286 right.north_south = i/60.0;
287 CLINE(dgc, &left, &right);
297 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
299 const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
300 gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
301 guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
302 struct LatLon ll, ll2, min, max;
308 utm.northing = center->northing - ( ympp * height / 2 );
310 a_coords_utm_to_latlon ( &utm, &ll );
312 utm.northing = center->northing + ( ympp * height / 2 );
314 a_coords_utm_to_latlon ( &utm, &ll2 );
317 /* find corner coords in lat/lon.
318 start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
320 struct LatLon topleft, topright, bottomleft, bottomright;
323 temp_utm.easting -= (width/2)*xmpp;
324 temp_utm.northing += (height/2)*ympp;
325 a_coords_utm_to_latlon ( &temp_utm, &topleft );
326 temp_utm.easting += (width*xmpp);
327 a_coords_utm_to_latlon ( &temp_utm, &topright );
328 temp_utm.northing -= (height*ympp);
329 a_coords_utm_to_latlon ( &temp_utm, &bottomright );
330 temp_utm.easting -= (width*xmpp);
331 a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
332 min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
333 max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
334 min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
335 max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
338 /* Can zoom out more than whole world and so the above can give invalid positions */
339 /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
340 if ( min.lon < -180.0 )
342 if ( max.lon > 180.0 )
344 if ( min.lat < -90.0 )
346 if ( max.lat > 90.0 )
349 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
350 ll.lon = ll2.lon = lon;
352 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
354 a_coords_latlon_to_utm ( &ll, &utm );
355 x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
356 a_coords_latlon_to_utm ( &ll2, &utm );
357 x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
358 vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
362 utm.easting = center->easting - ( xmpp * width / 2 );
364 a_coords_utm_to_latlon ( &utm, &ll );
366 utm.easting = center->easting + ( xmpp * width / 2 );
368 a_coords_utm_to_latlon ( &utm, &ll2 );
370 /* really lat, just reusing a variable */
371 lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
372 ll.lat = ll2.lat = lon;
374 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
376 a_coords_latlon_to_utm ( &ll, &utm );
377 x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
378 a_coords_latlon_to_utm ( &ll2, &utm );
379 x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
380 vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
385 static void coord_layer_free ( VikCoordLayer *vcl )
387 if ( vcl->gc != NULL )
388 g_object_unref ( G_OBJECT(vcl->gc) );
391 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
394 g_object_unref ( G_OBJECT(vcl->gc) );
396 vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
399 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
401 VikCoordLayer *vcl = coord_layer_new ( vp );
403 coord_layer_update_gc ( vcl, vp );