]> git.street.me.uk Git - andy/viking.git/blob - src/vikcoordlayer.c
Remove now unused alphabetical sort functions as they have been superseded.
[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 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 );
42
43 static VikLayerParamScale param_scales[] = {
44   { 0.05, 60.0, 0.25, 10 },
45   { 1, 10, 1, 0 },
46 };
47
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 );
51 }
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 ); }
54
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 },
57   { VIK_LAYER_COORD, "min_inc", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Minutes Width:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[0], NULL, NULL, min_inc_default },
58   { VIK_LAYER_COORD, "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Line Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[1], NULL, NULL, line_thickness_default },
59 };
60
61 enum { PARAM_COLOR = 0, PARAM_MIN_INC, PARAM_LINE_THICKNESS, NUM_PARAMS };
62
63 VikLayerInterface vik_coord_layer_interface = {
64   "Coord",
65   N_("Coordinate"),
66   NULL,
67   &vikcoordlayer_pixbuf,
68
69   NULL,
70   0,
71
72   coord_layer_params,
73   NUM_PARAMS,
74   NULL,
75   0,
76
77   VIK_MENU_ITEM_ALL,
78
79   (VikLayerFuncCreate)                  coord_layer_create,
80   (VikLayerFuncRealize)                 NULL,
81   (VikLayerFuncPostRead)                coord_layer_post_read,
82   (VikLayerFuncFree)                    coord_layer_free,
83
84   (VikLayerFuncProperties)              NULL,
85   (VikLayerFuncDraw)                    coord_layer_draw,
86   (VikLayerFuncChangeCoordMode)         NULL,
87
88   (VikLayerFuncSetMenuItemsSelection)   NULL,
89   (VikLayerFuncGetMenuItemsSelection)   NULL,
90
91   (VikLayerFuncAddMenuItems)            NULL,
92   (VikLayerFuncSublayerAddMenuItems)    NULL,
93
94   (VikLayerFuncSublayerRenameRequest)   NULL,
95   (VikLayerFuncSublayerToggleVisible)   NULL,
96   (VikLayerFuncSublayerTooltip)         NULL,
97   (VikLayerFuncLayerTooltip)            NULL,
98   (VikLayerFuncLayerSelected)           NULL,
99
100   (VikLayerFuncMarshall)                coord_layer_marshall,
101   (VikLayerFuncUnmarshall)              coord_layer_unmarshall,
102
103   (VikLayerFuncSetParam)                coord_layer_set_param,
104   (VikLayerFuncGetParam)                coord_layer_get_param,
105
106   (VikLayerFuncReadFileData)            NULL,
107   (VikLayerFuncWriteFileData)           NULL,
108
109   (VikLayerFuncDeleteItem)              NULL,
110   (VikLayerFuncCutItem)                 NULL,
111   (VikLayerFuncCopyItem)                NULL,
112   (VikLayerFuncPasteItem)               NULL,
113   (VikLayerFuncFreeCopiedItem)          NULL,
114   (VikLayerFuncDragDropRequest)         NULL,
115
116   (VikLayerFuncSelectClick)             NULL,
117   (VikLayerFuncSelectMove)              NULL,
118   (VikLayerFuncSelectRelease)           NULL,
119   (VikLayerFuncSelectedViewportMenu)    NULL,
120 };
121
122 struct _VikCoordLayer {
123   VikLayer vl;
124   GdkGC *gc;
125   gdouble deg_inc;
126   guint8 line_thickness;
127   GdkColor color;
128 };
129
130 GType vik_coord_layer_get_type ()
131 {
132   static GType vcl_type = 0;
133
134   if (!vcl_type)
135   {
136     static const GTypeInfo vcl_info =
137     {
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),
145       0,
146       NULL /* instance init */
147     };
148     vcl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikCoordLayer", &vcl_info, 0 );
149   }
150
151   return vcl_type;
152 }
153
154 static void coord_layer_marshall( VikCoordLayer *vcl, guint8 **data, gint *len )
155 {
156   vik_layer_marshall_params ( VIK_LAYER(vcl), data, len );
157 }
158
159 static VikCoordLayer *coord_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
160 {
161   VikCoordLayer *rv = coord_layer_new ();
162   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
163   return rv;
164 }
165
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 )
168 {
169   switch ( id )
170   {
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;
174   }
175   return TRUE;
176 }
177
178 static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id, gboolean is_file_operation )
179 {
180   VikLayerParamData rv;
181   switch ( id )
182   {
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;
186   }
187   return rv;
188 }
189
190 static void coord_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
191 {
192   VikCoordLayer *vcl = VIK_COORD_LAYER(vl);
193   if ( vcl->gc )
194     g_object_unref ( G_OBJECT(vcl->gc) );
195
196   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
197 }
198
199 static VikCoordLayer *coord_layer_new ( VikViewport *vvp )
200 {
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 );
203
204   vik_layer_set_defaults ( VIK_LAYER(vcl), vvp );
205
206   vcl->gc = NULL;
207
208   return vcl;
209 }
210
211 static void coord_layer_draw ( VikCoordLayer *vcl, VikViewport *vp )
212 {
213   if ( !vcl->gc ) {
214     return;
215   }
216
217   if ( vik_viewport_get_coord_mode(vp) != VIK_COORD_UTM ) 
218   {
219     VikCoord left, right, left2, right2;
220     gdouble l, r, i, j;
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));
226
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 );
231
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); \
236         }
237
238     l = left.east_west;
239     r = right.east_west;
240     if (60*fabs(l-r) < 4) {
241       secs = TRUE;
242       smod = MIN(6, (int)ceil(3600*fabs(l-r)/30.0));
243     }
244     if (fabs(l-r) < 4) {
245       mins = TRUE;
246       mmod = MIN(6, (int)ceil(60*fabs(l-r)/30.0));
247     }
248     for (i=floor(l*60); i<ceil(r*60); i+=1.0) {
249       if (secs) {
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);
254         }
255       }
256       if (mins) {
257         left.east_west = i/60.0;
258         left2.east_west = i/60.0;
259         if ((int)i % mmod == 0) CLINE(mgc, &left, &left2);
260       }
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);
265       }
266     }
267
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) {
272       if (secs) {
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);
277         }
278       }
279       if (mins) {
280         left.north_south = i/60.0;
281         right.north_south = i/60.0;
282         if ((int)i % mmod == 0) CLINE(mgc, &left, &right);
283       }
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);
288       }
289     }
290 #undef CLINE
291     g_object_unref(dgc);
292     g_object_unref(sgc);
293     g_object_unref(mgc);
294     return;
295   }
296
297   if ( vik_viewport_get_coord_mode(vp) == VIK_COORD_UTM ) 
298   {
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;
303     double lon;
304     int x1, x2;
305     struct UTM utm;
306
307     utm = *center;
308     utm.northing = center->northing - ( ympp * height / 2 );
309
310     a_coords_utm_to_latlon ( &utm, &ll );
311
312     utm.northing = center->northing + ( ympp * height / 2 );
313
314     a_coords_utm_to_latlon ( &utm, &ll2 );
315
316     {
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
319       */
320       struct LatLon topleft, topright, bottomleft, bottomright;
321       struct UTM temp_utm;
322       temp_utm = *center;
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;
336     }
337
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 )
341       min.lon = -180.0;
342     if ( max.lon > 180.0 )
343       max.lon = 180.0;
344     if ( min.lat < -90.0 )
345       min.lat = -90.0;
346     if ( max.lat > 90.0 )
347       max.lat = 90.0;
348
349     lon = ((double) ((long) ((min.lon)/ vcl->deg_inc))) * vcl->deg_inc;
350     ll.lon = ll2.lon = lon;
351
352     for (; ll.lon <= max.lon; ll.lon+=vcl->deg_inc, ll2.lon+=vcl->deg_inc )
353     {
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);
359     }
360
361     utm = *center;
362     utm.easting = center->easting - ( xmpp * width / 2 );
363
364     a_coords_utm_to_latlon ( &utm, &ll );
365
366     utm.easting = center->easting + ( xmpp * width / 2 );
367
368     a_coords_utm_to_latlon ( &utm, &ll2 );
369
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;
373
374     for (; ll.lat <= max.lat ; ll.lat+=vcl->deg_inc, ll2.lat+=vcl->deg_inc )
375     {
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);
381     }
382   }
383 }
384
385 static void coord_layer_free ( VikCoordLayer *vcl )
386 {
387   if ( vcl->gc != NULL )
388     g_object_unref ( G_OBJECT(vcl->gc) );
389 }
390
391 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp )
392 {
393   if ( vcl->gc )
394     g_object_unref ( G_OBJECT(vcl->gc) );
395
396   vcl->gc = vik_viewport_new_gc_from_color ( vp, &(vcl->color), vcl->line_thickness );
397 }
398
399 static VikCoordLayer *coord_layer_create ( VikViewport *vp )
400 {
401   VikCoordLayer *vcl = coord_layer_new ( vp );
402   if ( vp )
403     coord_layer_update_gc ( vcl, vp );
404   return vcl;
405 }