Commit 03d3d538 authored by DonLakeFlyer's avatar DonLakeFlyer

Support for Sync - Load KML

parent 4b3b4769
......@@ -515,6 +515,7 @@ HEADERS += \
src/Joystick/Joystick.h \
src/Joystick/JoystickManager.h \
src/JsonHelper.h \
src/KMLFileHelper.h \
src/LogCompressor.h \
src/MG.h \
src/MissionManager/CameraCalc.h \
......@@ -711,6 +712,7 @@ SOURCES += \
src/Joystick/Joystick.cc \
src/Joystick/JoystickManager.cc \
src/JsonHelper.cc \
src/KMLFileHelper.cc \
src/LogCompressor.cc \
src/MissionManager/CameraCalc.cc \
src/MissionManager/CameraSection.cc \
......
/****************************************************************************
*
* (c) 2009-2016 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 "KMLFileHelper.h"
#include <QFile>
QDomDocument KMLFileHelper::loadFile(const QString& kmlFile, QString& errorString)
{
QFile file(kmlFile);
errorString.clear();
if (!file.exists()) {
errorString = tr("File not found: %1").arg(kmlFile);
return QDomDocument();
}
if (!file.open(QIODevice::ReadOnly)) {
errorString = tr("Unable to open file: %1 error: $%2").arg(kmlFile).arg(file.errorString());
return QDomDocument();
}
QDomDocument doc;
QString errorMessage;
int errorLine;
if (!doc.setContent(&file, &errorMessage, &errorLine)) {
errorString = tr("Unable to parse KML file: %1 error: %2 line: %3").arg(kmlFile).arg(errorMessage).arg(errorLine);
return QDomDocument();
}
return doc;
}
QVariantList KMLFileHelper::determineFileContents(const QString& kmlFile)
{
QString errorString;
KMLFileContents fileContents = determineFileContents(kmlFile, errorString);
QVariantList varList;
varList.append(QVariant::fromValue(fileContents));
varList.append(QVariant::fromValue(errorString));
return varList;
}
KMLFileHelper::KMLFileContents KMLFileHelper::determineFileContents(const QString& kmlFile, QString& errorString)
{
QDomDocument domDocument = KMLFileHelper::loadFile(kmlFile, errorString);
if (!errorString.isEmpty()) {
return Error;
}
QDomNodeList rgNodes = domDocument.elementsByTagName("Polygon");
if (rgNodes.count()) {
return Polygon;
}
rgNodes = domDocument.elementsByTagName("LineString");
if (rgNodes.count()) {
return Polyline;
}
errorString = tr("No known type found in KML file.");
return Error;
}
bool KMLFileHelper::loadPolygonFromFile(const QString& kmlFile, QList<QGeoCoordinate>& vertices, QString& errorString)
{
errorString.clear();
vertices.clear();
QDomDocument domDocument = KMLFileHelper::loadFile(kmlFile, errorString);
if (!errorString.isEmpty()) {
return false;
}
QDomNodeList rgNodes = domDocument.elementsByTagName("Polygon");
if (rgNodes.count() == 0) {
errorString = tr("Unable to find Polygon node in KML");
return false;
}
QDomNode coordinatesNode = rgNodes.item(0).namedItem("outerBoundaryIs").namedItem("LinearRing").namedItem("coordinates");
if (coordinatesNode.isNull()) {
errorString = tr("Internal error: Unable to find coordinates node in KML");
return false;
}
QString coordinatesString = coordinatesNode.toElement().text().simplified();
QStringList rgCoordinateStrings = coordinatesString.split(" ");
QList<QGeoCoordinate> rgCoords;
for (int i=0; i<rgCoordinateStrings.count()-1; i++) {
QString coordinateString = rgCoordinateStrings[i];
QStringList rgValueStrings = coordinateString.split(",");
QGeoCoordinate coord;
coord.setLongitude(rgValueStrings[0].toDouble());
coord.setLatitude(rgValueStrings[1].toDouble());
rgCoords.append(coord);
}
// Determine winding, reverse if needed
double sum = 0;
for (int i=0; i<rgCoords.count(); i++) {
QGeoCoordinate coord1 = rgCoords[i];
QGeoCoordinate coord2 = (i == rgCoords.count() - 1) ? rgCoords[0] : rgCoords[i+1];
sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude());
}
bool reverse = sum < 0.0;
if (reverse) {
QList<QGeoCoordinate> rgReversed;
for (int i=0; i<rgCoords.count(); i++) {
rgReversed.prepend(rgCoords[i]);
}
rgCoords = rgReversed;
}
vertices = rgCoords;
return true;
}
bool KMLFileHelper::loadPolylineFromFile(const QString& kmlFile, QList<QGeoCoordinate>& coords, QString& errorString)
{
errorString.clear();
coords.clear();
QDomDocument domDocument = KMLFileHelper::loadFile(kmlFile, errorString);
if (!errorString.isEmpty()) {
return false;
}
QDomNodeList rgNodes = domDocument.elementsByTagName("LineString");
if (rgNodes.count() == 0) {
errorString = tr("Unable to find LineString node in KML");
return false;
}
QDomNode coordinatesNode = rgNodes.item(0).namedItem("coordinates");
if (coordinatesNode.isNull()) {
errorString = tr("Internal error: Unable to find coordinates node in KML");
return false;
}
QString coordinatesString = coordinatesNode.toElement().text().simplified();
QStringList rgCoordinateStrings = coordinatesString.split(" ");
QList<QGeoCoordinate> rgCoords;
for (int i=0; i<rgCoordinateStrings.count()-1; i++) {
QString coordinateString = rgCoordinateStrings[i];
QStringList rgValueStrings = coordinateString.split(",");
QGeoCoordinate coord;
coord.setLongitude(rgValueStrings[0].toDouble());
coord.setLatitude(rgValueStrings[1].toDouble());
rgCoords.append(coord);
}
coords = rgCoords;
return true;
}
/****************************************************************************
*
* (c) 2009-2016 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 <QObject>
#include <QDomDocument>
#include <QList>
#include <QGeoCoordinate>
/// 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.
class KMLFileHelper : public QObject
{
Q_OBJECT
public:
enum KMLFileContents {
Polygon,
Polyline,
Error
};
Q_ENUM(KMLFileContents)
Q_INVOKABLE static QVariantList determineFileContents(const QString& kmlFile);
static KMLFileContents determineFileContents(const QString& kmlFile, QString& errorString);
static QDomDocument loadFile(const QString& kmlFile, QString& errorString);
static bool loadPolygonFromFile(const QString& kmlFile, QList<QGeoCoordinate>& vertices, QString& errorString);
static bool loadPolylineFromFile(const QString& kmlFile, QList<QGeoCoordinate>& coords, QString& errorString);
};
......@@ -27,7 +27,7 @@ const char* CorridorScanComplexItem::_jsonEntryPointKey = "EntryPoint";
const char* CorridorScanComplexItem::jsonComplexItemTypeValue = "CorridorScan";
CorridorScanComplexItem::CorridorScanComplexItem(Vehicle* vehicle, bool flyView, QObject* parent)
CorridorScanComplexItem::CorridorScanComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlFile, QObject* parent)
: TransectStyleComplexItem (vehicle, flyView, settingsGroup, parent)
, _entryPoint (0)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CorridorScan.SettingsGroup.json"), this))
......@@ -50,6 +50,12 @@ CorridorScanComplexItem::CorridorScanComplexItem(Vehicle* vehicle, bool flyView,
connect(&_corridorPolyline, &QGCMapPolyline::pathChanged, this, &CorridorScanComplexItem::_rebuildCorridorPolygon);
connect(&_corridorWidthFact, &Fact::valueChanged, this, &CorridorScanComplexItem::_rebuildCorridorPolygon);
if (!kmlFile.isEmpty()) {
_corridorPolyline.loadKMLFile(kmlFile);
_corridorPolyline.setDirty(false);
}
setDirty(false);
}
void CorridorScanComplexItem::save(QJsonArray& planItems)
......
......@@ -23,7 +23,10 @@ class CorridorScanComplexItem : public TransectStyleComplexItem
Q_OBJECT
public:
CorridorScanComplexItem(Vehicle* vehicle, bool flyView, QObject* parent);
/// @param vehicle Vehicle which this is being contructed for
/// @param flyView true: Created for use in the Fly View, false: Created for use in the Plan View
/// @param kmlFile Polyline comes from this file, empty for default polyline
CorridorScanComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlFile, QObject* parent);
Q_PROPERTY(QGCMapPolyline* corridorPolyline READ corridorPolyline CONSTANT)
Q_PROPERTY(Fact* corridorWidth READ corridorWidth CONSTANT)
......
......@@ -23,7 +23,7 @@ void CorridorScanComplexItemTest::init(void)
UnitTest::init();
_offlineVehicle = new Vehicle(MAV_AUTOPILOT_PX4, MAV_TYPE_QUADROTOR, qgcApp()->toolbox()->firmwarePluginManager(), this);
_corridorItem = new CorridorScanComplexItem(_offlineVehicle, false /* flyView */, this);
_corridorItem = new CorridorScanComplexItem(_offlineVehicle, false /* flyView */, QString() /* kmlFile */, this /* parent */);
// vehicleSpeed need for terrain calcs
MissionController::MissionFlightStatus_t missionFlightStatus;
......
......@@ -389,25 +389,48 @@ int MissionController::insertROIMissionItem(QGeoCoordinate coordinate, int i)
int MissionController::insertComplexMissionItem(QString itemName, QGeoCoordinate mapCenterCoordinate, int i)
{
ComplexMissionItem* newItem;
bool surveyStyleItem = false;
int sequenceNumber = _nextSequenceNumber();
if (itemName == _surveyMissionItemName) {
newItem = new SurveyComplexItem(_controllerVehicle, _flyView, _visualItems);
newItem = new SurveyComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */);
newItem->setCoordinate(mapCenterCoordinate);
surveyStyleItem = true;
} else if (itemName == _fwLandingMissionItemName) {
newItem = new FixedWingLandingComplexItem(_controllerVehicle, _flyView, _visualItems);
newItem = new FixedWingLandingComplexItem(_controllerVehicle, _flyView, _visualItems /* parent */);
} else if (itemName == _structureScanMissionItemName) {
newItem = new StructureScanComplexItem(_controllerVehicle, _flyView, _visualItems);
newItem = new StructureScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */);
} else if (itemName == _corridorScanMissionItemName) {
newItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, _visualItems);
surveyStyleItem = true;
newItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, _visualItems /* parent */);
} else {
qWarning() << "Internal error: Unknown complex item:" << itemName;
return sequenceNumber;
}
return _insertComplexMissionItemWorker(newItem, i);
}
int MissionController::insertComplexMissionItemFromKML(QString itemName, QString kmlFile, int i)
{
ComplexMissionItem* newItem;
if (itemName == _surveyMissionItemName) {
newItem = new SurveyComplexItem(_controllerVehicle, _flyView, kmlFile, _visualItems);
} else if (itemName == _structureScanMissionItemName) {
newItem = new StructureScanComplexItem(_controllerVehicle, _flyView, kmlFile, _visualItems);
} else if (itemName == _corridorScanMissionItemName) {
newItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, kmlFile, _visualItems);
} else {
qWarning() << "Internal error: Unknown complex item:" << itemName;
return _nextSequenceNumber();
}
return _insertComplexMissionItemWorker(newItem, i);
}
int MissionController::_insertComplexMissionItemWorker(ComplexMissionItem* complexItem, int i)
{
int sequenceNumber = _nextSequenceNumber();
bool surveyStyleItem = qobject_cast<SurveyComplexItem*>(complexItem) || qobject_cast<CorridorScanComplexItem*>(complexItem);
if (surveyStyleItem) {
bool rollSupported = false;
bool pitchSupported = false;
......@@ -434,14 +457,18 @@ int MissionController::insertComplexMissionItem(QString itemName, QGeoCoordinate
}
}
newItem->setSequenceNumber(sequenceNumber);
_initVisualItem(newItem);
complexItem->setSequenceNumber(sequenceNumber);
_initVisualItem(complexItem);
_visualItems->insert(i, newItem);
if (i == -1) {
_visualItems->append(complexItem);
} else {
_visualItems->insert(i, complexItem);
}
_recalcAll();
return newItem->sequenceNumber();
return complexItem->sequenceNumber();
}
void MissionController::removeMissionItem(int index)
......@@ -529,7 +556,7 @@ bool MissionController::_loadJsonMissionFileV1(const QJsonObject& json, QmlObjec
return false;
}
SurveyComplexItem* item = new SurveyComplexItem(_controllerVehicle, _flyView, visualItems);
SurveyComplexItem* item = new SurveyComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, visualItems /* parent */);
const QJsonObject itemObject = itemValue.toObject();
if (item->load(itemObject, itemObject["id"].toInt(), errorString)) {
surveyItems.append(item);
......@@ -687,7 +714,7 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjec
if (complexItemType == SurveyComplexItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Survey: nextSequenceNumber" << nextSequenceNumber;
SurveyComplexItem* surveyItem = new SurveyComplexItem(_controllerVehicle, _flyView, visualItems);
SurveyComplexItem* surveyItem = new SurveyComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, visualItems);
if (!surveyItem->load(itemObject, nextSequenceNumber++, errorString)) {
return false;
}
......@@ -705,7 +732,7 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjec
visualItems->append(landingItem);
} else if (complexItemType == StructureScanComplexItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Structure Scan: nextSequenceNumber" << nextSequenceNumber;
StructureScanComplexItem* structureItem = new StructureScanComplexItem(_controllerVehicle, _flyView, visualItems);
StructureScanComplexItem* structureItem = new StructureScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, visualItems);
if (!structureItem->load(itemObject, nextSequenceNumber++, errorString)) {
return false;
}
......@@ -714,7 +741,7 @@ bool MissionController::_loadJsonMissionFileV2(const QJsonObject& json, QmlObjec
visualItems->append(structureItem);
} else if (complexItemType == CorridorScanComplexItem::jsonComplexItemTypeValue) {
qCDebug(MissionControllerLog) << "Loading Corridor Scan: nextSequenceNumber" << nextSequenceNumber;
CorridorScanComplexItem* corridorItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, visualItems);
CorridorScanComplexItem* corridorItem = new CorridorScanComplexItem(_controllerVehicle, _flyView, QString() /* kmlFile */, visualItems);
if (!corridorItem->load(itemObject, nextSequenceNumber++, errorString)) {
return false;
}
......
......@@ -25,6 +25,7 @@ class MissionSettingsItem;
class AppSettings;
class MissionManager;
class SimpleMissionItem;
class ComplexMissionItem;
class QDomDocument;
Q_DECLARE_LOGGING_CATEGORY(MissionControllerLog)
......@@ -89,6 +90,10 @@ public:
Q_PROPERTY(int batteryChangePoint READ batteryChangePoint NOTIFY batteryChangePointChanged)
Q_PROPERTY(int batteriesRequired READ batteriesRequired NOTIFY batteriesRequiredChanged)
Q_PROPERTY(QString surveyComplexItemName READ surveyComplexItemName CONSTANT)
Q_PROPERTY(QString corridorScanComplexItemName READ corridorScanComplexItemName CONSTANT)
Q_PROPERTY(QString structureScanComplexItemName READ structureScanComplexItemName CONSTANT)
Q_INVOKABLE void removeMissionItem(int index);
/// Add a new simple mission item to the list
......@@ -108,6 +113,12 @@ public:
/// @return Sequence number for new item
Q_INVOKABLE int insertComplexMissionItem(QString itemName, QGeoCoordinate mapCenterCoordinate, int i);
/// Add a new complex mission item to the list
/// @param itemName: Name of complex item to create (from complexMissionItemNames)
/// @param i: index to insert at, -1 for end
/// @return Sequence number for new item
Q_INVOKABLE int insertComplexMissionItemFromKML(QString itemName, QString kmlFile, int i);
Q_INVOKABLE void resumeMission(int resumeIndex);
/// Updates the altitudes of the items in the current mission to the new default altitude
......@@ -148,13 +159,16 @@ public:
// Property accessors
QmlObjectListModel* visualItems (void) { return _visualItems; }
QmlObjectListModel* waypointLines (void) { return &_waypointLines; }
QVariantList waypointPath (void) { return _waypointPath; }
QStringList complexMissionItemNames (void) const;
QGeoCoordinate plannedHomePosition (void) const;
VisualMissionItem* currentPlanViewItem (void) const;
double progressPct (void) const { return _progressPct; }
QmlObjectListModel* visualItems (void) { return _visualItems; }
QmlObjectListModel* waypointLines (void) { return &_waypointLines; }
QVariantList waypointPath (void) { return _waypointPath; }
QStringList complexMissionItemNames (void) const;
QGeoCoordinate plannedHomePosition (void) const;
VisualMissionItem* currentPlanViewItem (void) const;
double progressPct (void) const { return _progressPct; }
QString surveyComplexItemName (void) const { return _surveyMissionItemName; }
QString corridorScanComplexItemName (void) const { return _corridorScanMissionItemName; }
QString structureScanComplexItemName(void) const { return _structureScanMissionItemName; }
int currentMissionIndex (void) const;
int resumeMissionIndex (void) const;
......@@ -242,6 +256,7 @@ private:
void _addWaypointLineSegment(CoordVectHashTable& prevItemPairHashTable, VisualItemPair& pair);
void _addCommandTimeDelay(SimpleMissionItem* simpleItem, bool vtolInHover);
void _addTimeDistance(bool vtolInHover, double hoverTime, double cruiseTime, double extraTime, double distance, int seqNum);
int _insertComplexMissionItemWorker(ComplexMissionItem* complexItem, int i);
private:
MissionManager* _missionManager;
......
......@@ -484,7 +484,7 @@ QStringList PlanMasterController::saveNameFilters(void) const
return filters;
}
QStringList PlanMasterController::saveKmlFilters(void) const
QStringList PlanMasterController::fileKmlFilters(void) const
{
QStringList filters;
......
......@@ -43,7 +43,7 @@ public:
///< kml file extension for missions
Q_PROPERTY(QStringList loadNameFilters READ loadNameFilters CONSTANT) ///< File filter list loading plan files
Q_PROPERTY(QStringList saveNameFilters READ saveNameFilters CONSTANT) ///< File filter list saving plan files
Q_PROPERTY(QStringList saveKmlFilters READ saveKmlFilters CONSTANT) ///< File filter list saving KML files
Q_PROPERTY(QStringList fileKmlFilters READ fileKmlFilters CONSTANT) ///< File filter list for load/save KML files
/// Should be called immediately upon Component.onCompleted.
Q_INVOKABLE void start(bool flyView);
......@@ -81,7 +81,7 @@ public:
QString kmlFileExtension(void) const;
QStringList loadNameFilters (void) const;
QStringList saveNameFilters (void) const;
QStringList saveKmlFilters (void) const;
QStringList fileKmlFilters (void) const;
QJsonDocument saveToJson ();
......
......@@ -12,6 +12,7 @@
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include "QGCApplication.h"
#include "KMLFileHelper.h"
#include <QGeoRectangle>
#include <QDebug>
......@@ -453,71 +454,11 @@ void QGCMapPolygon::offset(double distance)
bool QGCMapPolygon::loadKMLFile(const QString& kmlFile)
{
QFile file(kmlFile);
if (!file.exists()) {
qgcApp()->showMessage(tr("File not found: %1").arg(kmlFile));
return false;
}
if (!file.open(QIODevice::ReadOnly)) {
qgcApp()->showMessage(tr("Unable to open file: %1 error: $%2").arg(kmlFile).arg(file.errorString()));
return false;
}
QDomDocument doc;
QString errorMessage;
int errorLine;
if (!doc.setContent(&file, &errorMessage, &errorLine)) {
qgcApp()->showMessage(tr("Unable to parse KML file: %1 error: %2 line: %3").arg(kmlFile).arg(errorMessage).arg(errorLine));
return false;
}
QDomNodeList rgNodes = doc.elementsByTagName("Polygon");
if (rgNodes.count() == 0) {
qgcApp()->showMessage(tr("Unable to find Polygon node in KML"));
return false;
}
QDomNode coordinatesNode = rgNodes.item(0).namedItem("outerBoundaryIs").namedItem("LinearRing").namedItem("coordinates");
if (coordinatesNode.isNull()) {
qgcApp()->showMessage(tr("Internal error: Unable to find coordinates node in KML"));
return false;
}
QString coordinatesString = coordinatesNode.toElement().text().simplified();
QStringList rgCoordinateStrings = coordinatesString.split(" ");
QString errorString;
QList<QGeoCoordinate> rgCoords;
for (int i=0; i<rgCoordinateStrings.count()-1; i++) {
QString coordinateString = rgCoordinateStrings[i];
QStringList rgValueStrings = coordinateString.split(",");
QGeoCoordinate coord;
coord.setLongitude(rgValueStrings[0].toDouble());
coord.setLatitude(rgValueStrings[1].toDouble());
rgCoords.append(coord);
}
// Determine winding, reverse if needed
double sum = 0;
for (int i=0; i<rgCoords.count(); i++) {
QGeoCoordinate coord1 = rgCoords[i];
QGeoCoordinate coord2 = (i == rgCoords.count() - 1) ? rgCoords[0] : rgCoords[i+1];
sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude());
}
bool reverse = sum < 0.0;
if (reverse) {
QList<QGeoCoordinate> rgReversed;
for (int i=0; i<rgCoords.count(); i++) {
rgReversed.prepend(rgCoords[i]);
}
rgCoords = rgReversed;
if (!KMLFileHelper::loadPolygonFromFile(kmlFile, rgCoords, errorString)) {
qgcApp()->showMessage(errorString);
return false;
}
clear();
......
......@@ -12,6 +12,7 @@
#include "JsonHelper.h"
#include "QGCQGeoCoordinate.h"
#include "QGCApplication.h"
#include "KMLFileHelper.h"
#include <QGeoRectangle>
#include <QDebug>
......@@ -338,52 +339,11 @@ QList<QGeoCoordinate> QGCMapPolyline::offsetPolyline(double distance)
bool QGCMapPolyline::loadKMLFile(const QString& kmlFile)
{
QFile file(kmlFile);
if (!file.exists()) {
qgcApp()->showMessage(tr("File not found: %1").arg(kmlFile));
return false;
}
if (!file.open(QIODevice::ReadOnly)) {
qgcApp()->showMessage(tr("Unable to open file: %1 error: $%2").arg(kmlFile).arg(file.errorString()));
return false;
}
QDomDocument doc;
QString errorMessage;
int errorLine;
if (!doc.setContent(&file, &errorMessage, &errorLine)) {
qgcApp()->showMessage(tr("Unable to parse KML file: %1 error: %2 line: %3").arg(kmlFile).arg(errorMessage).arg(errorLine));
return false;
}
QDomNodeList rgNodes = doc.elementsByTagName("LineString");
if (rgNodes.count() == 0) {
qgcApp()->showMessage(tr("Unable to find LineString node in KML"));
return false;
}
QDomNode coordinatesNode = rgNodes.item(0).namedItem("coordinates");
if (coordinatesNode.isNull()) {
qgcApp()->showMessage(tr("Internal error: Unable to find coordinates node in KML"));
return false;
}
QString coordinatesString = coordinatesNode.toElement().text().simplified();
QStringList rgCoordinateStrings = coordinatesString.split(" ");
QString errorString;
QList<QGeoCoordinate> rgCoords;
for (int i=0; i<rgCoordinateStrings.count()-1; i++) {
QString coordinateString = rgCoordinateStrings[i];
QStringList rgValueStrings = coordinateString.split(",");
QGeoCoordinate coord;
coord.setLongitude(rgValueStrings[0].toDouble());
coord.setLatitude(rgValueStrings[1].toDouble());
rgCoords.append(coord);
if (!KMLFileHelper::loadPolylineFromFile(kmlFile, rgCoords, errorString)) {
qgcApp()->showMessage(errorString);
return false;
}
clear();
......
......@@ -83,7 +83,7 @@ void SectionTest::_commonScanTest(Section* section)
waypointVisualItems.append(&simpleItem);
QmlObjectListModel complexVisualItems;
SurveyComplexItem surveyItem(_offlineVehicle, false /* fly View */, this);
SurveyComplexItem surveyItem(_offlineVehicle, false /* fly View */, QString() /* kmlFile */, this /* parent */);
complexVisualItems.append(&surveyItem);
// This tests the common cases which should not lead to scan succeess
......
......@@ -30,7 +30,7 @@ const char* StructureScanComplexItem::jsonComplexItemTypeValue = "StructureSc
const char* StructureScanComplexItem::_jsonCameraCalcKey = "CameraCalc";
const char* StructureScanComplexItem::_jsonAltitudeRelativeKey = "altitudeRelative";
StructureScanComplexItem::StructureScanComplexItem(Vehicle* vehicle, bool flyView, QObject* parent)
StructureScanComplexItem::StructureScanComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlFile, QObject* parent)
: ComplexMissionItem (vehicle, flyView, parent)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/StructureScan.SettingsGroup.json"), this /* QObject parent */))
, _sequenceNumber (0)
......@@ -75,6 +75,13 @@ StructureScanComplexItem::StructureScanComplexItem(Vehicle* vehicle, bool flyVie
connect(&_layersFact, &Fact::valueChanged, this, &StructureScanComplexItem::_recalcCameraShots);
_recalcLayerInfo();
if (!kmlFile.isEmpty()) {
_structurePolygon.loadKMLFile(kmlFile);
_structurePolygon.setDirty(false);
}
setDirty(false);
}
void StructureScanComplexItem::_setScanDistance(double scanDistance)
......
......@@ -25,7 +25,10 @@ class StructureScanComplexItem : public ComplexMissionItem
Q_OBJECT
public:
StructureScanComplexItem(Vehicle* vehicle, bool flyView, QObject* parent);
/// @param vehicle Vehicle which this is being contructed for
/// @param flyView true: Created for use in the Fly View, false: Created for use in the Plan View
/// @param kmlFile Polygon comes from this file, empty for default polygon
StructureScanComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlFile, QObject* parent);
Q_PROPERTY(CameraCalc* cameraCalc READ cameraCalc CONSTANT)
Q_PROPERTY(Fact* altitude READ altitude CONSTANT)
......
......@@ -24,7 +24,7 @@ void StructureScanComplexItemTest::init(void)
_rgSignals[dirtyChangedIndex] = SIGNAL(dirtyChanged(bool));
_offlineVehicle = new Vehicle(MAV_AUTOPILOT_PX4, MAV_TYPE_QUADROTOR, qgcApp()->toolbox()->firmwarePluginManager(), this);
_structureScanItem = new StructureScanComplexItem(_offlineVehicle, false /* flyView */, this);
_structureScanItem = new StructureScanComplexItem(_offlineVehicle, false /* flyView */, QString() /* kmlFile */, this /* parent */);
_structureScanItem->setDirty(false);
_multiSpy = new MultiSignalSpy();
......@@ -121,7 +121,7 @@ void StructureScanComplexItemTest::_testSaveLoad(void)
_structureScanItem->save(items);
QString errorString;
StructureScanComplexItem* newItem = new StructureScanComplexItem(_offlineVehicle, false /* flyView */, this);
StructureScanComplexItem* newItem = new StructureScanComplexItem(_offlineVehicle, false /* flyView */, QString() /* kmlFile */, this /* parent */);
QVERIFY(newItem->load(items[0].toObject(), 10, errorString));
QVERIFY(errorString.isEmpty());
_validateItem(newItem);
......
......@@ -59,7 +59,7 @@ const char* SurveyComplexItem::_jsonV3FixedValueIsAltitudeKey = "fixedVa
const char* SurveyComplexItem::_jsonV3Refly90DegreesKey = "refly90Degrees";
const char* SurveyComplexItem::_jsonFlyAlternateTransectsKey = "flyAlternateTransects";
SurveyComplexItem::SurveyComplexItem(Vehicle* vehicle, bool flyView, QObject* parent)
SurveyComplexItem::SurveyComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlFile, QObject* parent)