Skip to content

Commit d9ab0c6

Browse files
committed
Utilities: Fix KML/Shape Helpers
1 parent 7548ff7 commit d9ab0c6

File tree

12 files changed

+103
-114
lines changed

12 files changed

+103
-114
lines changed

src/PlanView/StructureScanMapVisual.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Item {
2323
id: _root
2424

2525
property var map ///< Map control to place item in
26+
property var vehicle
2627

2728
property var _missionItem: object
2829
property var _structurePolygon: object.structurePolygon

src/QGCApplication.cc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,6 @@ QGC_LOGGING_CATEGORY(QGCApplicationLog, "qgc.qgcapplication")
9292

9393
// Qml Singleton factories
9494

95-
static QObject *shapeFileHelperSingletonFactory(QQmlEngine*, QJSEngine*)
96-
{
97-
return new ShapeFileHelper;
98-
}
99-
10095
static QObject *mavlinkSingletonFactory(QQmlEngine*, QJSEngine*)
10196
{
10297
return new QGCMAVLink();
@@ -310,12 +305,10 @@ void QGCApplication::init()
310305
#endif
311306
qmlRegisterType<JoystickConfigController>("QGroundControl.Controllers", 1, 0, "JoystickConfigController");
312307

313-
314-
qmlRegisterSingletonType<ShapeFileHelper>("QGroundControl.ShapeFileHelper", 1, 0, "ShapeFileHelper", shapeFileHelperSingletonFactory);
308+
(void) qmlRegisterSingletonType<ShapeFileHelper>("QGroundControl.ShapeFileHelper", 1, 0, "ShapeFileHelper", [](QQmlEngine *, QJSEngine *) { return new ShapeFileHelper(); });
315309

316310
qmlRegisterSingletonType<QGCMAVLink>("MAVLink", 1, 0, "MAVLink", mavlinkSingletonFactory);
317311

318-
319312
// Although this should really be in _initForNormalAppBoot putting it here allowws us to create unit tests which pop up more easily
320313
if(QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) {
321314
qCWarning(QGCApplicationLog) << "Could not load /fonts/opensans font";

src/QmlControls/QGCMapPolyline.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ QList<QPointF> QGCMapPolyline::nedPolyline(void)
288288
return nedPolyline;
289289
}
290290

291-
292291
QList<QGeoCoordinate> QGCMapPolyline::offsetPolyline(double distance)
293292
{
294293
QList<QGeoCoordinate> rgNewPolyline;
@@ -403,6 +402,8 @@ void QGCMapPolyline::appendVertices(const QList<QGeoCoordinate>& coordinates)
403402
_polylineModel.append(objects);
404403

405404
_endResetIfNotActive();
405+
406+
emit pathChanged();
406407
}
407408

408409
void QGCMapPolyline::beginReset(void)

src/Utilities/CMakeLists.txt

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ target_sources(${CMAKE_PROJECT_NAME}
44
DeviceInfo.h
55
JsonHelper.cc
66
JsonHelper.h
7-
KML/KMLDomDocument.cc
8-
KML/KMLDomDocument.h
9-
KML/KMLHelper.cc
10-
KML/KMLHelper.h
117
FileSystem/QGCCachedFileDownload.cc
128
FileSystem/QGCCachedFileDownload.h
139
FileSystem/QGCFileDownload.cc
@@ -20,10 +16,6 @@ target_sources(${CMAKE_PROJECT_NAME}
2016
QGCLoggingCategory.h
2117
FileSystem/QGCTemporaryFile.cc
2218
FileSystem/QGCTemporaryFile.h
23-
Shape/ShapeFileHelper.cc
24-
Shape/ShapeFileHelper.h
25-
Shape/SHPFileHelper.cc
26-
Shape/SHPFileHelper.h
2719
StateMachine.cc
2820
StateMachine.h
2921
)
@@ -46,26 +38,11 @@ target_include_directories(${CMAKE_PROJECT_NAME}
4638
PRIVATE
4739
${CMAKE_CURRENT_SOURCE_DIR}
4840
FileSystem
49-
KML
50-
Shape
5141
)
5242

5343
#===========================================================================#
5444

55-
CPMAddPackage(
56-
NAME Shapelib
57-
VERSION 1.6.1
58-
GITHUB_REPOSITORY OSGeo/shapelib
59-
OPTIONS
60-
"BUILD_SHAPELIB_CONTRIB OFF"
61-
"BUILD_APPS OFF"
62-
"BUILD_TESTING OFF"
63-
)
64-
65-
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE shp)
66-
67-
#===========================================================================#
68-
6945
add_subdirectory(Audio)
7046
add_subdirectory(Compression)
7147
add_subdirectory(Geo)
48+
add_subdirectory(Shape)

src/Utilities/Shape/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
target_sources(${CMAKE_PROJECT_NAME}
2+
PRIVATE
3+
KMLDomDocument.cc
4+
KMLDomDocument.h
5+
KMLHelper.cc
6+
KMLHelper.h
7+
ShapeFileHelper.cc
8+
ShapeFileHelper.h
9+
SHPFileHelper.cc
10+
SHPFileHelper.h
11+
)
12+
13+
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
14+
15+
#===========================================================================#
16+
17+
CPMAddPackage(
18+
NAME Shapelib
19+
VERSION 1.6.1
20+
GITHUB_REPOSITORY OSGeo/shapelib
21+
OPTIONS
22+
"BUILD_SHAPELIB_CONTRIB OFF"
23+
"BUILD_APPS OFF"
24+
"BUILD_TESTING OFF"
25+
)
26+
27+
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE shp)
File renamed without changes.
File renamed without changes.

src/Utilities/KML/KMLHelper.cc renamed to src/Utilities/Shape/KMLHelper.cc

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ QDomDocument KMLHelper::_loadFile(const QString &kmlFile, QString &errorString)
2525

2626
QFile file(kmlFile);
2727
if (!file.exists()) {
28-
errorString = QString(_errorPrefix).arg(QObject::tr("File not found: %1").arg(kmlFile));
28+
errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP("KML", "File not found: %1")).arg(kmlFile));
2929
return QDomDocument();
3030
}
3131

3232
if (!file.open(QIODevice::ReadOnly)) {
33-
errorString = QString(_errorPrefix).arg(QObject::tr("Unable to open file: %1 error: $%2").arg(kmlFile).arg(file.errorString()));
33+
errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP("KML", "Unable to open file: %1 error: $%2")).arg(kmlFile).arg(file.errorString()));
3434
return QDomDocument();
3535
}
3636

3737
QDomDocument doc;
3838
const QDomDocument::ParseResult result = doc.setContent(&file, QDomDocument::ParseOption::Default);
3939
if (!result) {
40-
errorString = QString(_errorPrefix).arg(QObject::tr("Unable to parse KML file: %1 error: %2 line: %3").arg(kmlFile).arg(result.errorMessage).arg(result.errorLine));
40+
errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP("KML", "Unable to parse KML file: %1 error: %2 line: %3")).arg(kmlFile).arg(result.errorMessage).arg(result.errorLine));
4141
return QDomDocument();
4242
}
4343

@@ -46,23 +46,25 @@ QDomDocument KMLHelper::_loadFile(const QString &kmlFile, QString &errorString)
4646

4747
ShapeFileHelper::ShapeType KMLHelper::determineShapeType(const QString &kmlFile, QString &errorString)
4848
{
49+
using ShapeType = ShapeFileHelper::ShapeType;
50+
4951
const QDomDocument domDocument = KMLHelper::_loadFile(kmlFile, errorString);
5052
if (!errorString.isEmpty()) {
51-
return ShapeFileHelper::Error;
53+
return ShapeType::Error;
5254
}
5355

5456
const QDomNodeList rgNodesPolygon = domDocument.elementsByTagName("Polygon");
5557
if (!rgNodesPolygon.isEmpty()) {
56-
return ShapeFileHelper::Polygon;
58+
return ShapeType::Polygon;
5759
}
5860

5961
const QDomNodeList rgNodesLineString = domDocument.elementsByTagName("LineString");
6062
if (!rgNodesLineString.isEmpty()) {
61-
return ShapeFileHelper::Polyline;
63+
return ShapeType::Polyline;
6264
}
6365

64-
errorString = QString(_errorPrefix).arg(QObject::tr("No supported type found in KML file."));
65-
return ShapeFileHelper::Error;
66+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("KML", "No supported type found in KML file."));
67+
return ShapeType::Error;
6668
}
6769

6870
bool KMLHelper::loadPolygonFromFile(const QString &kmlFile, QList<QGeoCoordinate> &vertices, QString &errorString)
@@ -77,13 +79,13 @@ bool KMLHelper::loadPolygonFromFile(const QString &kmlFile, QList<QGeoCoordinate
7779

7880
const QDomNodeList rgNodes = domDocument.elementsByTagName("Polygon");
7981
if (rgNodes.isEmpty()) {
80-
errorString = QString(_errorPrefix).arg(QObject::tr("Unable to find Polygon node in KML"));
82+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("KML", "Unable to find Polygon node in KML"));
8183
return false;
8284
}
8385

8486
const QDomNode coordinatesNode = rgNodes.item(0).namedItem("outerBoundaryIs").namedItem("LinearRing").namedItem("coordinates");
8587
if (coordinatesNode.isNull()) {
86-
errorString = QString(_errorPrefix).arg(QObject::tr("Internal error: Unable to find coordinates node in KML"));
88+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("KML", "Internal error: Unable to find coordinates node in KML"));
8789
return false;
8890
}
8991

@@ -93,15 +95,15 @@ bool KMLHelper::loadPolygonFromFile(const QString &kmlFile, QList<QGeoCoordinate
9395
QList<QGeoCoordinate> rgCoords;
9496
for (const QString &coordinateString : rgCoordinateStrings) {
9597
const QStringList rgValueStrings = coordinateString.split(",");
96-
const QGeoCoordinate coord(rgValueStrings[0].toDouble(), rgValueStrings[1].toDouble());
98+
const QGeoCoordinate coord(rgValueStrings[1].toDouble(), rgValueStrings[0].toDouble());
9799
rgCoords.append(coord);
98100
}
99101

100102
// Determine winding, reverse if needed. QGC wants clockwise winding
101103
double sum = 0;
102104
for (int i=0; i<rgCoords.count(); i++) {
103105
const QGeoCoordinate coord1 = rgCoords[i];
104-
const QGeoCoordinate coord2 = (i == rgCoords.count() - 1) ? rgCoords[0] : rgCoords[i+1];
106+
const QGeoCoordinate coord2 = (i == (rgCoords.count() - 1)) ? rgCoords[0] : rgCoords[i+1];
105107

106108
sum += (coord2.longitude() - coord1.longitude()) * (coord2.latitude() + coord1.latitude());
107109
}
@@ -132,24 +134,23 @@ bool KMLHelper::loadPolylineFromFile(const QString &kmlFile, QList<QGeoCoordinat
132134

133135
const QDomNodeList rgNodes = domDocument.elementsByTagName("LineString");
134136
if (rgNodes.isEmpty()) {
135-
errorString = QString(_errorPrefix).arg(QObject::tr("Unable to find LineString node in KML"));
137+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("KML", "Unable to find LineString node in KML"));
136138
return false;
137139
}
138140

139141
const QDomNode coordinatesNode = rgNodes.item(0).namedItem("coordinates");
140142
if (coordinatesNode.isNull()) {
141-
errorString = QString(_errorPrefix).arg(QObject::tr("Internal error: Unable to find coordinates node in KML"));
143+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("KML", "Internal error: Unable to find coordinates node in KML"));
142144
return false;
143145
}
144146

145147
const QString coordinatesString = coordinatesNode.toElement().text().simplified();
146148
const QStringList rgCoordinateStrings = coordinatesString.split(" ");
147149

148150
QList<QGeoCoordinate> rgCoords;
149-
for (int i = 0; i < rgCoordinateStrings.count() - 1; i++) {
150-
const QString coordinateString = rgCoordinateStrings[i];
151+
for (const QString &coordinateString : rgCoordinateStrings) {
151152
const QStringList rgValueStrings = coordinateString.split(",");
152-
const QGeoCoordinate coord(rgValueStrings[0].toDouble(), rgValueStrings[1].toDouble());
153+
const QGeoCoordinate coord(rgValueStrings[1].toDouble(), rgValueStrings[0].toDouble());
153154
rgCoords.append(coord);
154155
}
155156

File renamed without changes.

src/Utilities/Shape/SHPFileHelper.cc

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,44 @@ bool SHPFileHelper::_validateSHPFiles(const QString &shpFile, int *utmZone, bool
3838
errorString.clear();
3939

4040
if (!shpFile.endsWith(QStringLiteral(".shp"))) {
41-
errorString = QString(_errorPrefix).arg(QObject::tr("File is not a .shp file: %1").arg(shpFile));
41+
errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP("SHP", "File is not a .shp file: %1")).arg(shpFile));
42+
return false;
4243
}
4344

4445
const QString prjFilename = shpFile.left(shpFile.length() - 4) + QStringLiteral(".prj");
4546
QFile prjFile(prjFilename);
4647
if (!prjFile.exists()) {
47-
errorString = QString(_errorPrefix).arg(QObject::tr("File not found: %1").arg(prjFilename));
48+
errorString = QString(_errorPrefix).arg(QString(QT_TRANSLATE_NOOP("SHP", "File not found: %1")).arg(prjFilename));
49+
return false;
4850
}
4951

5052
if (!prjFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
51-
errorString = QString(_errorPrefix).arg(QObject::tr("PRJ file open failed: %1"), prjFile.errorString());
53+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "PRJ file open failed: %1"), prjFile.errorString());
54+
return false;
5255
}
5356

5457
QTextStream strm(&prjFile);
5558
const QString line = strm.readLine();
5659
if (line.startsWith(QStringLiteral("GEOGCS[\"GCS_WGS_1984\","))) {
5760
*utmZone = 0;
5861
*utmSouthernHemisphere = false;
59-
} else if (!line.startsWith(QStringLiteral("PROJCS[\"WGS_1984_UTM_Zone_"))) {
60-
errorString = QString(_errorPrefix).arg(QObject::tr("Only WGS84 or UTM projections are supported."));
61-
}
62-
63-
static QRegularExpression regEx(QStringLiteral("^PROJCS\\[\"WGS_1984_UTM_Zone_(\\d+){1,2}([NS]{1})"));
64-
const QRegularExpressionMatch regExMatch = regEx.match(line);
65-
const QStringList rgCapture = regExMatch.capturedTexts();
66-
if (rgCapture.count() == 3) {
67-
const int zone = rgCapture[1].toInt();
68-
if ((zone >= 1) && (zone <= 60)) {
69-
*utmZone = zone;
70-
*utmSouthernHemisphere = (rgCapture[2] == QStringLiteral("S"));
62+
} else if (line.startsWith(QStringLiteral("PROJCS[\"WGS_1984_UTM_Zone_"))) {
63+
static QRegularExpression regEx(QStringLiteral("^PROJCS\\[\"WGS_1984_UTM_Zone_(\\d+){1,2}([NS]{1})"));
64+
const QRegularExpressionMatch regExMatch = regEx.match(line);
65+
const QStringList rgCapture = regExMatch.capturedTexts();
66+
if (rgCapture.count() == 3) {
67+
const int zone = rgCapture[1].toInt();
68+
if ((zone >= 1) && (zone <= 60)) {
69+
*utmZone = zone;
70+
*utmSouthernHemisphere = (rgCapture[2] == QStringLiteral("S"));
71+
}
7172
}
72-
}
7373

74-
if (*utmZone == 0) {
75-
errorString = QString(_errorPrefix).arg(QObject::tr("UTM projection is not in supported format. Must be PROJCS[\"WGS_1984_UTM_Zone_##N/S"));
74+
if (*utmZone == 0) {
75+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "UTM projection is not in supported format. Must be PROJCS[\"WGS_1984_UTM_Zone_##N/S"));
76+
}
77+
} else {
78+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "Only WGS84 or UTM projections are supported."));
7679
}
7780

7881
return errorString.isEmpty();
@@ -81,14 +84,14 @@ bool SHPFileHelper::_validateSHPFiles(const QString &shpFile, int *utmZone, bool
8184

8285
SHPHandle SHPFileHelper::_loadShape(const QString &shpFile, int *utmZone, bool *utmSouthernHemisphere, QString &errorString)
8386
{
84-
SHPHandle shpHandle = Q_NULLPTR;
87+
SHPHandle shpHandle = nullptr;
8588

8689
errorString.clear();
8790

8891
if (_validateSHPFiles(shpFile, utmZone, utmSouthernHemisphere, errorString)) {
8992
shpHandle = SHPOpen(shpFile.toUtf8().constData(), "rb");
9093
if (!shpHandle) {
91-
errorString = QString(_errorPrefix).arg(QObject::tr("SHPOpen failed."));
94+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "SHPOpen failed."));
9295
}
9396
}
9497

@@ -97,7 +100,9 @@ SHPHandle SHPFileHelper::_loadShape(const QString &shpFile, int *utmZone, bool *
97100

98101
ShapeFileHelper::ShapeType SHPFileHelper::determineShapeType(const QString &shpFile, QString &errorString)
99102
{
100-
ShapeFileHelper::ShapeType shapeType = ShapeFileHelper::Error;
103+
using ShapeType = ShapeFileHelper::ShapeType;
104+
105+
ShapeType shapeType = ShapeType::Error;
101106

102107
errorString.clear();
103108

@@ -106,14 +111,14 @@ ShapeFileHelper::ShapeType SHPFileHelper::determineShapeType(const QString &shpF
106111
SHPHandle shpHandle = SHPFileHelper::_loadShape(shpFile, &utmZone, &utmSouthernHemisphere, errorString);
107112
if (errorString.isEmpty()) {
108113
int cEntities, type;
109-
SHPGetInfo(shpHandle, &cEntities /* pnEntities */, &type, Q_NULLPTR /* padfMinBound */, Q_NULLPTR /* padfMaxBound */);
114+
SHPGetInfo(shpHandle, &cEntities /* pnEntities */, &type, nullptr /* padfMinBound */, nullptr /* padfMaxBound */);
110115
qCDebug(SHPFileHelperLog) << "SHPGetInfo" << shpHandle << cEntities << type;
111116
if (cEntities != 1) {
112-
errorString = QString(_errorPrefix).arg(QObject::tr("More than one entity found."));
117+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "More than one entity found."));
113118
} else if (type == SHPT_POLYGON) {
114-
shapeType = ShapeFileHelper::Polygon;
119+
shapeType = ShapeType::Polygon;
115120
} else {
116-
errorString = QString(_errorPrefix).arg(QObject::tr("No supported types found."));
121+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "No supported types found."));
117122
}
118123
}
119124

@@ -124,30 +129,29 @@ ShapeFileHelper::ShapeType SHPFileHelper::determineShapeType(const QString &shpF
124129

125130
bool SHPFileHelper::loadPolygonFromFile(const QString &shpFile, QList<QGeoCoordinate> &vertices, QString &errorString)
126131
{
132+
static constexpr double vertexFilterMeters = 5;
127133
int utmZone = 0;
128134
bool utmSouthernHemisphere = false;
129-
double vertexFilterMeters = 5;
130-
SHPHandle shpHandle = Q_NULLPTR;
131-
SHPObject *shpObject = Q_NULLPTR;
135+
SHPObject *shpObject = nullptr;
132136

133137
errorString.clear();
134138
vertices.clear();
135139

136-
shpHandle = SHPFileHelper::_loadShape(shpFile, &utmZone, &utmSouthernHemisphere, errorString);
140+
SHPHandle shpHandle = SHPFileHelper::_loadShape(shpFile, &utmZone, &utmSouthernHemisphere, errorString);
137141
if (!errorString.isEmpty()) {
138142
goto Error;
139143
}
140144

141145
int cEntities, shapeType;
142-
SHPGetInfo(shpHandle, &cEntities, &shapeType, Q_NULLPTR /* padfMinBound */, Q_NULLPTR /* padfMaxBound */);
146+
SHPGetInfo(shpHandle, &cEntities, &shapeType, nullptr /* padfMinBound */, nullptr /* padfMaxBound */);
143147
if (shapeType != SHPT_POLYGON) {
144-
errorString = QString(_errorPrefix).arg(QObject::tr("File does not contain a polygon."));
148+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "File does not contain a polygon."));
145149
goto Error;
146150
}
147151

148152
shpObject = SHPReadObject(shpHandle, 0);
149153
if (shpObject->nParts != 1) {
150-
errorString = QString(_errorPrefix).arg(QObject::tr("Only single part polygons are supported."));
154+
errorString = QString(_errorPrefix).arg(QT_TRANSLATE_NOOP("SHP", "Only single part polygons are supported."));
151155
goto Error;
152156
}
153157

0 commit comments

Comments
 (0)