altosui: Add map and GPS data to graph window. Trac #50
authorKeith Packard <keithp@keithp.com>
Sun, 10 Feb 2013 23:34:56 +0000 (15:34 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 11 Feb 2013 02:15:25 +0000 (18:15 -0800)
See where the rocket landed without having to replay the whole flight.

Signed-off-by: Keith Packard <keithp@keithp.com>
altosui/AltosFlightStats.java
altosui/AltosFlightStatsTable.java
altosui/AltosGraphUI.java
altosui/AltosSiteMap.java

index 0f32ae5e5b23f4c394c5b80cd80107fa9b895d38..7f0c9adba49e0c4f6b44dde0a2741b7280925d36 100644 (file)
@@ -34,6 +34,8 @@ public class AltosFlightStats {
        int             flight;
        int             year, month, day;
        int             hour, minute, second;
        int             flight;
        int             year, month, day;
        int             hour, minute, second;
+       double          lat, lon;
+       double          pad_lat, pad_lon;
 
        double landed_time(AltosRecordIterable iterable) {
                AltosState      state = null;
 
        double landed_time(AltosRecordIterable iterable) {
                AltosState      state = null;
@@ -98,6 +100,7 @@ public class AltosFlightStats {
                year = month = day = -1;
                hour = minute = second = -1;
                serial = flight = -1;
                year = month = day = -1;
                hour = minute = second = -1;
                serial = flight = -1;
+               lat = lon = -1;
                for (AltosRecord record : iterable) {
                        if (serial < 0)
                                serial = record.serial;
                for (AltosRecord record : iterable) {
                        if (serial < 0)
                                serial = record.serial;
@@ -137,6 +140,14 @@ public class AltosFlightStats {
                                        max_speed = state.max_baro_speed;
                                max_acceleration = state.max_acceleration;
                        }
                                        max_speed = state.max_baro_speed;
                                max_acceleration = state.max_acceleration;
                        }
+                       if (state.gps.locked && state.gps.nsat >= 4) {
+                               if (state.state <= Altos.ao_flight_pad) {
+                                       pad_lat = state.gps.lat;
+                                       pad_lon = state.gps.lon;
+                               }
+                               lat = state.gps.lat;
+                               lon = state.gps.lon;
+                       }
                }
                for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {
                        if (state_count[s] > 0) {
                }
                for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {
                        if (state_count[s] > 0) {
index 2b3e4d5ddf5b866080b2af839f142a6c36aa455b..5ed53c1a8a716786fba14abbe6ab7b407f3d1054 100644 (file)
@@ -58,6 +58,17 @@ public class AltosFlightStatsTable extends JComponent {
 
        }
 
 
        }
 
+       static String pos(double p, String pos, String neg) {
+               String  h = pos;
+               if (p < 0) {
+                       h = neg;
+                       p = -p;
+               }
+               int deg = (int) Math.floor(p);
+               double min = (p - Math.floor(p)) * 60.0;
+               return String.format("%s %4d° %9.6f'", h, deg, min);
+       }
+
        public AltosFlightStatsTable(AltosFlightStats stats) {
                layout = new GridBagLayout();
 
        public AltosFlightStatsTable(AltosFlightStats stats) {
                layout = new GridBagLayout();
 
@@ -65,12 +76,18 @@ public class AltosFlightStatsTable extends JComponent {
                int y = 0;
                new FlightStat(layout, y++, "Serial", String.format("%d", stats.serial));
                new FlightStat(layout, y++, "Flight", String.format("%d", stats.flight));
                int y = 0;
                new FlightStat(layout, y++, "Serial", String.format("%d", stats.serial));
                new FlightStat(layout, y++, "Flight", String.format("%d", stats.flight));
-               if (stats.year > 0)
-                       new FlightStat(layout, y++, "Date",
-                                      String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
-               if (stats.hour > 0)
-                       new FlightStat(layout, y++, "Time",
+               if (stats.year > 0 && stats.hour > 0)
+                       new FlightStat(layout, y++, "Date/Time",
+                                      String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day),
                                       String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
                                       String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
+               else {
+                       if (stats.year > 0)
+                               new FlightStat(layout, y++, "Date",
+                                              String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
+                       if (stats.hour > 0)
+                               new FlightStat(layout, y++, "Time",
+                                              String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
+               }
                new FlightStat(layout, y++, "Maximum height",
                               String.format("%5.0f m", stats.max_height),
                               String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
                new FlightStat(layout, y++, "Maximum height",
                               String.format("%5.0f m", stats.max_height),
                               String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
@@ -94,14 +111,29 @@ public class AltosFlightStatsTable extends JComponent {
                new FlightStat(layout, y++, "Main descent rate",
                               String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]),
                               String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main])));
                new FlightStat(layout, y++, "Main descent rate",
                               String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]),
                               String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main])));
-               for (int s = Altos.ao_flight_boost; s <= Altos.ao_flight_main; s++) {
-                       new FlightStat(layout, y++, String.format("%s time", AltosLib.state_name_capital(s)),
-                                      String.format("%6.0f s", stats.state_end[s] - stats.state_start[s]));
-               }
-               new FlightStat(layout, y++, "Flight Time",
-                              String.format("%6.0f s", stats.state_end[Altos.ao_flight_main] -
+               new FlightStat(layout, y++, "Ascent time",
+                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_boost] - stats.state_start[AltosLib.ao_flight_boost],
+                                            AltosLib.state_name(Altos.ao_flight_boost)),
+                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_fast] - stats.state_start[AltosLib.ao_flight_fast],
+                                            AltosLib.state_name(Altos.ao_flight_fast)),
+                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_coast] - stats.state_start[AltosLib.ao_flight_coast],
+                                            AltosLib.state_name(Altos.ao_flight_coast)));
+               new FlightStat(layout, y++, "Descent time",
+                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_drogue] - stats.state_start[AltosLib.ao_flight_drogue],
+                                            AltosLib.state_name(Altos.ao_flight_drogue)),
+                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_main] - stats.state_start[AltosLib.ao_flight_main],
+                                            AltosLib.state_name(Altos.ao_flight_main)));
+               new FlightStat(layout, y++, "Flight time",
+                              String.format("%6.1f s", stats.state_end[Altos.ao_flight_main] -
                                             stats.state_start[Altos.ao_flight_boost]));
                                             stats.state_start[Altos.ao_flight_boost]));
-               
+               if (stats.lat != -1 && stats.lon != -1) {
+                       new FlightStat(layout, y++, "Pad location",
+                                      pos(stats.pad_lat,"N","S"),
+                                      pos(stats.pad_lon,"E","W"));
+                       new FlightStat(layout, y++, "Last reported location",
+                                      pos(stats.lat,"N","S"),
+                                      pos(stats.lon,"E","W"));
+               }
        }
        
 }
\ No newline at end of file
        }
        
 }
\ No newline at end of file
index b376f7de69ee29d4adea4d1d46e56b003bd21af9..ac20f84b26a23ad7bfc4b22b6374348829778318 100644 (file)
@@ -21,8 +21,24 @@ public class AltosGraphUI extends AltosUIFrame
        JTabbedPane             pane;
        AltosGraph              graph;
        AltosUIEnable           enable;
        JTabbedPane             pane;
        AltosGraph              graph;
        AltosUIEnable           enable;
+       AltosSiteMap            map;
+       AltosState              state;
+
+       boolean fill_map(AltosRecordIterable records) {
+               boolean         any_gps = false;
+               for (AltosRecord record : records) {
+                       state = new AltosState(record, state);
+                       if (state.data.gps != null) {
+                               map.show(state, 0);
+                               any_gps = true;
+                       }
+               }
+               return any_gps;
+       }
 
        AltosGraphUI(AltosRecordIterable records, String file) throws InterruptedException, IOException {
 
        AltosGraphUI(AltosRecordIterable records, String file) throws InterruptedException, IOException {
+               state = null;
+
                pane = new JTabbedPane();
 
                enable = new AltosUIEnable();
                pane = new JTabbedPane();
 
                enable = new AltosUIEnable();
@@ -31,17 +47,24 @@ public class AltosGraphUI extends AltosUIFrame
 
                graph.setDataSet(new AltosGraphDataSet(records));
 
 
                graph.setDataSet(new AltosGraphDataSet(records));
 
+               map = new AltosSiteMap();
+
                pane.add("Flight Graph", graph.panel);
                pane.add("Configure Graph", enable);
 
                AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records));
                pane.add("Flight Statistics", stats);
 
                pane.add("Flight Graph", graph.panel);
                pane.add("Configure Graph", enable);
 
                AltosFlightStatsTable stats = new AltosFlightStatsTable(new AltosFlightStats(records));
                pane.add("Flight Statistics", stats);
 
+               if (fill_map(records))
+                       pane.add("Map", map);
+
                setContentPane (pane);
 
                pack();
 
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                setVisible(true);
                setContentPane (pane);
 
                pack();
 
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                setVisible(true);
+               if (state != null)
+                       map.centre(state);
        }
 }
        }
 }
index f111e62d45066d0d4dd6e6295a4fb44df955a0c8..f614eae65fc526370b1508b45a6477cd9ccd077d 100644 (file)
@@ -322,6 +322,22 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
                last_state = state.state;
        }
 
                last_state = state.state;
        }
 
+       public 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;
+               int dy = (int)copt.y - r.height/2 - r.y;
+               r.x += dx;
+               r.y += dy;
+               comp.scrollRectToVisible(r);
+       }
+
+       public void centre(AltosState state) {
+               if (!state.gps.locked && state.gps.nsat < 4)
+                       return;
+               centre(pt(state.gps.lat, state.gps.lon));
+       }
+
        public void draw_circle(double lat, double lon) {
                final Point2D.Double pt = pt(lat, lon);
 
        public void draw_circle(double lat, double lon) {
                final Point2D.Double pt = pt(lat, lon);