X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=altosuilib%2FAltosUIMap.java;h=7b9459a128068adabce4501d2c84ee06573df983;hp=5c6d5bdf7938fb8bb84437d504cc675013c77ab6;hb=b631f88b0bf19c6740eb21b65bd4be7c25049773;hpb=4231d68bae69d9a7d1f52205002db452cd5f986d diff --git a/altosuilib/AltosUIMap.java b/altosuilib/AltosUIMap.java index 5c6d5bdf..7b9459a1 100644 --- a/altosuilib/AltosUIMap.java +++ b/altosuilib/AltosUIMap.java @@ -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 @@ -15,41 +16,290 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -package org.altusmetrum.altosuilib_6; +package org.altusmetrum.altosuilib_13; import java.awt.*; import java.awt.event.*; +import java.awt.image.*; import javax.swing.*; import java.io.*; import java.lang.Math; import java.awt.geom.*; import java.util.*; import java.util.concurrent.*; -import org.altusmetrum.altoslib_6.*; +import javax.imageio.*; +import org.altusmetrum.altoslib_13.*; -public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosUIMapZoomListener { +public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosMapInterface { - static final int px_size = 512; + AltosMap map; + Graphics2D g; + Font tile_font; + Font line_font; - static final int maptype_hybrid = 0; - static final int maptype_roadmap = 1; - static final int maptype_satellite = 2; - static final int maptype_terrain = 3; - static final int maptype_default = maptype_hybrid; + static Point2D.Double point2d(AltosPointDouble pt) { + return new Point2D.Double(pt.x, pt.y); + } - static final String[] maptype_names = { - "hybrid", - "roadmap", - "satellite", - "terrain" - }; + static final AltosPointDouble point_double(Point pt) { + return new AltosPointDouble(pt.x, pt.y); + } - public static final String[] maptype_labels = { - "Hybrid", - "Roadmap", - "Satellite", - "Terrain" - }; + class MapMark extends AltosMapMark { + public void paint(AltosMapTransform t) { + AltosPointDouble pt = t.screen(lat_lon); + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + + if (0 <= state && state < AltosUIMap.stateColors.length) + g.setColor(AltosUIMap.stateColors[state]); + else + g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]); + + g.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10); + g.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40); + g.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70); + } + + MapMark(double lat, double lon, int state) { + super(lat, lon, state); + } + } + + class MapView extends JComponent implements MouseMotionListener, MouseListener, ComponentListener, MouseWheelListener { + + private VolatileImage create_back_buffer() { + return getGraphicsConfiguration().createCompatibleVolatileImage(getWidth(), getHeight()); + } + + private void do_paint(Graphics my_g) { + g = (Graphics2D) my_g; + + map.paint(); + } + + public void paint(Graphics my_g) { + VolatileImage back_buffer = create_back_buffer(); + + Graphics2D top_g = (Graphics2D) my_g; + + do { + GraphicsConfiguration gc = getGraphicsConfiguration(); + int code = back_buffer.validate(gc); + if (code == VolatileImage.IMAGE_INCOMPATIBLE) + back_buffer = create_back_buffer(); + + Graphics g_back = back_buffer.getGraphics(); + g_back.setClip(top_g.getClip()); + do_paint(g_back); + g_back.dispose(); + + top_g.drawImage(back_buffer, 0, 0, this); + } while (back_buffer.contentsLost()); + back_buffer.flush(); + } + + public void repaint(AltosRectangle damage) { + repaint(damage.x, damage.y, damage.width, damage.height); + } + + private boolean is_drag_event(MouseEvent e) { + return e.getModifiersEx() == InputEvent.BUTTON1_DOWN_MASK; + } + + /* MouseMotionListener methods */ + + public void mouseDragged(MouseEvent e) { + map.touch_continue(e.getPoint().x, e.getPoint().y, is_drag_event(e)); + } + + public void mouseMoved(MouseEvent e) { + } + + /* MouseListener methods */ + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + map.touch_start(e.getPoint().x, e.getPoint().y, is_drag_event(e)); + } + + public void mouseReleased(MouseEvent e) { + } + + /* MouseWheelListener methods */ + + public void mouseWheelMoved(MouseWheelEvent e) { + int zoom_change = e.getWheelRotation(); + + map.set_zoom_centre(map.get_zoom() - zoom_change, new AltosPointInt(e.getPoint().x, e.getPoint().y)); + } + + /* ComponentListener methods */ + + public void componentHidden(ComponentEvent e) { + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentResized(ComponentEvent e) { + map.set_transform(); + } + + public void componentShown(ComponentEvent e) { + map.set_transform(); + } + + MapView() { + addComponentListener(this); + addMouseMotionListener(this); + addMouseListener(this); + addMouseWheelListener(this); + } + } + + class MapLine extends AltosMapLine { + + public void paint(AltosMapTransform t) { + + if (start == null || end == null) + return; + + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + Line2D.Double line = new Line2D.Double(point2d(t.screen(start)), + point2d(t.screen(end))); + + g.setColor(Color.WHITE); + g.setStroke(new BasicStroke(stroke_width+4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g.draw(line); + + g.setColor(Color.BLUE); + g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g.draw(line); + + String message = line_dist(); + Rectangle2D bounds; + bounds = line_font.getStringBounds(message, g.getFontRenderContext()); + + float x = (float) line.x1; + float y = (float) line.y1 + (float) bounds.getHeight() / 2.0f; + + if (line.x1 < line.x2) { + x -= (float) bounds.getWidth() + 2.0f; + } else { + x += 2.0f; + } + + g.setFont(line_font); + g.setColor(Color.WHITE); + for (int dy = -2; dy <= 2; dy += 2) + for (int dx = -2; dx <= 2; dx += 2) + g.drawString(message, x + dx, y + dy); + g.setColor(Color.BLUE); + g.drawString(message, x, y); + } + + public MapLine() { + } + } + + class MapPath extends AltosMapPath { + public void paint(AltosMapTransform t) { + Point2D.Double prev = null; + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + + for (AltosMapPathPoint point : points) { + Point2D.Double cur = point2d(t.screen(point.lat_lon)); + if (prev != null) { + Line2D.Double line = new Line2D.Double (prev, cur); + Rectangle bounds = line.getBounds(); + + if (g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height)) { + if (0 <= point.state && point.state < AltosUIMap.stateColors.length) + g.setColor(AltosUIMap.stateColors[point.state]); + else + g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]); + + g.draw(line); + } + } + prev = cur; + } + } + } + + class MapTile extends AltosMapTile { + public MapTile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) { + super(cache, upper_left, center, zoom, maptype, px_size, scale); + } + + public void paint(AltosMapTransform t) { + + AltosPointDouble point_double = t.screen(upper_left); + Point point = new Point((int) (point_double.x + 0.5), + (int) (point_double.y + 0.5)); + + if (!g.hitClip(point.x, point.y, px_size, px_size)) + return; + + AltosImage altos_image = get_image(); + AltosUIImage ui_image = (AltosUIImage) altos_image; + Image image = null; + + if (ui_image != null) + image = ui_image.image; + + if (image != null) { + g.drawImage(image, point.x, point.y, null); + } else { + g.setColor(Color.GRAY); + g.fillRect(point.x, point.y, px_size, px_size); + + if (t.has_location()) { + String message = null; + switch (status) { + case AltosMapTile.fetching: + message = "Fetching..."; + break; + case AltosMapTile.bad_request: + message = "Internal error"; + break; + case AltosMapTile.failed: + message = "Network error"; + break; + case AltosMapTile.forbidden: + message = "Outside of launch area"; + break; + } + if (message != null && tile_font != null) { + g.setFont(tile_font); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + Rectangle2D bounds = tile_font.getStringBounds(message, g.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; + g.setColor(Color.BLACK); + g.drawString(message, (float) point_double.x + x, (float) point_double.y + y); + } + } + } + } + } public static final Color stateColors[] = { Color.WHITE, // startup @@ -65,92 +315,141 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU Color.CYAN, // stateless }; - public void reset() { - // nothing + /* AltosMapInterface functions */ + + public AltosMapPath new_path() { + return new MapPath(); } - public void font_size_changed(int font_size) { - view.set_font(); + public AltosMapLine new_line() { + return new MapLine(); } - public void units_changed(boolean imperial_units) { - view.set_units(); + public AltosImage load_image(File file) throws Exception { + return new AltosUIImage(ImageIO.read(file)); } - JLabel zoom_label; + public AltosMapMark new_mark(double lat, double lon, int state) { + return new MapMark(lat, lon, state); + } - private void set_zoom_label() { - zoom_label.setText(String.format("Zoom %d", view.zoom() - view.default_zoom)); + public AltosMapTile new_tile(AltosMapCache cache, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size, int scale) { + return new MapTile(cache, upper_left, center, zoom, maptype, px_size, scale); } - public void zoom_changed(int zoom) { - set_zoom_label(); + public int width() { + return view.getWidth(); } - public void set_zoom(int zoom) { - view.set_zoom(zoom); + public int height() { + return view.getHeight(); } - public int get_zoom() { - return view.zoom(); + public void repaint() { + view.repaint(); } - public void set_maptype(int type) { - view.set_maptype(type); - maptype_combo.setSelectedIndex(type); + public void repaint(AltosRectangle damage) { + view.repaint(damage); } - public void show(AltosState state, AltosListenerState listener_state) { - view.show(state, listener_state); + public void set_zoom_label(String label) { + zoom_label.setText(label); } - public void centre(double lat, double lon) { - view.centre(lat, lon); + public void select_object(AltosLatLon latlon) { + debug("select at %f,%f\n", latlon.lat, latlon.lon); } - public void centre(AltosState state) { - if (!state.gps.locked && state.gps.nsat < 4) - return; - centre(state.gps.lat, state.gps.lon); + public void debug(String format, Object ... arguments) { + if (AltosUIPreferences.serial_debug()) + System.out.printf(format, arguments); } - public void add_mark(double lat, double lon, int state) { - view.add_mark(lat, lon, state); + + /* AltosFlightDisplay interface */ + + public void set_font() { + tile_font = AltosUILib.value_font; + line_font = AltosUILib.status_font; } - public void clear_marks() { - view.clear_marks(); + public void font_size_changed(int font_size) { + set_font(); + repaint(); } - AltosUIMapView view; + public void units_changed(boolean imperial_units) { + repaint(); + } - private GridBagLayout layout = new GridBagLayout(); + JLabel zoom_label; - JComboBox maptype_combo; + public void set_maptype(int type) { +/* + map.set_maptype(type); + maptype_combo.setSelectedIndex(type); +*/ + } + + /* AltosUIMapPreload functions */ + + public void set_zoom(int zoom) { + map.set_zoom(zoom); + } + + public void add_mark(double lat, double lon, int status) { + map.add_mark(lat, lon, status); + } - public void set_load_params(double lat, double lon, int radius, AltosUIMapTileListener listener) { - view.set_load_params(lat, lon, radius, listener); + public void clear_marks() { + map.clear_marks(); } - public boolean all_fetched() { - return view.all_fetched(); + /* AltosFlightDisplay interface */ + public void reset() { + // nothing + } + + public void show(AltosState state, AltosListenerState listener_state) { + map.show(state, listener_state); } - public static void prefetch_maps(double lat, double lon) { + public void show(AltosGPS gps, int state) { + map.show(gps, state); } public String getName() { return "Map"; } + /* AltosGraphUI interface */ + public void centre(AltosState state) { + map.centre(state); + } + + public void centre(AltosGPS gps) { + map.centre(gps); + } + + /* internal layout bits */ + private GridBagLayout layout = new GridBagLayout(); + +/* + JComboBox maptype_combo; +*/ + + MapView view; + public AltosUIMap() { - view = new AltosUIMapView(); + set_font(); + + view = new MapView(); view.setPreferredSize(new Dimension(500,500)); view.setVisible(true); view.setEnabled(true); - view.add_zoom_listener(this); GridBagLayout my_layout = new GridBagLayout(); @@ -170,7 +469,6 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU int y = 0; zoom_label = new JLabel("", JLabel.CENTER); - set_zoom_label(); c = new GridBagConstraints(); c.anchor = GridBagConstraints.CENTER; @@ -184,7 +482,7 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU JButton zoom_reset = new JButton("0"); zoom_reset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - set_zoom(view.default_zoom); + map.set_zoom(map.default_zoom); } }); @@ -200,7 +498,7 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU JButton zoom_in = new JButton("+"); zoom_in.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - set_zoom(get_zoom() + 1); + map.set_zoom(map.get_zoom() + 1); } }); @@ -216,7 +514,7 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU JButton zoom_out = new JButton("-"); zoom_out.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - set_zoom(get_zoom() - 1); + map.set_zoom(map.get_zoom() - 1); } }); c = new GridBagConstraints(); @@ -228,13 +526,14 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU c.weighty = 0; add(zoom_out, c); - maptype_combo = new JComboBox(maptype_labels); +/* + maptype_combo = new JComboBox(map.maptype_labels); maptype_combo.setEditable(false); maptype_combo.setMaximumRowCount(maptype_combo.getItemCount()); maptype_combo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { - view.set_maptype(maptype_combo.getSelectedIndex()); + map.set_maptype(maptype_combo.getSelectedIndex()); } }); @@ -246,5 +545,7 @@ public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosU c.weightx = 0; c.weighty = 0; add(maptype_combo, c); +*/ + map = new AltosMap(this); } }