2 * Copyright © 2015 Keith Packard <keithp@keithp.com>
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.
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.
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.
18 package org.altusmetrum.altoslib_11;
22 import java.util.concurrent.*;
24 import java.lang.Math;
26 import java.net.URLConnection;
28 public class AltosMapLoader extends Thread implements AltosMapStoreListener {
29 AltosMapLoaderListener listener;
31 double latitude, longitude;
40 int tiles_loaded_layer;
41 int tiles_loaded_total;
47 private static final int MAX_LOADING = 200;
49 private Semaphore loading = new Semaphore(MAX_LOADING);
53 int tile_radius(int zoom) {
54 double delta_lon = AltosMapTransform.lon_from_distance(latitude, radius);
56 AltosMapTransform t = new AltosMapTransform(256, 256, zoom + AltosMap.default_zoom, new AltosLatLon(latitude, longitude));
58 AltosPointDouble center = t.point(new AltosLatLon(latitude, longitude));
59 AltosPointDouble edge = t.point(new AltosLatLon(latitude, longitude + delta_lon));
61 int tile_radius = (int) Math.ceil(Math.abs(center.x - edge.x) / AltosMap.px_size);
66 int tiles_per_layer(int zoom) {
67 int tile_radius = tile_radius(zoom);
68 return (tile_radius * 2 + 1) * (tile_radius * 2 + 1);
71 private boolean do_load() {
72 tiles_this_layer = tiles_per_layer(cur_z);
73 tiles_loaded_layer = 0;
74 listener.debug("tiles_this_layer %d (zoom %d)\n", tiles_this_layer, cur_z);
76 int load_radius = tile_radius(cur_z);
77 int zoom = cur_z + AltosMap.default_zoom;
78 int maptype = cur_type;
79 AltosLatLon load_centre = new AltosLatLon(latitude, longitude);
80 AltosMapTransform transform = new AltosMapTransform(256, 256, zoom, load_centre);
82 AltosPointInt upper_left;
83 AltosPointInt lower_right;
85 AltosPointInt centre = AltosMap.floor(transform.point(load_centre));
87 upper_left = new AltosPointInt(centre.x - load_radius * AltosMap.px_size,
88 centre.y - load_radius * AltosMap.px_size);
89 lower_right = new AltosPointInt(centre.x + load_radius * AltosMap.px_size,
90 centre.y + load_radius * AltosMap.px_size);
93 for (int y = (int) upper_left.y; y <= lower_right.y; y += AltosMap.px_size) {
94 for (int x = (int) upper_left.x; x <= lower_right.x; x += AltosMap.px_size) {
97 } catch (InterruptedException ie) {
100 AltosPointInt point = new AltosPointInt(x, y);
101 AltosLatLon ul = transform.lat_lon(point);
102 AltosLatLon center = transform.lat_lon(new AltosPointDouble(x + AltosMap.px_size/2, y + AltosMap.px_size/2));
103 AltosMapStore store = AltosMapStore.get(center, zoom, maptype, AltosMap.px_size, scale);
104 listener.debug("load state %s url %s\n", AltosMapTile.status_name(store.status()), store.url);
105 store.add_listener(this);
113 private int next_type(int start) {
115 for (next_type = start;
116 next_type <= AltosMap.maptype_terrain && (all_types & (1 << next_type)) == 0;
122 private boolean next_load() {
123 int next_type = next_type(cur_type + 1);
125 if (next_type > AltosMap.maptype_terrain) {
126 if (cur_z == max_z) {
131 next_type = next_type(0);
133 cur_type = next_type;
142 for (int t = AltosMap.maptype_hybrid; t <= AltosMap.maptype_terrain; t++)
143 if ((all_types & (1 << t)) != 0)
146 all_types = (1 << AltosMap.maptype_hybrid);
150 cur_type = next_type(0);
153 for (int z = min_z; z <= max_z; z++)
154 tiles_total += tiles_per_layer(z) * ntype;
156 layers_total = (max_z - min_z + 1) * ntype;
158 tiles_loaded_total = 0;
160 listener.debug("total tiles %d layers %d\n", tiles_total, layers_total);
162 listener.loader_start(tiles_total);
166 } while (next_load());
168 listener.loader_done(tiles_total);
171 public synchronized void notify_store(AltosMapStore store, int status) {
172 boolean do_next = false;
173 if (status == AltosMapTile.fetching)
178 store.remove_listener(this);
180 if (layers_loaded >= layers_total)
183 ++tiles_loaded_total;
184 ++tiles_loaded_layer;
186 listener.debug("AltosMapLoader.notify_store status %d total %d of %d layer %d of %d\n",
187 status, tiles_loaded_total, tiles_total, tiles_loaded_layer, tiles_this_layer);
189 if (tiles_loaded_layer == tiles_this_layer) {
191 listener.debug("%d layers loaded\n", layers_loaded);
195 if (tiles_loaded_total == tiles_total)
196 listener.loader_done(tiles_total);
198 listener.loader_notify(tiles_loaded_total,
199 tiles_total, store.file.toString());
202 public void abort() {
206 public AltosMapLoader(AltosMapLoaderListener listener,
207 double latitude, double longitude, int min_z, int max_z, double radius, int all_types, int scale) {
208 listener.debug("lat %f lon %f min_z %d max_z %d radius %f all_types %d\n",
209 latitude, longitude, min_z, max_z, radius, all_types);
210 this.listener = listener;
211 this.latitude = latitude;
212 this.longitude = longitude;
215 this.radius = radius;
216 this.all_types = all_types;