altosui: sitemap uses rocket gps if no pad gps
[fw/altos] / ao-tools / altosui / AltosSiteMap.java
index 25450e7eac02fb65ec4408a15e870ac3c50d9dc8..d4a4cbf43dbaa66b7c0c69ca6da2be09bef08e5c 100644 (file)
@@ -40,6 +40,8 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
 
        static final int px_size = 512;
 
+       static final int MAX_TILE_DELTA = 100;
+
        private static Point2D.Double translatePoint(Point2D.Double p,
                        Point2D.Double d)
        {
@@ -106,15 +108,10 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
                return latlng(pt, scale_x, scale_y);
        }
 
-       Vector<AltosSiteMapTile> mapTiles = new Vector<AltosSiteMapTile>();
+       HashMap<Point,AltosSiteMapTile> mapTiles = new HashMap<Point,AltosSiteMapTile>();
        Point2D.Double centre;
 
-       private Point tileOffset(AltosSiteMapTile tile) {
-               GridBagConstraints c = layout.getConstraints(tile);
-               return new Point(c.gridx - 100, c.gridy - 100);
-       }
-       private Point2D.Double tileCoordOffset(AltosSiteMapTile tile) {
-               Point p = tileOffset(tile);
+       private Point2D.Double tileCoordOffset(Point p) {
                return new Point2D.Double(centre.x - p.x*px_size,
                                          centre.y - p.y * px_size);
        }
@@ -194,10 +191,10 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
                }
        }
 
-       private void initMap(AltosSiteMapTile tile) {
-               Point2D.Double offset = tileCoordOffset(tile);
+       private void initMap(AltosSiteMapTile tile, Point offset) {
+               Point2D.Double coord = tileCoordOffset(offset);
 
-               LatLng map_latlng = latlng(px_size/2-offset.x, px_size/2-offset.y);
+               LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y);
 
                File pngfile = MapFile(map_latlng.lat, map_latlng.lng);
                String pngurl = MapURL(map_latlng.lat, map_latlng.lng);
@@ -207,8 +204,8 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
        private void initMaps(double lat, double lng) {
                centre = getBaseLocation(lat, lng);
 
-               for (AltosSiteMapTile tile : mapTiles) {
-                       initMap(tile);
+               for (Point k : mapTiles.keySet()) {
+                       initMap(mapTiles.get(k), k);
                }
        }
 
@@ -229,23 +226,26 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
        boolean initialised = false;
        Point2D.Double last_pt = null;
        int last_state = -1;
-       public void show(AltosState state, int crc_errors) {
+       public void show(final AltosState state, final int crc_errors) {
                // if insufficient gps data, nothing to update
                if (state.gps == null)
                        return;
-               if (!state.gps.locked) {
-                       if (state.pad_lat == 0 && state.pad_lon == 0)
-                               return;
-                       if (state.gps.nsat < 4)
-                               return;
-               }
+               if (!state.gps.locked && state.gps.nsat < 4)
+                       return;
 
                if (!initialised) {
-                       initMaps(state.pad_lat, state.pad_lon);
-                       initialised = true;
+                       if (state.pad_lat != 0 || state.pad_lon != 0) {
+                               initMaps(state.pad_lat, state.pad_lon);
+                               initialised = true;
+                       } else if (state.gps.lat != 0 || state.gps.lon != 0) {
+                               initMaps(state.gps.lat, state.gps.lon);
+                               initialised = true;
+                       } else {
+                               return;
+                       }
                }
 
-               Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
+               final Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
                if (last_pt == pt && last_state == state.state)
                        return;
 
@@ -253,44 +253,115 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
                        last_pt = pt;
                }
                boolean in_any = false;
-               for (AltosSiteMapTile tile : mapTiles) {
+               for (Point offset : mapTiles.keySet()) {
+                       AltosSiteMapTile tile = mapTiles.get(offset);
                        Point2D.Double ref, lref;
-                       ref = translatePoint(pt, tileCoordOffset(tile));
-                       lref = translatePoint(last_pt, tileCoordOffset(tile));
+                       ref = translatePoint(pt, tileCoordOffset(offset));
+                       lref = translatePoint(last_pt, tileCoordOffset(offset));
                        tile.show(state, crc_errors, lref, ref);
                        if (0 <= ref.x && ref.x < px_size)
                                if (0 <= ref.y && ref.y < px_size)
                                        in_any = true;
                }
+
+               Point offset = tileOffset(pt);
                if (!in_any) {
-                       AltosSiteMapTile tile = addTileAt(tileOffset(pt));
                        Point2D.Double ref, lref;
-                       ref = translatePoint(pt, tileCoordOffset(tile));
-                       lref = translatePoint(last_pt, tileCoordOffset(tile));
-                       initMap(tile);
-                       setViewportView(comp);
+                       ref = translatePoint(pt, tileCoordOffset(offset));
+                       lref = translatePoint(last_pt, tileCoordOffset(offset));
+
+                       AltosSiteMapTile tile = createTile(offset);
                        tile.show(state, crc_errors, lref, ref);
+                       initMap(tile, offset);
+                       finishTileLater(tile, offset);
                }
+
+               scrollRocketToVisible(pt);
+
+               if (offset != tileOffset(last_pt)) {
+                       ensureTilesAround(offset);
+               }
+
                last_pt = pt;
                last_state = state.state;
        }
 
-       private AltosSiteMapTile addTileAt(Point offset) {
+       private AltosSiteMapTile createTile(Point offset) {
+               AltosSiteMapTile tile = new AltosSiteMapTile(px_size);
+               mapTiles.put(offset, tile);
+               return tile;
+       }
+       private void finishTileLater(final AltosSiteMapTile tile,
+                                    final Point offset)
+       {
+               SwingUtilities.invokeLater( new Runnable() {
+                       public void run() {
+                               addTileAt(tile, offset);
+                       }
+               } );
+       }
+
+       private void ensureTilesAround(Point base_offset) {
+               for (int x = -1; x <= 1; x++) {
+                       for (int y = -1; y <= 1; y++) {
+                               Point offset = new Point(base_offset.x + x, base_offset.y + y);
+                               if (mapTiles.containsKey(offset))
+                                       continue;
+                               AltosSiteMapTile tile = createTile(offset);
+                               initMap(tile, offset);
+                               finishTileLater(tile, offset);
+                       }
+               }
+       }
+
+       private Point topleft = new Point(0,0);
+       private void scrollRocketToVisible(Point2D.Double pt) {
+               Rectangle r = comp.getVisibleRect();
+               Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft));
+               int dx = (int)copt.x - r.width/2 - r.x;
+               int dy = (int)copt.y - r.height/2 - r.y;
+               if (Math.abs(dx) > r.width/4 || Math.abs(dy) > r.height/4) {
+                       r.x += dx;
+                       r.y += dy;
+                       comp.scrollRectToVisible(r);
+               }
+       }
+
+       private void addTileAt(AltosSiteMapTile tile, Point offset) {
+               if (Math.abs(offset.x) >= MAX_TILE_DELTA ||
+                               Math.abs(offset.y) >= MAX_TILE_DELTA)
+               {
+                       System.out.printf("Rocket too far away from pad (tile %d,%d)\n",
+                                         offset.x, offset.y);
+                       return;
+               }
+
+               boolean review = false;
+               Rectangle r = comp.getVisibleRect();
+               if (offset.x < topleft.x) {
+                       r.x += (topleft.x - offset.x) * px_size;
+                       topleft.x = offset.x;
+                       review = true;
+               }
+               if (offset.y < topleft.y) {
+                       r.y += (topleft.y - offset.y) * px_size;
+                       topleft.y = offset.y;
+                       review = true;
+               }
                GridBagConstraints c = new GridBagConstraints();
                c.anchor = GridBagConstraints.CENTER;
                c.fill = GridBagConstraints.BOTH;
-
                // put some space between the map tiles, debugging only
                // c.insets = new Insets(5, 5, 5, 5);
-               //
-               AltosSiteMapTile t = new AltosSiteMapTile(px_size);
-               mapTiles.add(t);
-               c.gridx = offset.x + 100;
-               c.gridy = offset.y + 100;
-               layout.setConstraints(t, c);
-               comp.add(t);
-
-               return t;
+
+               c.gridx = offset.x + MAX_TILE_DELTA;
+               c.gridy = offset.y + MAX_TILE_DELTA;
+               layout.setConstraints(tile, c);
+
+               comp.add(tile);
+               if (review) {
+                       comp.scrollRectToVisible(r);
+               }
        }
 
        private AltosSiteMap(boolean knowWhatYouAreDoing) {
@@ -299,25 +370,19 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
                }
        }
 
-       JComponent comp;
-       private GridBagLayout layout;
+       JComponent comp = new JComponent() { };
+       private GridBagLayout layout = new GridBagLayout();
 
        public AltosSiteMap() {
-               comp = new JComponent() {
-                       GrabNDrag scroller = new GrabNDrag(this);
-                       {
-                               addMouseMotionListener(scroller);
-                               addMouseListener(scroller);
-                               setAutoscrolls(true);
-                       }
-               };
+               GrabNDrag scroller = new GrabNDrag(comp);
 
-               layout = new GridBagLayout();
                comp.setLayout(layout);
 
                for (int x = -1; x <= 1; x++) {
                        for (int y = -1; y <= 1; y++) {
-                               addTileAt(new Point(x, y));
+                               Point offset = new Point(x, y);
+                               AltosSiteMapTile t = createTile(offset);
+                               addTileAt(t, offset);
                        }
                }
                setViewportView(comp);