*
* 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
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-package org.altusmetrum.altoslib_11;
+package org.altusmetrum.altoslib_14;
import java.io.*;
import java.util.*;
File name;
PrintWriter out;
int flight_state = -1;
- AltosState prev = null;
- double gps_start_altitude;
+ 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
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_path_end =
+ " </coordinates>\n" +
+ " </LineString>\n" +
+ " </Placemark>\n";
- static final String kml_placemark_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 (AltosState record) {
- out.printf(kml_header_start, record.flight, record.serial);
- out.printf("Date: %04d-%02d-%02d\n",
- record.gps.year, record.gps.month, record.gps.day);
- out.printf("Time: %2d:%02d:%02d\n",
- record.gps.hour, record.gps.minute, record.gps.second);
+ 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("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",
+ 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 folder_end() {
+ out.printf(kml_folder_end);
+ }
+
+ void path_style_start(String style, String color) {
+ out.printf(kml_path_style_start, style, color);
+ }
- void state_start(AltosState state) {
- String state_name = AltosLib.state_name(state.state());
- String state_color = state_color(state.state());
- out.printf(kml_style_start, state_name, state_color);
- out.printf("\tState: %s\n", state_name);
- out.printf("%s", kml_style_end);
- out.printf(kml_placemark_start, state_name, state_name);
+ void path_style_end() {
+ out.printf(kml_path_style_end);
}
- void state_end(AltosState state) {
- out.printf("%s", kml_placemark_end);
+ void point_style_start(String style, String color) {
+ out.printf(kml_point_style_start, style, color, color);
}
- void coord(AltosState state) {
- AltosGPS gps = state.gps;
- double altitude;
+ void point_style_end() {
+ out.printf(kml_point_style_end);
+ }
+
+ void path_start(String name, String style) {
+ out.printf(kml_path_start, name, style);
+ }
- if (state.height() != AltosLib.MISSING)
- altitude = state.height() + gps_start_altitude;
- else
- altitude = gps.alt;
+ 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,
- state.time, gps.nsat);
+ time, gps.nsat);
}
void end() {
}
public void close() {
- if (prev != null) {
- state_end(prev);
- end();
- prev = null;
- }
if (out != null) {
out.close();
out = null;
}
}
- public void write(AltosState state) {
- AltosGPS gps = state.gps;
-
+ public void write(AltosGPS gps, double alt)
+ {
if (gps == null)
return;
-
if (gps.lat == AltosLib.MISSING)
return;
if (gps.lon == AltosLib.MISSING)
return;
- if (!started) {
- start(state);
- started = true;
- gps_start_altitude = gps.alt;
+ if (alt == AltosLib.MISSING) {
+ alt = cal_data.gps_pad_altitude;
+ if (alt == AltosLib.MISSING)
+ return;
}
- if (prev != null && prev.gps_sequence == state.gps_sequence)
- return;
- if (state.state() != flight_state) {
- flight_state = state.state();
- if (prev != null) {
- coord(state);
- state_end(prev);
- }
- state_start(state);
+ coord(0, gps, alt);
+ prev = gps;
+ }
+
+ 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);
+
+ 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;
}
- coord(state);
- prev = state;
+ point_style_end();
+ point_start(full_name, style_name);
+ gps = series.gps_before(tv.time);
+ write(gps, altitude);
+ point_end();
}
- public void write(AltosStateIterable states) {
- for (AltosState state : states) {
- if ((state.set & AltosState.set_gps) != 0)
- write(state);
+ public void write(AltosFlightSeries series) {
+ this.series = series;
+ series.finish();
+ stats = new AltosFlightStats(series);
+ cal_data = series.cal_data();
+ start();
+ if (series.height_series != null) {
+ 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.gps, baro_altitude(series, gtv.time));
+ path_end();
+ if (series.state_series != null) {
+ 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();
+ if (series.state_series != null) {
+ for (AltosTimeValue tv : series.state_series) {
+ write_point(tv, true);
+ }
}
+ folder_end();
+ end();
}
public AltosKML(File in_name) throws FileNotFoundException {