libaltos: Test both bluetooth and USB APIs with cjnitest
[fw/altos] / altoslib / AltosKML.java
1 /*
2  * Copyright © 2010 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package org.altusmetrum.altoslib_12;
20
21 import java.io.*;
22 import java.util.*;
23
24 class KMLWriter extends PrintWriter {
25         public PrintWriter printf(String format, Object ... arguments) {
26                 return printf(Locale.ROOT, format, arguments);
27         }
28
29         public KMLWriter(File name) throws FileNotFoundException {
30                 super(name);
31         }
32 }
33
34 public class AltosKML implements AltosWriter {
35
36         File                    name;
37         PrintWriter             out;
38         int                     flight_state = -1;
39         AltosGPS                prev = null;
40         double                  gps_start_altitude = AltosLib.MISSING;
41         AltosFlightStats        stats;
42
43         static final String[] kml_state_colors = {
44                 "FF000000",     // startup
45                 "FF000000",     // idle
46                 "FF000000",     // pad
47                 "FF0000FF",     // boost
48                 "FF4080FF",     // fast
49                 "FF00FFFF",     // coast
50                 "FFFF0000",     // drogue
51                 "FF00FF00",     // main
52                 "FF000000",     // landed
53                 "FFFFFFFF",     // invalid
54                 "FFFF0000",     // stateless
55         };
56
57         static String state_color(int state) {
58                 if (state < 0 || kml_state_colors.length <= state)
59                         return kml_state_colors[AltosLib.ao_flight_invalid];
60                 return kml_state_colors[state];
61         }
62
63         static final String kml_header_start =
64                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
65                 "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
66                 "<Document>\n" +
67                 "  <name>AO Flight#%d S/N: %03d</name>\n" +
68                 "  <description>\n";
69         static final String kml_header_end =
70                 "  </description>\n" +
71                 "  <open>0</open>\n";
72
73         static final String kml_style_start =
74                 "  <Style id=\"ao-flightstate-%s\">\n" +
75                 "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
76                 "    <BalloonStyle>\n" +
77                 "      <text>\n";
78
79         static final String kml_style_end =
80                 "      </text>\n" +
81                 "    </BalloonStyle>\n" +
82                 "  </Style>\n";
83
84         static final String kml_placemark_start =
85                 "  <Placemark>\n" +
86                 "    <name>%s</name>\n" +
87                 "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
88                 "    <LineString>\n" +
89                 "      <tessellate>1</tessellate>\n" +
90                 "      <altitudeMode>absolute</altitudeMode>\n" +
91                 "      <coordinates>\n";
92
93         static final String kml_coord_fmt =
94         "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
95
96         static final String kml_placemark_end =
97                 "      </coordinates>\n" +
98                 "    </LineString>\n" +
99                 "  </Placemark>\n";
100
101         static final String kml_footer =
102                 "</Document>\n" +
103                 "</kml>\n";
104
105         void start (AltosCalData cal_data) {
106                 AltosGPS gps = cal_data.gps_pad;
107
108                 gps_start_altitude = cal_data.gps_pad_altitude;
109                 out.printf(kml_header_start, cal_data.flight, cal_data.serial);
110                 out.printf("Date:   %04d-%02d-%02d\n",
111                            gps.year, gps.month, gps.day);
112                 out.printf("Time:     %2d:%02d:%02d\n",
113                            gps.hour, gps.minute, gps.second);
114                 out.printf("%s", kml_header_end);
115         }
116
117         boolean started = false;
118
119         void state_start(int state) {
120                 String  state_name = AltosLib.state_name(state);
121                 String  state_color = state_color(state);
122                 out.printf(kml_style_start, state_name, state_color);
123                 out.printf("State: %s\n", state_name);
124                 out.printf("Time: %6.2f s\n", stats.state_end[state] - stats.state_start[state]);
125                 out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state]));
126                 out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state]));
127                 out.printf("%s", kml_style_end);
128                 out.printf(kml_placemark_start, state_name, state_name);
129         }
130
131         void state_end() {
132                 out.printf("%s", kml_placemark_end);
133         }
134
135         void coord(double time, AltosGPS gps, int state, double height) {
136                 double          altitude;
137
138                 if (height != AltosLib.MISSING)
139                         altitude = height + gps_start_altitude;
140                 else
141                         altitude = gps.alt;
142                 out.printf(kml_coord_fmt,
143                            gps.lon, gps.lat,
144                            altitude, (double) gps.alt,
145                            time, gps.nsat);
146         }
147
148         void end() {
149                 out.printf("%s", kml_footer);
150         }
151
152         public void close() {
153                 if (prev != null) {
154                         state_end();
155                         end();
156                         prev = null;
157                 }
158                 if (out != null) {
159                         out.close();
160                         out = null;
161                 }
162         }
163
164         public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) {
165                 AltosGPS gps = gtv.gps;
166                 if (gps.lat == AltosLib.MISSING)
167                         return;
168                 if (gps.lon == AltosLib.MISSING)
169                         return;
170                 if (state != flight_state) {
171                         flight_state = state;
172                         if (prev != null) {
173                                 coord(gtv.time, gps, state, height);
174                                 state_end();
175                         }
176                         state_start(state);
177                 }
178                 coord(0, gps, state, height);
179                 prev = gps;
180         }
181
182         private int state(AltosFlightSeries series, double time) {
183                 return (int) series.value_before(AltosFlightSeries.state_name, time);
184         }
185
186         private double height(AltosFlightSeries series, double time) {
187                 return series.value(AltosFlightSeries.height_name, time);
188         }
189
190         public void write(AltosFlightSeries series) {
191                 stats = new AltosFlightStats(series);
192                 start(series.cal_data());
193                 for (AltosGPSTimeValue gtv : series.gps_series)
194                         write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time));
195         }
196
197         public AltosKML(File in_name) throws FileNotFoundException {
198                 name = in_name;
199                 out = new KMLWriter(name);
200         }
201
202         public AltosKML(String in_string) throws FileNotFoundException {
203                 this(new File(in_string));
204         }
205 }