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 void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len );
34 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
35 static gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
36 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation );
37 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color );
38 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
40 static VikLayerParamScale param_scales[] = {
41 { 0.05, 60.0, 0.25, 10 },
45 static VikLayerParam coord_layer_params[] = {
46 { "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
47 { "min_inc", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Minutes Width:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
48 { "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Line Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 1 },
52 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
54 VikLayerInterface vik_coord_layer_interface = {
58 &vikcoordlayer_pixbuf,
70 (VikLayerFuncCreate) vik_coord_layer_create,
71 (VikLayerFuncRealize) NULL,
72 (VikLayerFuncPostRead) coord_layer_post_read,
73 (VikLayerFuncFree) vik_coord_layer_free,
75 (VikLayerFuncProperties) NULL,
76 (VikLayerFuncDraw) vik_coord_layer_draw,
77 (VikLayerFuncChangeCoordMode) NULL,
79 (VikLayerFuncSetMenuItemsSelection) NULL,
80 (VikLayerFuncGetMenuItemsSelection) NULL,
82 (VikLayerFuncAddMenuItems) NULL,
83 (VikLayerFuncSublayerAddMenuItems) NULL,
85 (VikLayerFuncSublayerRenameRequest) NULL,
86 (VikLayerFuncSublayerToggleVisible) NULL,
87 (VikLayerFuncSublayerTooltip) NULL,
88 (VikLayerFuncLayerTooltip) NULL,
89 (VikLayerFuncLayerSelected) NULL,
91 (VikLayerFuncMarshall) coord_layer_marshall,
92 (VikLayerFuncUnmarshall) coord_layer_unmarshall,
94 (VikLayerFuncSetParam) coord_layer_set_param,
95 (VikLayerFuncGetParam) coord_layer_get_param,
97 (VikLayerFuncReadFileData) NULL,
98 (VikLayerFuncWriteFileData) NULL,
100 (VikLayerFuncDeleteItem) NULL,
101 (VikLayerFuncCutItem) NULL,
102 (VikLayerFuncCopyItem) NULL,
103 (VikLayerFuncPasteItem) NULL,
104 (VikLayerFuncFreeCopiedItem) NULL,
105 (VikLayerFuncDragDropRequest) NULL,
107 (VikLayerFuncSelectClick) NULL,
108 (VikLayerFuncSelectMove) NULL,
109 (VikLayerFuncSelectRelease) NULL,
110 (VikLayerFuncSelectedViewportMenu) NULL,
113 struct _VikCoordLayer {
117 guint8 line_thickness;
121 GType vik_coord_layer_get_type ()
123 static GType vcl_type = 0;
127 static const GTypeInfo vcl_info =
129 sizeof (VikCoordLayerClass),
130 NULL, /* base_init */
131 NULL, /* base_finalize */
132 NULL, /* class init */
133 NULL, /* class_finalize */
134 NULL, /* class_data */
135 sizeof (VikCoordLayer),
137 NULL /* instance init */
139 vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
145 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
147 vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
150 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
152 VikCoordLayer *rv = vik_coord_layer_new ();
153 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
157 gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
161 case PARAM_COLOR: if ( vcl->color ) gdk_color_free ( vcl->color ); vcl->color = gdk_color_copy( &(data.c)); break;
162 case PARAM_MIN_INC: vcl->deg_inc = data.d / 60.0; break;
163 case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vcl->line_thickness = data.u; break;
168 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
170 VikLayerParamData rv;
176 rv.c.pixel = vcl->color->pixel;
177 rv.c.red = vcl->color->red;
178 rv.c.green = vcl->color->green;
179 rv.c.blue = vcl->color->blue;
182 case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
183 case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
188 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
190 VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
192 g_object_unref ( G_OBJECT(vcl->gc) );
194 vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
198 VikCoordLayer *vik_coord_layer_new ( )
202 VikCoordLayer *vcl = VIK_COORD_LAYER ( g_object_new ( VIK_COORD_LAYER_TYPE, NULL ) );
203 vik_layer_set_type ( VIK_LAYER(vcl), VIK_LAYER_COORD );
206 InitColor.red = 65535;
207 InitColor.green = 65535;
208 InitColor.blue = 65535;
211 vcl->deg_inc = 1.0/60.0;
212 vcl->line_thickness = 3;
213 vcl->color = gdk_color_copy (&InitColor);
217 void vik_coord_layer_draw ( VikCoordLayer *vcl, gpointer data )
219 VikViewport *vp = (VikViewport *) data;
225 if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM )
227 VikCoord left, right, left2, right2;
229 gint x1, y1, x2, y2, smod = 1, mmod = 1;
230 gboolean mins = FALSE, secs = FALSE;
231 GdkGC *dgc = vik_viewport_new_gc_from_color(vp, vcl->color, vcl->line_thickness);
232 GdkGC *mgc = vik_viewport_new_gc_from_color(vp, vcl->color, MAX(vcl->line_thickness/2, 1));
233 GdkGC *sgc = vik_viewport_new_gc_from_color(vp, vcl->color, MAX(vcl->line_thickness/5, 1));
235 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
236 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &right );
237 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &left2 );
238 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &right2 );
240 #define CLINE(gc, c1, c2) { \
241 vik_viewport_coord_to_screen(vp, (c1), &x1, &y1); \
242 vik_viewport_coord_to_screen(vp, (c2), &x2, &y2); \
243 vik_viewport_draw_line (vp, (gc), x1, y1, x2, y2); \
248 if (60*fabs(l-r) < 4) {
250 smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
254 mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
256 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
258 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
259 left.east_west = j/3600.0;
260 left2.east_west = j/3600.0;
261 if ((int)j % smod == 0) CLINE(sgc, &left, &left2);
265 left.east_west = i/60.0;
266 left2.east_west = i/60.0;
267 if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
269 if ((int)i % 60 == 0) {
270 left.east_west = i/60.0;
271 left2.east_west = i/60.0;
272 CLINE(dgc, &left, &left2);
276 vik_viewport_screen_to_coord ( vp, 0, 0, &left );
277 l = left2.north_south;
278 r = left.north_south;
279 for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
281 for (j=i*60+1; j<(i+1)*60; j+=1.0) {
282 left.north_south = j/3600.0;
283 right.north_south = j/3600.0;
284 if ((int)j % smod == 0) CLINE(sgc, &left, &right);
288 left.north_south = i/60.0;
289 right.north_south = i/60.0;
290 if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
292 if ((int)i % 60 == 0) {
293 left.north_south = i/60.0;
294 right.north_south = i/60.0;
295 CLINE(dgc, &left, &right);
305 if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM )
307 const struct UTM *center = (const struct UTM *)vik_viewport_get_center ( vp );
308 gdouble xmpp = vik_viewport_get_xmpp ( vp ), ympp = vik_viewport_get_ympp ( vp );
309 guint16 width = vik_viewport_get_width ( vp ), height = vik_viewport_get_height ( vp );
310 struct LatLon ll, ll2, min, max;
316 utm.northing = center->northing - ( ympp * height / 2 );
318 a_coords_utm_to_latlon ( &utm, &ll );
320 utm.northing = center->northing + ( ympp * height / 2 );
322 a_coords_utm_to_latlon ( &utm, &ll2 );
325 /* find corner coords in lat/lon.
326 start at whichever is less: top or bottom left lon. goto whichever more: top or bottom right lon
328 struct LatLon topleft, topright, bottomleft, bottomright;
331 temp_utm.easting -= (width/2)*xmpp;
332 temp_utm.northing += (height/2)*ympp;
333 a_coords_utm_to_latlon ( &temp_utm, &topleft );
334 temp_utm.easting += (width*xmpp);
335 a_coords_utm_to_latlon ( &temp_utm, &topright );
336 temp_utm.northing -= (height*ympp);
337 a_coords_utm_to_latlon ( &temp_utm, &bottomright );
338 temp_utm.easting -= (width*xmpp);
339 a_coords_utm_to_latlon ( &temp_utm, &bottomleft );
340 min.lon = (topleft.lon < bottomleft.lon) ? topleft.lon : bottomleft.lon;
341 max.lon = (topright.lon > bottomright.lon) ? topright.lon : bottomright.lon;
342 min.lat = (bottomleft.lat < bottomright.lat) ? bottomleft.lat : bottomright.lat;
343 max.lat = (topleft.lat > topright.lat) ? topleft.lat : topright.lat;
346 /* Can zoom out more than whole world and so the above can give invalid positions */
347 /* Restrict values properly so drawing doesn't go into a near 'infinite' loop */
348 if ( min.lon < -180.0 )
350 if ( max.lon > 180.0 )
352 if ( min.lat < -90.0 )
354 if ( max.lat > 90.0 )
357 lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
358 ll.lon = ll2.lon = lon;
360 for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
362 a_coords_latlon_to_utm ( &ll, &utm );
363 x1 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
364 a_coords_latlon_to_utm ( &ll2, &utm );
365 x2 = ( (utm.easting - center->easting) / xmpp ) + (width / 2);
366 vik_viewport_draw_line (vp, vcl->gc, x1, height, x2, 0);
370 utm.easting = center->easting - ( xmpp * width / 2 );
372 a_coords_utm_to_latlon ( &utm, &ll );
374 utm.easting = center->easting + ( xmpp * width / 2 );
376 a_coords_utm_to_latlon ( &utm, &ll2 );
378 /* really lat, just reusing a variable */
379 lon = ((double) ((long) ((min.lat)/ vcl->deg_inc))) * vcl->deg_inc;
380 ll.lat = ll2.lat = lon;
382 for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
384 a_coords_latlon_to_utm ( &ll, &utm );
385 x1 = (height / 2) - ( (utm.northing - center->northing) / ympp );
386 a_coords_latlon_to_utm ( &ll2, &utm );
387 x2 = (height / 2) - ( (utm.northing - center->northing) / ympp );
388 vik_viewport_draw_line (vp, vcl->gc, width, x2, 0, x1);
393 void vik_coord_layer_free ( VikCoordLayer *vcl )
395 if ( vcl->gc != NULL )
396 g_object_unref ( G_OBJECT(vcl->gc) );
398 if ( vcl->color != NULL )
399 gdk_color_free ( vcl->color );
402 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color )
407 gdk_color_free ( vcl->color );
409 gdk_color_parse( color, &InitColor);
410 vcl->color = gdk_color_copy( &InitColor );
413 g_object_unref ( G_OBJECT(vcl->gc) );
415 vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
418 VikCoordLayer *vik_coord_layer_create ( VikViewport *vp )
420 VikCoordLayer *vcl = vik_coord_layer_new ();
421 coord_layer_update_gc ( vcl, vp, "red" );