]> git.street.me.uk Git - andy/viking.git/blob - src/vikcoordlayer.c
Add method to return the type of Viking data held in the clipboard
[andy/viking.git] / src / vikcoordlayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #include <glib/gi18n.h>
29
30 #include "viking.h"
31 #include "icons/icons.h"
32
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 );
39
40 static VikLayerParamScale param_scales[] = {
41   { 0.05, 60.0, 0.25, 10 },
42   { 1, 10, 1, 0 },
43 };
44
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 },
49 };
50
51
52 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
53
54 VikLayerInterface vik_coord_layer_interface = {
55   "Coord",
56   N_("Coordinate"),
57   NULL,
58   &vikcoordlayer_pixbuf,
59
60   NULL,
61   0,
62
63   coord_layer_params,
64   NUM_PARAMS,
65   NULL,
66   0,
67
68   VIK_MENU_ITEM_ALL,
69
70   (VikLayerFuncCreate)                  vik_coord_layer_create,
71   (VikLayerFuncRealize)                 NULL,
72   (VikLayerFuncPostRead)                coord_layer_post_read,
73   (VikLayerFuncFree)                    vik_coord_layer_free,
74
75   (VikLayerFuncProperties)              NULL,
76   (VikLayerFuncDraw)                    vik_coord_layer_draw,
77   (VikLayerFuncChangeCoordMode)         NULL,
78
79   (VikLayerFuncSetMenuItemsSelection)   NULL,
80   (VikLayerFuncGetMenuItemsSelection)   NULL,
81
82   (VikLayerFuncAddMenuItems)            NULL,
83   (VikLayerFuncSublayerAddMenuItems)    NULL,
84
85   (VikLayerFuncSublayerRenameRequest)   NULL,
86   (VikLayerFuncSublayerToggleVisible)   NULL,
87   (VikLayerFuncSublayerTooltip)         NULL,
88   (VikLayerFuncLayerTooltip)            NULL,
89   (VikLayerFuncLayerSelected)           NULL,
90
91   (VikLayerFuncMarshall)                coord_layer_marshall,
92   (VikLayerFuncUnmarshall)              coord_layer_unmarshall,
93
94   (VikLayerFuncSetParam)                coord_layer_set_param,
95   (VikLayerFuncGetParam)                coord_layer_get_param,
96
97   (VikLayerFuncReadFileData)            NULL,
98   (VikLayerFuncWriteFileData)           NULL,
99
100   (VikLayerFuncDeleteItem)              NULL,
101   (VikLayerFuncCutItem)                 NULL,
102   (VikLayerFuncCopyItem)                NULL,
103   (VikLayerFuncPasteItem)               NULL,
104   (VikLayerFuncFreeCopiedItem)          NULL,
105   (VikLayerFuncDragDropRequest)         NULL,
106
107   (VikLayerFuncSelectClick)             NULL,
108   (VikLayerFuncSelectMove)              NULL,
109   (VikLayerFuncSelectRelease)           NULL,
110   (VikLayerFuncSelectedViewportMenu)    NULL,
111 };
112
113 struct _VikCoordLayer {
114   VikLayer vl;
115   GdkGC *gc;
116   gdouble deg_inc;
117   guint8 line_thickness;
118   GdkColor *color;
119 };
120
121 GType vik_coord_layer_get_type ()
122 {
123   static GType vcl_type = 0;
124
125   if (!vcl_type)
126   {
127     static const GTypeInfo vcl_info =
128     {
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),
136       0,
137       NULL /* instance init */
138     };
139     vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
140   }
141
142   return vcl_type;
143 }
144
145 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
146 {
147   vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
148 }
149
150 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
151 {
152   VikCoordLayer *rv = vik_coord_layer_new ();
153   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
154   return rv;
155 }
156
157 gboolean coord_layer_set_param ( VikCoordLayer *vcl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
158 {
159   switch ( id )
160   {
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;
164   }
165   return TRUE;
166 }
167
168 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
169 {
170   VikLayerParamData rv;
171   switch ( id )
172   {
173     case PARAM_COLOR:
174       if (vcl->color)
175       {
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;
180       }
181       break;
182     case PARAM_MIN_INC: rv.d = vcl->deg_inc * 60.0; break;
183     case PARAM_LINE_THICKNESS: rv.i = vcl->line_thickness; break;
184   }
185   return rv;
186 }
187
188 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
189 {
190   VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
191   if ( vcl->gc )
192     g_object_unref ( G_OBJECT(vcl->gc) );
193
194   vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
195
196 }
197
198 VikCoordLayer *vik_coord_layer_new ( )
199 {
200   GdkColor InitColor;
201   
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 );
204
205   InitColor.pixel = 0;
206   InitColor.red = 65535;
207   InitColor.green = 65535;
208   InitColor.blue = 65535;
209
210   vcl->gc = NULL;
211   vcl->deg_inc = 1.0/60.0;
212   vcl->line_thickness = 3;
213   vcl->color = gdk_color_copy (&InitColor);
214   return vcl;
215 }
216
217 void vik_coord_layer_draw ( VikCoordLayer *vcl, gpointer data )
218 {
219   VikViewport *vp = (VikViewport *) data;
220
221   if ( !vcl->gc ) {
222     return;
223   }
224
225   if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM ) 
226   {
227     VikCoord left, right, left2, right2;
228     gdouble l, r, i, j;
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));
234
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 );
239
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); \
244         }
245
246     l = left.east_west;
247     r = right.east_west;
248     if (60*fabs(l-r) < 4) {
249       secs = TRUE;
250       smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
251     }
252     if (fabs(l-r) < 4) {
253       mins = TRUE;
254       mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
255     }
256     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
257       if (secs) {
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);
262         }
263       }
264       if (mins) {
265         left.east_west = i/60.0;
266         left2.east_west = i/60.0;
267         if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
268       }
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);
273       }
274     }
275
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) {
280       if (secs) {
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);
285         }
286       }
287       if (mins) {
288         left.north_south = i/60.0;
289         right.north_south = i/60.0;
290         if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
291       }
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);
296       }
297     }
298 #undef CLINE
299     g_object_unref(dgc);
300     g_object_unref(sgc);
301     g_object_unref(mgc);
302     return;
303   }
304
305   if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM ) 
306   {
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;
311     double lon;
312     int x1, x2;
313     struct UTM utm;
314
315     utm = *center;
316     utm.northing = center->northing - ( ympp * height / 2 );
317
318     a_coords_utm_to_latlon ( &utm, &ll );
319
320     utm.northing = center->northing + ( ympp * height / 2 );
321
322     a_coords_utm_to_latlon ( &utm, &ll2 );
323
324     {
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
327       */
328       struct LatLon topleft, topright, bottomleft, bottomright;
329       struct UTM temp_utm;
330       temp_utm = *center;
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;
344     }
345
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 )
349       min.lon = -180.0;
350     if ( max.lon > 180.0 )
351       max.lon = 180.0;
352     if ( min.lat < -90.0 )
353       min.lat = -90.0;
354     if ( max.lat > 90.0 )
355       max.lat = 90.0;
356
357     lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
358     ll.lon = ll2.lon = lon;
359
360     for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
361     {
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);
367     }
368
369     utm = *center;
370     utm.easting = center->easting - ( xmpp * width / 2 );
371
372     a_coords_utm_to_latlon ( &utm, &ll );
373
374     utm.easting = center->easting + ( xmpp * width / 2 );
375
376     a_coords_utm_to_latlon ( &utm, &ll2 );
377
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;
381
382     for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
383     {
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);
389     }
390   }
391 }
392
393 void vik_coord_layer_free ( VikCoordLayer *vcl )
394 {
395   if ( vcl->gc != NULL )
396     g_object_unref ( G_OBJECT(vcl->gc) );
397
398   if ( vcl->color != NULL )
399     gdk_color_free ( vcl->color );
400 }
401
402 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color )
403 {
404   GdkColor InitColor;
405   
406   if ( vcl->color )
407     gdk_color_free ( vcl->color );
408
409   gdk_color_parse( color, &InitColor);
410   vcl->color = gdk_color_copy( &InitColor );
411
412   if ( vcl->gc )
413     g_object_unref ( G_OBJECT(vcl->gc) );
414
415   vcl->gc = vik_viewport_new_gc_from_color ( vp, vcl->color, vcl->line_thickness );
416 }
417
418 VikCoordLayer *vik_coord_layer_create ( VikViewport *vp )
419 {
420   VikCoordLayer *vcl = vik_coord_layer_new ();
421   coord_layer_update_gc ( vcl, vp, "red" );
422   return vcl;
423 }
424