diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index fcc340dc6b91fb851700adf4868d6a1cb7c426e5..9309e9ef4344a1301a92297b951faff8e4de74bb 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -575,7 +575,8 @@ HEADERS += \ src/Joystick/Joystick.h \ src/Joystick/JoystickManager.h \ src/JsonHelper.h \ - src/KMLFileHelper.h \ + src/KMLDomDocument.h \ + src/KMLHelper.h \ src/LogCompressor.h \ src/MissionManager/CameraCalc.h \ src/MissionManager/CameraSection.h \ @@ -780,7 +781,8 @@ SOURCES += \ src/Joystick/Joystick.cc \ src/Joystick/JoystickManager.cc \ src/JsonHelper.cc \ - src/KMLFileHelper.cc \ + src/KMLDomDocument.cc \ + src/KMLHelper.cc \ src/LogCompressor.cc \ src/MissionManager/CameraCalc.cc \ src/MissionManager/CameraSection.cc \ diff --git a/src/KMLDomDocument.cc b/src/KMLDomDocument.cc new file mode 100644 index 0000000000000000000000000000000000000000..3571f9e7260b84843a5a0b45f9aacd36bbd5e1c1 --- /dev/null +++ b/src/KMLDomDocument.cc @@ -0,0 +1,96 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "KMLDomDocument.h" +#include "QGCPalette.h" +#include "QGCApplication.h" +#include "MissionCommandTree.h" +#include "MissionCommandUIInfo.h" +#include "FactMetaData.h" + +#include +#include + +const char* KMLDomDocument::balloonStyleName = "BalloonStyle"; + +KMLDomDocument::KMLDomDocument(const QString& name) +{ + 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"); + + _rootDocumentElement = createElement(QStringLiteral("Document")); + kmlElement.appendChild(_rootDocumentElement); + appendChild(kmlElement); + + addTextElement(_rootDocumentElement, "name", name); + addTextElement(_rootDocumentElement, "open", "1"); + + _addStandardStyles(); +} + +QString KMLDomDocument::kmlCoordString(const QGeoCoordinate& coord) +{ + double altitude = qIsNaN(coord.altitude() ) ? 0 : coord.altitude(); + return QStringLiteral("%1,%2,%3").arg(QString::number(coord.longitude(), 'f', 7)).arg(QString::number(coord.latitude(), 'f', 7)).arg(QString::number(altitude, 'f', 2)); +} + +QString KMLDomDocument::kmlColorString (const QColor& color, double opacity) +{ + return QStringLiteral("%1%2%3%4").arg(static_cast(255.0 * opacity), 2, 16, QChar('0')).arg(color.blue(), 2, 16, QChar('0')).arg(color.green(), 2, 16, QChar('0')).arg(color.red(), 2, 16, QChar('0')); +} + +void KMLDomDocument::_addStandardStyles(void) +{ + QGCPalette palette; + + QDomElement styleElementForBalloon = createElement("Style"); + styleElementForBalloon.setAttribute("id", balloonStyleName); + QDomElement balloonStyleElement = createElement("BalloonStyle"); + addTextElement(balloonStyleElement, "text", "$[description]"); + styleElementForBalloon.appendChild(balloonStyleElement); + _rootDocumentElement.appendChild(styleElementForBalloon); +} + +void KMLDomDocument::addTextElement(QDomElement& parentElement, const QString &name, const QString &value) +{ + QDomElement textElement = createElement(name); + textElement.appendChild(createTextNode(value)); + parentElement.appendChild(textElement); +} + +void KMLDomDocument::addLookAt(QDomElement& parentElement, 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"); + parentElement.appendChild(lookAtElement); +} + +QDomElement KMLDomDocument::addPlacemark(const QString& name, bool visible) +{ + QDomElement placemarkElement = createElement("Placemark"); + _rootDocumentElement.appendChild(placemarkElement); + + addTextElement(placemarkElement, "name", name); + addTextElement(placemarkElement, "visibility", visible ? "1" : "0"); + + return placemarkElement; +} + +QDomNode KMLDomDocument::appendChildToRoot(const QDomNode& child) +{ + _rootDocumentElement.appendChild(child); +} diff --git a/src/KMLDomDocument.h b/src/KMLDomDocument.h new file mode 100644 index 0000000000000000000000000000000000000000..357c92c23ecbcc2a79b72547de2139abe78a5bcb --- /dev/null +++ b/src/KMLDomDocument.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#pragma once + +#include +#include +#include + +class MissionItem; +class Vehicle; + +/// Used to convert a Plan to a KML document +class KMLDomDocument : public QDomDocument +{ + +public: + KMLDomDocument(const QString& name); + + QDomNode appendChildToRoot (const QDomNode& child); + QDomElement addPlacemark (const QString& name, bool visible); + void addTextElement (QDomElement& parentElement, const QString& name, const QString& value); + QString kmlColorString (const QColor& color, double opacity = 1); + QString kmlCoordString (const QGeoCoordinate& coord); + void addLookAt (QDomElement& parentElement, const QGeoCoordinate& coord); + + static const char* balloonStyleName; + +protected: + QDomElement _rootDocumentElement; + + +private: + void _addStandardStyles(void); +}; diff --git a/src/KMLFileHelper.cc b/src/KMLHelper.cc similarity index 85% rename from src/KMLFileHelper.cc rename to src/KMLHelper.cc index 3e8096e23010f302d5ff3b85a8519a05aba7a5e0..f8cc8789d38ebba5c080131a1f079154e1c52e37 100644 --- a/src/KMLFileHelper.cc +++ b/src/KMLHelper.cc @@ -7,14 +7,14 @@ * ****************************************************************************/ -#include "KMLFileHelper.h" +#include "KMLHelper.h" #include #include -const char* KMLFileHelper::_errorPrefix = QT_TR_NOOP("KML file load failed. %1"); +const char* KMLHelper::_errorPrefix = QT_TR_NOOP("KML file load failed. %1"); -QDomDocument KMLFileHelper::_loadFile(const QString& kmlFile, QString& errorString) +QDomDocument KMLHelper::_loadFile(const QString& kmlFile, QString& errorString) { QFile file(kmlFile); @@ -41,9 +41,9 @@ QDomDocument KMLFileHelper::_loadFile(const QString& kmlFile, QString& errorStri return doc; } -ShapeFileHelper::ShapeType KMLFileHelper::determineShapeType(const QString& kmlFile, QString& errorString) +ShapeFileHelper::ShapeType KMLHelper::determineShapeType(const QString& kmlFile, QString& errorString) { - QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString); + QDomDocument domDocument = KMLHelper::_loadFile(kmlFile, errorString); if (!errorString.isEmpty()) { return ShapeFileHelper::Error; } @@ -62,12 +62,12 @@ ShapeFileHelper::ShapeType KMLFileHelper::determineShapeType(const QString& kmlF return ShapeFileHelper::Error; } -bool KMLFileHelper::loadPolygonFromFile(const QString& kmlFile, QList& vertices, QString& errorString) +bool KMLHelper::loadPolygonFromFile(const QString& kmlFile, QList& vertices, QString& errorString) { errorString.clear(); vertices.clear(); - QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString); + QDomDocument domDocument = KMLHelper::_loadFile(kmlFile, errorString); if (!errorString.isEmpty()) { return false; } @@ -123,12 +123,12 @@ bool KMLFileHelper::loadPolygonFromFile(const QString& kmlFile, QList& coords, QString& errorString) +bool KMLHelper::loadPolylineFromFile(const QString& kmlFile, QList& coords, QString& errorString) { errorString.clear(); coords.clear(); - QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString); + QDomDocument domDocument = KMLHelper::_loadFile(kmlFile, errorString); if (!errorString.isEmpty()) { return false; } diff --git a/src/KMLFileHelper.h b/src/KMLHelper.h similarity index 96% rename from src/KMLFileHelper.h rename to src/KMLHelper.h index 1a879e96b086bf740ba65f90b134e65cacf19064..84d9c4dd865d26dca3880c97fcf0bce1def3e93e 100644 --- a/src/KMLFileHelper.h +++ b/src/KMLHelper.h @@ -16,7 +16,7 @@ #include "ShapeFileHelper.h" -class KMLFileHelper : public QObject +class KMLHelper : public QObject { Q_OBJECT diff --git a/src/MissionManager/ComplexMissionItem.cc b/src/MissionManager/ComplexMissionItem.cc index 0580c1d30b4d4a51d0d1de89bb18d5c1145e87e5..5fec0c0d77c34bb52a4d676022da2d171c13c429 100644 --- a/src/MissionManager/ComplexMissionItem.cc +++ b/src/MissionManager/ComplexMissionItem.cc @@ -107,3 +107,8 @@ QJsonObject ComplexMissionItem::_loadPresetJson(const QString& name) settings.beginGroup(_presetSettingsKey); return QJsonDocument::fromBinaryData(settings.value(name).toByteArray()).object(); } + +void ComplexMissionItem::addKMLVisuals(KMLPlanDomDocument& /* domDocument */) +{ + // Default implementation has no visuals +} diff --git a/src/MissionManager/ComplexMissionItem.h b/src/MissionManager/ComplexMissionItem.h index 8133ba32f52ce5e5c26370db0939cfdef638bc3b..54170fc35e211f5090a1503cebd494ec89982a96 100644 --- a/src/MissionManager/ComplexMissionItem.h +++ b/src/MissionManager/ComplexMissionItem.h @@ -13,6 +13,7 @@ #include "QGCGeo.h" #include "QGCToolbox.h" #include "SettingsManager.h" +#include "KMLPlanDomDocument.h" #include @@ -51,7 +52,7 @@ public: /// @param name User visible name for preset. Will replace existing preset if already exists. Q_INVOKABLE virtual void savePreset(const QString& name); - Q_INVOKABLE void deletePreset(const QString& name); + Q_INVOKABLE void deletePreset(const QString& name); /// Get the point of complex mission item furthest away from a coordinate @@ -68,6 +69,8 @@ public: /// Empty string signals no support for presets. virtual QString presetsSettingsGroup(void) { return QString(); } + virtual void addKMLVisuals(KMLPlanDomDocument& domDocument); + bool presetsSupported (void) { return !presetsSettingsGroup().isEmpty(); } bool isIncomplete (void) const { return _isIncomplete; } diff --git a/src/MissionManager/KMLPlanDomDocument.cc b/src/MissionManager/KMLPlanDomDocument.cc index 25e3715101f7193e1d707b86f757f544c1971195..a85f8a0f9540df340b8489bda3fe0063d92c7d26 100644 --- a/src/MissionManager/KMLPlanDomDocument.cc +++ b/src/MissionManager/KMLPlanDomDocument.cc @@ -13,54 +13,39 @@ #include "MissionCommandTree.h" #include "MissionCommandUIInfo.h" #include "FactMetaData.h" +#include "ComplexMissionItem.h" +#include "QmlObjectListModel.h" #include #include -const char* KMLPlanDomDocument::_missionLineStyleName = "MissionLineStyle"; -const char* KMLPlanDomDocument::_ballonStyleName = "BalloonStyle"; +const char* KMLPlanDomDocument::_missionLineStyleName = "MissionLineStyle"; +const char* KMLPlanDomDocument::surveyPolygonStyleName = "SurveyPolygonStyle"; KMLPlanDomDocument::KMLPlanDomDocument() + : KMLDomDocument(QStringLiteral("%1 Plan KML").arg(qgcApp()->applicationName())) { - 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 rgMissionItems) +void KMLPlanDomDocument::_addFlightPath(Vehicle* vehicle, QList rgMissionItems) { if (rgMissionItems.count() == 0) { return; } QDomElement itemFolderElement = createElement("Folder"); - _documentElement.appendChild(itemFolderElement); + _rootDocumentElement.appendChild(itemFolderElement); - _addTextElement(itemFolderElement, "name", "Items"); + addTextElement(itemFolderElement, "name", "Items"); QDomElement flightPathElement = createElement("Placemark"); - _documentElement.appendChild(flightPathElement); + _rootDocumentElement.appendChild(flightPathElement); - _addTextElement(flightPathElement, "styleUrl", QStringLiteral("#%1").arg(_missionLineStyleName)); - _addTextElement(flightPathElement, "name", "Flight Path"); - _addTextElement(flightPathElement, "visibility", "1"); - _addLookAt(flightPathElement, rgMissionItems[0]->coordinate()); + 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 rgFlightCoords; @@ -87,13 +72,13 @@ void KMLPlanDomDocument::addMissionItems(Vehicle* vehicle, QList r // 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)); + 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(balloonStyleName)); QDomElement wpPointElement = createElement("Point"); - _addTextElement(wpPointElement, "altitudeMode", "absolute"); - _addTextElement(wpPointElement, "coordinates", _kmlCoordString(coord)); - _addTextElement(wpPointElement, "extrude", "1"); + addTextElement(wpPointElement, "altitudeMode", "absolute"); + addTextElement(wpPointElement, "coordinates", kmlCoordString(coord)); + addTextElement(wpPointElement, "extrude", "1"); QDomElement descriptionElement = createElement("description"); QString htmlString; @@ -118,20 +103,31 @@ void KMLPlanDomDocument::addMissionItems(Vehicle* vehicle, QList r QDomElement lineStringElement = createElement("LineString"); flightPathElement.appendChild(lineStringElement); - _addTextElement(lineStringElement, "extruder", "1"); - _addTextElement(lineStringElement, "tessellate", "1"); - _addTextElement(lineStringElement, "altitudeMode", "absolute"); + 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)); + coordString += QStringLiteral("%1\n").arg(kmlCoordString(coord)); } - _addTextElement(lineStringElement, "coordinates", coordString); + addTextElement(lineStringElement, "coordinates", coordString); } -QString KMLPlanDomDocument::_kmlColorString (const QColor& color) +void KMLPlanDomDocument::_addComplexItems(QmlObjectListModel* visualItems) { - 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')); + for (int i=0; icount(); i++) { + ComplexMissionItem* complexItem = visualItems->value(i); + if (complexItem) { + complexItem->addKMLVisuals(*this); + } + } +} + +void KMLPlanDomDocument::addMission(Vehicle* vehicle, QmlObjectListModel* visualItems, QList rgMissionItems) +{ + _addFlightPath(vehicle, rgMissionItems); + _addComplexItems(visualItems); } void KMLPlanDomDocument::_addStyles(void) @@ -141,35 +137,20 @@ void KMLPlanDomDocument::_addStyles(void) QDomElement styleElement1 = createElement("Style"); styleElement1.setAttribute("id", _missionLineStyleName); QDomElement lineStyleElement = createElement("LineStyle"); - _addTextElement(lineStyleElement, "color", _kmlColorString(palette.mapMissionTrajectory())); - _addTextElement(lineStyleElement, "width", "4"); + addTextElement(lineStyleElement, "color", kmlColorString(palette.mapMissionTrajectory())); + addTextElement(lineStyleElement, "width", "4"); styleElement1.appendChild(lineStyleElement); + QString kmlSurveyColorString = kmlColorString(palette.surveyPolygonInterior(), 0.5 /* opacity */); 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); + styleElement2.setAttribute("id", surveyPolygonStyleName); + QDomElement polygonStyleElement = createElement("PolyStyle"); + addTextElement(polygonStyleElement, "color", kmlSurveyColorString); + QDomElement polygonLineStyleElement = createElement("LineStyle"); + addTextElement(polygonLineStyleElement, "color", kmlSurveyColorString); + styleElement2.appendChild(polygonStyleElement); + styleElement2.appendChild(polygonLineStyleElement); + + _rootDocumentElement.appendChild(styleElement1); + _rootDocumentElement.appendChild(styleElement2); } diff --git a/src/MissionManager/KMLPlanDomDocument.h b/src/MissionManager/KMLPlanDomDocument.h index 2afaf1cd9439dd250f476a14d95795455edd1bd7..7ebdb34b01fcacd82dd74e9243e3ff729acc13c0 100644 --- a/src/MissionManager/KMLPlanDomDocument.h +++ b/src/MissionManager/KMLPlanDomDocument.h @@ -9,31 +9,27 @@ #pragma once -#include -#include -#include +#include "KMLDomDocument.h" class MissionItem; class Vehicle; +class QmlObjectListModel; /// Used to convert a Plan to a KML document -class KMLPlanDomDocument : public QDomDocument +class KMLPlanDomDocument : public KMLDomDocument { public: KMLPlanDomDocument(); - void addMissionItems(Vehicle* vehicle, QList rgMissionItems); + void addMission(Vehicle* vehicle, QmlObjectListModel* visualItems, QList 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); + static const char* surveyPolygonStyleName; - QDomElement _documentElement; +private: + void _addStyles (void); + void _addFlightPath (Vehicle* vehicle, QList rgMissionItems); + void _addComplexItems (QmlObjectListModel* visualItems); static const char* _missionLineStyleName; - static const char* _ballonStyleName; }; diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index 2b8e1fc9c466d90420613b4aafda61d761e1c12a..144a682ef3f67087f15a50a43495ea84d8c1d1da 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -279,7 +279,7 @@ void MissionController::addMissionToKML(KMLPlanDomDocument& planKML) QList rgMissionItems; _convertToMissionItems(_visualItems, rgMissionItems, deleteParent); - planKML.addMissionItems(_controllerVehicle, rgMissionItems); + planKML.addMission(_controllerVehicle, _visualItems, rgMissionItems); deleteParent->deleteLater(); } diff --git a/src/MissionManager/QGCMapPolygon.cc b/src/MissionManager/QGCMapPolygon.cc index 3c37a742ac514eecab0d27917f122cef458e8e48..f1c1a1b262a87d8e5ac17ba582ed1eadc316156b 100644 --- a/src/MissionManager/QGCMapPolygon.cc +++ b/src/MissionManager/QGCMapPolygon.cc @@ -555,3 +555,46 @@ void QGCMapPolygon::_endResetIfNotActive(void) endReset(); } } + +QDomElement QGCMapPolygon::kmlPolygonElement(KMLDomDocument& domDocument) +{ +#if 0 + + + 0 + 0 + clampToGround + + + + + ... + + + + + ... + + + +#endif + + QDomElement polygonElement = domDocument.createElement("Polygon"); + + domDocument.addTextElement(polygonElement, "altitudeMode", "clampToGround"); + + QDomElement outerBoundaryIsElement = domDocument.createElement("outerBoundaryIs"); + QDomElement linearRingElement = domDocument.createElement("LinearRing"); + + outerBoundaryIsElement.appendChild(linearRingElement); + polygonElement.appendChild(outerBoundaryIsElement); + + QString coordString; + for (const QVariant& varCoord : _polygonPath) { + coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(varCoord.value())); + } + coordString += QStringLiteral("%1\n").arg(domDocument.kmlCoordString(_polygonPath.first().value())); + domDocument.addTextElement(linearRingElement, "coordinates", coordString); + + return polygonElement; +} diff --git a/src/MissionManager/QGCMapPolygon.h b/src/MissionManager/QGCMapPolygon.h index 7e103a5457489b2e8d04339ccf09a61dcdc3ddd8..132e9888e0824b73e7830592c52a7d2e3d388e10 100644 --- a/src/MissionManager/QGCMapPolygon.h +++ b/src/MissionManager/QGCMapPolygon.h @@ -16,6 +16,7 @@ #include #include "QmlObjectListModel.h" +#include "KMLDomDocument.h" /// The QGCMapPolygon class provides a polygon which can be displayed on a map using a map visuals control. /// It maintains a representation of the polygon on QVariantList and QmlObjectListModel format. @@ -92,6 +93,8 @@ public: /// Returns the area of the polygon in meters squared double area(void) const; + QDomElement kmlPolygonElement(KMLDomDocument& domDocument); + // Property methods int count (void) const { return _polygonPath.count(); } diff --git a/src/MissionManager/QGCMapPolyline.cc b/src/MissionManager/QGCMapPolyline.cc index e3d1620265ef611f379a567c7606257ef0b2cbcd..abbfd9b8c39db00b47b39e74b1dbe84fba159b75 100644 --- a/src/MissionManager/QGCMapPolyline.cc +++ b/src/MissionManager/QGCMapPolyline.cc @@ -12,7 +12,7 @@ #include "JsonHelper.h" #include "QGCQGeoCoordinate.h" #include "QGCApplication.h" -#include "KMLFileHelper.h" +#include "KMLHelper.h" #include #include @@ -352,7 +352,7 @@ bool QGCMapPolyline::loadKMLFile(const QString& kmlFile) QString errorString; QList rgCoords; - if (!KMLFileHelper::loadPolylineFromFile(kmlFile, rgCoords, errorString)) { + if (!KMLHelper::loadPolylineFromFile(kmlFile, rgCoords, errorString)) { qgcApp()->showMessage(errorString); return false; } diff --git a/src/MissionManager/TransectStyleComplexItem.cc b/src/MissionManager/TransectStyleComplexItem.cc index 78941c7e9e1d5e2f90cfa85a53c384cfbc917378..20e6c52d87af7bdc8b8a6a9349fc1fc58ddf2761 100644 --- a/src/MissionManager/TransectStyleComplexItem.cc +++ b/src/MissionManager/TransectStyleComplexItem.cc @@ -989,3 +989,15 @@ void TransectStyleComplexItem::_appendLoadedMissionItems(QList& it items.append(item); } } + +void TransectStyleComplexItem::addKMLVisuals(KMLPlanDomDocument& domDocument) +{ + // We add the survey area polygon as a Placemark + + QDomElement placemarkElement = domDocument.addPlacemark(QStringLiteral("Survey Area"), true); + QDomElement polygonElement = _surveyAreaPolygon.kmlPolygonElement(domDocument); + + placemarkElement.appendChild(polygonElement); + domDocument.addTextElement(placemarkElement, "styleUrl", QStringLiteral("#%1").arg(domDocument.surveyPolygonStyleName)); + domDocument.appendChildToRoot(placemarkElement); +} diff --git a/src/MissionManager/TransectStyleComplexItem.h b/src/MissionManager/TransectStyleComplexItem.h index bcc36884651b7a39ff7c16bee82a3a0d7780db3f..1732f8524b105a00c5b8682614aa1bcc89721f08 100644 --- a/src/MissionManager/TransectStyleComplexItem.h +++ b/src/MissionManager/TransectStyleComplexItem.h @@ -78,10 +78,10 @@ public: int _transectCount(void) const { return _transects.count(); } // Overrides from ComplexMissionItem - - int lastSequenceNumber (void) const final; - QString mapVisualQML (void) const override = 0; - bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) override = 0; + int lastSequenceNumber (void) const final; + QString mapVisualQML (void) const override = 0; + bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) override = 0; + void addKMLVisuals (KMLPlanDomDocument& domDocument) final; double complexDistance (void) const final { return _complexDistance; } double greatestDistanceTo (const QGeoCoordinate &other) const final; diff --git a/src/PlanView/TransectStyleMapVisuals.qml b/src/PlanView/TransectStyleMapVisuals.qml index 3f0ac520ad7f15af8cb2a488aae217b4775591e1..2c262885474c370fd0c0842330fa285bbf8c196f 100644 --- a/src/PlanView/TransectStyleMapVisuals.qml +++ b/src/PlanView/TransectStyleMapVisuals.qml @@ -73,7 +73,7 @@ Item { interactive: polygonInteractive && _missionItem.isCurrentItem borderWidth: 1 borderColor: "black" - interiorColor: "green" + interiorColor: QGroundControl.globalPalette.surveyPolygonInterior interiorOpacity: 0.5 } diff --git a/src/QGCPalette.cc b/src/QGCPalette.cc index 69986af82f6b2e6617ff2a33afbd07e3c2f780a0..fb2f3a9bbaa283c093aa0de4a34bdb83d9a8f138 100644 --- a/src/QGCPalette.cc +++ b/src/QGCPalette.cc @@ -87,9 +87,10 @@ void QGCPalette::_buildMap() DECLARE_QGC_NONTHEMED_COLOR(brandingBlue, "#48D6FF", "#6045c5") // Colors not affecting by theming or enable/disable - DECLARE_QGC_SINGLE_COLOR(mapWidgetBorderLight, "#ffffff") - DECLARE_QGC_SINGLE_COLOR(mapWidgetBorderDark, "#000000") - DECLARE_QGC_SINGLE_COLOR(mapMissionTrajectory, "#be781c") + DECLARE_QGC_SINGLE_COLOR(mapWidgetBorderLight, "#ffffff") + DECLARE_QGC_SINGLE_COLOR(mapWidgetBorderDark, "#000000") + DECLARE_QGC_SINGLE_COLOR(mapMissionTrajectory, "#be781c") + DECLARE_QGC_SINGLE_COLOR(surveyPolygonInterior, "green") } void QGCPalette::setColorGroupEnabled(bool enabled) diff --git a/src/QGCPalette.h b/src/QGCPalette.h index 62fbf5a5e00403157f6ca43650c65687d240ba4f..e04e456256809da3abb41c9c6558174dddc6c939 100644 --- a/src/QGCPalette.h +++ b/src/QGCPalette.h @@ -147,6 +147,7 @@ public: DEFINE_QGC_COLOR(statusFailedText, setstatusFailedText) DEFINE_QGC_COLOR(statusPassedText, setstatusPassedText) DEFINE_QGC_COLOR(statusPendingText, setstatusPendingText) + DEFINE_QGC_COLOR(surveyPolygonInterior, setSurveyPolygonInterior) QGCPalette(QObject* parent = nullptr); ~QGCPalette(); diff --git a/src/ShapeFileHelper.cc b/src/ShapeFileHelper.cc index 79a73ccf7caae76d765bd16a779da8ef24661624..b27542d6828f5738b2e350e8c3d979aa3f8104ef 100644 --- a/src/ShapeFileHelper.cc +++ b/src/ShapeFileHelper.cc @@ -9,7 +9,7 @@ #include "ShapeFileHelper.h" #include "AppSettings.h" -#include "KMLFileHelper.h" +#include "KMLHelper.h" #include "SHPFileHelper.h" #include @@ -52,7 +52,7 @@ ShapeFileHelper::ShapeType ShapeFileHelper::determineShapeType(const QString& fi bool fileIsKML = _fileIsKML(file, errorString); if (errorString.isEmpty()) { if (fileIsKML) { - shapeType = KMLFileHelper::determineShapeType(file, errorString); + shapeType = KMLHelper::determineShapeType(file, errorString); } else { shapeType = SHPFileHelper::determineShapeType(file, errorString); } @@ -71,7 +71,7 @@ bool ShapeFileHelper::loadPolygonFromFile(const QString& file, QList