/*******************************************************************************
* Gaggle is Copyright 2010 by Geeksville Industries LLC, a California limited liability corporation.
*
* Gaggle is distributed under a dual license. We've chosen this approach because within Gaggle we've used a number
* of components that Geeksville Industries LLC might reuse for commercial products. Gaggle can be distributed under
* either of the two licenses listed below.
*
* 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.
*
* Commercial Distribution License
* If you would like to distribute Gaggle (or portions thereof) under a license other than
* the "GNU General Public License, version 2", contact Geeksville Industries. Geeksville Industries reserves
* the right to release Gaggle source code under a commercial license of its choice.
*
* GNU Public License, version 2
* All other distribution of Gaggle must conform to the terms of the GNU Public License, version 2. The full
* text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt.
******************************************************************************/
package com.geeksville.location;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import com.geeksville.info.Units;
/*
"
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>KML Samples</name>
<open>1</open>
<description>Unleash your creativity with the help of these examples!</description>
<Style id="yellowLineGreenPoly">
<LineStyle>
<color>7f00ffff</color>
<width>4</width>
</LineStyle>
<PolyStyle>
<color>7f00ff00</color>
</PolyStyle>
</Style>
<Folder>
<Placemark>
<name>Absolute Extruded</name>
<visibility>0</visibility>
<description>Transparent green wall with yellow outlines</description>
<LookAt>
<longitude>-112.2643334742529</longitude>
<latitude>36.08563154742419</latitude>
<altitude>0</altitude>
<heading>-125.7518698668815</heading>
<tilt>44.61038665812578</tilt>
<range>4451.842204068102</range>
</LookAt>
<styleUrl>#yellowLineGreenPoly</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<coordinates> -112.2550785337791,36.07954952145647,2357
-112.2549277039738,36.08117083492122,2357
-112.2552505069063,36.08260761307279,2357
-112.2564540158376,36.08395660588506,2357
-112.2580238976449,36.08511401044813,2357
-112.2595218489022,36.08584355239394,2357
-112.2608216347552,36.08612634548589,2357
-112.262073428656,36.08626019085147,2357
-112.2633204928495,36.08621519860091,2357
-112.2644963846444,36.08627897945274,2357
-112.2656969554589,36.08649599090644,2357 </coordinates>
</LineString>
</Placemark>
</Folder>
</Document>
</kml>
"
*/
public class KMLWriter implements PositionWriter {
PrintStream out;
boolean didProlog = false;
String pilotName;
String flightDesc;
String gliderType;
String pilotId;
float minHeight = Float.MAX_VALUE, maxHeight = Float.MIN_VALUE;
long firstTimeMs, lastTimeMs;
boolean isFirst = true;
public KMLWriter(OutputStream dest, String pilotName, String flightDesc, String gliderType,
String pilotId) throws IOException {
out = new PrintStream(dest);
this.gliderType = gliderType;
this.pilotId = pilotId;
this.pilotName = pilotName;
this.flightDesc = flightDesc;
}
/**
* We close the output stream in the epilog
*/
@Override
public void emitEpilog() {
out.println("</coordinates>" +
"</LineString>" +
createDescription() + // gen our description after reading all
// our points
"</Placemark>" +
"</Document>" +
"</kml>");
out.close();
}
/**
*
* @param time
* UTC time of this fix, in milliseconds since January 1, 1970.
* @param latitude
* @param longitude
*
* sect 4.1, B=fix plus extension data mentioned in I
*/
@Override
public void emitPosition(long time, double latitude, double longitude, float altitude,
int bearing, float groundSpeed, float[] accel, float vspd) {
// B
// HHMMSS - time UTC
// DDMMmmmN(or S) latitude
// DDDMMmmmE(or W) longitude
// A (3d valid) or V (2d only)
// PPPPP pressure altitude (00697 in this case)
// GGGGG alt above WGS ellipsode (00705 in this case)
// GSP is 000 here (ground speed in km/hr)
// B1851353728534N12151678WA0069700705000
if (isFirst) {
firstTimeMs = time;
isFirst = false;
}
lastTimeMs = time;
boolean is3D = !Double.isNaN(altitude);
if (!is3D)
altitude = 0f;
else {
minHeight = Math.min(altitude, minHeight);
maxHeight = Math.max(altitude, maxHeight);
}
// Use US format to ensure floats have dots not commas ;-)
out.format(Locale.US, "%f,%f,%d\n", longitude, latitude, (int) altitude);
}
private String getTimespan(long numMs) {
Date d = new Date(numMs);
String res = String.format("%02d:%02d:%02d", d.getHours(), d.getMinutes(), d.getSeconds());
return res;
}
/**
* Generate a verbose description of the flight
*
* @return
*/
private String createDescription() {
DateFormat dformat = DateFormat.getDateInstance();
DateFormat tformat = DateFormat.getTimeInstance();
StringBuilder builder = new StringBuilder();
builder.append("<description>");
// builder.append("Gaggle Tracklog");
builder.append("<![CDATA[");
builder.append("Gaggle Tracklog\n");
builder.append("<pre>\n");
builder.append("Flight statistics\n");
builder.append(String.format("Pilot name %s\n", pilotName));
builder.append(String.format("Pilot ID %s\n", pilotId));
builder.append(String.format("Glider type %s\n", gliderType));
builder
.append(String
.format("Date %s\n", dformat.format(new Date(firstTimeMs))));
builder.append(String.format("Start/finish %s - %s\n", tformat.format(new Date(
firstTimeMs)), tformat.format(new Date(lastTimeMs))));
builder.append(String.format("Duration %s\n", getTimespan(lastTimeMs
- firstTimeMs)));
builder.append(String.format("Max/min height %s%s / %s%s\n", Units.instance
.metersToAltitude(maxHeight), Units.instance.getAltitudeUnits(),
Units.instance.metersToAltitude(minHeight),
Units.instance.getAltitudeUnits()));
builder.append("</pre>\n");
builder.append("]]>");
builder.append("</description>");
return builder.toString();
}
@Override
public void emitProlog() {
out
.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">"
+
"<Document>"
+
"<name>Gaggle KML</name>"
+
"<open>1</open>"
+
"<description>Gaggle KML file</description>"
+
"<Style id=\"yellowLineGreenPoly\">" +
"<LineStyle>" +
"<color>7f00ffff</color>" +
"<width>4</width>" +
"</LineStyle>" +
"<PolyStyle>" +
"<color>7f00ff00</color>" +
"</PolyStyle>" +
"</Style>" +
"<Placemark>" +
"<name>Flight</name>" +
"<visibility>1</visibility>" +
// createDescription() +
"<styleUrl>#yellowLineGreenPoly</styleUrl>" +
"<LineString>" +
"<extrude>1</extrude>" +
"<tessellate>1</tessellate>" +
"<altitudeMode>absolute</altitudeMode>" +
"<coordinates>");
}
}