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