diff options
| author | Keith Packard <keithp@keithp.com> | 2017-10-04 13:42:16 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2017-10-04 13:42:16 -0700 | 
| commit | 730ee7bf91f607ece42c010a10c53d0013492b96 (patch) | |
| tree | 75ec3efd39013d3d58483df90089ce07bd66231b /altoslib | |
| parent | 98dc29a7a964f8d653b73989c6751695d168844c (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')
| -rw-r--r-- | altoslib/AltosFlightStats.java | 7 | ||||
| -rw-r--r-- | altoslib/AltosKML.java | 289 | 
2 files changed, 222 insertions, 74 deletions
| diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index ea1a9675..6bb83581 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -27,6 +27,8 @@ public class AltosFlightStats {  	public double		max_acceleration;  	public double[]		state_speed = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_enter_speed = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_height = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_gps_height = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_accel = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_time = new double[AltosLib.ao_flight_invalid + 1];  	public String		product; @@ -134,6 +136,11 @@ public class AltosFlightStats {  		if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) {  			if (state_enter_speed[state] == AltosLib.MISSING)  				state_enter_speed[state] = series.speed_series.value(start_time); +			if (state_enter_height[state] == AltosLib.MISSING) +				state_enter_height[state] = series.height_series.value(start_time); +			if (state_enter_gps_height[state] == AltosLib.MISSING) +				if (series.gps_height != null) +					state_enter_gps_height[state] = series.gps_height.value(start_time);  			speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time;  			speeds[state].time += delta_time;  			accels[state].value += series.accel_series.average(start_time, end_time) * delta_time; 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 { | 
