22 changed files with 454 additions and 158 deletions
@ -0,0 +1,176 @@
@@ -0,0 +1,176 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* (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; |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* (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); |
||||
}; |
Loading…
Reference in new issue