]> git.street.me.uk Git - andy/viking.git/blame - src/dems.c
Set 'Cancel' default for merge track dialog. User needs to select items first.
[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"
25
26typedef struct {
27 VikDEM *dem;
28 guint ref_count;
29} LoadedDEM;
30
31GHashTable *loaded_dems = NULL;
32/* filename -> DEM */
33
34static void loaded_dem_free ( LoadedDEM *ldem )
35{
36 vik_dem_free ( ldem->dem );
37 g_free ( ldem );
38}
39
40void 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 */
49VikDEM *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
73void 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 */
86VikDEM *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 */
106void 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 */
125void 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
136GList *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
153gint16 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}
55906514
QT
182
183typedef struct {
184 const VikCoord *coord;
5ef1d57e 185 VikDemInterpol method;
55906514
QT
186 gint elev;
187} CoordElev;
188
189static gboolean get_elev_by_coord(gpointer key, LoadedDEM *ldem, CoordElev *ce)
190{
191 VikDEM *dem = ldem->dem;
5ef1d57e 192 gdouble lat, lon;
55906514
QT
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 );
5ef1d57e
QT
197 lat = ll_tmp.lat * 3600;
198 lon = ll_tmp.lon * 3600;
55906514
QT
199 } else if (dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS) {
200 static struct UTM utm_tmp;
5ef1d57e
QT
201 if (utm_tmp.zone != dem->utm_zone)
202 return FALSE;
55906514 203 vik_coord_to_utm (ce->coord, &utm_tmp);
5ef1d57e
QT
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;
55906514 219 }
5ef1d57e 220 return (ce->elev != VIK_DEM_INVALID_ELEVATION);
55906514
QT
221}
222
223/* TODO: keep a (sorted) linked list of DEMs and select the best resolution one */
5ef1d57e 224gint16 a_dems_get_elev_by_coord ( const VikCoord *coord, VikDemInterpol method )
55906514
QT
225{
226 CoordElev ce;
227
228 if (!loaded_dems)
229 return VIK_DEM_INVALID_ELEVATION;
230
231 ce.coord = coord;
5ef1d57e 232 ce.method = method;
55906514
QT
233 ce.elev = VIK_DEM_INVALID_ELEVATION;
234
0654760a 235 if(!g_hash_table_find(loaded_dems, (GHRFunc)get_elev_by_coord, &ce))
55906514
QT
236 return VIK_DEM_INVALID_ELEVATION;
237 return ce.elev;
238}