summaryrefslogtreecommitdiff
path: root/altoslib/AltosKML.java
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-10-04 13:42:16 -0700
committerKeith Packard <keithp@keithp.com>2017-10-04 13:42:16 -0700
commit730ee7bf91f607ece42c010a10c53d0013492b96 (patch)
tree75ec3efd39013d3d58483df90089ce07bd66231b /altoslib/AltosKML.java
parent98dc29a7a964f8d653b73989c6751695d168844c (diff)
altoslib: Adapt KML output to make TRA record people happier
Provide two paths, one using GPS data the other baro. Replace separate path segments for each state with markers so that the path is a single unit, able to be displayed in the elevation profile widget. Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'altoslib/AltosKML.java')
-rw-r--r--altoslib/AltosKML.java289
1 files changed, 215 insertions, 74 deletions
diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java
index 587b845b..4738ac91 100644
--- a/altoslib/AltosKML.java
+++ b/altoslib/AltosKML.java
@@ -38,16 +38,18 @@ public class AltosKML implements AltosWriter {
int flight_state = -1;
AltosGPS prev = null;
double gps_start_altitude = AltosLib.MISSING;
+ AltosFlightSeries series;
AltosFlightStats stats;
+ AltosCalData cal_data;
static final String[] kml_state_colors = {
"FF000000", // startup
"FF000000", // idle
"FF000000", // pad
"FF0000FF", // boost
+ "FF8040FF", // coast
"FF4080FF", // fast
- "FF00FFFF", // coast
- "FFFF0000", // drogue
+ "FF00FFFF", // drogue
"FF00FF00", // main
"FF000000", // landed
"FFFFFFFF", // invalid
@@ -60,85 +62,169 @@ public class AltosKML implements AltosWriter {
return kml_state_colors[state];
}
+ static final String[] kml_style_colors = {
+ "FF0000FF", // baro
+ "FFFF0000", // gps
+ };
+
+ static String style_color(int style) {
+ if (style < 0 || kml_style_colors.length <= style)
+ return kml_style_colors[0];
+ return kml_style_colors[style];
+ }
+
static final String kml_header_start =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
"<Document>\n" +
" <name>AO Flight#%d S/N: %03d</name>\n" +
- " <description>\n";
+ " <Snippet maxLines=\"8\">\n";
+
static final String kml_header_end =
- " </description>\n" +
- " <open>0</open>\n";
-
- static final String kml_style_start =
- " <Style id=\"ao-flightstate-%s\">\n" +
- " <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
- " <BalloonStyle>\n" +
- " <text>\n";
-
- static final String kml_style_end =
- " </text>\n" +
- " </BalloonStyle>\n" +
- " </Style>\n";
-
- static final String kml_placemark_start =
- " <Placemark>\n" +
- " <name>%s</name>\n" +
- " <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
- " <LineString>\n" +
- " <tessellate>1</tessellate>\n" +
- " <altitudeMode>absolute</altitudeMode>\n" +
- " <coordinates>\n";
+ " </Snippet>\n" +
+ " <open>1</open>\n";
+
+ static final String kml_folder_start =
+ " <Folder>\n" +
+ " <name>%s</name>\n";
+
+ static final String kml_path_style_start =
+ " <Style id=\"ao-style-%s\">\n" +
+ " <LineStyle><color>%s</color><width>8</width></LineStyle>\n" +
+ " <BalloonStyle>\n" +
+ " <text>\n";
+
+ static final String kml_path_style_end =
+ " </text>\n" +
+ " </BalloonStyle>\n" +
+ " </Style>\n";
+
+ static final String kml_point_style_start =
+ " <Style id=\"ao-style-%s\">\n" +
+ " <LabelStyle><color>%s</color></LabelStyle>\n" +
+ " <IconStyle><color>%s</color></IconStyle>\n" +
+ " <BalloonStyle>\n" +
+ " <text>\n";
+
+ static final String kml_point_style_end =
+ " </text>\n" +
+ " </BalloonStyle>\n" +
+ " </Style>\n";
+
+ static final String kml_path_start =
+ " <Placemark>\n" +
+ " <name>%s</name>\n" +
+ " <styleUrl>#ao-style-%s</styleUrl>\n" +
+ " <LineString>\n" +
+ " <tessellate>1</tessellate>\n" +
+ " <altitudeMode>absolute</altitudeMode>\n" +
+ " <coordinates>\n";
static final String kml_coord_fmt =
- " %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+ " %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
- static final String kml_placemark_end =
- " </coordinates>\n" +
- " </LineString>\n" +
- " </Placemark>\n";
+ static final String kml_path_end =
+ " </coordinates>\n" +
+ " </LineString>\n" +
+ " </Placemark>\n";
+
+ static final String kml_point_start =
+ " <Placemark>\n" +
+ " <name>%s</name>\n" +
+ " <styleUrl>#ao-style-%s</styleUrl>\n" +
+ " <Point>\n" +
+ " <tessellate>1</tessellate>\n" +
+ " <altitudeMode>absolute</altitudeMode>\n" +
+ " <coordinates>\n";
+
+ static final String kml_point_end =
+ " </coordinates>\n" +
+ " </Point>\n" +
+ " </Placemark>\n";
+
+ static final String kml_folder_end =
+ " </Folder>\n";
static final String kml_footer =
"</Document>\n" +
"</kml>\n";
- void start (AltosCalData cal_data) {
+ void start () {
AltosGPS gps = cal_data.gps_pad;
gps_start_altitude = cal_data.gps_pad_altitude;
out.printf(kml_header_start, cal_data.flight, cal_data.serial);
- out.printf("Date: %04d-%02d-%02d\n",
+ out.printf("Product: %s\n", stats.product);
+ out.printf("Firmware: %s\n", stats.firmware_version);
+ out.printf("Date: %04d-%02d-%02d\n",
gps.year, gps.month, gps.day);
- out.printf("Time: %2d:%02d:%02d\n",
+ out.printf("Time: %2d:%02d:%02d\n",
gps.hour, gps.minute, gps.second);
+ if (stats.max_height != AltosLib.MISSING)
+ out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height));
+ if (stats.max_gps_height != AltosLib.MISSING)
+ out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+ if (stats.max_speed != AltosLib.MISSING)
+ out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed));
+ if (stats.max_acceleration != AltosLib.MISSING)
+ out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
out.printf("%s", kml_header_end);
}
- boolean started = false;
+ void folder_start(String folder_name) {
+ out.printf(kml_folder_start, folder_name);
+ }
- void state_start(int state) {
- String state_name = AltosLib.state_name(state);
- String state_color = state_color(state);
- out.printf(kml_style_start, state_name, state_color);
- out.printf("State: %s\n", state_name);
- out.printf("Time: %6.2f s\n", stats.state_time[state]);
- out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state]));
- out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state]));
- out.printf("%s", kml_style_end);
- out.printf(kml_placemark_start, state_name, state_name);
+ void folder_end() {
+ out.printf(kml_folder_end);
}
- void state_end() {
- out.printf("%s", kml_placemark_end);
+ void path_style_start(String style, String color) {
+ out.printf(kml_path_style_start, style, color);
}
- void coord(double time, AltosGPS gps, int state, double height) {
- double altitude;
+ void path_style_end() {
+ out.printf(kml_path_style_end);
+ }
+
+ void point_style_start(String style, String color) {
+ out.printf(kml_point_style_start, style, color, color);
+ }
+
+ void point_style_end() {
+ out.printf(kml_point_style_end);
+ }
- if (height != AltosLib.MISSING)
- altitude = height + gps_start_altitude;
- else
- altitude = gps.alt;
+ void path_start(String name, String style) {
+ out.printf(kml_path_start, name, style);
+ }
+
+ void path_end() {
+ out.printf(kml_path_end);
+ }
+
+ void point_start(String name, String style) {
+ out.printf(kml_point_start, name, style);
+ }
+
+ void point_end() {
+ out.printf(kml_point_end);
+ }
+
+ boolean started = false;
+
+ private double baro_altitude(AltosFlightSeries series, double time) {
+ double height = series.value(AltosFlightSeries.height_name, time);
+
+ if (height == AltosLib.MISSING)
+ return AltosLib.MISSING;
+ if (cal_data.gps_pad_altitude == AltosLib.MISSING)
+ return AltosLib.MISSING;
+
+ return height + cal_data.gps_pad_altitude;
+ }
+
+ void coord(double time, AltosGPS gps, double altitude) {
out.printf(kml_coord_fmt,
gps.lon, gps.lat,
altitude, (double) gps.alt,
@@ -150,48 +236,103 @@ public class AltosKML implements AltosWriter {
}
public void close() {
- if (prev != null) {
- state_end();
- end();
- prev = null;
- }
if (out != null) {
out.close();
out = null;
}
}
- public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) {
- AltosGPS gps = gtv.gps;
+ public void write(AltosGPS gps, double alt)
+ {
if (gps.lat == AltosLib.MISSING)
return;
if (gps.lon == AltosLib.MISSING)
return;
- if (state != flight_state) {
- flight_state = state;
- if (prev != null) {
- coord(gtv.time, gps, state, height);
- state_end();
- }
- state_start(state);
+ if (alt == AltosLib.MISSING) {
+ alt = cal_data.gps_pad_altitude;
+ if (alt == AltosLib.MISSING)
+ return;
}
- coord(0, gps, state, height);
+ coord(0, gps, alt);
prev = gps;
}
- private int state(AltosFlightSeries series, double time) {
- return (int) series.value_before(AltosFlightSeries.state_name, time);
- }
+ public void write_point(AltosTimeValue tv, boolean is_gps) {
+ int state = (int) tv.value;
+ String style_prefix = is_gps ? "gps-" : "baro-";
+ String state_name = AltosLib.state_name(state);
+ String state_label = AltosLib.state_name_capital(state);
+ String style_name = style_prefix + state_name;
+ String folder_name = is_gps ? "GPS" : "Baro";
+ String full_name = state_label + " (" + folder_name + ")";
+ AltosGPS gps = series.gps_before(tv.time);
+ double altitude = is_gps ? gps.alt : baro_altitude(series, tv.time);
- private double height(AltosFlightSeries series, double time) {
- return series.value(AltosFlightSeries.height_name, time);
+ point_style_start(style_name, state_color(state));
+ out.printf("%s\n", full_name);
+ switch (state) {
+ case AltosLib.ao_flight_boost:
+ out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration));
+ out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed));
+ break;
+ case AltosLib.ao_flight_coast:
+ case AltosLib.ao_flight_fast:
+ out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state]));
+ out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+ break;
+ case AltosLib.ao_flight_drogue:
+ out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height));
+ out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+ break;
+ case AltosLib.ao_flight_main:
+ out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+ out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude));
+ out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state]));
+ break;
+ case AltosLib.ao_flight_landed:
+ out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state]));
+ break;
+ }
+ point_style_end();
+ point_start(full_name, style_name);
+ gps = series.gps_before(tv.time);
+ write(gps, altitude);
+ point_end();
}
public void write(AltosFlightSeries series) {
+ this.series = series;
+ series.finish();
stats = new AltosFlightStats(series);
- start(series.cal_data());
+ cal_data = series.cal_data();
+ start();
+ folder_start("Barometric Altitude");
+ path_style_start("baro", style_color(0));
+ out.printf("Barometric Altitude\n");
+ out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height));
+ path_style_end();
+ path_start("Barometric Altitude", "baro");
for (AltosGPSTimeValue gtv : series.gps_series)
- write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time));
+ write(gtv.gps, baro_altitude(series, gtv.time));
+ path_end();
+ for (AltosTimeValue tv : series.state_series) {
+ write_point(tv, false);
+ }
+ folder_end();
+ folder_start("GPS Altitude");
+ path_style_start("gps", style_color(1));
+ out.printf("GPS Altitude");
+ out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height));
+ path_style_end();
+ path_start("GPS Altitude", "gps");
+ for (AltosGPSTimeValue gtv : series.gps_series)
+ write(gtv.gps, gtv.gps.alt);
+ path_end();
+ for (AltosTimeValue tv : series.state_series) {
+ write_point(tv, true);
+ }
+ folder_end();
+ end();
}
public AltosKML(File in_name) throws FileNotFoundException {