forked from ghorn/vis-o-mex
-
Notifications
You must be signed in to change notification settings - Fork 0
/
imagery_manager.c
342 lines (285 loc) · 10.6 KB
/
imagery_manager.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
* This file is part of vis-o-mex.
*
* Copyright (C) 2010-2011 Greg Horn <ghorn@stanford.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* imagery_manager.c
* cache satellite imagery from the web for display in visualizer
*/
#include <stdio.h>
#include <Imlib2.h>
#include <inttypes.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include "imagery_manager.h"
#include "imagery_drawer.h"
#include "imagery_prober.h"
#include <ap_types.h>
#define MAX_ZOOM_LEVEL 16 // must be <= 21
#define NUM_SQUARE_RINGS 3
#define NUM_IMAGE_TILES ( 2*(2*NUM_SQUARE_RINGS-1)*(2*NUM_SQUARE_RINGS-1) )
// 2*(2*rings-1)^2: { 1 -> 2, 2 -> 18, 3 -> 50, 4 -> 98}
#define MAX_STRING_LENGTH 3000
#define EARTH_RADIUS 6371000.0
#define MAX_FILENAME_LENGTH 100
// don't compile if trying to draw more than a hard limit of image tiles
// this is here to stay off the blacklist :)
#define MAX_NUM_IMAGE_TILES 50
#if (NUM_IMAGE_TILES > MAX_NUM_IMAGE_TILES)
#error too many layers of tiles requested in imagery_magager.c
#endif
int test_for_blank_image( const uint32_t ix, const uint32_t iy, const uint8_t zoom_level);
int imagery_in_memory(const uint32_t ix, const uint32_t iy, const uint8_t zoom_level);
int imagery_cached( image_tile_t * image_tile);
void load_tile_from_cache(image_tile_t * image_tile);
int imagery_downloading(const uint32_t ix, const uint32_t iy, const uint8_t zoom_level);
void start_tile_download(image_tile_t * image_tile);
void lat_lon_centered_from_ix_iy_zoom( double * lat, double * lon, const uint32_t ix, const uint32_t iy, const uint8_t zoom_level);
void set_tiles();
void ix_iy_from_lat_lon_zoom( uint32_t * ix, uint32_t * iy, const double lat, const double lon, const uint8_t zoom_level);
void set_north_east_bounds_from_ix_iy_zoom( image_tile_t * image_tile);
// the origin according to joby gnss
double lat0 = 0;
double lon0 = 0;
double alt0 = 0;
// the closest indeces to the origin
uint32_t ix0,iy0;
// array of image_tiles
image_tile_t image_tiles[NUM_IMAGE_TILES];
// don't start looking for imagery until we know what imagery to pull
int got_lla_origin = 0;
// highest zoom level where there is still imagery available
int zoom_level;
void
init_imagery()
{
reset_probe( MAX_ZOOM_LEVEL);
// clear all times and assign all texture numbers
for (int k=0; k<NUM_IMAGE_TILES; k++){
image_tiles[k].status = TILE_UNINITIALIZED;
glGenTextures( 1, &(image_tiles[k].texture) );
}
}
void
reset_imagery()
{
reset_probe( MAX_ZOOM_LEVEL );
// clear all tiles from memory
for (int k=0; k<NUM_IMAGE_TILES; k++){
// unallocate memory if allocated
if (image_tiles[k].status == TILE_READY){
imlib_context_set_image(image_tiles[k].image);
imlib_free_image();
}
image_tiles[k].status = TILE_UNINITIALIZED;
}
}
#define EPSILON 1e-8
// get the lat0/lon0/alt0 ned origin from gps
// if the origin changes, re-initialize imagery
void
update_imagery_origin(const gpsPhys_t * const gpsPhys)
{
if (gpsPhys->solution_valid == 0)
return;
double dlat = fabs(lat0 - gpsPhys->lat0);
double dlon = fabs(lon0 - gpsPhys->lon0);
double dalt = fabs(alt0 - gpsPhys->alt0);
double originnorm = sqrt(dlat*dlat + dlon*dlon + dalt*dalt);
if (originnorm > EPSILON) {
lat0 = gpsPhys->lat0;
lon0 = gpsPhys->lon0;
alt0 = gpsPhys->alt0;
printf("gps origin lat0: %.9f, lon0: %.9f, alt0: %.2f\n", lat0, lon0, alt0);
if (got_lla_origin == 1){
printf("gps lla origin changed by %lf (2-norm{rad,rad,m}),"
" re-setting gps lla origin and reallocating tiles\n", originnorm);
}
reset_imagery(MAX_ZOOM_LEVEL);
}
got_lla_origin = 1;
}
// main image handler: probe for best zoom level, then get and draw tiles
void
manage_imagery()
{
// return if we don't know what imagery to get
if (got_lla_origin == 0)
return;
// if zoom level unknown, keep probing
if (zoom_level_known() == 0){
int ret = run_probe(lat0, lon0);
// return if zoom level still unknown
if (ret == -1)
return;
// if zoom level figured out, set zoom level and init tiles
zoom_level = ret;
ix_iy_from_lat_lon_zoom( &ix0, &iy0, lat0, lon0, zoom_level );
printf("Imagery available at zoom level: %d\n", zoom_level);
set_tiles();
}
// if zoom level is know, get/load tiles if they're not already gotten
for ( int k=0; k < NUM_IMAGE_TILES; k++){
get_imagery( &(image_tiles[k]));
draw_tile( &(image_tiles[k]) );
}
// finally, display a message when all tiles are fetched/loaded
for ( int k=0; k < NUM_IMAGE_TILES; k++)
if (image_tiles[k].status != TILE_READY)
return;
static int last_tile_loaded = 0;
if ( last_tile_loaded == 0 ){
last_tile_loaded = 1;
printf("Imagery finished downloading and/or loading from cache.\n"
"%d image tiles loaded at zoom level %d\n", NUM_IMAGE_TILES, zoom_level);
}
}
// figure out which tiles to draw
void
set_tiles()
{
uint32_t ix,iy;
uint32_t ix_list[NUM_IMAGE_TILES];
uint32_t iy_list[NUM_IMAGE_TILES];
int num_tiles = 0;
int dix_min = - 2*NUM_SQUARE_RINGS + 2;
int dix_max = 2*NUM_SQUARE_RINGS - 1;
int diy_min = - NUM_SQUARE_RINGS + 1;
int diy_max = NUM_SQUARE_RINGS - 1;
for ( ix = ix0 + dix_min; ix <= ix0 + dix_max; ix++){
for ( iy = iy0 + diy_min; iy <=iy0 + diy_max; iy++){
ix_list[num_tiles] = ix;
iy_list[num_tiles] = iy;
num_tiles++;
}
}
// now we know which tiles to draw, load this information into the tile array
for (int k=0; k<NUM_IMAGE_TILES; k++)
{
image_tiles[k].status = TILE_UNINITIALIZED;
image_tiles[k].ix = ix_list[k];
image_tiles[k].iy = iy_list[k];
image_tiles[k].zoom_level = zoom_level;
set_north_east_bounds_from_ix_iy_zoom( &(image_tiles[k]) );
}
}
void
get_imagery(image_tile_t * image_tile)
{
// if tile is already in memory, do nothing
if ( image_tile->status == TILE_READY)
return;
// if tile isn't in memory but it is cached, then load it and set status to TILE_READY
if (imagery_cached(image_tile) == 1 ){
load_tile_from_cache( image_tile );
return;
}
// if image is neither in memory nor cached, but it is downloading, do nothing
if ( image_tile->status == TILE_DOWNLOADING )
return;
// if tile is not in memory, cached, or downloading, then download it
printf("start image downloading\n");
start_tile_download( image_tile);
}
// check and see if the image is cached
// if so, change it's status to TILE_UNINITIALIZED (to handle downloading tiles) and return 1
int imagery_cached( image_tile_t * image_tile)
{
char filename[MAX_FILENAME_LENGTH];
filename_of_ix_iy_zoom(filename, image_tile->ix, image_tile->iy, image_tile->zoom_level);
FILE * imagefile;
if ((imagefile = fopen(filename,"r")) == NULL){
return 0;
}
fclose(imagefile);
return 1;
}
void
load_tile_from_cache( image_tile_t * image_tile)
{
char filename[MAX_FILENAME_LENGTH];
filename_of_ix_iy_zoom(filename, image_tile->ix, image_tile->iy, image_tile->zoom_level);
FILE * imagefile;
if ((imagefile = fopen(filename,"r")) == NULL){
printf("this file was supposed to be available but it's not\n");
fclose(imagefile);
exit(1);
}
fclose(imagefile);
if ( ( image_tile->image = imlib_load_image(filename) ) != 0){
image_tile->status = TILE_READY;
setup_texture( image_tile );
} else {
printf("imlib_load_image fail\n");
exit(1);
}
}
void
filename_of_ix_iy_zoom(char * filename, const uint32_t ix, const uint32_t iy, const uint8_t zoom_level)
{
sprintf(filename, "image_cache/satellite_imagery_zoom_%d_ix_%d_iy_%d.png", zoom_level, ix, iy);
}
void
start_tile_download( image_tile_t * image_tile)
{
image_tile->status = TILE_DOWNLOADING;
double lat,lon;
lat_lon_centered_from_ix_iy_zoom( &lat, &lon, image_tile->ix, image_tile->iy, image_tile->zoom_level);
char filename[MAX_FILENAME_LENGTH];
filename_of_ix_iy_zoom( filename, image_tile->ix, image_tile->iy, image_tile->zoom_level );
printf("downloading %s\n", filename);
char system_call[1024];
sprintf(system_call, "sh shake_n_bake.sh 'http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=256x256&maptype=satellite&format=png32&sensor=false' %s &", lat, lon, zoom_level, filename);
system(system_call);
}
void
ix_iy_from_lat_lon_zoom( uint32_t * ix, uint32_t * iy, const double lat, const double lon, const uint8_t zoom_level)
{
*ix = (lat + 90.0) / 180.0 * (1 << zoom_level );
*iy = (lon + 180.0) / 360.0 * (1 << zoom_level );
}
void
lat_lon_centered_from_ix_iy_zoom( double * lat, double * lon, const uint32_t ix, const uint32_t iy, const uint8_t zoom_level)
{
int num_segments = (1 << zoom_level);
double lat_degrees_per_segment = 180.0/num_segments;
*lat = lat_degrees_per_segment*(ix + 0.5) - 90.0;
double lon_degrees_per_segment = 360.0/num_segments;
*lon = lon_degrees_per_segment*(iy + 0.5) - 180.0;
}
void
set_north_east_bounds_from_ix_iy_zoom( image_tile_t * image_tile)
{
double lat_center,lon_center;
lat_lon_centered_from_ix_iy_zoom( &lat_center, &lon_center, image_tile->ix, image_tile->iy, image_tile->zoom_level);
int num_segments = (1 << image_tile->zoom_level);
double lat_degrees_per_segment = 360.0/num_segments;
double lon_degrees_per_segment = 360.0/num_segments;
double lat_min = lat_center - 0.5*lat_degrees_per_segment;
double lat_max = lat_center + 0.5*lat_degrees_per_segment;
double lon_min = lon_center - 0.5*lon_degrees_per_segment;
double lon_max = lon_center + 0.5*lon_degrees_per_segment;
image_tile->x_min = (lat_min - lat0)*M_PI*EARTH_RADIUS/180.0*cos(lat0*M_PI/180.0);
image_tile->x_max = (lat_max - lat0)*M_PI*EARTH_RADIUS/180.0*cos(lat0*M_PI/180.0);
image_tile->y_min = (lon_min - lon0)*M_PI*EARTH_RADIUS/180.0*cos(lat0*M_PI/180.0);
image_tile->y_max = (lon_max - lon0)*M_PI*EARTH_RADIUS/180.0*cos(lat0*M_PI/180.0);
double x_mean = 0.5*(image_tile->x_max + image_tile->x_min);
image_tile->x_max = x_mean + 0.5*(image_tile->y_max - image_tile->y_min);
image_tile->x_min = x_mean - 0.5*(image_tile->y_max - image_tile->y_min);
}