KMLFileHelper.cc 5.33 KB
Newer Older
DonLakeFlyer's avatar
DonLakeFlyer committed
1
2
3
4
5
6
7
8
9
10
11
12
/****************************************************************************
 *
 *   (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>
13
#include <QVariant>
DonLakeFlyer's avatar
DonLakeFlyer committed
14

Don Gagne's avatar
   
Don Gagne committed
15
16
const char* KMLFileHelper::_errorPrefix = QT_TR_NOOP("KML file load failed. %1");

17
QDomDocument KMLFileHelper::_loadFile(const QString& kmlFile, QString& errorString)
DonLakeFlyer's avatar
DonLakeFlyer committed
18
19
20
21
22
23
{
    QFile file(kmlFile);

    errorString.clear();

    if (!file.exists()) {
Don Gagne's avatar
   
Don Gagne committed
24
        errorString = QString(_errorPrefix).arg(tr("File not found: %1").arg(kmlFile));
DonLakeFlyer's avatar
DonLakeFlyer committed
25
26
27
28
        return QDomDocument();
    }

    if (!file.open(QIODevice::ReadOnly)) {
Don Gagne's avatar
   
Don Gagne committed
29
        errorString = QString(_errorPrefix).arg(tr("Unable to open file: %1 error: $%2").arg(kmlFile).arg(file.errorString()));
DonLakeFlyer's avatar
DonLakeFlyer committed
30
31
32
33
34
35
36
        return QDomDocument();
    }

    QDomDocument doc;
    QString errorMessage;
    int errorLine;
    if (!doc.setContent(&file, &errorMessage, &errorLine)) {
Don Gagne's avatar
   
Don Gagne committed
37
        errorString = QString(_errorPrefix).arg(tr("Unable to parse KML file: %1 error: %2 line: %3").arg(kmlFile).arg(errorMessage).arg(errorLine));
DonLakeFlyer's avatar
DonLakeFlyer committed
38
39
40
41
42
43
        return QDomDocument();
    }

    return doc;
}

44
ShapeFileHelper::ShapeType KMLFileHelper::determineShapeType(const QString& kmlFile, QString& errorString)
DonLakeFlyer's avatar
DonLakeFlyer committed
45
{
46
    QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString);
DonLakeFlyer's avatar
DonLakeFlyer committed
47
    if (!errorString.isEmpty()) {
48
        return ShapeFileHelper::Error;
DonLakeFlyer's avatar
DonLakeFlyer committed
49
50
51
52
    }

    QDomNodeList rgNodes = domDocument.elementsByTagName("Polygon");
    if (rgNodes.count()) {
53
        return ShapeFileHelper::Polygon;
DonLakeFlyer's avatar
DonLakeFlyer committed
54
55
56
57
    }

    rgNodes = domDocument.elementsByTagName("LineString");
    if (rgNodes.count()) {
58
        return ShapeFileHelper::Polyline;
DonLakeFlyer's avatar
DonLakeFlyer committed
59
60
    }

Don Gagne's avatar
   
Don Gagne committed
61
    errorString = QString(_errorPrefix).arg(tr("No supported type found in KML file."));
62
    return ShapeFileHelper::Error;
DonLakeFlyer's avatar
DonLakeFlyer committed
63
64
65
66
67
68
69
}

bool KMLFileHelper::loadPolygonFromFile(const QString& kmlFile, QList<QGeoCoordinate>& vertices, QString& errorString)
{
    errorString.clear();
    vertices.clear();

70
    QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString);
DonLakeFlyer's avatar
DonLakeFlyer committed
71
72
73
74
75
76
    if (!errorString.isEmpty()) {
        return false;
    }

    QDomNodeList rgNodes = domDocument.elementsByTagName("Polygon");
    if (rgNodes.count() == 0) {
Don Gagne's avatar
   
Don Gagne committed
77
        errorString = QString(_errorPrefix).arg(tr("Unable to find Polygon node in KML"));
DonLakeFlyer's avatar
DonLakeFlyer committed
78
79
80
81
82
        return false;
    }

    QDomNode coordinatesNode = rgNodes.item(0).namedItem("outerBoundaryIs").namedItem("LinearRing").namedItem("coordinates");
    if (coordinatesNode.isNull()) {
Don Gagne's avatar
   
Don Gagne committed
83
        errorString = QString(_errorPrefix).arg(tr("Internal error: Unable to find coordinates node in KML"));
DonLakeFlyer's avatar
DonLakeFlyer committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        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);
    }

Don Gagne's avatar
   
Don Gagne committed
103
    // Determine winding, reverse if needed. QGC wants clockwise winding
DonLakeFlyer's avatar
DonLakeFlyer committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    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();

131
    QDomDocument domDocument = KMLFileHelper::_loadFile(kmlFile, errorString);
DonLakeFlyer's avatar
DonLakeFlyer committed
132
133
134
135
136
137
    if (!errorString.isEmpty()) {
        return false;
    }

    QDomNodeList rgNodes = domDocument.elementsByTagName("LineString");
    if (rgNodes.count() == 0) {
Don Gagne's avatar
   
Don Gagne committed
138
        errorString = QString(_errorPrefix).arg(tr("Unable to find LineString node in KML"));
DonLakeFlyer's avatar
DonLakeFlyer committed
139
140
141
142
143
        return false;
    }

    QDomNode coordinatesNode = rgNodes.item(0).namedItem("coordinates");
    if (coordinatesNode.isNull()) {
Don Gagne's avatar
   
Don Gagne committed
144
        errorString = QString(_errorPrefix).arg(tr("Internal error: Unable to find coordinates node in KML"));
DonLakeFlyer's avatar
DonLakeFlyer committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
        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;
}