From db2443fdbf65b65703217174303027c439124a83 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 11 Jun 2014 18:46:47 -0700 Subject: altosuilib: Rewrite map GUI bits Use a single large Canvas and draw images on top by hand. Signed-off-by: Keith Packard --- altosuilib/AltosUIMapTile.java | 190 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 altosuilib/AltosUIMapTile.java (limited to 'altosuilib/AltosUIMapTile.java') diff --git a/altosuilib/AltosUIMapTile.java b/altosuilib/AltosUIMapTile.java new file mode 100644 index 00000000..6fbcdb4b --- /dev/null +++ b/altosuilib/AltosUIMapTile.java @@ -0,0 +1,190 @@ +/* + * Copyright © 2010 Anthony Towns + * + * 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. + * + * 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altosuilib_2; + +import java.awt.*; +import java.awt.image.*; +import javax.swing.*; +import javax.imageio.*; +import java.awt.geom.*; +import java.io.*; +import java.util.*; +import java.awt.RenderingHints.*; +import org.altusmetrum.altoslib_4.*; + +public class AltosUIMapTile { + AltosUIMapTileListener listener; + AltosUILatLon upper_left, center; + int px_size; + int zoom; + int maptype; + AltosUIMapStore store; + int status; + + private File map_file() { + double lat = center.lat; + double lon = center.lon; + char chlat = lat < 0 ? 'S' : 'N'; + char chlon = lon < 0 ? 'W' : 'E'; + + if (lat < 0) lat = -lat; + if (lon < 0) lon = -lon; + String maptype_string = String.format("%s-", AltosUIMap.maptype_names[maptype]); + String format_string; + if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain) + format_string = "jpg"; + else + format_string = "png"; + return new File(AltosUIPreferences.mapdir(), + String.format("map-%c%.6f,%c%.6f-%s%d.%s", + chlat, lat, chlon, lon, maptype_string, zoom, format_string)); + } + + private String map_url() { + String format_string; + if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain) + format_string = "jpg"; + else + format_string = "png32"; + + if (AltosUIVersion.has_google_maps_api_key()) + return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s&key=%s", + center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string, AltosUIVersion.google_maps_api_key); + else + return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s", + center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string); + } + private Font font = null; + + public void set_font(Font font) { + this.font = font; + } + + int painting_serial; + int painted_serial; + + Image image; + + public void paint_graphics(Graphics2D g2d, AltosUIMapTransform t, int serial) { + if (serial < painted_serial) + return; + + Point2D.Double point_double = t.screen(upper_left); + Point point = new Point((int) (point_double.x + 0.5), + (int) (point_double.y + 0.5)); + + painted_serial = serial; + + if (!g2d.hitClip(point.x, point.y, px_size, px_size)) + return; + + if (image != null) { + g2d.drawImage(image, point.x, point.y, null); + image = null; + } else { + g2d.setColor(Color.GRAY); + g2d.fillRect(point.x, point.y, px_size, px_size); + + if (t.has_location()) { + String message = null; + switch (status) { + case AltosUIMapCache.loading: + message = "Loading..."; + break; + case AltosUIMapCache.bad_request: + message = "Internal error"; + break; + case AltosUIMapCache.failed: + message = "Network error, check connection"; + break; + case AltosUIMapCache.forbidden: + message = "Too many requests, try later"; + break; + } + if (message != null && font != null) { + g2d.setFont(font); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + Rectangle2D bounds = font.getStringBounds(message, g2d.getFontRenderContext()); + + float x = px_size / 2.0f; + float y = px_size / 2.0f; + x = x - (float) bounds.getWidth() / 2.0f; + y = y + (float) bounds.getHeight() / 2.0f; + g2d.setColor(Color.BLACK); + g2d.drawString(message, (float) point_double.x + x, (float) point_double.y + y); + } + } + } + } + + public void set_status(int status) { + this.status = status; + listener.notify_tile(this, status); + } + + public void notify_image(Image image) { + listener.notify_tile(this, status); + } + + public void paint(Graphics g, AltosUIMapTransform t) { + Graphics2D g2d = (Graphics2D) g; + boolean queued = false; + + Point2D.Double point = t.screen(upper_left); + + if (!g.hitClip((int) (point.x + 0.5), (int) (point.y + 0.5), px_size, px_size)) + return; + + ++painting_serial; + + if (image == null && t.has_location()) + image = AltosUIMapCache.get(this, store, px_size, px_size); + + paint_graphics(g2d, t, painting_serial); + } + + public int store_status() { + return store.status(); + } + + public void add_store_listener(AltosUIMapStoreListener listener) { + store.add_listener(listener); + } + + public void remove_store_listener(AltosUIMapStoreListener listener) { + store.remove_listener(listener); + } + + public AltosUIMapTile(AltosUIMapTileListener listener, AltosUILatLon upper_left, AltosUILatLon center, int zoom, int maptype, int px_size, Font font) { + this.listener = listener; + this.upper_left = upper_left; + + while (center.lon < -180.0) + center.lon += 360.0; + while (center.lon > 180.0) + center.lon -= 360.0; + + this.center = center; + this.zoom = zoom; + this.maptype = maptype; + this.px_size = px_size; + this.font = font; + status = AltosUIMapCache.loading; + store = AltosUIMapStore.get(map_url(), map_file()); + } +} -- cgit v1.2.3 From 9a6a3c34293eac6442f766e13ce148f595e891eb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 13 Jun 2014 21:26:33 -0700 Subject: altosuilib: Make map-cache per-window instead of global This consumes more memory, but avoids cache conflicts between windows Signed-off-by: Keith Packard --- altosuilib/AltosUIMapCache.java | 22 ++++++++++++---------- altosuilib/AltosUIMapPreload.java | 3 +++ altosuilib/AltosUIMapTile.java | 4 +++- altosuilib/AltosUIMapTileListener.java | 2 ++ altosuilib/AltosUIMapView.java | 6 +++++- 5 files changed, 25 insertions(+), 12 deletions(-) (limited to 'altosuilib/AltosUIMapTile.java') diff --git a/altosuilib/AltosUIMapCache.java b/altosuilib/AltosUIMapCache.java index e849da79..55311d8c 100644 --- a/altosuilib/AltosUIMapCache.java +++ b/altosuilib/AltosUIMapCache.java @@ -31,18 +31,19 @@ public class AltosUIMapCache { static final int bad_request = 3; static final int forbidden = 4; - static private Object fetch_lock = new Object(); + static final int min_cache_size = 9; + static final int max_cache_size = 24; - static final int min_cache_size = 9; - static final int max_cache_size = 24; + private Object fetch_lock = new Object(); + private Object cache_lock = new Object(); - static int cache_size = min_cache_size; + int cache_size = min_cache_size; - static AltosUIMapImage[] images = new AltosUIMapImage[cache_size]; + AltosUIMapImage[] images = new AltosUIMapImage[cache_size]; - static Object cache_lock = new Object(); + long used; - public static void set_cache_size(int new_size) { + public void set_cache_size(int new_size) { if (new_size < min_cache_size) new_size = min_cache_size; if (new_size > max_cache_size) @@ -64,9 +65,7 @@ public class AltosUIMapCache { } } - static long used; - - public static Image get(AltosUIMapTile tile, AltosUIMapStore store, int width, int height) { + public Image get(AltosUIMapTile tile, AltosUIMapStore store, int width, int height) { int oldest = -1; long age = used; @@ -109,4 +108,7 @@ public class AltosUIMapCache { } } } + + public AltosUIMapCache() { + } } diff --git a/altosuilib/AltosUIMapPreload.java b/altosuilib/AltosUIMapPreload.java index d702dddf..3bdba39e 100644 --- a/altosuilib/AltosUIMapPreload.java +++ b/altosuilib/AltosUIMapPreload.java @@ -209,6 +209,7 @@ class AltosUISites extends Thread { public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, ItemListener, AltosUIMapTileListener { AltosUIFrame owner; AltosUIMap map; + AltosUIMapCache cache = new AltosUIMapCache(); AltosUIMapPos lat; AltosUIMapPos lon; @@ -353,6 +354,8 @@ public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, I } } + public AltosUIMapCache cache() { return cache; } + public void set_sites() { int i = 1; for (AltosUISite site : sites.sites) { diff --git a/altosuilib/AltosUIMapTile.java b/altosuilib/AltosUIMapTile.java index 6fbcdb4b..7c823183 100644 --- a/altosuilib/AltosUIMapTile.java +++ b/altosuilib/AltosUIMapTile.java @@ -34,6 +34,7 @@ public class AltosUIMapTile { int zoom; int maptype; AltosUIMapStore store; + AltosUIMapCache cache; int status; private File map_file() { @@ -153,7 +154,7 @@ public class AltosUIMapTile { ++painting_serial; if (image == null && t.has_location()) - image = AltosUIMapCache.get(this, store, px_size, px_size); + image = cache.get(this, store, px_size, px_size); paint_graphics(g2d, t, painting_serial); } @@ -173,6 +174,7 @@ public class AltosUIMapTile { public AltosUIMapTile(AltosUIMapTileListener listener, AltosUILatLon upper_left, AltosUILatLon center, int zoom, int maptype, int px_size, Font font) { this.listener = listener; this.upper_left = upper_left; + cache = listener.cache(); while (center.lon < -180.0) center.lon += 360.0; diff --git a/altosuilib/AltosUIMapTileListener.java b/altosuilib/AltosUIMapTileListener.java index 4cc3ff2f..4ca13539 100644 --- a/altosuilib/AltosUIMapTileListener.java +++ b/altosuilib/AltosUIMapTileListener.java @@ -19,4 +19,6 @@ package org.altusmetrum.altosuilib_2; public interface AltosUIMapTileListener { abstract public void notify_tile(AltosUIMapTile tile, int status); + + abstract public AltosUIMapCache cache(); } diff --git a/altosuilib/AltosUIMapView.java b/altosuilib/AltosUIMapView.java index efae3767..4df178e2 100644 --- a/altosuilib/AltosUIMapView.java +++ b/altosuilib/AltosUIMapView.java @@ -34,6 +34,8 @@ public class AltosUIMapView extends Component implements MouseMotionListener, Mo AltosUIMapLine line = new AltosUIMapLine(); + AltosUIMapCache cache = new AltosUIMapCache(); + LinkedList marks = new LinkedList(); LinkedList zoom_listeners = new LinkedList(); @@ -368,7 +370,7 @@ public class AltosUIMapView extends Component implements MouseMotionListener, Mo for (Point point : to_remove) tiles.remove(point); - AltosUIMapCache.set_cache_size(((lower_right.y - upper_left.y) / px_size + 1) * ((lower_right.x - upper_left.x) / px_size + 1)); + cache.set_cache_size(((lower_right.y - upper_left.y) / px_size + 1) * ((lower_right.x - upper_left.x) / px_size + 1)); for (int y = upper_left.y; y <= lower_right.y; y += px_size) { for (int x = upper_left.x; x <= lower_right.x; x += px_size) { Point point = new Point(x, y); @@ -394,6 +396,8 @@ public class AltosUIMapView extends Component implements MouseMotionListener, Mo } } + public AltosUIMapCache cache() { return cache; } + /* AltosUIMapStoreListener methods */ public void notify_store(AltosUIMapStore store, int status) { if (load_listener != null) { -- cgit v1.2.3