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