From 9c21a19ae0524c0fa8f00ea092ba5b96349eb9b4 Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 22 Nov 2018 11:26:26 -0800 Subject: [PATCH] Support UTM SHP files --- src/SHPFileHelper.cc | 53 +++++++++++++++++++++++++++++++++++++------- src/SHPFileHelper.h | 4 ++-- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/SHPFileHelper.cc b/src/SHPFileHelper.cc index 184c0897e..ab4854fd8 100644 --- a/src/SHPFileHelper.cc +++ b/src/SHPFileHelper.cc @@ -8,15 +8,22 @@ ****************************************************************************/ #include "SHPFileHelper.h" +#include "UTM.h" #include #include #include +#include const char* SHPFileHelper::_errorPrefix = QT_TR_NOOP("SHP file load failed. %1"); -bool SHPFileHelper::_validateSHPFiles(const QString& shpFile, QString& errorString) +/// Validates the specified SHP file is truly a SHP file and is in the format we understand. +/// @param utmZone[out] Zone for UTM shape, 0 for lat/lon shape +/// @param utmSouthernHemisphere[out] true/false for UTM hemisphere +/// @return true: Valid supported SHP file found, false: Invalid or unsupported file found +bool SHPFileHelper::_validateSHPFiles(const QString& shpFile, int* utmZone, bool* utmSouthernHemisphere, QString& errorString) { + *utmZone = 0; errorString.clear(); if (shpFile.endsWith(QStringLiteral(".shp"))) { @@ -26,8 +33,25 @@ bool SHPFileHelper::_validateSHPFiles(const QString& shpFile, QString& errorStri if (prjFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream strm(&prjFile); QString line = strm.readLine(); - if (!line.startsWith(QStringLiteral("GEOGCS[\"GCS_WGS_1984\","))) { - errorString = QString(_errorPrefix).arg(tr("Only WGS84 projections are supported.")); + if (line.startsWith(QStringLiteral("GEOGCS[\"GCS_WGS_1984\","))) { + *utmZone = 0; + *utmSouthernHemisphere = false; + } else if (line.startsWith(QStringLiteral("PROJCS[\"WGS_1984_UTM_Zone_"))) { + QRegularExpression regEx(QStringLiteral("^PROJCS\\[\"WGS_1984_UTM_Zone_(\\d+){1,2}([NS]{1})")); + QRegularExpressionMatch regExMatch = regEx.match(line); + QStringList rgCapture = regExMatch.capturedTexts(); + if (rgCapture.count() == 3) { + int zone = rgCapture[1].toInt(); + if (zone >= 1 && zone <= 60) { + *utmZone = zone; + *utmSouthernHemisphere = rgCapture[2] == QStringLiteral("S"); + } + } + if (*utmZone == 0) { + errorString = QString(_errorPrefix).arg(tr("UTM projection is not in supported format. Must be PROJCS[\"WGS_1984_UTM_Zone_##N/S")); + } + } else { + errorString = QString(_errorPrefix).arg(tr("Only WGS84 or UTM projections are supported.")); } } else { errorString = QString(_errorPrefix).arg(tr("PRJ file open failed: %1").arg(prjFile.errorString())); @@ -42,13 +66,15 @@ bool SHPFileHelper::_validateSHPFiles(const QString& shpFile, QString& errorStri return errorString.isEmpty(); } -SHPHandle SHPFileHelper::_loadShape(const QString& shpFile, QString& errorString) +/// @param utmZone[out] Zone for UTM shape, 0 for lat/lon shape +/// @param utmSouthernHemisphere[out] true/false for UTM hemisphere +SHPHandle SHPFileHelper::_loadShape(const QString& shpFile, int* utmZone, bool* utmSouthernHemisphere, QString& errorString) { SHPHandle shpHandle = Q_NULLPTR; errorString.clear(); - if (_validateSHPFiles(shpFile, errorString)) { + if (_validateSHPFiles(shpFile, utmZone, utmSouthernHemisphere, errorString)) { if (!(shpHandle = SHPOpen(shpFile.toUtf8(), "rb"))) { errorString = QString(_errorPrefix).arg(tr("SHPOpen failed.")); } @@ -63,7 +89,9 @@ ShapeFileHelper::ShapeType SHPFileHelper::determineShapeType(const QString& shpF errorString.clear(); - SHPHandle shpHandle = SHPFileHelper::_loadShape(shpFile, errorString); + int utmZone; + bool utmSouthernHemisphere; + SHPHandle shpHandle = SHPFileHelper::_loadShape(shpFile, &utmZone, &utmSouthernHemisphere, errorString); if (errorString.isEmpty()) { int cEntities, type; @@ -85,6 +113,8 @@ ShapeFileHelper::ShapeType SHPFileHelper::determineShapeType(const QString& shpF bool SHPFileHelper::loadPolygonFromFile(const QString& shpFile, QList& vertices, QString& errorString) { + int utmZone = 0; + bool utmSouthernHemisphere; double vertexFilterMeters = 5; SHPHandle shpHandle = Q_NULLPTR; SHPObject* shpObject = Q_NULLPTR; @@ -92,7 +122,7 @@ bool SHPFileHelper::loadPolygonFromFile(const QString& shpFile, QListnVertices; i++) { - vertices.append(QGeoCoordinate(shpObject->padfY[i], shpObject->padfX[i])); + double lat, lon; + if (utmZone) { + UTMXYToLatLon(shpObject->padfX[i], shpObject->padfY[i], utmZone, utmSouthernHemisphere, lat, lon); + } else { + lat = shpObject->padfY[i]; + lon = shpObject->padfX[i]; + } + vertices.append(QGeoCoordinate(lat, lon)); } // Filter last vertex such that it differs from first diff --git a/src/SHPFileHelper.h b/src/SHPFileHelper.h index 3c02033b0..872192688 100644 --- a/src/SHPFileHelper.h +++ b/src/SHPFileHelper.h @@ -29,8 +29,8 @@ public: static bool loadPolygonFromFile(const QString& shpFile, QList& vertices, QString& errorString); private: - static bool _validateSHPFiles(const QString& shpFile, QString& errorString); - static SHPHandle _loadShape(const QString& shpFile, QString& errorString); + static bool _validateSHPFiles(const QString& shpFile, int* utmZone, bool* utmSouthernHemisphere, QString& errorString); + static SHPHandle _loadShape(const QString& shpFile, int* utmZone, bool* utmSouthernHemisphere, QString& errorString); static const char* _errorPrefix; }; -- 2.22.0