]> git.street.me.uk Git - andy/viking.git/blame - src/dems.c
gtk_object_sink has been deprecated since gtk version 2.10, use g_object_ref_sink...
[andy/viking.git] / src / dems.c
CommitLineData
032154e2
RN
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2008, Evan Battaglia <gtoevan@gmx.net>
a482007a 5 * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
032154e2
RN
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 */
ad0a8c2d
EB
22#include <glib.h>
23
24#include "dems.h"
29392f59 25#include "background.h"
ad0a8c2d
EB
26
27typedef struct {
28 VikDEM *dem;
29 guint ref_count;
30} LoadedDEM;
31
32GHashTable *loaded_dems = NULL;
33/* filename -> DEM */
34
35static void loaded_dem_free ( LoadedDEM *ldem )
36{
37 vik_dem_free ( ldem->dem );
38 g_free ( ldem );
39}
40
41void a_dems_uninit ()
42{
43 if ( loaded_dems )
44 g_hash_table_destroy ( loaded_dems );
45}
46
47/* To load a dem. if it was already loaded, will simply
48 * reference the one already loaded and return it.
49 */
50VikDEM *a_dems_load(const gchar *filename)
51{
52 LoadedDEM *ldem;
53
54 /* dems init hash table */
55 if ( ! loaded_dems )
56 loaded_dems = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) loaded_dem_free );
57
58 ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
59 if ( ldem ) {
60 ldem->ref_count++;
61 return ldem->dem;
62 } else {
63 VikDEM *dem = vik_dem_new_from_file ( filename );
64 if ( ! dem )
65 return NULL;
66 ldem = g_malloc ( sizeof(LoadedDEM) );
67 ldem->ref_count = 1;
68 ldem->dem = dem;
69 g_hash_table_insert ( loaded_dems, g_strdup(filename), ldem );
70 return dem;
71 }
72}
73
74void a_dems_unref(const gchar *filename)
75{
76 LoadedDEM *ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
29392f59
RN
77 if ( !ldem ) {
78 /* This is fine - probably means the loaded list was aborted / not completed for some reason */
79 return;
80 }
81 ldem->ref_count--;
ad0a8c2d
EB
82 if ( ldem->ref_count == 0 )
83 g_hash_table_remove ( loaded_dems, filename );
84}
85
86/* to get a DEM that was already loaded.
87 * assumes that its in there already,
88 * although it could not be if earlier load failed.
89 */
90VikDEM *a_dems_get(const gchar *filename)
91{
92 LoadedDEM *ldem = g_hash_table_lookup ( loaded_dems, filename );
93 if ( ldem )
94 return ldem->dem;
95 return NULL;
96}
97
98
99/* Load a string list (GList of strings) of dems. You have to use get to at them later.
100 * When updating a list as a parameter, this should be bfore freeing the list so
101 * the same DEMs won't be loaded & unloaded.
102 * Modifies the list to remove DEMs which did not load.
103 */
104
105/* TODO: don't delete them when they don't exist.
106 * we need to warn the user, but we should keep them in the GList.
107 * we need to know that they weren't referenced though when we
108 * do the a_dems_list_free().
109 */
29392f59 110int a_dems_load_list ( GList **dems, gpointer threaddata )
ad0a8c2d
EB
111{
112 GList *iter = *dems;
29392f59
RN
113 guint dem_count = 0;
114 const guint dem_total = g_list_length ( *dems );
ad0a8c2d
EB
115 while ( iter ) {
116 if ( ! a_dems_load((const gchar *) (iter->data)) ) {
117 GList *iter_temp = iter->next;
118 g_free ( iter->data );
119 (*dems) = g_list_remove_link ( (*dems), iter );
120 iter = iter_temp;
121 } else {
122 iter = iter->next;
123 }
29392f59
RN
124 /* When running a thread - inform of progress */
125 if ( threaddata ) {
126 dem_count++;
127 /* NB Progress also detects abort request via the returned value */
128 int result = a_background_thread_progress ( threaddata, ((gdouble)dem_count) / dem_total );
129 if ( result != 0 )
130 return -1; /* Abort thread */
131 }
ad0a8c2d 132 }
29392f59 133 return 0;
ad0a8c2d
EB
134}
135
136/* Takes a string list (GList of strings) of dems (filenames).
137 * Unrefs all the dems (i.e. "unloads" them), then frees the
138 * strings, the frees the list.
139 */
140void a_dems_list_free ( GList *dems )
141{
142 GList *iter = dems;
143 while ( iter ) {
144 a_dems_unref ((const gchar *)iter->data);
145 g_free ( iter->data );
146 iter = iter->next;
147 }
148 g_list_free ( dems );
149}
150
151GList *a_dems_list_copy ( GList *dems )
152{
153 GList *rv = g_list_copy ( dems );
154 GList *iter = rv;
155 while ( iter ) {
156 if ( ! a_dems_load((const gchar *) (iter->data)) ) {
157 GList *iter_temp = iter->next; /* delete link, don't bother strdup'ing and free'ing string */
158 rv = g_list_remove_link ( rv, iter );
159 iter = iter_temp;
160 } else {
161 iter->data = g_strdup((gchar *)iter->data); /* copy the string too. */
162 iter = iter->next;
163 }
164 }
165 return rv;
166}
167
168gint16 a_dems_list_get_elev_by_coord ( GList *dems, const VikCoord *coord )
169{
170 static struct UTM utm_tmp;
171 static struct LatLon ll_tmp;
172 GList *iter = dems;
173 VikDEM *dem;
174 gint elev;
175
176 while ( iter ) {
177 dem = a_dems_get ( (gchar *) iter->data );
178 if ( dem ) {
179 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
180 vik_coord_to_latlon ( coord, &ll_tmp );
181 ll_tmp.lat *= 3600;
182 ll_tmp.lon *= 3600;
183 elev = vik_dem_get_east_north(dem, ll_tmp.lon, ll_tmp.lat);
184 if ( elev != VIK_DEM_INVALID_ELEVATION )
185 return elev;
186 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
187 vik_coord_to_utm ( coord, &utm_tmp );
188 if ( utm_tmp.zone == dem->utm_zone &&
189 (elev = vik_dem_get_east_north(dem, utm_tmp.easting, utm_tmp.northing)) != VIK_DEM_INVALID_ELEVATION )
190 return elev;
191 }
192 }
193 iter = iter->next;
194 }
195 return VIK_DEM_INVALID_ELEVATION;
196}
55906514
QT
197
198typedef struct {
199 const VikCoord *coord;
5ef1d57e 200 VikDemInterpol method;
55906514
QT
201 gint elev;
202} CoordElev;
203
204static gboolean get_elev_by_coord(gpointer key, LoadedDEM *ldem, CoordElev *ce)
205{
206 VikDEM *dem = ldem->dem;
5ef1d57e 207 gdouble lat, lon;
55906514
QT
208
209 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
210 struct LatLon ll_tmp;
211 vik_coord_to_latlon (ce->coord, &ll_tmp );
5ef1d57e
QT
212 lat = ll_tmp.lat * 3600;
213 lon = ll_tmp.lon * 3600;
55906514
QT
214 } else if (dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS) {
215 static struct UTM utm_tmp;
5ef1d57e
QT
216 if (utm_tmp.zone != dem->utm_zone)
217 return FALSE;
55906514 218 vik_coord_to_utm (ce->coord, &utm_tmp);
5ef1d57e
QT
219 lat = utm_tmp.northing;
220 lon = utm_tmp.easting;
221 } else
222 return FALSE;
223
224 switch (ce->method) {
225 case VIK_DEM_INTERPOL_NONE:
226 ce->elev = vik_dem_get_east_north(dem, lon, lat);
227 break;
228 case VIK_DEM_INTERPOL_SIMPLE:
229 ce->elev = vik_dem_get_simple_interpol(dem, lon, lat);
230 break;
231 case VIK_DEM_INTERPOL_BEST:
232 ce->elev = vik_dem_get_shepard_interpol(dem, lon, lat);
233 break;
55906514 234 }
5ef1d57e 235 return (ce->elev != VIK_DEM_INVALID_ELEVATION);
55906514
QT
236}
237
238/* TODO: keep a (sorted) linked list of DEMs and select the best resolution one */
5ef1d57e 239gint16 a_dems_get_elev_by_coord ( const VikCoord *coord, VikDemInterpol method )
55906514
QT
240{
241 CoordElev ce;
242
243 if (!loaded_dems)
244 return VIK_DEM_INVALID_ELEVATION;
245
246 ce.coord = coord;
5ef1d57e 247 ce.method = method;
55906514
QT
248 ce.elev = VIK_DEM_INVALID_ELEVATION;
249
0654760a 250 if(!g_hash_table_find(loaded_dems, (GHRFunc)get_elev_by_coord, &ce))
55906514
QT
251 return VIK_DEM_INVALID_ELEVATION;
252 return ce.elev;
253}