summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Beattie <mike@ethernal.org>2010-06-17 14:04:01 +1200
committerMike Beattie <mike@ethernal.org>2010-06-17 14:04:01 +1200
commit24393eab0ea085f2d0224b59fdc3c00693e5d3a9 (patch)
tree781ba09ed469d56acde2b4498ffeaee980bc00e0
parent93c1e29b07c331a5ca6e0f647b9d2e9266ed3014 (diff)
Extension to KML output format, and minor bug fix
Extended KML output by breaking flight into coloured segments representing flight state. Add extra statistical information to description bubbles visible in Google Earth when clicking on links in My Places. Fix Bugs: * output kml to file provided as argument. * move kml coordinate output code to take advantage of nsat calculation * remove superfluous %9.2f format specifier from raw_file output. Signed-off-by: Mike Beattie <mike@ethernal.org>
-rw-r--r--ao-tools/ao-postflight/ao-postflight.c169
1 files changed, 126 insertions, 43 deletions
diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c
index cbf9c047..bf427d3b 100644
--- a/ao-tools/ao-postflight/ao-postflight.c
+++ b/ao-tools/ao-postflight/ao-postflight.c
@@ -39,6 +39,19 @@ static const char *state_names[] = {
"invalid"
};
+static const char *kml_state_colours[] = {
+ "FF000000",
+ "FF000000",
+ "FF000000",
+ "FF0000FF",
+ "FF4080FF",
+ "FF00FFFF",
+ "FFFF0000",
+ "FF00FF00",
+ "FF000000",
+ "FFFFFFFF"
+};
+
static int plot_colors[3][3] = {
{ 0, 0x90, 0 }, /* height */
{ 0xa0, 0, 0 }, /* speed */
@@ -161,28 +174,48 @@ merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split
return pd;
}
-static const char kml_header[] =
+static const char kml_header_start[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n"
+ "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
+ "<Document>\n"
+ " <name>%s</name>\n"
+ " <description>\n";
+static const char kml_header_end[] =
+ " </description>\n"
+ " <open>0</open>\n";
+
+static const char kml_style_start[] =
+ " <Style id=\"ao-flightstate-%s\">\n"
+ " <LineStyle><color>%s</color><width>4</width></LineStyle>\n"
+ " <BalloonStyle>\n"
+ " <text>\n";
+static const char kml_style_end[] =
+ " </text>\n"
+ " </BalloonStyle>\n"
+ " </Style>\n";
+
+static const char kml_placemark_start[] =
" <Placemark>\n"
- " <name>gps</name>\n"
- " <Style id=\"khStyle690\">\n"
- " <LineStyle id=\"khLineStyle694\">\n"
- " <color>ff00ffff</color>\n"
- " <width>4</width>\n"
- " </LineStyle>\n"
- " </Style>\n"
- " <MultiGeometry id=\"khMultiGeometry697\">\n"
- " <LineString id=\"khLineString698\">\n"
- " <tessellate>1</tessellate>\n"
- " <altitudeMode>absolute</altitudeMode>\n"
- " <coordinates>\n";
+ " <name>%s</name>\n"
+ " <styleUrl>#ao-flightstate-%s</styleUrl>\n"
+ " <LineString>\n"
+ " <tessellate>1</tessellate>\n"
+ " <altitudeMode>absolute</altitudeMode>\n"
+ " <coordinates>\n";
+
+static const char kml_coord_fmt[] =
+ " %12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+
+static const char kml_placemark_end[] =
+ " </coordinates>\n"
+ " </LineString>\n"
+ " </Placemark>\n";
static const char kml_footer[] =
- "</coordinates>\n"
+ " </coordinates>\n"
" </LineString>\n"
- " </MultiGeometry>\n"
- "</Placemark>\n"
+ " </Placemark>\n"
+ "</Document>\n"
"</kml>\n";
static unsigned
@@ -272,22 +305,33 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
double state_start, state_stop;
struct cc_flightcooked *cooked;
double apogee;
+ char buf[128];
+
+ if (kml_file) {
+ snprintf(buf, sizeof (buf), "AO Flight#%d S/N: %03d", f->flight, f->serial);
+ fprintf(kml_file, kml_header_start, buf);
+ }
fprintf(summary_file,
"Serial: %9d\n"
"Flight: %9d\n",
f->serial, f->flight);
+
if (f->year) {
- fprintf(summary_file,
+ snprintf(buf, sizeof (buf),
"Date: %04d-%02d-%02d\n",
f->year, f->month, f->day);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
if (f->gps.num) {
- fprintf(summary_file,
+ snprintf(buf, sizeof (buf),
"Time: %2d:%02d:%02d\n",
f->gps.data[0].hour,
f->gps.data[0].minute,
f->gps.data[0].second);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
boost_start = f->accel.data[0].time;
boost_stop = f->accel.data[f->accel.num-1].time;
@@ -309,10 +353,12 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
min_pres = f->pres.data[pres_i].value;
height = cc_barometer_to_altitude(min_pres) -
cc_barometer_to_altitude(f->ground_pres);
- fprintf(summary_file, "Max height: %9.2fm %9.2fft %9.2fs\n",
+ apogee = f->pres.data[pres_i].time;
+ snprintf(buf, sizeof (buf), "Max height: %9.2fm %9.2fft %9.2fs\n",
height, height * 100 / 2.54 / 12,
(f->pres.data[pres_i].time - boost_start) / 100.0);
- apogee = f->pres.data[pres_i].time;
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
cooked = cc_flight_cook(f);
@@ -320,9 +366,11 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
speed_i = cc_perioddata_max(&cooked->accel_speed, boost_start, boost_stop);
if (speed_i >= 0) {
speed = cooked->accel_speed.data[speed_i];
- fprintf(summary_file, "Max speed: %9.2fm/s %9.2fft/s %9.2fs\n",
+ snprintf(buf, sizeof (buf), "Max speed: %9.2fm/s %9.2fft/s %9.2fs\n",
speed, speed * 100 / 2.4 / 12.0,
(cooked->accel_speed.start + speed_i * cooked->accel_speed.step - boost_start) / 100.0);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
}
accel_i = cc_timedata_min(&f->accel, boost_start, boost_stop);
@@ -330,11 +378,16 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
{
accel = cc_accelerometer_to_acceleration(f->accel.data[accel_i].value,
f->ground_accel);
- fprintf(summary_file, "Max accel: %9.2fm/s² %9.2fg %9.2fs\n",
+ snprintf(buf, sizeof (buf), "Max accel: %9.2fm/s² %9.2fg %9.2fs\n",
accel, accel / 9.80665,
(f->accel.data[accel_i].time - boost_start) / 100.0);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
+ if (kml_file)
+ fprintf(kml_file, "%s", kml_header_end);
+
for (i = 0; i < f->state.num; i++) {
state = f->state.data[i].value;
state_start = f->state.data[i].time;
@@ -347,14 +400,23 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
fprintf(summary_file, "State: %s\n", state_names[state]);
fprintf(summary_file, "\tStart: %9.2fs\n", (state_start - boost_start) / 100.0);
fprintf(summary_file, "\tDuration: %9.2fs\n", (state_stop - state_start) / 100.0);
+ if (kml_file) {
+ fprintf(kml_file, kml_style_start, state_names[state], kml_state_colours[state]);
+ fprintf(kml_file, "\tState: %s\n", state_names[state]);
+ fprintf(kml_file, "\tStart: %9.2fs\n", (state_start - boost_start) / 100.0);
+ fprintf(kml_file, "\tDuration: %9.2fs\n", (state_stop - state_start) / 100.0);
+ }
+
accel_i = cc_timedata_min(&f->accel, state_start, state_stop);
if (accel_i >= 0)
{
accel = cc_accelerometer_to_acceleration(f->accel.data[accel_i].value,
f->ground_accel);
- fprintf(summary_file, "\tMax accel: %9.2fm/s² %9.2fg %9.2fs\n",
+ snprintf(buf, sizeof (buf), "\tMax accel: %9.2fm/s² %9.2fg %9.2fs\n",
accel, accel / 9.80665,
(f->accel.data[accel_i].time - boost_start) / 100.0);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
if (cooked) {
@@ -371,11 +433,16 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
}
if (speed_i >= 0)
{
- fprintf(summary_file, "\tMax speed: %9.2fm/s %9.2fft/s %9.2fs\n",
+ snprintf(buf, sizeof (buf), "\tMax speed: %9.2fm/s %9.2fft/s %9.2fs\n",
speed, speed * 100 / 2.4 / 12.0,
(cooked->accel_speed.start + speed_i * cooked->accel_speed.step - boost_start) / 100.0);
- fprintf(summary_file, "\tAvg speed: %9.2fm/s %9.2fft/s\n",
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
+
+ snprintf(buf, sizeof (buf), "\tAvg speed: %9.2fm/s %9.2fft/s\n",
avg_speed, avg_speed * 100 / 2.4 / 12.0);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
}
pres_i = cc_timedata_min(&f->pres, state_start, state_stop);
@@ -384,10 +451,13 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
min_pres = f->pres.data[pres_i].value;
height = cc_barometer_to_altitude(min_pres) -
cc_barometer_to_altitude(f->ground_pres);
- fprintf(summary_file, "\tMax height: %9.2fm %9.2fft %9.2fs\n",
+ snprintf(buf, sizeof (buf), "\tMax height: %9.2fm %9.2fft %9.2fs\n",
height, height * 100 / 2.54 / 12,
(f->pres.data[pres_i].time - boost_start) / 100.0);
+ fprintf(summary_file, "%s", buf);
+ if (kml_file) fprintf(kml_file, "%s", buf);
}
+ if (kml_file) fprintf(kml_file, "%s", kml_style_end);
}
if (cooked && detail_file) {
double max_height = 0;
@@ -431,7 +501,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
daytime = compute_daytime_ms(time, &f->gps);
else
daytime = 0;
- fprintf(raw_file, "%9.2f %9.2f %9.2f %9.2f %02d:%02d:%02d.%03d\n",
+ fprintf(raw_file, "%9.2f %9.2f %9.2f %02d:%02d:%02d.%03d\n",
time, pres, accel,
daytime_hour(daytime),
daytime_minute(daytime),
@@ -443,13 +513,17 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
int j = 0, baro_pos;
double baro_offset;
double baro = 0.0;
+ int state_idx = 0;
if (gps_file)
fprintf(gps_file, "%2s %2s %2s %9s %12s %12s %9s %8s %5s\n",
"hr", "mn", "sc",
"time", "lat", "lon", "alt", "baro", "nsat");
if (kml_file)
- fprintf(kml_file, "%s", kml_header);
+ fprintf(kml_file, kml_placemark_start,
+ state_names[(int)f->state.data[state_idx].value],
+ state_names[(int)f->state.data[state_idx].value]);
+
if (f->gps.num)
baro_offset = f->gps.data[0].alt;
else
@@ -484,19 +558,6 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
f->gps.data[i].lon,
f->gps.data[i].alt,
baro + baro_offset);
- if (kml_file) {
- fprintf(kml_file, "%12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->",
- f->gps.data[i].lon,
- f->gps.data[i].lat,
- baro + baro_offset,
- f->gps.data[i].alt,
- (f->gps.data[i].time - boost_start) / 100.0,
- nsat);
- if (i < f->gps.num - 1)
- fprintf(kml_file, ",\n");
- else
- fprintf(kml_file, "\n");
- }
nsat = 0;
if (f->gps.sats) {
@@ -516,6 +577,28 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file,
fprintf(gps_file, "\n");
}
}
+
+ if (kml_file) {
+ snprintf(buf, sizeof (buf), kml_coord_fmt,
+ f->gps.data[i].lon,
+ f->gps.data[i].lat,
+ baro + baro_offset,
+ f->gps.data[i].alt,
+ (f->gps.data[i].time - boost_start) / 100.0,
+ nsat);
+ fprintf(kml_file, "%s", buf);
+ if (state_idx + 1 <= f->state.num && f->state.data[state_idx + 1].time <= f->gps.data[i].time) {
+ state_idx++;
+ if (f->state.data[state_idx - 1].value != f->state.data[state_idx].value) {
+ fprintf(kml_file, "%s", kml_placemark_end);
+ fprintf(kml_file, kml_placemark_start,
+ state_names[(int)f->state.data[state_idx].value],
+ state_names[(int)f->state.data[state_idx].value]);
+ fprintf(kml_file, "%s", buf);
+ }
+ }
+ }
+
}
if (kml_file)
fprintf(kml_file, "%s", kml_footer);
@@ -705,7 +788,7 @@ main (int argc, char **argv)
if (has_gps && !gps_file)
gps_file = open_output(gps_name, argv[i], ".gps");
if (has_kml && !kml_file)
- kml_file = open_output(gps_name, argv[i], ".kml");
+ kml_file = open_output(kml_name, argv[i], ".kml");
s = strstr(argv[i], "-serial-");
if (s)
serial = atoi(s + 8);