]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/dems.c
Refactoring: retrieve the VikWindow from the VikViewport via its GtkWidget nature
[andy/viking.git] / src / dems.c
... / ...
CommitLineData
1#include <glib.h>
2
3#include "dems.h"
4
5typedef struct {
6 VikDEM *dem;
7 guint ref_count;
8} LoadedDEM;
9
10GHashTable *loaded_dems = NULL;
11/* filename -> DEM */
12
13static void loaded_dem_free ( LoadedDEM *ldem )
14{
15 vik_dem_free ( ldem->dem );
16 g_free ( ldem );
17}
18
19void 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 */
28VikDEM *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
52void 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 */
65VikDEM *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 */
85void 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 */
104void 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
115GList *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
132gint16 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
162typedef struct {
163 const VikCoord *coord;
164 gint elev;
165} CoordElev;
166
167static gboolean get_elev_by_coord(gpointer key, LoadedDEM *ldem, CoordElev *ce)
168{
169 VikDEM *dem = ldem->dem;
170
171 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
172 struct LatLon ll_tmp;
173 vik_coord_to_latlon (ce->coord, &ll_tmp );
174 ll_tmp.lat *= 3600;
175 ll_tmp.lon *= 3600;
176 ce->elev = vik_dem_get_east_north(dem, ll_tmp.lon, ll_tmp.lat);
177 return (ce->elev != VIK_DEM_INVALID_ELEVATION);
178 } else if (dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS) {
179 static struct UTM utm_tmp;
180 vik_coord_to_utm (ce->coord, &utm_tmp);
181 if ( utm_tmp.zone == dem->utm_zone &&
182 (ce->elev = vik_dem_get_east_north(dem, utm_tmp.easting, utm_tmp.northing)) != VIK_DEM_INVALID_ELEVATION )
183 return TRUE;
184 }
185 return FALSE;
186}
187
188/* TODO: keep a (sorted) linked list of DEMs and select the best resolution one */
189gint16 a_dems_get_elev_by_coord ( const VikCoord *coord )
190{
191 CoordElev ce;
192
193 if (!loaded_dems)
194 return VIK_DEM_INVALID_ELEVATION;
195
196 ce.coord = coord;
197 ce.elev = VIK_DEM_INVALID_ELEVATION;
198
199 if(!g_hash_table_find(loaded_dems, get_elev_by_coord, &ce))
200 return VIK_DEM_INVALID_ELEVATION;
201 return ce.elev;
202}