Initial Commit - Copy from Altus Metrum AltOS
This commit is contained in:
354
altoslib/AltosKML.java
Normal file
354
altoslib/AltosKML.java
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright © 2010 Keith Packard <keithp@keithp.com>
|
||||
*
|
||||
* 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; 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
package org.altusmetrum.altoslib_14;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
class KMLWriter extends PrintWriter {
|
||||
public PrintWriter printf(String format, Object ... arguments) {
|
||||
return printf(Locale.ROOT, format, arguments);
|
||||
}
|
||||
|
||||
public KMLWriter(File name) throws FileNotFoundException {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
public class AltosKML implements AltosWriter {
|
||||
|
||||
File name;
|
||||
PrintWriter out;
|
||||
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", // drogue
|
||||
"FF00FF00", // main
|
||||
"FF000000", // landed
|
||||
"FFFFFFFF", // invalid
|
||||
"FFFF0000", // stateless
|
||||
};
|
||||
|
||||
static String state_color(int state) {
|
||||
if (state < 0 || kml_state_colors.length <= state)
|
||||
return kml_state_colors[AltosLib.ao_flight_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" +
|
||||
" <Snippet maxLines=\"8\">\n";
|
||||
|
||||
static final String kml_header_end =
|
||||
" </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";
|
||||
|
||||
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 () {
|
||||
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);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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,
|
||||
time, gps.nsat);
|
||||
}
|
||||
|
||||
void end() {
|
||||
out.printf("%s", kml_footer);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void write(AltosGPS gps, double alt)
|
||||
{
|
||||
if (gps == null)
|
||||
return;
|
||||
if (gps.lat == AltosLib.MISSING)
|
||||
return;
|
||||
if (gps.lon == AltosLib.MISSING)
|
||||
return;
|
||||
if (alt == AltosLib.MISSING) {
|
||||
alt = cal_data.gps_pad_altitude;
|
||||
if (alt == AltosLib.MISSING)
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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 {
|
||||
name = in_name;
|
||||
out = new KMLWriter(name);
|
||||
}
|
||||
|
||||
public AltosKML(String in_string) throws FileNotFoundException {
|
||||
this(new File(in_string));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user