]> git.street.me.uk Git - andy/viking.git/blob - src/dems.c
Merge branch 'i18n-launchpad' into master
[andy/viking.git] / src / dems.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2008, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 #include <glib.h>
23
24 #include "dems.h"
25
26 typedef struct {
27   VikDEM *dem;
28   guint ref_count;
29 } LoadedDEM;
30
31 GHashTable *loaded_dems = NULL;
32 /* filename -> DEM */
33
34 static void loaded_dem_free ( LoadedDEM *ldem )
35 {
36   vik_dem_free ( ldem->dem );
37   g_free ( ldem );
38 }
39
40 void a_dems_uninit ()
41 {
42   if ( loaded_dems )
43     g_hash_table_destroy ( loaded_dems );
44 }
45
46 /* To load a dem. if it was already loaded, will simply
47  * reference the one already loaded and return it.
48  */
49 VikDEM *a_dems_load(const gchar *filename)
50 {
51   LoadedDEM *ldem;
52
53   /* dems init hash table */
54   if ( ! loaded_dems )
55     loaded_dems = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) loaded_dem_free );
56
57   ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
58   if ( ldem ) {
59     ldem->ref_count++;
60     return ldem->dem;
61   } else {
62     VikDEM *dem = vik_dem_new_from_file ( filename );
63     if ( ! dem )
64       return NULL;
65     ldem = g_malloc ( sizeof(LoadedDEM) );
66     ldem->ref_count = 1;
67     ldem->dem = dem;
68     g_hash_table_insert ( loaded_dems, g_strdup(filename), ldem );
69     return dem;
70   }
71 }
72
73 void a_dems_unref(const gchar *filename)
74 {
75   LoadedDEM *ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
76   g_assert ( ldem );
77   ldem->ref_count --;
78   if ( ldem->ref_count == 0 )
79     g_hash_table_remove ( loaded_dems, filename );
80 }
81
82 /* to get a DEM that was already loaded.
83  * assumes that its in there already,
84  * although it could not be if earlier load failed.
85  */
86 VikDEM *a_dems_get(const gchar *filename)
87 {
88   LoadedDEM *ldem = g_hash_table_lookup ( loaded_dems, filename );
89   if ( ldem )
90     return ldem->dem;
91   return NULL;
92 }
93
94
95 /* Load a string list (GList of strings) of dems. You have to use get to at them later.
96  * When updating a list as a parameter, this should be bfore freeing the list so
97  * the same DEMs won't be loaded & unloaded.
98  * Modifies the list to remove DEMs which did not load.
99  */
100
101 /* TODO: don't delete them when they don't exist.
102  * we need to warn the user, but we should keep them in the GList.
103  * we need to know that they weren't referenced though when we
104  * do the a_dems_list_free().
105  */
106 void a_dems_load_list ( GList **dems )
107 {
108   GList *iter = *dems;
109   while ( iter ) {
110     if ( ! a_dems_load((const gchar *) (iter->data)) ) {
111       GList *iter_temp = iter->next;
112       g_free ( iter->data );
113       (*dems) = g_list_remove_link ( (*dems), iter );
114       iter = iter_temp;
115     } else {
116       iter = iter->next;
117     }
118   }
119 }
120
121 /* Takes a string list (GList of strings) of dems (filenames).
122  * Unrefs all the dems (i.e. "unloads" them), then frees the
123  * strings, the frees the list.
124  */
125 void a_dems_list_free ( GList *dems )
126 {
127   GList *iter = dems;
128   while ( iter ) {
129     a_dems_unref ((const gchar *)iter->data);
130     g_free ( iter->data );
131     iter = iter->next;
132   }
133   g_list_free ( dems );
134 }
135
136 GList *a_dems_list_copy ( GList *dems )
137 {
138   GList *rv = g_list_copy ( dems );
139   GList *iter = rv;
140   while ( iter ) {
141     if ( ! a_dems_load((const gchar *) (iter->data)) ) {
142       GList *iter_temp = iter->next; /* delete link, don't bother strdup'ing and free'ing string */
143       rv = g_list_remove_link ( rv, iter );
144       iter = iter_temp;
145     } else {
146       iter->data = g_strdup((gchar *)iter->data); /* copy the string too. */
147       iter = iter->next;
148     }
149   }
150   return rv;
151 }
152
153 gint16 a_dems_list_get_elev_by_coord ( GList *dems, const VikCoord *coord )
154 {
155   static struct UTM utm_tmp;
156   static struct LatLon ll_tmp;
157   GList *iter = dems;
158   VikDEM *dem;
159   gint elev;
160
161   while ( iter ) {
162     dem = a_dems_get ( (gchar *) iter->data );
163     if ( dem ) {
164       if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
165         vik_coord_to_latlon ( coord, &ll_tmp );
166         ll_tmp.lat *= 3600;
167         ll_tmp.lon *= 3600;
168         elev = vik_dem_get_east_north(dem, ll_tmp.lon, ll_tmp.lat);
169         if ( elev != VIK_DEM_INVALID_ELEVATION )
170           return elev;
171       } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
172         vik_coord_to_utm ( coord, &utm_tmp );
173         if ( utm_tmp.zone == dem->utm_zone &&
174              (elev = vik_dem_get_east_north(dem, utm_tmp.easting, utm_tmp.northing)) != VIK_DEM_INVALID_ELEVATION )
175             return elev;
176       }
177     }
178     iter = iter->next;
179   }
180   return VIK_DEM_INVALID_ELEVATION;
181 }
182
183 typedef struct {
184   const VikCoord *coord;
185   VikDemInterpol method;
186   gint elev;
187 } CoordElev;
188
189 static gboolean get_elev_by_coord(gpointer key, LoadedDEM *ldem, CoordElev *ce)
190 {
191   VikDEM *dem = ldem->dem;
192   gdouble lat, lon;
193
194   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
195     struct LatLon ll_tmp;
196     vik_coord_to_latlon (ce->coord, &ll_tmp );
197     lat = ll_tmp.lat * 3600;
198     lon = ll_tmp.lon * 3600;
199   } else if (dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS) {
200     static struct UTM utm_tmp;
201     if (utm_tmp.zone != dem->utm_zone)
202       return FALSE;
203     vik_coord_to_utm (ce->coord, &utm_tmp);
204     lat = utm_tmp.northing;
205     lon = utm_tmp.easting;
206   } else
207     return FALSE;
208
209   switch (ce->method) {
210     case VIK_DEM_INTERPOL_NONE:
211       ce->elev = vik_dem_get_east_north(dem, lon, lat);
212       break;
213     case VIK_DEM_INTERPOL_SIMPLE:
214       ce->elev = vik_dem_get_simple_interpol(dem, lon, lat);
215       break;
216     case VIK_DEM_INTERPOL_BEST:
217       ce->elev = vik_dem_get_shepard_interpol(dem, lon, lat);
218       break;
219   }
220   return (ce->elev != VIK_DEM_INVALID_ELEVATION);
221 }
222
223 /* TODO: keep a (sorted) linked list of DEMs and select the best resolution one */
224 gint16 a_dems_get_elev_by_coord ( const VikCoord *coord, VikDemInterpol method )
225 {
226   CoordElev ce;
227
228   if (!loaded_dems)
229     return VIK_DEM_INVALID_ELEVATION;
230
231   ce.coord = coord;
232   ce.method = method;
233   ce.elev = VIK_DEM_INVALID_ELEVATION;
234
235   if(!g_hash_table_find(loaded_dems, (GHRFunc)get_elev_by_coord, &ce))
236     return VIK_DEM_INVALID_ELEVATION;
237   return ce.elev;
238 }