Update java library versions
[fw/altos] / altoslib / AltosMapLoader.java
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package org.altusmetrum.altoslib_9;
19
20 import java.io.*;
21 import java.util.*;
22 import java.text.*;
23 import java.lang.Math;
24 import java.net.URL;
25 import java.net.URLConnection;
26
27 public class AltosMapLoader implements AltosMapTileListener, AltosMapStoreListener {
28         AltosMapLoaderListener  listener;
29
30         double  latitude, longitude;
31         int     min_z;
32         int     max_z;
33         int     cur_z;
34         int     all_types;
35         int     cur_type;
36         double  radius;
37
38         int     tiles_loaded_layer;
39         int     tiles_loaded_total;
40         int     tiles_this_layer;
41         int     tiles_total;
42         int     layers_total;
43         int     layers_loaded;
44
45         AltosMap        map;
46
47         int tile_radius(int zoom) {
48                 double  delta_lon = AltosMapTransform.lon_from_distance(latitude, radius);
49
50                 AltosMapTransform t = new AltosMapTransform(256, 256, zoom + AltosMap.default_zoom, new AltosLatLon(latitude, longitude));
51
52                 AltosPointDouble        center = t.point(new AltosLatLon(latitude, longitude));
53                 AltosPointDouble        edge = t.point(new AltosLatLon(latitude, longitude + delta_lon));
54
55                 int tile_radius = (int) Math.ceil(Math.abs(center.x - edge.x) / AltosMap.px_size);
56
57                 return tile_radius;
58         }
59
60         int tiles_per_layer(int zoom) {
61                 int     tile_radius = tile_radius(zoom);
62                 return (tile_radius * 2 + 1) * (tile_radius * 2 + 1);
63         }
64
65         public void do_load() {
66                 tiles_this_layer = tiles_per_layer(cur_z);
67                 tiles_loaded_layer = 0;
68                 listener.debug("tiles_this_layer %d (zoom %d)\n", tiles_this_layer, cur_z);
69
70                 int load_radius = tile_radius(cur_z);
71                 int zoom = cur_z + AltosMap.default_zoom;
72                 int maptype = cur_type;
73                 AltosLatLon load_centre = new AltosLatLon(latitude, longitude);
74                 AltosMapTransform transform = new AltosMapTransform(256, 256, zoom, load_centre);
75
76                 map.centre(load_centre);
77
78                 AltosPointInt   upper_left;
79                 AltosPointInt   lower_right;
80
81                 AltosPointInt centre = AltosMap.floor(transform.point(load_centre));
82
83                 upper_left = new AltosPointInt(centre.x - load_radius * AltosMap.px_size,
84                                                centre.y - load_radius * AltosMap.px_size);
85                 lower_right = new AltosPointInt(centre.x + load_radius * AltosMap.px_size,
86                                                 centre.y + load_radius * AltosMap.px_size);
87
88
89                 for (int y = (int) upper_left.y; y <= lower_right.y; y += AltosMap.px_size) {
90                         for (int x = (int) upper_left.x; x <= lower_right.x; x += AltosMap.px_size) {
91                                 listener.debug("Make tile at %d, %d\n", x, y);
92                                 AltosPointInt   point = new AltosPointInt(x, y);
93                                 AltosLatLon     ul = transform.lat_lon(point);
94                                 AltosLatLon     center = transform.lat_lon(new AltosPointDouble(x + AltosMap.px_size/2, y + AltosMap.px_size/2));
95                                 AltosMapTile    tile = map.map_interface.new_tile(this, ul, center, zoom, maptype, AltosMap.px_size);
96                                 tile.add_store_listener(this);
97                                 if (tile.store_status() != AltosMapTile.loading)
98                                         notify_tile(tile, tile.store_status());
99                         }
100                 }
101         }
102
103         public int next_type(int start) {
104                 int next_type;
105                 for (next_type = start;
106                      next_type <= AltosMap.maptype_terrain && (all_types & (1 << next_type)) == 0;
107                      next_type++)
108                         ;
109                 return next_type;
110         }
111
112         public void next_load() {
113                 int next_type = next_type(cur_type + 1);
114
115                 if (next_type > AltosMap.maptype_terrain) {
116                         if (cur_z == max_z) {
117                                 return;
118                         } else {
119                                 cur_z++;
120                         }
121                         next_type = next_type(0);
122                 }
123                 cur_type = next_type;
124                 do_load();
125         }
126
127         private void start_load() {
128
129                 cur_z = min_z;
130                 int ntype = 0;
131
132                 for (int t = AltosMap.maptype_hybrid; t <= AltosMap.maptype_terrain; t++)
133                         if ((all_types & (1 << t)) != 0)
134                                 ntype++;
135                 if (ntype == 0) {
136                         all_types = (1 << AltosMap.maptype_hybrid);
137                         ntype = 1;
138                 }
139
140                 cur_type = next_type(0);
141
142                 for (int z = min_z; z <= max_z; z++)
143                         tiles_total += tiles_per_layer(z);
144
145                 layers_total = (max_z - min_z + 1) * ntype;
146                 layers_loaded = 0;
147                 tiles_loaded_total = 0;
148
149                 listener.debug("total tiles %d\n", tiles_total);
150
151                 listener.loader_start(tiles_total);
152                 do_load();
153         }
154
155         public void load(double latitude, double longitude, int min_z, int max_z, double radius, int all_types) {
156                 listener.debug("lat %f lon %f min_z %d max_z %d radius %f all_types %d\n",
157                                latitude, longitude, min_z, max_z, radius, all_types);
158                 this.latitude = latitude;
159                 this.longitude = longitude;
160                 this.min_z = min_z;
161                 this.max_z = max_z;
162                 this.radius = radius;
163                 this.all_types = all_types;
164                 start_load();
165         }
166
167         public synchronized void notify_store(AltosMapStore store, int status) {
168                 boolean do_next = false;
169                 if (status == AltosMapTile.loading)
170                         return;
171
172                 if (layers_loaded >= layers_total)
173                         return;
174
175                 ++tiles_loaded_total;
176                 ++tiles_loaded_layer;
177                 listener.debug("total %d layer %d\n", tiles_loaded_total, tiles_loaded_layer);
178
179                 if (tiles_loaded_layer == tiles_this_layer) {
180                         ++layers_loaded;
181                         listener.debug("%d layers loaded\n", layers_loaded);
182                         if (layers_loaded == layers_total) {
183                                 listener.loader_done(tiles_total);
184                                 return;
185                         } else {
186                                 do_next = true;
187                         }
188                 }
189                 listener.loader_notify(tiles_loaded_total,
190                                        tiles_total, store.file.toString());
191                 if (do_next)
192                         next_load();
193         }
194
195         public synchronized void notify_tile(AltosMapTile tile, int status) {
196                 notify_store(tile.store, status);
197         }
198
199         public AltosMapCache cache() { return map.cache(); }
200
201         public AltosMapLoader(AltosMap map, AltosMapLoaderListener listener) {
202                 this.map = map;
203                 this.listener = listener;
204         }
205 }