summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2015-07-11 19:15:08 -0700
committerKeith Packard <keithp@keithp.com>2015-07-11 19:16:41 -0700
commitd015cfc1499a263549f52d46e9e5b934fcb94f53 (patch)
treecffb877a16d4f22b4ffd7dcdb32fde0c028e5711
parentafa37e4667ace42c1f43b01b613e639772cfeb75 (diff)
altoslib: Preload maps based on distance rather than number of tiles
This lets you get the specific area requested at all zoom levels, rather than having further detail only at lower resolution zooms. Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--altosdroid/res/layout/map_preload.xml8
-rw-r--r--altosdroid/res/values/strings.xml2
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/PreloadMapActivity.java66
-rw-r--r--altoslib/AltosMapLoader.java99
-rw-r--r--altoslib/AltosMapLoaderListener.java2
-rw-r--r--altosuilib/AltosUIMapPreloadNew.java35
6 files changed, 179 insertions, 33 deletions
diff --git a/altosdroid/res/layout/map_preload.xml b/altosdroid/res/layout/map_preload.xml
index 1d1fca32..dc613bf2 100644
--- a/altosdroid/res/layout/map_preload.xml
+++ b/altosdroid/res/layout/map_preload.xml
@@ -103,15 +103,15 @@
android:prompt="@string/preload_max_zoom"
android:spinnerMode="dropdown"
/>
- <TextView android:id="@+id/preload_tile_radius_label"
+ <TextView android:id="@+id/preload_radius_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@string/preload_tile_radius"
+ android:text="@string/preload_radius"
/>
- <Spinner android:id="@+id/preload_tile_radius"
+ <Spinner android:id="@+id/preload_radius"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:prompt="@string/preload_tile_radius"
+ android:prompt="@string/preload_radius"
android:spinnerMode="dropdown"
/>
<Button android:id="@+id/preload_load"
diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml
index 8c299a35..36b07bc2 100644
--- a/altosdroid/res/values/strings.xml
+++ b/altosdroid/res/values/strings.xml
@@ -106,7 +106,7 @@
<string name="preload_terrain">Terrain</string>
<string name="preload_min_zoom">Minimum Zoom</string>
<string name="preload_max_zoom">Maximum Zoom</string>
- <string name="preload_tile_radius">Tile Radius</string>
+ <string name="preload_radius">Radius</string>
<string name="preload_load">Load Map</string>
</resources>
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/PreloadMapActivity.java b/altosdroid/src/org/altusmetrum/AltosDroid/PreloadMapActivity.java
index 1968edae..498b208e 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/PreloadMapActivity.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/PreloadMapActivity.java
@@ -61,7 +61,8 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
private Spinner known_sites_spinner;
private Spinner min_zoom;
private Spinner max_zoom;
- private Spinner tile_radius;
+ private TextView radius_label;
+ private Spinner radius;
private EditText latitude;
private EditText longitude;
@@ -227,8 +228,17 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
return value(max_zoom);
}
- private int radius() {
- return value(tile_radius);
+ private double value_distance(Spinner spinner) {
+ return (Double) spinner.getSelectedItem();
+ }
+
+ private double radius() {
+ double r = value_distance(radius);
+ if (AltosPreferences.imperial_units())
+ r = AltosConvert.distance.inverse(r);
+ else
+ r = r * 1000;
+ return r;
}
private int bit(CheckBox box, int value) {
@@ -250,11 +260,14 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
double lon = longitude();
int min = min_z();
int max = max_z();
- int r = radius();
+ double r = radius();
int t = types();
+ AltosDebug.debug("PreloadMap load %f %f %d %d %f %d\n",
+ lat, lon, min, max, r, t);
loader.load(lat, lon, min, max, r, t);
} catch (ParseException e) {
+ AltosDebug.debug("PreloadMap load raised exception %s", e.toString());
}
}
@@ -276,6 +289,37 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
spinner.setSelection(spinner_def);
}
+
+ private void add_distance(Spinner spinner, double[] distances_km, double def_km, double[] distances_mi, double def_mi) {
+
+ ArrayAdapter<Double> adapter = new ArrayAdapter<Double>(this, android.R.layout.simple_spinner_item);
+
+ int spinner_def = 0;
+ int pos = 0;
+
+ double[] distances;
+ double def;
+ if (AltosPreferences.imperial_units()) {
+ distances = distances_mi;
+ def = def_mi;
+ } else {
+ distances = distances_km;
+ def = def_km;
+ }
+
+ for (int i = 0; i < distances.length; i++) {
+ adapter.add(distances[i]);
+ if (distances[i] == def)
+ spinner_def = pos;
+ pos++;
+ }
+
+ spinner.setAdapter(adapter);
+ spinner.setSelection(spinner_def);
+ }
+
+
+
class SiteListListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
AltosLaunchSite site = (AltosLaunchSite) parent.getItemAtPosition(pos);
@@ -289,6 +333,11 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
}
}
+ double[] radius_mi = { 1, 2, 5, 10, 20 };
+ double radius_def_mi = 2;
+ double[] radius_km = { 1, 2, 5, 10, 20, 30 };
+ double radius_def_km = 2;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -326,8 +375,13 @@ public class PreloadMapActivity extends Activity implements AltosLaunchSiteListe
add_numbers(max_zoom,
AltosMap.min_zoom - AltosMap.default_zoom,
AltosMap.max_zoom - AltosMap.default_zoom, 2);
- tile_radius = (Spinner) findViewById(R.id.preload_tile_radius);
- add_numbers(tile_radius, 1, 5, 5);
+ radius_label = (TextView) findViewById(R.id.preload_radius_label);
+ radius = (Spinner) findViewById(R.id.preload_radius);
+ if (AltosPreferences.imperial_units())
+ radius_label.setText("Radius (miles)");
+ else
+ radius_label.setText("Radius (km)");
+ add_distance(radius, radius_km, radius_def_km, radius_mi, radius_def_mi);
progress = (ProgressBar) findViewById(R.id.preload_progress);
diff --git a/altoslib/AltosMapLoader.java b/altoslib/AltosMapLoader.java
index cf7169ba..2cd5dbd3 100644
--- a/altoslib/AltosMapLoader.java
+++ b/altoslib/AltosMapLoader.java
@@ -24,7 +24,7 @@ import java.lang.Math;
import java.net.URL;
import java.net.URLConnection;
-public class AltosMapLoader implements AltosMapTileListener {
+public class AltosMapLoader implements AltosMapTileListener, AltosMapStoreListener {
AltosMapLoaderListener listener;
double latitude, longitude;
@@ -33,17 +33,71 @@ public class AltosMapLoader implements AltosMapTileListener {
int cur_z;
int all_types;
int cur_type;
- int radius;
+ double radius;
- 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;
+ 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 void do_load() {
- map.set_load_params(cur_z + AltosMap.default_zoom, cur_type, latitude, longitude, radius, this);
+ 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);
+
+ map.centre(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) {
+ listener.debug("Make tile at %d, %d\n", x, y);
+ 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));
+ AltosMapTile tile = map.map_interface.new_tile(this, ul, center, zoom, maptype, AltosMap.px_size);
+ tile.add_store_listener(this);
+ if (tile.store_status() != AltosMapTile.loading)
+ notify_tile(tile, tile.store_status());
+ }
+ }
}
public int next_type(int start) {
@@ -84,16 +138,23 @@ public class AltosMapLoader implements AltosMapTileListener {
}
cur_type = next_type(0);
- tiles_per_layer = (radius * 2 + 1) * (radius * 2 + 1);
+
+ for (int z = min_z; z <= max_z; z++)
+ tiles_total += tiles_per_layer(z);
+
layers_total = (max_z - min_z + 1) * ntype;
layers_loaded = 0;
- tiles_loaded = 0;
+ tiles_loaded_total = 0;
+
+ listener.debug("total tiles %d\n", tiles_total);
- listener.loader_start(layers_total * tiles_per_layer);
+ listener.loader_start(tiles_total);
do_load();
}
- public void load(double latitude, double longitude, int min_z, int max_z, int radius, int all_types) {
+ public void load(double latitude, double longitude, int min_z, int max_z, double radius, int all_types) {
+ 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.latitude = latitude;
this.longitude = longitude;
this.min_z = min_z;
@@ -103,7 +164,7 @@ public class AltosMapLoader implements AltosMapTileListener {
start_load();
}
- 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)
return;
@@ -111,24 +172,30 @@ public class AltosMapLoader implements AltosMapTileListener {
if (layers_loaded >= layers_total)
return;
- ++tiles_loaded;
+ ++tiles_loaded_total;
+ ++tiles_loaded_layer;
+ listener.debug("total %d layer %d\n", tiles_loaded_total, tiles_loaded_layer);
- if (tiles_loaded == tiles_per_layer) {
- tiles_loaded = 0;
+ if (tiles_loaded_layer == tiles_this_layer) {
++layers_loaded;
+ listener.debug("%d layers loaded\n", layers_loaded);
if (layers_loaded == layers_total) {
- listener.loader_done(layers_total * tiles_per_layer);
+ listener.loader_done(tiles_total);
return;
} else {
do_next = true;
}
}
- listener.loader_notify(layers_loaded * tiles_per_layer + tiles_loaded,
- layers_total * tiles_per_layer, tile.store.file.toString());
+ listener.loader_notify(tiles_loaded_total,
+ tiles_total, store.file.toString());
if (do_next)
next_load();
}
+ public synchronized void notify_tile(AltosMapTile tile, int status) {
+ notify_store(tile.store, status);
+ }
+
public AltosMapCache cache() { return map.cache(); }
public AltosMapLoader(AltosMap map, AltosMapLoaderListener listener) {
diff --git a/altoslib/AltosMapLoaderListener.java b/altoslib/AltosMapLoaderListener.java
index 79f8b9df..11f59b28 100644
--- a/altoslib/AltosMapLoaderListener.java
+++ b/altoslib/AltosMapLoaderListener.java
@@ -23,4 +23,6 @@ public interface AltosMapLoaderListener {
public abstract void loader_notify(int cur, int max, String name);
public abstract void loader_done(int max);
+
+ public abstract void debug(String format, Object ... arguments);
}
diff --git a/altosuilib/AltosUIMapPreloadNew.java b/altosuilib/AltosUIMapPreloadNew.java
index 4a5764c8..ba559534 100644
--- a/altosuilib/AltosUIMapPreloadNew.java
+++ b/altosuilib/AltosUIMapPreloadNew.java
@@ -140,10 +140,15 @@ public class AltosUIMapPreloadNew extends AltosUIFrame implements ActionListener
JComboBox<Integer> min_zoom;
JComboBox<Integer> max_zoom;
- JComboBox<Integer> radius;
+ JComboBox<Double> radius;
Integer[] zooms = { -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 };
- Integer[] radii = { 1, 2, 3, 4, 5 };
+
+ Double[] radius_mi = { 1.0, 2.0, 5.0, 10.0, 20.0 };
+ Double radius_def_mi = 5.0;
+ Double[] radius_km = { 2.0, 5.0, 10.0, 20.0, 30.0 };
+ Double radius_def_km = 10.0;
+
static final String[] lat_hemi_names = { "N", "S" };
static final String[] lon_hemi_names = { "E", "W" };
@@ -183,6 +188,11 @@ public class AltosUIMapPreloadNew extends AltosUIFrame implements ActionListener
});
}
+ public void debug(String format, Object ... arguments) {
+ System.out.printf(format, arguments);
+ }
+
+
private int all_types() {
int all_types = 0;
for (int t = AltosMap.maptype_hybrid; t <= AltosMap.maptype_terrain; t++)
@@ -219,7 +229,12 @@ public class AltosUIMapPreloadNew extends AltosUIFrame implements ActionListener
int max_z = (Integer) max_zoom.getSelectedItem();
if (max_z < min_z)
max_z = min_z;
- int r = (Integer) radius.getSelectedItem();
+ Double r = (Double) radius.getSelectedItem();
+
+ if (AltosPreferences.imperial_units())
+ r = AltosConvert.distance.inverse(r);
+ else
+ r = r * 1000;
loading = true;
loader.load(latitude, longitude, min_z, max_z, r, all_types());
@@ -430,13 +445,21 @@ public class AltosUIMapPreloadNew extends AltosUIFrame implements ActionListener
c.gridy = 3;
pane.add(max_zoom, c);
- JLabel radius_label = new JLabel("Tile Radius");
+ JLabel radius_label = new JLabel(String.format("Map Radius (%s)",
+ AltosPreferences.imperial_units() ? "miles" : "km"));
c.gridx = 4;
c.gridy = 4;
pane.add(radius_label, c);
- radius = new JComboBox<Integer>(radii);
- radius.setSelectedItem(radii[4]);
+ Double[] radii;
+ Double radius_default;
+
+ if (AltosPreferences.imperial_units())
+ radii = radius_mi;
+ else
+ radii = radius_km;
+ radius = new JComboBox<Double>(radii);
+ radius.setSelectedItem(radii[2]);
radius.setEditable(true);
c.gridx = 5;
c.gridy = 4;