25108bf97c67ad27660f8d1e3915b561c1724b8e
[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_11;
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         AltosState              prev = null;
40         double                  gps_start_altitude;
41
42         static final String[] kml_state_colors = {
43                 "FF000000",     // startup
44                 "FF000000",     // idle
45                 "FF000000",     // pad
46                 "FF0000FF",     // boost
47                 "FF4080FF",     // fast
48                 "FF00FFFF",     // coast
49                 "FFFF0000",     // drogue
50                 "FF00FF00",     // main
51                 "FF000000",     // landed
52                 "FFFFFFFF",     // invalid
53                 "FFFF0000",     // stateless
54         };
55
56         static String state_color(int state) {
57                 if (state < 0 || kml_state_colors.length <= state)
58                         return kml_state_colors[AltosLib.ao_flight_invalid];
59                 return kml_state_colors[state];
60         }
61
62         static final String kml_header_start =
63                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
64                 "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
65                 "<Document>\n" +
66                 "  <name>AO Flight#%d S/N: %03d</name>\n" +
67                 "  <description>\n";
68         static final String kml_header_end =
69                 "  </description>\n" +
70                 "  <open>0</open>\n";
71
72         static final String kml_style_start =
73                 "  <Style id=\"ao-flightstate-%s\">\n" +
74                 "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
75                 "    <BalloonStyle>\n" +
76                 "      <text>\n";
77
78         static final String kml_style_end =
79                 "      </text>\n" +
80                 "    </BalloonStyle>\n" +
81                 "  </Style>\n";
82
83         static final String kml_placemark_start =
84                 "  <Placemark>\n" +
85                 "    <name>%s</name>\n" +
86                 "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
87                 "    <LineString>\n" +
88                 "      <tessellate>1</tessellate>\n" +
89                 "      <altitudeMode>absolute</altitudeMode>\n" +
90                 "      <coordinates>\n";
91
92         static final String kml_coord_fmt =
93         "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
94
95         static final String kml_placemark_end =
96                 "      </coordinates>\n" +
97                 "    </LineString>\n" +
98                 "  </Placemark>\n";
99
100         static final String kml_footer =
101                 "</Document>\n" +
102                 "</kml>\n";
103
104         void start (AltosState record) {
105                 out.printf(kml_header_start, record.flight, record.serial);
106                 out.printf("Date:   %04d-%02d-%02d\n",
107                            record.gps.year, record.gps.month, record.gps.day);
108                 out.printf("Time:     %2d:%02d:%02d\n",
109                            record.gps.hour, record.gps.minute, record.gps.second);
110                 out.printf("%s", kml_header_end);
111         }
112
113         boolean started = false;
114
115         void state_start(AltosState state) {
116                 String  state_name = AltosLib.state_name(state.state());
117                 String  state_color = state_color(state.state());
118                 out.printf(kml_style_start, state_name, state_color);
119                 out.printf("\tState: %s\n", state_name);
120                 out.printf("%s", kml_style_end);
121                 out.printf(kml_placemark_start, state_name, state_name);
122         }
123
124         void state_end(AltosState state) {
125                 out.printf("%s", kml_placemark_end);
126         }
127
128         void coord(AltosState state) {
129                 AltosGPS        gps = state.gps;
130                 double          altitude;
131
132                 if (state.height() != AltosLib.MISSING)
133                         altitude = state.height() + gps_start_altitude;
134                 else
135                         altitude = gps.alt;
136                 out.printf(kml_coord_fmt,
137                            gps.lon, gps.lat,
138                            altitude, (double) gps.alt,
139                            state.time, gps.nsat);
140         }
141
142         void end() {
143                 out.printf("%s", kml_footer);
144         }
145
146         public void close() {
147                 if (prev != null) {
148                         state_end(prev);
149                         end();
150                         prev = null;
151                 }
152                 if (out != null) {
153                         out.close();
154                         out = null;
155                 }
156         }
157
158         public void write(AltosState state) {
159                 AltosGPS        gps = state.gps;
160
161                 if (gps == null)
162                         return;
163
164                 if (gps.lat == AltosLib.MISSING)
165                         return;
166                 if (gps.lon == AltosLib.MISSING)
167                         return;
168                 if (!started) {
169                         start(state);
170                         started = true;
171                         gps_start_altitude = gps.alt;
172                 }
173                 if (prev != null && prev.gps_sequence == state.gps_sequence)
174                         return;
175                 if (state.state() != flight_state) {
176                         flight_state = state.state();
177                         if (prev != null) {
178                                 coord(state);
179                                 state_end(prev);
180                         }
181                         state_start(state);
182                 }
183                 coord(state);
184                 prev = state;
185         }
186
187         public void write(AltosStateIterable states) {
188                 for (AltosState state : states) {
189                         if ((state.set & AltosState.set_gps) != 0)
190                                 write(state);
191                 }
192         }
193
194         public AltosKML(File in_name) throws FileNotFoundException {
195                 name = in_name;
196                 out = new KMLWriter(name);
197         }
198
199         public AltosKML(String in_string) throws FileNotFoundException {
200                 this(new File(in_string));
201         }
202 }