From 52ce41952c5a3c31532fa4f0d1b3155a162b76f4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 28 May 2014 10:16:38 -0700 Subject: [PATCH] altosuilib: Update map preloading UI to include zoom and maptypes This lets you specify precisely which maps to load. Signed-off-by: Keith Packard --- altosuilib/AltosSiteMap.java | 166 ++++++++++++++++++---------- altosuilib/AltosSiteMapCache.java | 2 + altosuilib/AltosSiteMapImage.java | 7 +- altosuilib/AltosSiteMapPreload.java | 139 +++++++++++++++++++---- altosuilib/AltosSiteMapTile.java | 23 ++-- 5 files changed, 245 insertions(+), 92 deletions(-) diff --git a/altosuilib/AltosSiteMap.java b/altosuilib/AltosSiteMap.java index d9ea564c..461886c7 100644 --- a/altosuilib/AltosSiteMap.java +++ b/altosuilib/AltosSiteMap.java @@ -74,7 +74,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous "terrain" }; - static final String[] maptype_labels = { + public static final String[] maptype_labels = { "Hybrid", "Roadmap", "Satellite", @@ -240,7 +240,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous String pngurl; } - public AltosSiteMapPrefetch prefetchMap(int x, int y) { + private AltosSiteMapPrefetch prefetchMap(int x, int y) { AltosSiteMapPrefetch prefetch = new AltosSiteMapPrefetch(); LatLng map_latlng = latlng( -centre.x + x*px_size + px_size/2, @@ -257,28 +257,34 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous return prefetch; } - public static void prefetchMaps(double lat, double lng) { - int w = AltosSiteMapPreload.width; - int h = AltosSiteMapPreload.height; + public static void prefetchMaps(double lat, double lng, int radius, int maptypes, int min_zoom, int max_zoom) { AltosSiteMap asm = new AltosSiteMap(true); - asm.centre = asm.getBaseLocation(lat, lng); - - int dx = -w/2, dy = -h/2; - for (int y = dy; y < h+dy; y++) { - for (int x = dx; x < w+dx; x++) { - AltosSiteMapPrefetch prefetch = asm.prefetchMap(x, y); - switch (prefetch.result) { - case 1: - System.out.printf("Already have %s\n", prefetch.pngfile); - break; - case 0: - System.out.printf("Fetched map %s\n", prefetch.pngfile); - break; - case -1: - System.out.printf("# Failed to fetch file %s\n", prefetch.pngfile); - System.out.printf(" wget -O '%s' ''\n", - prefetch.pngfile, prefetch.pngurl); - break; + + for (int z = min_zoom; z <= max_zoom; z++) { + asm.zoom = z; + asm.set_radius(radius); + asm.centre = asm.getBaseLocation(lat, lng); + for (int t = maptype_hybrid; t <= maptype_terrain; t++) { + if ((maptypes & (1 << t)) !=0) { + asm.maptype = t; + for (int y = -radius; y <= radius; y++) { + for (int x = -radius; x <= radius; x++) { + AltosSiteMapPrefetch prefetch = asm.prefetchMap(x, y); + switch (prefetch.result) { + case 1: + System.out.printf("Already have %s\n", prefetch.pngfile); + break; + case 0: + System.out.printf("Fetched map %s\n", prefetch.pngfile); + break; + case -1: + System.out.printf("# Failed to fetch file %s\n", prefetch.pngfile); + System.out.printf(" wget -O '%s' ''\n", + prefetch.pngfile, prefetch.pngurl); + break; + } + } + } } } } @@ -296,7 +302,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous return pngfile; } - public void initAndFinishMapAsync (final AltosSiteMapTile tile, final Point offset) { + private void initAndFinishMapAsync (final AltosSiteMapTile tile, final Point offset) { Thread thread = new Thread() { public void run() { init_map(offset, load_mode_cached|load_mode_uncached); @@ -318,6 +324,10 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous circle_set = false; points = new LinkedList(); line_start = line_end = null; + for (AltosSiteMapTile tile : mapTiles.values()) { + tile.clearMap(); + tile.set_status(AltosSiteMapCache.loading); + } } public void setBaseLocation(double lat, double lng) { @@ -382,7 +392,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous MapPoint last_point = null; int last_state = -1; - public void show(double lat, double lon) { + private void show(double lat, double lon) { System.out.printf ("show %g %g\n", lat, lon); return; // initMaps(lat, lon); @@ -391,15 +401,17 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous JLabel zoom_label; - public void set_zoom_label() { + private void set_zoom_label() { zoom_label.setText(String.format("Zoom %d", zoom - default_zoom)); } public void set_zoom(int zoom) { if (min_zoom <= zoom && zoom <= max_zoom) { this.zoom = zoom; - if (base_location_set) + if (base_location_set) { + set_tiles(); initMaps(lat, lon); + } redraw(); set_zoom_label(); } @@ -409,7 +421,15 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous return zoom; } - public void draw(MapPoint last_point, MapPoint point) { + public void set_maptype(int type) { + maptype = type; + maptype_combo.setSelectedIndex(type); + if (base_location_set) + initMaps(lat, lon); + redraw(); + } + + private void draw(MapPoint last_point, MapPoint point) { boolean force_ensure = false; if (last_point == null) { force_ensure = true; @@ -449,7 +469,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous } } - public void redraw() { + private void redraw() { MapPoint last_point = null; for (MapPoint point : points) { @@ -496,7 +516,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous last_point = point; } - public void centre(Point2D.Double pt) { + private void centre(Point2D.Double pt) { Rectangle r = comp.getVisibleRect(); Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft)); int dx = (int)copt.x - r.width/2 - r.x; @@ -508,7 +528,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous comp.scrollRectToVisible(r); } - public void centre(AltosState state) { + private void centre(AltosState state) { if (!state.gps.locked && state.gps.nsat < 4) return; centre(pt(state.gps.lat, state.gps.lon)); @@ -550,6 +570,32 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous } } + private void set_tiles() { + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + Point offset = new Point(x, y); + if (mapTiles.containsKey(offset)) + continue; + AltosSiteMapTile t = createTile(offset); + addTileAt(t, offset); + } + } + for (Point offset : mapTiles.keySet()) { + if (offset.x < -radius || offset.x > radius || + offset.y < -radius || offset.y > radius) + { + removeTileAt(offset); + } + } + } + + public void set_radius(int radius) { + if (radius != this.radius) { + this.radius = radius; + set_tiles(); + } + } + private Point topleft = new Point(0,0); private void scrollRocketToVisible(Point2D.Double pt) { Rectangle r = comp.getVisibleRect(); @@ -573,18 +619,11 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous return; } - boolean review = false; - Rectangle r = comp.getVisibleRect(); - if (offset.x < topleft.x) { - r.x += (topleft.x - offset.x) * px_size; + if (offset.x < topleft.x) topleft.x = offset.x; - review = true; - } - if (offset.y < topleft.y) { - r.y += (topleft.y - offset.y) * px_size; + if (offset.y < topleft.y) topleft.y = offset.y; - review = true; - } + GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.CENTER; c.fill = GridBagConstraints.BOTH; @@ -596,9 +635,6 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous layout.setConstraints(tile, c); comp.add(tile); -// if (review) { -// comp.scrollRectToVisible(r); -// } } private AltosSiteMap(boolean knowWhatYouAreDoing) { @@ -607,6 +643,21 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous } } + private void removeTileAt(Point offset) { + AltosSiteMapTile tile = mapTiles.get(offset); + + mapTiles.remove(offset); + comp.remove(tile); + + topleft = new Point(MAX_TILE_DELTA, MAX_TILE_DELTA); + for (Point o : mapTiles.keySet()) { + if (o.x < topleft.x) + topleft.x = o.x; + if (o.y < topleft.y) + topleft.y = o.y; + } + } + JComponent comp; private GridBagLayout layout = new GridBagLayout(); @@ -634,11 +685,13 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous } static void debug_component(Component who, String where) { -// Rectangle r = who.getBounds(); -// int x = r.x / px_size; -// int y = r.y / px_size; -// -// System.out.printf ("%3d, %3d: %s\n", x, y, where); +/* + Rectangle r = who.getBounds(); + int x = r.x / px_size; + int y = r.y / px_size; + + System.out.printf ("%3d, %3d: %s\n", x, y, where); +*/ } LatLng latlng(MouseEvent e) { @@ -684,7 +737,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous public void mouseReleased(MouseEvent e) { } - public void set_cache_size() { + private void set_cache_size() { Rectangle r = comp.getVisibleRect(); int width_tiles = (r.width + 2*px_size) / px_size; @@ -704,6 +757,8 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous JScrollPane pane = new JScrollPane(); + JComboBox maptype_combo; + public AltosSiteMap(int in_radius) { radius = in_radius; @@ -717,13 +772,8 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous comp.setLayout(layout); - for (int x = -radius; x <= radius; x++) { - for (int y = -radius; y <= radius; y++) { - Point offset = new Point(x, y); - AltosSiteMapTile t = createTile(offset); - addTileAt(t, offset); - } - } + set_tiles(); + pane.setViewportView(comp); pane.setPreferredSize(new Dimension(500,500)); pane.setVisible(true); @@ -805,7 +855,7 @@ public class AltosSiteMap extends JComponent implements AltosFlightDisplay, Mous c.weighty = 0; add(zoom_out, c); - final JComboBox maptype_combo = new JComboBox(maptype_labels); + maptype_combo = new JComboBox(maptype_labels); maptype_combo.setEditable(false); maptype_combo.setMaximumRowCount(maptype_combo.getItemCount()); diff --git a/altosuilib/AltosSiteMapCache.java b/altosuilib/AltosSiteMapCache.java index 7f436ef0..3e08e1b3 100644 --- a/altosuilib/AltosSiteMapCache.java +++ b/altosuilib/AltosSiteMapCache.java @@ -176,6 +176,7 @@ public class AltosSiteMapCache { return new Point (x, y); } +/* private static void dump_cache() { int min_x = 1000, max_x = -1000, min_y = 1000, max_y = -1000; @@ -208,6 +209,7 @@ public class AltosSiteMapCache { System.out.printf("\n"); } } +*/ public static AltosSiteMapImage get_image(AltosSiteMapTile tile, File file, int width, int height) { int oldest = -1; diff --git a/altosuilib/AltosSiteMapImage.java b/altosuilib/AltosSiteMapImage.java index f08c0b26..ae32418f 100644 --- a/altosuilib/AltosSiteMapImage.java +++ b/altosuilib/AltosSiteMapImage.java @@ -34,7 +34,7 @@ public class AltosSiteMapImage { Thread load_thread; - public boolean validate() { + public boolean validate(final int serial) { if (image != null) { AltosSiteMap.debug_component(tile, "valid"); return true; @@ -42,16 +42,15 @@ public class AltosSiteMapImage { AltosSiteMap.debug_component(tile, "loading"); load_thread = new Thread() { public void run() { - image = null; try { image = ImageIO.read(file); } catch (Exception e) { } SwingUtilities.invokeLater( new Runnable() { public void run() { - AltosSiteMap.debug_component(tile, "later"); + AltosSiteMap.debug_component(tile, file.toString()); Graphics2D g2d = (Graphics2D) tile.getGraphics(); - tile.paint_graphics(g2d, image); + tile.paint_graphics(g2d, image, serial); load_thread = null; } }); diff --git a/altosuilib/AltosSiteMapPreload.java b/altosuilib/AltosSiteMapPreload.java index 107b09f8..6b8066b3 100644 --- a/altosuilib/AltosSiteMapPreload.java +++ b/altosuilib/AltosSiteMapPreload.java @@ -206,18 +206,15 @@ class AltosSites extends Thread { } } -public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener, ItemListener { +public class AltosSiteMapPreload extends AltosUIFrame implements ActionListener, ItemListener { AltosUIFrame owner; AltosSiteMap map; AltosMapPos lat; AltosMapPos lon; - final static int radius = 5; - final static int width = (radius * 2 + 1); - final static int height = (radius * 2 + 1); - JProgressBar pbar; + int pbar_max; AltosSites sites; JLabel site_list_label; @@ -227,6 +224,15 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener boolean loading; JButton close_button; + JCheckBox[] maptypes = new JCheckBox[AltosSiteMap.maptype_terrain - AltosSiteMap.maptype_hybrid + 1]; + + JComboBox min_zoom; + JComboBox max_zoom; + JComboBox 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 }; + static final String[] lat_hemi_names = { "N", "S" }; static final String[] lon_hemi_names = { "E", "W" }; @@ -234,15 +240,16 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener int n; String s; - public updatePbar(int x, int y, String in_s) { - n = (x + radius) + (y + radius) * width + 1; + public updatePbar(int n, String in_s) { + this.n = n; s = in_s; } public void run() { pbar.setValue(n); pbar.setString(s); - if (n < width * height) { + if (n < pbar_max) { + pbar.setMaximum(pbar_max); pbar.setValue(n); pbar.setString(s); } else { @@ -258,17 +265,54 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener AltosSiteMap map; - public bgLoad(AltosSiteMap in_map) { + double lat, lon; + + int types = 0; + int r; + + int min_z = (Integer) min_zoom.getSelectedItem(); + int max_z = (Integer) max_zoom.getSelectedItem(); + + public bgLoad(AltosSiteMap in_map, double lat, double lon) { map = in_map; + this.lat = lat; + this.lon = lon; + if (max_z < min_z) + max_z = min_z; + int ntype = 0; + for (int t = AltosSiteMap.maptype_hybrid; t <= AltosSiteMap.maptype_terrain; t++) + if (maptypes[t].isSelected()) { + types |= (1 << t); + ntype++; + } + if (ntype == 0) { + types |= (1 << AltosSiteMap.maptype_hybrid); + ntype = 1; + } + r = (Integer) radius.getSelectedItem(); + pbar_max = (max_z - min_z + 1) * ntype * (r * 2 + 1) * (r * 2 + 1); } public void run() { - for (int y = -map.radius; y <= map.radius; y++) { - for (int x = -map.radius; x <= map.radius; x++) { - File pngfile; - pngfile = map.init_map(new Point(x,y), - AltosSiteMap.load_mode_cached|AltosSiteMap.load_mode_uncached); - SwingUtilities.invokeLater(new updatePbar(x, y, pngfile.toString())); + int i = 0; + for (int z = min_z; z <= max_z; z++) { + for (int t = AltosSiteMap.maptype_hybrid; t <= AltosSiteMap.maptype_terrain; t++) { + if ((types & (1 << t)) == 0) + continue; + map.clear_base_location(); + map.set_zoom(z + AltosSiteMap.default_zoom); + map.set_maptype(t); + map.set_radius(r); + map.setBaseLocation(lat, lon); + map.draw_circle(lat, lon); + for (int y = -r; y <= r; y++) { + for (int x = -r; x <= r; x++) { + File pngfile; + pngfile = map.init_map(new Point(x,y), + AltosSiteMap.load_mode_cached|AltosSiteMap.load_mode_uncached); + SwingUtilities.invokeLater(new updatePbar(++i, pngfile.toString())); + } + } } } } @@ -310,7 +354,7 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener map.setBaseLocation(latitude,longitude); map.draw_circle(latitude,longitude); loading = true; - bgLoad thread = new bgLoad(map); + bgLoad thread = new bgLoad(map, latitude, longitude); thread.start(); } catch (NumberFormatException ne) { load_button.setSelected(false); @@ -326,9 +370,11 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener GridBagConstraints c = new GridBagConstraints(); Insets i = new Insets(4,4,4,4); + setTitle("AltOS Load Maps"); + pane.setLayout(new GridBagLayout()); - map = new AltosSiteMap(radius); + map = new AltosSiteMap(2); c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; @@ -338,14 +384,14 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener c.gridx = 0; c.gridy = 0; - c.gridwidth = 2; + c.gridwidth = 10; c.anchor = GridBagConstraints.CENTER; pane.add(map, c); pbar = new JProgressBar(); pbar.setMinimum(0); - pbar.setMaximum(width * height); + pbar.setMaximum(1); pbar.setValue(0); pbar.setString(""); pbar.setStringPainted(true); @@ -358,7 +404,7 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener c.gridx = 0; c.gridy = 1; - c.gridwidth = 2; + c.gridwidth = 10; pane.add(pbar, c); @@ -462,6 +508,59 @@ public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener pane.add(close_button, c); + JLabel types_label = new JLabel("Map Types"); + c.gridx = 2; + c.gridwidth = 2; + c.gridy = 2; + pane.add(types_label, c); + + c.gridwidth = 1; + + for (int type = AltosSiteMap.maptype_hybrid; type <= AltosSiteMap.maptype_terrain; type++) { + maptypes[type] = new JCheckBox(AltosSiteMap.maptype_labels[type], + type == AltosSiteMap.maptype_hybrid); + c.gridx = 2 + (type >> 1); + c.fill = GridBagConstraints.HORIZONTAL; + c.gridy = (type & 1) + 3; + pane.add(maptypes[type], c); + } + + JLabel min_zoom_label = new JLabel("Minimum Zoom"); + c.gridx = 4; + c.gridy = 2; + pane.add(min_zoom_label, c); + + min_zoom = new JComboBox(zooms); + min_zoom.setSelectedItem(zooms[10]); + min_zoom.setEditable(false); + c.gridx = 5; + c.gridy = 2; + pane.add(min_zoom, c); + + JLabel max_zoom_label = new JLabel("Maximum Zoom"); + c.gridx = 4; + c.gridy = 3; + pane.add(max_zoom_label, c); + + max_zoom = new JComboBox(zooms); + max_zoom.setSelectedItem(zooms[14]); + max_zoom.setEditable(false); + c.gridx = 5; + c.gridy = 3; + pane.add(max_zoom, c); + + JLabel radius_label = new JLabel("Tile Radius"); + c.gridx = 4; + c.gridy = 4; + pane.add(radius_label, c); + + radius = new JComboBox(radii); + radius.setSelectedItem(radii[4]); + radius.setEditable(false); + c.gridx = 5; + c.gridy = 4; + pane.add(radius, c); + pack(); setLocationRelativeTo(owner); setVisible(true); diff --git a/altosuilib/AltosSiteMapTile.java b/altosuilib/AltosSiteMapTile.java index 136fbd7a..f8b924a8 100644 --- a/altosuilib/AltosSiteMapTile.java +++ b/altosuilib/AltosSiteMapTile.java @@ -155,9 +155,16 @@ public class AltosSiteMapTile extends JComponent { return String.format(format, distance); } - boolean painting; + int painting_serial; + int painted_serial; + + public void paint_graphics(Graphics2D g2d, Image image, int serial) { + + if (serial < painted_serial) + return; + + painted_serial = serial; - public void paint_graphics(Graphics2D g2d, Image image) { if (image != null) { AltosSiteMap.debug_component(this, "paint_graphics"); g2d.drawImage(image, 0, 0, null); @@ -239,7 +246,6 @@ public class AltosSiteMapTile extends JComponent { } g2d.drawString(message, x, y); } - painting = false; } public void paint(Graphics g) { @@ -247,26 +253,23 @@ public class AltosSiteMapTile extends JComponent { Image image = null; boolean queued = false; - if (painting) { - AltosSiteMap.debug_component(this, "already painting"); - return; - } AltosSiteMap.debug_component(this, "paint"); + ++painting_serial; + if (file != null) { AltosSiteMapImage aimage; aimage = AltosSiteMapCache.get_image(this, file, px_size, px_size); if (aimage != null) { - if (aimage.validate()) + if (aimage.validate(painting_serial)) image = aimage.image; else queued = true; } } if (!queued) - paint_graphics(g2d, image); - painting = queued; + paint_graphics(g2d, image, painting_serial); } public void show(int state, Point2D.Double last_pt, Point2D.Double pt) -- 2.30.2