#include #include #include #include "Kml.hpp" Kml::Kml(const char *pDocRoot) : kml(nullptr) , m_pPlanePlaceMark(nullptr) , m_pPathPlaceMark(nullptr) , m_docRoot(pDocRoot) , m_altitudeModeString("absolute") , m_pathColorString("0xff00ffff") , m_cameraAlt(1000) , m_cameraTilt(0) , m_cameraAutoHeading(false) , m_cameraAutoRoll(false) { memset(m_path, 0, sizeof(m_path)); } Kml::~Kml(void) { kml = nullptr; } const char* Kml::getPath() { return m_path; } void Kml::create() { time_t time_departure; struct tm *time_now; if (kml) destroy(); kml = new XmlElement("kml"); XmlElement *pNetworkLinkControl = kml->createNewChildElement("NetworkLinkControl"); pNetworkLinkControl->createNewChildElement("LinkName")->addTextElement("FsTrack"); XmlElement *pCamera = pNetworkLinkControl->createNewChildElement("Camera"); XmlElement *pDoc = kml->createNewChildElement("Document"); XmlElement *pFile = kml->getChildByName("Document")->createNewChildElement("filename"); XmlElement *pSnippet = kml->getChildByName("Document")->createNewChildElement("Snippet"); time(&time_departure); time_now = localtime(&time_departure); char time_str[256]; // Create an outer XML element.. kml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2"); kml->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); pFile->addTextElement(m_path); pSnippet->setAttribute("maxLines", "2"); 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); pSnippet->addTextElement(time_str); // Camera pCamera->createNewChildElement("longitude")->addTextElement("0"); pCamera->createNewChildElement("latitude")->addTextElement("0"); pCamera->createNewChildElement("altitude")->addTextElement("0"); pCamera->createNewChildElement("heading")->addTextElement("0"); pCamera->createNewChildElement("tilt")->addTextElement("0"); pCamera->createNewChildElement("roll")->addTextElement("0"); pCamera->createNewChildElement("altitudeMode")->addTextElement(m_altitudeModeString); } void Kml::destroy() { kml = nullptr; m_pPlanePlaceMark = nullptr; m_pPathPlaceMark = nullptr; } void Kml::setAltitudeMode(String const &modeString) { m_altitudeModeString = modeString; if (m_pPlanePlaceMark) { m_pPlanePlaceMark->getChildByName("Point")->getChildByName("altitudeMode")->getFirstChildElement()->setText(modeString); } if (m_pPathPlaceMark) { m_pPathPlaceMark->getChildByName("LineString")->getChildByName("altitudeMode")->getFirstChildElement()->setText(modeString); } } void Kml::setPathColor(String const &colorString) { const ScopedLock sl (m_lock); m_pathColorString = colorString; if (m_pPathPlaceMark) { m_pPathPlaceMark->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::update(FlightData const &flightData) { const ScopedLock sl (m_lock); updatePlane(flightData); updatePath(flightData); } void Kml::setCameraAutoHeading(bool enable) { m_cameraAutoHeading = enable; } void Kml::setCameraAutoRoll(bool enable) { m_cameraAutoRoll = enable; } void Kml::updatePlane(FlightData const &flightData) { char temp_str[1024]; XmlElement *pDoc = kml->getChildByName("Document"); XmlElement *pPlacemark = m_pPlanePlaceMark; 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; XmlElement *pCamera; if(pPlacemark == NULL) { // Placemark pPlacemark = pDoc->createNewChildElement("Placemark"); // Name sprintf(temp_str, "Unknown flight"); if (strlen(flightData.atcFlightIDStr)) { if (strlen(flightData.atcFlightNumStr) == 0) { sprintf(temp_str, "%s", flightData.atcFlightIDStr); } else { sprintf(temp_str, "%s/%s", flightData.atcFlightIDStr, flightData.atcFlightNumStr); } } pName = pPlacemark->createNewChildElement("name"); pName->addTextElement(temp_str); printf("%s\n", temp_str); // Description pDescr = pPlacemark->createNewChildElement("description"); sprintf(temp_str, "%s\nAltitude: %d ft, Speed: %d kts", flightData.atcFlightIDStr, (int)(flightData.alt_feet+0.5), (int)(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(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", flightData.lon, flightData.lat, flightData.alt_meter); pCoords->addTextElement(temp_str); m_pPlanePlaceMark = pPlacemark; } else { // Description sprintf(temp_str, "%s\nAltitude: %d ft, Speed: %d kts", flightData.atcFlightIDStr, (int)(flightData.alt_feet+0.5), (int)(flightData.gs_knots+0.5)); pDescr = pPlacemark->getChildByName("description"); pDescr->getFirstChildElement()->setText(temp_str); // Heading pHeading = pPlacemark->getChildByName("Style")->getChildByName("IconStyle")->getChildByName("heading"); pHeading->getFirstChildElement()->setText(String(flightData.hdgTrue_deg)); // Coordinates sprintf(temp_str, "%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); pCoords = pPlacemark->getChildByName("Point")->getChildByName("coordinates"); pCoords->getFirstChildElement()->setText(temp_str); pCamera = kml->getChildByName("NetworkLinkControl")->getChildByName("Camera"); pCamera->getChildByName("longitude")->getFirstChildElement()->setText(String(flightData.lon)); pCamera->getChildByName("latitude")->getFirstChildElement()->setText(String(flightData.lat)); pCamera->getChildByName("altitude")->getFirstChildElement()->setText(String(flightData.alt_meter+m_cameraAlt)); if (m_cameraAutoHeading) pCamera->getChildByName("heading")->getFirstChildElement()->setText(String(flightData.hdgTrue_deg)); pCamera->getChildByName("tilt")->getFirstChildElement()->setText(String(m_cameraTilt)); if (m_cameraAutoRoll) pCamera->getChildByName("roll")->getFirstChildElement()->setText(String(flightData.bank_deg)); pCamera->getChildByName("altitudeMode")->getFirstChildElement()->setText(m_altitudeModeString); } } void Kml::updatePath(FlightData const &flightData) { char temp_str[1024]; XmlElement *pDoc = kml->getChildByName("Document"); XmlElement *pPlacemark = m_pPathPlaceMark; XmlElement *pName; XmlElement *pStyle; XmlElement *pLineStyle; XmlElement *pLineColor; XmlElement *pLineWidth; XmlElement *pPolyStyle; XmlElement *pPolyColor; XmlElement *pLineString; XmlElement *pExtrude; XmlElement *pTesselate; XmlElement *pAltitudeMode; XmlElement *pCoords; if(pPlacemark == NULL) { // Placemark pPlacemark = pDoc->createNewChildElement("Placemark"); // 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); pCoords = pLineString->createNewChildElement("coordinates"); sprintf(temp_str, "%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); pCoords->addTextElement(temp_str); m_pPathPlaceMark = pPlacemark; } else { // Coordinates sprintf(temp_str, "\n%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); pCoords = pPlacemark->getChildByName("LineString")->getChildByName("coordinates"); pCoords->addTextElement(temp_str); } } void Kml::exportKml(const char *pPath) { const ScopedLock sl (m_lock); if (pPath && kml) { File file(pPath); kml->writeToFile(file, StringRef("")); } } void Kml::exportKmz(const char *pPath) { // ToDo: add Compression if available in Juce const ScopedLock sl (m_lock); if (pPath && kml) { File file(pPath); file.deleteFile(); ScopedPointer pStream = file.createOutputStream(); kml->writeToStream(*pStream, StringRef("")); pStream = nullptr; } } void Kml::onUpdate(const char *pPath, ViewFormat const &viewFormat) { if (kml == nullptr) return; // LookAt XmlElement *pCamera; pCamera = kml->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); } exportKmz(pPath); }