altos/lisp: Fix uninitialized values in ao_lisp_make_const
[fw/altos] / altoslib / AltosMapLoader.java
index 5db20cf8cbe54fecd7eb0f01e1d323e0dd075328..17e88bf414757411222f4021dde18336421f246f 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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; version 2 of the License.
+ * 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
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_7;
+package org.altusmetrum.altoslib_11;
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.*;
 import java.text.*;
 import java.lang.Math;
 import java.net.URL;
 import java.net.URLConnection;
 
-public class AltosMapLoader implements AltosMapTileListener {
+public class AltosMapLoader extends Thread implements AltosMapStoreListener {
        AltosMapLoaderListener  listener;
 
        double  latitude, longitude;
@@ -33,23 +35,83 @@ public class AltosMapLoader implements AltosMapTileListener {
        int     cur_z;
        int     all_types;
        int     cur_type;
-       int     radius;
+       double  radius;
+       int     scale;
 
-       int     tiles_per_layer;
-       int     tiles_loaded;
+       int     tiles_loaded_layer;
+       int     tiles_loaded_total;
+       int     tiles_this_layer;
+       int     tiles_total;
        int     layers_total;
        int     layers_loaded;
 
-       AltosMap        map;
-       AltosMapCache   cache;
+       private static final int        MAX_LOADING = 200;
 
-       public void do_load() {
-               map.set_zoom(cur_z + AltosMap.default_zoom);
-               map.set_maptype(cur_type);
-               map.set_load_params(latitude, longitude, radius, this);
+       private Semaphore       loading = new Semaphore(MAX_LOADING);
+
+       boolean abort;
+
+       int tile_radius(int zoom) {
+               double  delta_lon = AltosMapTransform.lon_from_distance(latitude, radius);
+
+               AltosMapTransform t = new AltosMapTransform(256, 256, zoom + AltosMap.default_zoom, new AltosLatLon(latitude, longitude));
+
+               AltosPointDouble        center = t.point(new AltosLatLon(latitude, longitude));
+               AltosPointDouble        edge = t.point(new AltosLatLon(latitude, longitude + delta_lon));
+
+               int tile_radius = (int) Math.ceil(Math.abs(center.x - edge.x) / AltosMap.px_size);
+
+               return tile_radius;
+       }
+
+       int tiles_per_layer(int zoom) {
+               int     tile_radius = tile_radius(zoom);
+               return (tile_radius * 2 + 1) * (tile_radius * 2 + 1);
        }
 
-       public int next_type(int start) {
+       private boolean do_load() {
+               tiles_this_layer = tiles_per_layer(cur_z);
+               tiles_loaded_layer = 0;
+               listener.debug("tiles_this_layer %d (zoom %d)\n", tiles_this_layer, cur_z);
+
+               int load_radius = tile_radius(cur_z);
+               int zoom = cur_z + AltosMap.default_zoom;
+               int maptype = cur_type;
+               AltosLatLon load_centre = new AltosLatLon(latitude, longitude);
+               AltosMapTransform transform = new AltosMapTransform(256, 256, zoom, load_centre);
+
+               AltosPointInt   upper_left;
+               AltosPointInt   lower_right;
+
+               AltosPointInt centre = AltosMap.floor(transform.point(load_centre));
+
+               upper_left = new AltosPointInt(centre.x - load_radius * AltosMap.px_size,
+                                              centre.y - load_radius * AltosMap.px_size);
+               lower_right = new AltosPointInt(centre.x + load_radius * AltosMap.px_size,
+                                               centre.y + load_radius * AltosMap.px_size);
+
+
+               for (int y = (int) upper_left.y; y <= lower_right.y; y += AltosMap.px_size) {
+                       for (int x = (int) upper_left.x; x <= lower_right.x; x += AltosMap.px_size) {
+                               try {
+                                       loading.acquire();
+                               } catch (InterruptedException ie) {
+                                       return false;
+                               }
+                               AltosPointInt   point = new AltosPointInt(x, y);
+                               AltosLatLon     ul = transform.lat_lon(point);
+                               AltosLatLon     center = transform.lat_lon(new AltosPointDouble(x + AltosMap.px_size/2, y + AltosMap.px_size/2));
+                               AltosMapStore   store = AltosMapStore.get(center, zoom, maptype, AltosMap.px_size, scale);
+                               listener.debug("load state %s url %s\n", AltosMapTile.status_name(store.status()), store.url);
+                               store.add_listener(this);
+                               if (abort)
+                                       return false;
+                       }
+               }
+               return true;
+       }
+
+       private int next_type(int start) {
                int next_type;
                for (next_type = start;
                     next_type <= AltosMap.maptype_terrain && (all_types & (1 << next_type)) == 0;
@@ -58,22 +120,22 @@ public class AltosMapLoader implements AltosMapTileListener {
                return next_type;
        }
 
-       public void next_load() {
+       private boolean next_load() {
                int next_type = next_type(cur_type + 1);
 
                if (next_type > AltosMap.maptype_terrain) {
                        if (cur_z == max_z) {
-                               return;
+                               return false;
                        } else {
                                cur_z++;
                        }
                        next_type = next_type(0);
                }
                cur_type = next_type;
-               do_load();
+               return true;
        }
 
-       private void start_load() {
+       public void run() {
 
                cur_z = min_z;
                int ntype = 0;
@@ -87,57 +149,74 @@ public class AltosMapLoader implements AltosMapTileListener {
                }
 
                cur_type = next_type(0);
-               tiles_per_layer = (radius * 2 + 1) * (radius * 2 + 1);
+
+               tiles_total = 0;
+               for (int z = min_z; z <= max_z; z++)
+                       tiles_total += tiles_per_layer(z) * ntype;
+
                layers_total = (max_z - min_z + 1) * ntype;
                layers_loaded = 0;
-               tiles_loaded = 0;
+               tiles_loaded_total = 0;
 
-               listener.loader_start(layers_total * tiles_per_layer);
-               do_load();
-       }
+               listener.debug("total tiles %d layers %d\n", tiles_total, layers_total);
 
-       public void load(double latitude, double longitude, int min_z, int max_z, int radius, int all_types) {
-               this.latitude = latitude;
-               this.longitude = longitude;
-               this.min_z = min_z;
-               this.max_z = max_z;
-               this.radius = radius;
-               this.all_types = all_types;
-               start_load();
+               listener.loader_start(tiles_total);
+               do {
+                       if (!do_load())
+                               break;
+               } while (next_load());
+               if (abort)
+                       listener.loader_done(tiles_total);
        }
 
-       public synchronized void notify_tile(AltosMapTile tile, int status) {
+       public synchronized void notify_store(AltosMapStore store, int status) {
                boolean do_next = false;
-               if (status == AltosMapTile.loading)
+               if (status == AltosMapTile.fetching)
                        return;
 
+               loading.release();
+
+               store.remove_listener(this);
+
                if (layers_loaded >= layers_total)
                        return;
 
-               ++tiles_loaded;
+               ++tiles_loaded_total;
+               ++tiles_loaded_layer;
+
+               listener.debug("AltosMapLoader.notify_store status %d total %d of %d layer %d of %d\n",
+                              status, tiles_loaded_total, tiles_total, tiles_loaded_layer, tiles_this_layer);
 
-               if (tiles_loaded == tiles_per_layer) {
-                       tiles_loaded = 0;
+               if (tiles_loaded_layer == tiles_this_layer) {
                        ++layers_loaded;
-                       if (layers_loaded == layers_total) {
-                               listener.loader_done(layers_total * tiles_per_layer);
-                               return;
-                       } else {
-                               do_next = true;
-                       }
+                       listener.debug("%d layers loaded\n", layers_loaded);
+                       do_next = true;
                }
-               listener.loader_notify(layers_loaded * tiles_per_layer + tiles_loaded,
-                                      layers_total * tiles_per_layer, tile.store.file.toString());
-               if (do_next)
-                       next_load();
+
+               if (tiles_loaded_total == tiles_total)
+                       listener.loader_done(tiles_total);
+               else
+                       listener.loader_notify(tiles_loaded_total,
+                                              tiles_total, store.file.toString());
        }
 
-       public AltosMapCache cache() { return cache; }
+       public void abort() {
+               this.abort = true;
+       }
 
-       public AltosMapLoader(AltosMap map, AltosMapCache cache,
-                             AltosMapLoaderListener listener) {
-               this.map = map;
-               this.cache = cache;
+       public AltosMapLoader(AltosMapLoaderListener listener,
+                             double latitude, double longitude, int min_z, int max_z, double radius, int all_types, int scale) {
+               listener.debug("lat %f lon %f min_z %d max_z %d radius %f all_types %d\n",
+                              latitude, longitude, min_z, max_z, radius, all_types);
                this.listener = listener;
+               this.latitude = latitude;
+               this.longitude = longitude;
+               this.min_z = min_z;
+               this.max_z = max_z;
+               this.radius = radius;
+               this.all_types = all_types;
+               this.scale = scale;
+               this.abort = false;
+               start();
        }
 }