30 changed files with 300 additions and 238 deletions
@ -1,128 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
||||||
* |
|
||||||
* QGroundControl is licensed according to the terms in the file |
|
||||||
* COPYING.md in the root of the source code directory. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
#include "KML.h" |
|
||||||
|
|
||||||
#include <QDomDocument> |
|
||||||
#include <QStringList> |
|
||||||
|
|
||||||
const QString Kml::_version("version=\"1.0\""); |
|
||||||
const QString Kml::_encoding("encoding=\"UTF-8\""); |
|
||||||
const QString Kml::_opengis("http://www.opengis.net/kml/2.2"); |
|
||||||
const QString Kml::_qgckml("QGC KML"); |
|
||||||
|
|
||||||
Kml::Kml() |
|
||||||
{ |
|
||||||
//create header
|
|
||||||
createHeader(); |
|
||||||
//name
|
|
||||||
createTextElement(_docEle, "name", _qgckml); |
|
||||||
//open
|
|
||||||
createTextElement(_docEle, "open", "1"); |
|
||||||
//create style
|
|
||||||
createStyles(); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::points(const QStringList& points) |
|
||||||
{ |
|
||||||
//create placemark
|
|
||||||
QDomElement placemark = _domDocument.createElement("Placemark"); |
|
||||||
_docEle.appendChild(placemark); |
|
||||||
createTextElement(placemark, "styleUrl", "yellowLineGreenPoly"); |
|
||||||
createTextElement(placemark, "name", "Absolute"); |
|
||||||
createTextElement(placemark, "visibility", "0"); |
|
||||||
createTextElement(placemark, "description", "Transparent purple line"); |
|
||||||
|
|
||||||
QStringList latLonAlt = points[0].split(","); |
|
||||||
QStringList lookAtList({latLonAlt[0], latLonAlt[1], "0" \
|
|
||||||
, "-100", "45", "2500"}); |
|
||||||
createLookAt(placemark, lookAtList); |
|
||||||
|
|
||||||
//Add linestring
|
|
||||||
QDomElement lineString = _domDocument.createElement("LineString"); |
|
||||||
placemark.appendChild(lineString); |
|
||||||
|
|
||||||
//extruder
|
|
||||||
createTextElement(lineString, "extruder", "1"); |
|
||||||
createTextElement(lineString, "tessellate", "1"); |
|
||||||
createTextElement(lineString, "altitudeMode", "absolute"); |
|
||||||
QString coordinates; |
|
||||||
for(const auto& point : points) { |
|
||||||
coordinates += point + "\n"; |
|
||||||
} |
|
||||||
createTextElement(lineString, "coordinates", coordinates); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::save(QDomDocument& document) |
|
||||||
{ |
|
||||||
document = _domDocument; |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::createHeader() |
|
||||||
{ |
|
||||||
QDomProcessingInstruction header = _domDocument.createProcessingInstruction("xml", _version + " " + _encoding); |
|
||||||
_domDocument.appendChild(header); |
|
||||||
QDomElement kml = _domDocument.createElement("kml"); |
|
||||||
kml.setAttribute("xmlns", _opengis); |
|
||||||
_docEle = _domDocument.createElement("Document"); |
|
||||||
kml.appendChild(_docEle); |
|
||||||
_domDocument.appendChild(kml); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::createStyles() |
|
||||||
{ |
|
||||||
QDomElement style = _domDocument.createElement("Style"); |
|
||||||
style.setAttribute("id", "yellowLineGreenPoly"); |
|
||||||
createStyleLine(style, "7f00ffff", "4", "7f00ff00"); |
|
||||||
_docEle.appendChild(style); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::createLookAt(QDomElement& placemark, const QStringList &lookAtList) |
|
||||||
{ |
|
||||||
QDomElement lookAt = _domDocument.createElement("LookAt"); |
|
||||||
placemark.appendChild(lookAt); |
|
||||||
createTextElement(lookAt, "longitude", lookAtList[0]); |
|
||||||
createTextElement(lookAt, "latitude", lookAtList[1]); |
|
||||||
createTextElement(lookAt, "altitude", lookAtList[2]); |
|
||||||
createTextElement(lookAt, "heading", lookAtList[3]); |
|
||||||
createTextElement(lookAt, "tilt", lookAtList[4]); |
|
||||||
createTextElement(lookAt, "range", lookAtList[5]); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::createTextElement(QDomElement& domEle, const QString& elementName, const QString& textElement) |
|
||||||
{ |
|
||||||
// <elementName>textElement</elementName>
|
|
||||||
auto element = _domDocument.createElement(elementName); |
|
||||||
element.appendChild(_domDocument.createTextNode(textElement)); |
|
||||||
domEle.appendChild(element); |
|
||||||
} |
|
||||||
|
|
||||||
void Kml::createStyleLine(QDomElement& domEle, const QString& lineColor, const QString& lineWidth, const QString& polyColor) |
|
||||||
{ |
|
||||||
/*
|
|
||||||
<LineStyle> |
|
||||||
<color>7f00ffff</color> |
|
||||||
<width>4</width> |
|
||||||
</LineStyle> |
|
||||||
<PolyStyle> |
|
||||||
<color>7f00ff00</color> |
|
||||||
</PolyStyle> |
|
||||||
*/ |
|
||||||
auto lineStyle = _domDocument.createElement("LineStyle"); |
|
||||||
auto polyStyle = _domDocument.createElement("PolyStyle"); |
|
||||||
domEle.appendChild(lineStyle); |
|
||||||
domEle.appendChild(polyStyle); |
|
||||||
createTextElement(lineStyle, "color", lineColor); |
|
||||||
createTextElement(lineStyle, "width", lineWidth); |
|
||||||
createTextElement(polyStyle, "color", polyColor); |
|
||||||
} |
|
||||||
|
|
||||||
Kml::~Kml() |
|
||||||
{ |
|
||||||
} |
|
@ -1,42 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
||||||
* |
|
||||||
* QGroundControl is licensed according to the terms in the file |
|
||||||
* COPYING.md in the root of the source code directory. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
#ifndef KML_H |
|
||||||
#define KML_H |
|
||||||
|
|
||||||
#include <QDomDocument> |
|
||||||
#include <QDomElement> |
|
||||||
|
|
||||||
class Kml |
|
||||||
{ |
|
||||||
|
|
||||||
public: |
|
||||||
Kml(); |
|
||||||
~Kml(); |
|
||||||
|
|
||||||
void points(const QStringList& points); |
|
||||||
void polygon(const QStringList& points); |
|
||||||
void save(QDomDocument& document); |
|
||||||
|
|
||||||
private: |
|
||||||
void createHeader(); |
|
||||||
void createLookAt(QDomElement& placemark, const QStringList &lookAtList); |
|
||||||
void createStyles(); |
|
||||||
void createStyleLine(QDomElement& domEle, const QString& lineColor, const QString& lineWidth, const QString& polyColor); |
|
||||||
void createTextElement(QDomElement& domEle, const QString& elementName, const QString& textElement); |
|
||||||
|
|
||||||
QDomDocument _domDocument; |
|
||||||
QDomElement _docEle; |
|
||||||
static const QString _encoding; |
|
||||||
static const QString _opengis; |
|
||||||
static const QString _qgckml; |
|
||||||
static const QString _version; |
|
||||||
}; |
|
||||||
|
|
||||||
#endif |
|
@ -0,0 +1,175 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#include "KMLPlanDomDocument.h" |
||||||
|
#include "QGCPalette.h" |
||||||
|
#include "QGCApplication.h" |
||||||
|
#include "MissionCommandTree.h" |
||||||
|
#include "MissionCommandUIInfo.h" |
||||||
|
#include "FactMetaData.h" |
||||||
|
|
||||||
|
#include <QDomDocument> |
||||||
|
#include <QStringList> |
||||||
|
|
||||||
|
const char* KMLPlanDomDocument::_missionLineStyleName = "MissionLineStyle"; |
||||||
|
const char* KMLPlanDomDocument::_ballonStyleName = "BalloonStyle"; |
||||||
|
|
||||||
|
KMLPlanDomDocument::KMLPlanDomDocument() |
||||||
|
{ |
||||||
|
QDomProcessingInstruction header = createProcessingInstruction(QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"")); |
||||||
|
appendChild(header); |
||||||
|
|
||||||
|
QDomElement kmlElement = createElement(QStringLiteral("kml")); |
||||||
|
kmlElement.setAttribute(QStringLiteral("xmlns"), "http://www.opengis.net/kml/2.2"); |
||||||
|
|
||||||
|
_documentElement = createElement(QStringLiteral("Document")); |
||||||
|
kmlElement.appendChild(_documentElement); |
||||||
|
appendChild(kmlElement); |
||||||
|
|
||||||
|
_addTextElement(_documentElement, "name", QStringLiteral("%1 Plan KML").arg(qgcApp()->applicationName())); |
||||||
|
_addTextElement(_documentElement, "open", "1"); |
||||||
|
|
||||||
|
_addStyles(); |
||||||
|
} |
||||||
|
|
||||||
|
QString KMLPlanDomDocument::_kmlCoordString(const QGeoCoordinate& coord) |
||||||
|
{ |
||||||
|
return QStringLiteral("%1,%2,%3").arg(QString::number(coord.longitude(), 'f', 7)).arg(QString::number(coord.latitude(), 'f', 7)).arg(QString::number(coord.altitude(), 'f', 2)); |
||||||
|
} |
||||||
|
|
||||||
|
void KMLPlanDomDocument::addMissionItems(Vehicle* vehicle, QList<MissionItem*> rgMissionItems) |
||||||
|
{ |
||||||
|
if (rgMissionItems.count() == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
QDomElement itemFolderElement = createElement("Folder"); |
||||||
|
_documentElement.appendChild(itemFolderElement); |
||||||
|
|
||||||
|
_addTextElement(itemFolderElement, "name", "Items"); |
||||||
|
|
||||||
|
QDomElement flightPathElement = createElement("Placemark"); |
||||||
|
_documentElement.appendChild(flightPathElement); |
||||||
|
|
||||||
|
_addTextElement(flightPathElement, "styleUrl", QStringLiteral("#%1").arg(_missionLineStyleName)); |
||||||
|
_addTextElement(flightPathElement, "name", "Flight Path"); |
||||||
|
_addTextElement(flightPathElement, "visibility", "1"); |
||||||
|
_addLookAt(flightPathElement, rgMissionItems[0]->coordinate()); |
||||||
|
|
||||||
|
// Build up the mission trajectory line coords
|
||||||
|
QList<QGeoCoordinate> rgFlightCoords; |
||||||
|
QGeoCoordinate homeCoord = rgMissionItems[0]->coordinate(); |
||||||
|
for (const MissionItem* item : rgMissionItems) { |
||||||
|
const MissionCommandUIInfo* uiInfo = qgcApp()->toolbox()->missionCommandTree()->getUIInfo(vehicle, item->command()); |
||||||
|
if (uiInfo) { |
||||||
|
double altAdjustment = item->frame() == MAV_FRAME_GLOBAL ? 0 : homeCoord.altitude(); // Used to convert to amsl
|
||||||
|
if (uiInfo->isTakeoffCommand() && !vehicle->fixedWing()) { |
||||||
|
// These takeoff items go straight up from home position to specified altitude
|
||||||
|
QGeoCoordinate coord = homeCoord; |
||||||
|
coord.setAltitude(item->param7() + altAdjustment); |
||||||
|
rgFlightCoords += coord; |
||||||
|
} |
||||||
|
if (uiInfo->specifiesCoordinate()) { |
||||||
|
QGeoCoordinate coord = item->coordinate(); |
||||||
|
coord.setAltitude(coord.altitude() + altAdjustment); // convert to amsl
|
||||||
|
|
||||||
|
if (!uiInfo->isStandaloneCoordinate()) { |
||||||
|
// Flight path goes through this item
|
||||||
|
rgFlightCoords += coord; |
||||||
|
} |
||||||
|
|
||||||
|
// Add a place mark for each WP
|
||||||
|
|
||||||
|
QDomElement wpPlacemarkElement = createElement("Placemark"); |
||||||
|
_addTextElement(wpPlacemarkElement, "name", QStringLiteral("%1 %2").arg(QString::number(item->sequenceNumber())).arg(item->command() == MAV_CMD_NAV_WAYPOINT ? "" : uiInfo->friendlyName())); |
||||||
|
_addTextElement(wpPlacemarkElement, "styleUrl", QStringLiteral("#%1").arg(_ballonStyleName)); |
||||||
|
|
||||||
|
QDomElement wpPointElement = createElement("Point"); |
||||||
|
_addTextElement(wpPointElement, "altitudeMode", "absolute"); |
||||||
|
_addTextElement(wpPointElement, "coordinates", _kmlCoordString(coord)); |
||||||
|
_addTextElement(wpPointElement, "extrude", "1"); |
||||||
|
|
||||||
|
QDomElement descriptionElement = createElement("description"); |
||||||
|
QString htmlString; |
||||||
|
htmlString += QStringLiteral("Index: %1\n").arg(item->sequenceNumber()); |
||||||
|
htmlString += uiInfo->friendlyName() + "\n"; |
||||||
|
htmlString += QStringLiteral("Alt AMSL: %1 %2\n").arg(QString::number(FactMetaData::metersToAppSettingsDistanceUnits(coord.altitude()).toDouble(), 'f', 2)).arg(FactMetaData::appSettingsDistanceUnitsString()); |
||||||
|
htmlString += QStringLiteral("Alt Rel: %1 %2\n").arg(QString::number(FactMetaData::metersToAppSettingsDistanceUnits(coord.altitude() - homeCoord.altitude()).toDouble(), 'f', 2)).arg(FactMetaData::appSettingsDistanceUnitsString()); |
||||||
|
htmlString += QStringLiteral("Lat: %1\n").arg(QString::number(coord.latitude(), 'f', 7)); |
||||||
|
htmlString += QStringLiteral("Lon: %1\n").arg(QString::number(coord.longitude(), 'f', 7)); |
||||||
|
QDomCDATASection cdataSection = createCDATASection(htmlString); |
||||||
|
descriptionElement.appendChild(cdataSection); |
||||||
|
|
||||||
|
wpPlacemarkElement.appendChild(descriptionElement); |
||||||
|
wpPlacemarkElement.appendChild(wpPointElement); |
||||||
|
itemFolderElement.appendChild(wpPlacemarkElement); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Create a LineString element from the coords
|
||||||
|
|
||||||
|
QDomElement lineStringElement = createElement("LineString"); |
||||||
|
flightPathElement.appendChild(lineStringElement); |
||||||
|
|
||||||
|
_addTextElement(lineStringElement, "extruder", "1"); |
||||||
|
_addTextElement(lineStringElement, "tessellate", "1"); |
||||||
|
_addTextElement(lineStringElement, "altitudeMode", "absolute"); |
||||||
|
|
||||||
|
QString coordString; |
||||||
|
for (const QGeoCoordinate& coord : rgFlightCoords) { |
||||||
|
coordString += QStringLiteral("%1\n").arg(_kmlCoordString(coord)); |
||||||
|
} |
||||||
|
_addTextElement(lineStringElement, "coordinates", coordString); |
||||||
|
} |
||||||
|
|
||||||
|
QString KMLPlanDomDocument::_kmlColorString (const QColor& color) |
||||||
|
{ |
||||||
|
return QStringLiteral("ff%1%2%3").arg(color.blue(), 2, 16, QChar('0')).arg(color.green(), 2, 16, QChar('0')).arg(color.red(), 2, 16, QChar('0')); |
||||||
|
} |
||||||
|
|
||||||
|
void KMLPlanDomDocument::_addStyles(void) |
||||||
|
{ |
||||||
|
QGCPalette palette; |
||||||
|
|
||||||
|
QDomElement styleElement1 = createElement("Style"); |
||||||
|
styleElement1.setAttribute("id", _missionLineStyleName); |
||||||
|
QDomElement lineStyleElement = createElement("LineStyle"); |
||||||
|
_addTextElement(lineStyleElement, "color", _kmlColorString(palette.mapMissionTrajectory())); |
||||||
|
_addTextElement(lineStyleElement, "width", "4"); |
||||||
|
styleElement1.appendChild(lineStyleElement); |
||||||
|
|
||||||
|
QDomElement styleElement2 = createElement("Style"); |
||||||
|
styleElement2.setAttribute("id", _ballonStyleName); |
||||||
|
QDomElement balloonStyleElement = createElement("BalloonStyle"); |
||||||
|
_addTextElement(balloonStyleElement, "text", "$[description]"); |
||||||
|
styleElement2.appendChild(balloonStyleElement); |
||||||
|
|
||||||
|
_documentElement.appendChild(styleElement1); |
||||||
|
_documentElement.appendChild(styleElement2); |
||||||
|
} |
||||||
|
|
||||||
|
void KMLPlanDomDocument::_addTextElement(QDomElement &element, const QString &name, const QString &value) |
||||||
|
{ |
||||||
|
QDomElement textElement = createElement(name); |
||||||
|
textElement.appendChild(createTextNode(value)); |
||||||
|
element.appendChild(textElement); |
||||||
|
} |
||||||
|
|
||||||
|
void KMLPlanDomDocument::_addLookAt(QDomElement& element, const QGeoCoordinate& coord) |
||||||
|
{ |
||||||
|
QDomElement lookAtElement = createElement("LookAt"); |
||||||
|
_addTextElement(lookAtElement, "latitude", QString::number(coord.latitude(), 'f', 7)); |
||||||
|
_addTextElement(lookAtElement, "longitude", QString::number(coord.longitude(), 'f', 7)); |
||||||
|
_addTextElement(lookAtElement, "altitude", QString::number(coord.longitude(), 'f', 2)); |
||||||
|
_addTextElement(lookAtElement, "heading", "-100"); |
||||||
|
_addTextElement(lookAtElement, "tilt", "45"); |
||||||
|
_addTextElement(lookAtElement, "range", "2500"); |
||||||
|
element.appendChild(lookAtElement); |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <QDomDocument> |
||||||
|
#include <QDomElement> |
||||||
|
#include <QGeoCoordinate> |
||||||
|
|
||||||
|
class MissionItem; |
||||||
|
class Vehicle; |
||||||
|
|
||||||
|
/// Used to convert a Plan to a KML document
|
||||||
|
class KMLPlanDomDocument : public QDomDocument |
||||||
|
{ |
||||||
|
|
||||||
|
public: |
||||||
|
KMLPlanDomDocument(); |
||||||
|
|
||||||
|
void addMissionItems(Vehicle* vehicle, QList<MissionItem*> rgMissionItems); |
||||||
|
|
||||||
|
private: |
||||||
|
void _addStyles (void); |
||||||
|
QString _kmlColorString (const QColor& color); |
||||||
|
void _addTextElement (QDomElement& element, const QString& name, const QString& value); |
||||||
|
QString _kmlCoordString (const QGeoCoordinate& coord); |
||||||
|
void _addLookAt(QDomElement& element, const QGeoCoordinate& coord); |
||||||
|
|
||||||
|
QDomElement _documentElement; |
||||||
|
|
||||||
|
static const char* _missionLineStyleName; |
||||||
|
static const char* _ballonStyleName; |
||||||
|
}; |
Loading…
Reference in new issue