Files
FsTrack/Source/Kml.cpp
T
jens fd05a8501a [FsTrack]
- improved cam tilt and pitch

git-svn-id: http://moon:8086/svn/software/trunk/projects/FsTrack@355 b431acfa-c32f-4a4a-93f1-934dc6c82436
2017-06-16 00:13:53 +00:00

446 lines
13 KiB
C++

#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "Kml.hpp"
//#define WITH_FANCY_CAMERA
Kml::Kml(const char *pDocRoot)
: m_pKml(nullptr)
, m_pTrackPlaceMark(nullptr)
, m_docRoot(pDocRoot)
, m_altitudeModeString("absolute")
, m_pathColorString("0xff00ffff")
, m_cameraAlt(1000)
, m_cameraTilt(0)
, m_cameraAutoHeading(false)
, m_cameraAutoRoll(false)
, m_cameraFlyToView(false)
{
memset(m_path, 0, sizeof(m_path));
m_pKml = new XmlElement("kml");
// Create an empty kml
m_pKml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
m_pKml->setAttribute("xmlns:gx", "http://www.google.com/kml/ext/2.2");
}
Kml::~Kml(void)
{
m_pKml = nullptr;
}
void Kml::updateFlightData(FlightData const &flightData)
{
const ScopedLock sl (m_lock);
m_flightData = flightData;
}
const char* Kml::getPath()
{
return m_path;
}
void Kml::createNetworkLinkFile(String const &path, String const &hostIp)
{
File file(path);
if (file.exists())
{
return;
}
ScopedPointer<XmlElement> pKml = new XmlElement("kml");
pKml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
XmlElement *pDoc = pKml->createNewChildElement("Document");
pDoc->createNewChildElement("visibility")->addTextElement("1");
XmlElement *pNetworkLink = pDoc->createNewChildElement("NetworkLink");
pNetworkLink->setAttribute("id", "NetworkLink_0");
pNetworkLink->createNewChildElement("name")->addTextElement("Link");
XmlElement *pFlyToView = pNetworkLink->createNewChildElement("flyToView");
if (m_cameraFlyToView)
{
pFlyToView->addTextElement("1");
}
else
{
pFlyToView->addTextElement("0");
}
XmlElement *pLink = pNetworkLink->createNewChildElement("Link");
pLink->createNewChildElement("href")->addTextElement(String("http://") + hostIp + String(":5001/flight.kml"));
pLink->createNewChildElement("refreshMode")->addTextElement("onInterval");
pLink->createNewChildElement("refreshInterval")->addTextElement("1");
pLink->createNewChildElement("viewRefreshMode")->addTextElement("onStop");
pLink->createNewChildElement("viewRefreshInterval")->addTextElement("0");
pLink->createNewChildElement("viewFormat")->addTextElement("BBOX=[bboxWest],[bboxSouth],[bboxEast],[bboxNorth];CAMERA=[lookatLon],[lookatLat],[lookatRange],[lookatTilt],[lookatHeading];VIEW=[horizFov],[vertFov],[horizPixels],[vertPixels],[terrainEnabled]");
pKml->writeToFile(file, StringRef(""));
}
void Kml::create()
{
time_t time_departure;
struct tm *time_now;
XmlElement *pDoc = m_pKml->createNewChildElement("Document");
time(&time_departure);
time_now = localtime(&time_departure);
char time_str[256];
// Create an outer XML element..
m_pKml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
m_pKml->setAttribute("xmlns:gx", "http://www.google.com/kml/ext/2.2");
sprintf(m_path, "%s\\flight_%4.4d%2.2d%2.2d_%2.2d%2.2d%2.2d.kml", m_docRoot, 1900+time_now->tm_year, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, time_now->tm_min, time_now->tm_sec);
pDoc->createNewChildElement("filename")->addTextElement(m_path);
sprintf(time_str, "Created on %4.4d-%2.2d-%2.2d at %2.2d:%2.2d:%2.2d", 1900+time_now->tm_year, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, time_now->tm_min, time_now->tm_sec);
XmlElement *pSnippet = pDoc->createNewChildElement("Snippet");
pSnippet->setAttribute("maxLines", "2");
pSnippet->addTextElement(time_str);
m_pTrackPlaceMark = createTrack();
}
void Kml::destroy()
{
m_pKml->removeChildElement(m_pKml->getChildByName("Document"), true);
m_pTrackPlaceMark = nullptr;
}
XmlElement* Kml::createNetworkLinkControl()
{
XmlElement *pNetworkLinkControl = new XmlElement("NetworkLinkControl");
pNetworkLinkControl->createNewChildElement("LinkName")->addTextElement("Link");
XmlElement *pCamera = pNetworkLinkControl->createNewChildElement("Camera");
pCamera->createNewChildElement("longitude")->addTextElement(String(m_flightData.lon));
pCamera->createNewChildElement("latitude")->addTextElement(String(m_flightData.lat));
pCamera->createNewChildElement("altitude")->addTextElement(String(m_flightData.alt_meter+m_cameraAlt));
if (m_cameraAutoHeading)
{
pCamera->createNewChildElement("heading")->addTextElement(String(m_flightData.hdgTrue_deg));
}
else
{
pCamera->createNewChildElement("heading")->addTextElement("0");
}
pCamera->createNewChildElement("tilt")->addTextElement(String(90.0 - (m_flightData.pitch_deg + m_cameraTilt)));
if (m_cameraAutoRoll)
{
pCamera->createNewChildElement("roll")->addTextElement(String(m_flightData.bank_deg));
}
else
{
pCamera->createNewChildElement("roll")->addTextElement("0");
}
pCamera->createNewChildElement("altitudeMode")->addTextElement(m_altitudeModeString);
#if 0
XmlElement *pUpdate = pNetworkLinkControl->createNewChildElement("Update");
pUpdate->createNewChildElement("targetHref")->addTextElement("FsTrack.kml");
XmlElement *pChange = pUpdate->createNewChildElement("Change");
XmlElement *pNetworkLink = pChange->createNewChildElement("NetworkLink");
pNetworkLink->setAttribute("targetId", "NetworkLink_0");
XmlElement *pFlyToView = pNetworkLink->createNewChildElement("flyToView");
if (m_cameraFlyToView)
{
pFlyToView->addTextElement("0");
}
else
{
pFlyToView->addTextElement("1");
}
#endif
return pNetworkLinkControl;
}
XmlElement* Kml::createPlane()
{
const ScopedLock sl (m_lock);
char temp_str[1024];
XmlElement *pPlacemark;
XmlElement *pName;
XmlElement *pStyle;
XmlElement *pIconStyle;
XmlElement *pIcon;
XmlElement *pHref;
XmlElement *pHeading;
XmlElement *pY, *pW, *pH;
XmlElement *pDescr;
XmlElement *pPoint;
XmlElement *pExtrude;
XmlElement *pTesselate;
XmlElement *pAltitudeMode;
XmlElement *pCoords;
// Placemark
pPlacemark = new XmlElement("Placemark");
pPlacemark->setAttribute("id", "Plane_0");
// Name
sprintf(temp_str, "Unknown flight");
if (strlen(m_flightData.atcFlightIDStr))
{
if (strlen(m_flightData.atcFlightNumStr) == 0)
{
sprintf(temp_str, "%s", m_flightData.atcFlightIDStr);
}
else
{
sprintf(temp_str, "%s/%s", m_flightData.atcFlightIDStr, m_flightData.atcFlightNumStr);
}
}
pName = pPlacemark->createNewChildElement("name");
pName->addTextElement(temp_str);
// Description
pDescr = pPlacemark->createNewChildElement("description");
sprintf(temp_str, "Altitude: %d ft, Heading: %d\nGround speed: %d kts", (int)(m_flightData.alt_feet+0.5), (int)(m_flightData.hdgTrue_deg+0.5), (int)(m_flightData.gs_knots+0.5));
pDescr->addTextElement(temp_str);
// Style
pStyle = pPlacemark->createNewChildElement("Style");
// IconStyle
pIconStyle = pStyle->createNewChildElement("IconStyle");
pHeading = pIconStyle->createNewChildElement("heading");
pHeading->addTextElement(String(m_flightData.hdgTrue_deg));
// Icon
pIcon = pIconStyle->createNewChildElement("Icon");
pHref = pIcon->createNewChildElement("href");
pHref->addTextElement("root://icons/palette-2.png");
pY = pIcon->createNewChildElement("y");
pY->addTextElement("0");
pW = pIcon->createNewChildElement("w");
pW->addTextElement("32");
pH = pIcon->createNewChildElement("h");
pH->addTextElement("32");
// Point
pPoint = pPlacemark->createNewChildElement("Point");
pPoint->setAttribute("id", "Pointy");
pExtrude = pPoint->createNewChildElement("extrude");
pExtrude->addTextElement("1");
pTesselate = pPoint->createNewChildElement("tesselate");
pTesselate->addTextElement("1");
pAltitudeMode = pPoint->createNewChildElement("altitudeMode");
pAltitudeMode->addTextElement(m_altitudeModeString);
pCoords = pPoint->createNewChildElement("coordinates");
sprintf(temp_str, "%9.6f,%9.6f,%9.6f", m_flightData.lon, m_flightData.lat, m_flightData.alt_meter);
pCoords->addTextElement(temp_str);
return pPlacemark;
}
XmlElement* Kml::createTrack()
{
const ScopedLock sl (m_lock);
char temp_str[1024];
XmlElement *pPlacemark;
XmlElement *pName;
XmlElement *pStyle;
XmlElement *pLineStyle;
XmlElement *pLineColor;
XmlElement *pLineWidth;
XmlElement *pPolyStyle;
XmlElement *pPolyColor;
XmlElement *pLineString;
XmlElement *pExtrude;
XmlElement *pTesselate;
XmlElement *pAltitudeMode;
XmlElement *pCoords;
// Placemark
pPlacemark = new XmlElement("Placemark");
pPlacemark->setAttribute("id", "Track_0");
// Name
pName = pPlacemark->createNewChildElement("name");
pName->addTextElement("Track");
// Style
pStyle = pPlacemark->createNewChildElement("Style");
// LineStyle
pLineStyle = pStyle->createNewChildElement("LineStyle");
pLineColor = pLineStyle->createNewChildElement("color");
pLineColor->addTextElement(m_pathColorString);
pLineWidth = pLineStyle->createNewChildElement("width");
pLineWidth->addTextElement("4");
// PolyStyle
pPolyStyle = pStyle->createNewChildElement("PolyStyle");
pPolyColor = pPolyStyle->createNewChildElement("color");
sprintf(temp_str, "%4.4X", 0x7f00ff00);
pPolyColor->addTextElement(temp_str);
// LineString
pLineString = pPlacemark->createNewChildElement("LineString");
pExtrude = pLineString->createNewChildElement("extrude");
pExtrude->addTextElement("1");
pTesselate = pLineString->createNewChildElement("tesselate");
pTesselate->addTextElement("1");
pAltitudeMode = pLineString->createNewChildElement("altitudeMode");
pAltitudeMode->addTextElement(m_altitudeModeString);
sprintf(temp_str, "\n%9.6f,%9.6f,%9.6f", m_flightData.lon, m_flightData.lat, m_flightData.alt_meter);
pCoords = pLineString->createNewChildElement("coordinates");
pCoords = pPlacemark->getChildByName("LineString")->getChildByName("coordinates");
pCoords->addTextElement(temp_str);
return pPlacemark;
}
void Kml::updateTrack()
{
const ScopedLock sl (m_lock);
char temp_str[1024];
if (!m_pTrackPlaceMark)
{
return;
}
// Coordinates
sprintf(temp_str, "\n%9.6f,%9.6f,%9.6f", m_flightData.lon, m_flightData.lat, m_flightData.alt_meter);
XmlElement *pCoords = m_pTrackPlaceMark->getChildByName("LineString")->getChildByName("coordinates");
pCoords->addTextElement(temp_str);
}
void Kml::setAltitudeMode(String const &modeString)
{
m_altitudeModeString = modeString;
}
void Kml::setPathColor(String const &colorString)
{
const ScopedLock sl (m_lock);
m_pathColorString = colorString;
if (m_pTrackPlaceMark)
{
m_pTrackPlaceMark->getChildByName("Style")->getChildByName("LineStyle")->getChildByName("color")->getFirstChildElement()->setText(colorString);
}
}
void Kml::setCameraAltitude(float alt_meters)
{
m_cameraAlt = alt_meters;
}
void Kml::setCameraTilt(float tilt_deg)
{
m_cameraTilt = tilt_deg;
}
void Kml::setCameraFlyToView(bool enable)
{
m_cameraFlyToView = enable;
}
void Kml::setCameraAutoHeading(bool enable)
{
m_cameraAutoHeading = enable;
}
void Kml::setCameraAutoRoll(bool enable)
{
m_cameraAutoRoll = enable;
}
void Kml::exportKml(const char *pPath)
{
const ScopedLock sl (m_lock);
if (pPath && m_pKml)
{
XmlElement *pDoc;
File file(pPath);
ScopedPointer<XmlElement> pPlane = createPlane();
ScopedPointer<XmlElement> pNetworkLinkcontrol = createNetworkLinkControl();
m_pKml->addChildElement(pNetworkLinkcontrol);
pDoc = m_pKml->getChildByName("Document");
if (pDoc)
{
pDoc->addChildElement(pPlane);
pDoc->addChildElement(m_pTrackPlaceMark);
}
m_pKml->writeToFile(file, StringRef(""));
m_pKml->removeChildElement(pNetworkLinkcontrol, false);
if (pDoc)
{
pDoc->removeChildElement(pPlane, false);
pDoc->removeChildElement(m_pTrackPlaceMark, false);
}
}
}
void Kml::exportKmz(const char *pPath)
{
// ToDo: add Compression if available in Juce
const ScopedLock sl (m_lock);
if (pPath && m_pKml)
{
File file(pPath);
file.deleteFile();
ScopedPointer<OutputStream> pStream = file.createOutputStream();
m_pKml->writeToStream(*pStream, StringRef(""));
pStream = nullptr;
}
}
void Kml::onUpdate(const char *pPath, ViewFormat const &viewFormat)
{
// LookAt
// XmlElement *pCamera;
// pCamera = m_pKml->getChildByName("NetworkLinkControl")->getChildByName("Camera");
if (viewFormat.has_camera)
{
// pCamera->getChildByName("longitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatLon));
// pCamera->getChildByName("latitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatLat));
// pCamera->getChildByName("altitude")->getFirstChildElement()->setText(String(viewFormat.camera.lookatRange));
// pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(viewFormat.camera.lookatHeading));
// pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(0));
// pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(viewFormat.camera.lookatTilt));
// pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(0));
// pCamera->getChildByName("range")->getFirstChildElement()->setText(String(viewFormat.camera.lookatRange));
// pCamera->getChildByName("range")->getFirstChildElement()->setText(String("10000"));
// pCamera->getChildByName("altitudeMode")->getFirstChildElement()->setText(m_altitudeModeString);
}
exportKml(pPath);
}