diff --git a/src/core/georeferencing.cpp b/src/core/georeferencing.cpp index 43b28fec6..04cf5374d 100644 --- a/src/core/georeferencing.cpp +++ b/src/core/georeferencing.cpp @@ -626,6 +626,7 @@ void Georeferencing::load(QXmlStreamReader& xml, bool load_scale_only) if (language != literal::proj_4) throw FileFormatException(tr("Unknown CRS specification language: %1").arg(language)); projected_crs_spec = xml.readElementText(); + ensureOrthoIsSpheroidal(projected_crs_spec); } else if (xml.name() == literal::parameter) { @@ -1239,6 +1240,19 @@ QString Georeferencing::degToDMS(double val) return ret; } +void Georeferencing::ensureOrthoIsSpheroidal(QString &spec) +{ + const QString ortho_proj = QLatin1String("+proj=ortho "); + auto flattening_param = QLatin1String(" +f="); + auto i = spec.indexOf(ortho_proj); + if (i >= 0 && !spec.contains(flattening_param)) + { + auto pos = i + ortho_proj.length() - 1; + // Insert to make "+proj=ortho +f=0", no flattening. + spec.insert(pos, flattening_param + QLatin1String("0")); + } +} + QDebug operator<<(QDebug dbg, const Georeferencing &georef) { auto state = [](auto state) -> const char* { diff --git a/src/core/georeferencing.h b/src/core/georeferencing.h index 144295a2d..dde7a1c79 100644 --- a/src/core/georeferencing.h +++ b/src/core/georeferencing.h @@ -527,6 +527,11 @@ friend QDebug operator<<(QDebug dbg, const Georeferencing& georef); */ static QString degToDMS(double val); + /** + * Ensure specs using ortho projection are explicitly spheroidal. + */ + static void ensureOrthoIsSpheroidal(QString &spec); + /** * Updates the transformation parameters between map coordinates and diff --git a/src/gdal/ogr_file_format.cpp b/src/gdal/ogr_file_format.cpp index 37ac197cd..e7d20dea6 100644 --- a/src/gdal/ogr_file_format.cpp +++ b/src/gdal/ogr_file_format.cpp @@ -1007,7 +1007,7 @@ ogr::unique_srs OgrFileImport::importGeoreferencing(OGRDataSourceH data_source) auto ortho_georef = Georeferencing(); ortho_georef.setScaleDenominator(int(map->getScaleDenominator())); ortho_georef.setProjectedCRS(QString{}, - QString::fromLatin1("+proj=ortho +datum=WGS84 +ellps=WGS84 +units=m +lat_0=%1 +lon_0=%2 +no_defs") + QString::fromLatin1("+proj=ortho +f=0 +datum=WGS84 +ellps=WGS84 +units=m +lat_0=%1 +lon_0=%2 +no_defs") .arg(latitude, 0, 'f') .arg(longitude, 0, 'f') ); ortho_georef.setProjectedRefPoint({}, false, false); diff --git a/src/gdal/ogr_template.cpp b/src/gdal/ogr_template.cpp index 6f2c2a1ab..46f7e60be 100644 --- a/src/gdal/ogr_template.cpp +++ b/src/gdal/ogr_template.cpp @@ -201,12 +201,12 @@ std::unique_ptr OgrTemplate::makeOrthographicGeoreferencing(cons /// \todo Use the template's datum etc. instead of WGS84? auto georef = std::make_unique(); georef->setScaleDenominator(int(map->getGeoreferencing().getScaleDenominator())); - georef->setProjectedCRS(QString{}, QStringLiteral("+proj=ortho +datum=WGS84 +ellps=WGS84 +units=m +no_defs")); + georef->setProjectedCRS(QString{}, QStringLiteral("+proj=ortho +f=0 +datum=WGS84 +ellps=WGS84 +units=m +no_defs")); if (OgrFileImport::checkGeoreferencing(path, *georef)) { auto center = OgrFileImport::calcAverageLatLon(path); georef->setProjectedCRS(QString{}, - QString::fromLatin1("+proj=ortho +datum=WGS84 +ellps=WGS84 +units=m +lat_0=%1 +lon_0=%2 +no_defs") + QString::fromLatin1("+proj=ortho +f=0 +datum=WGS84 +ellps=WGS84 +units=m +lat_0=%1 +lon_0=%2 +no_defs") .arg(center.latitude()).arg(center.longitude())); georef->setProjectedRefPoint({}, false, false); georef->setCombinedScaleFactor(1.0); @@ -573,6 +573,7 @@ bool OgrTemplate::loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) else if (xml.name() == literal::crs_spec) { track_crs_spec = xml.readElementText(); + Georeferencing::ensureOrthoIsSpheroidal(track_crs_spec); template_track_compatibility = true; } else if (xml.name() == literal::projected_crs_spec) diff --git a/src/gui/georeferencing_dialog.cpp b/src/gui/georeferencing_dialog.cpp index 51fd0086d..c9ff4fc54 100644 --- a/src/gui/georeferencing_dialog.cpp +++ b/src/gui/georeferencing_dialog.cpp @@ -666,6 +666,7 @@ void GeoreferencingDialog::crsEdited() Q_ASSERT(crs_template); if (spec.isEmpty()) spec = QStringLiteral(" "); // intentionally non-empty: enforce non-local state. + Georeferencing::ensureOrthoIsSpheroidal(spec); georef_copy.setProjectedCRS(crs_template->id(), spec, crs_selector->parameters()); Q_ASSERT(georef_copy.getState() != Georeferencing::Local); if (keep_geographic_radio->isChecked()) diff --git a/src/templates/template_image.cpp b/src/templates/template_image.cpp index 50d4c59fc..91cfbc526 100644 --- a/src/templates/template_image.cpp +++ b/src/templates/template_image.cpp @@ -193,6 +193,7 @@ bool TemplateImage::loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) { /// \todo check specification language available_georef.effective.crs_spec = xml.readElementText(); + Georeferencing::ensureOrthoIsSpheroidal(available_georef.effective.crs_spec); } else xml.skipCurrentElement(); // unsupported diff --git a/src/templates/template_track.cpp b/src/templates/template_track.cpp index b2bcc3184..4e804e4fb 100644 --- a/src/templates/template_track.cpp +++ b/src/templates/template_track.cpp @@ -219,6 +219,7 @@ bool TemplateTrack::loadTypeSpecificTemplateConfiguration(QXmlStreamReader& xml) if (xml.name() == QLatin1String("crs_spec")) { track_crs_spec = xml.readElementText(); + Georeferencing::ensureOrthoIsSpheroidal(track_crs_spec); } else if (xml.name() == QLatin1String("projected_crs_spec")) { @@ -601,7 +602,7 @@ void TemplateTrack::updateGeoreferencing() QString TemplateTrack::calculateLocalGeoreferencing() const { LatLon proj_center = track.calcAveragePosition(); - return QString::fromLatin1("+proj=ortho +datum=WGS84 +lat_0=%1 +lon_0=%2") + return QString::fromLatin1("+proj=ortho +f=0 +datum=WGS84 +lat_0=%1 +lon_0=%2") .arg(proj_center.latitude(), 0, 'f') .arg(proj_center.longitude(), 0, 'f'); diff --git a/test/data/templates/template-track-ortho.xmap b/test/data/templates/template-track-ortho.xmap new file mode 100644 index 000000000..1b8e85a29 --- /dev/null +++ b/test/data/templates/template-track-ortho.xmap @@ -0,0 +1,92 @@ + + + This map to demonstrate issue GH-2016, trimmed for testing purposes. +In order to get an orthographic projection, this map was initially created by import from a .osm map similar to 'map.osm', but in the region of template-track.gpx. +Then the OpenStreetMap objects were deleted, and the template-track.xmap was imported to get its line objects. Templates were added for template-track.gpx so that template_t.cpp could easily be expanded to validate the handling of this projection. + + + +proj=ortho +datum=WGS84 +ellps=WGS84 +units=m +lat_0=51.394000 +lon_0=21.199000 +no_defs + + + +proj=latlong +datum=WGS84 + + + + + + + PURPLE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/template_t.cpp b/test/template_t.cpp index 8eeca94e2..4558594fa 100644 --- a/test/template_t.cpp +++ b/test/template_t.cpp @@ -424,6 +424,8 @@ private slots: QTest::newRow("OgrTemplate NAD83") << QStringLiteral("testdata:templates/template-track-NA.xmap") << 1; QTest::newRow("TemplateTrack from v0.8.4") << QStringLiteral("testdata:templates/template-track-NA-084.xmap") << 0; QTest::newRow("TemplateTrack from v0.9.3") << QStringLiteral("testdata:templates/template-track-NA-093-PROJ.xmap") << 0; + QTest::newRow("TemplateTrack ortho") << QStringLiteral("testdata:templates/template-track-ortho.xmap") << 0; + QTest::newRow("OgrTemplate ortho") << QStringLiteral("testdata:templates/template-track-ortho.xmap") << 1; } void templateTrackTest() @@ -476,6 +478,8 @@ private slots: QTest::newRow("OgrTemplate NAD83") << QStringLiteral("testdata:templates/template-track-NA.xmap") << 1; QTest::newRow("TemplateTrack from v0.8.4") << QStringLiteral("testdata:templates/template-track-NA-084.xmap") << 0; QTest::newRow("OGRTemplate from v0.9.3") << QStringLiteral("testdata:templates/template-track-NA-093-GDAL.xmap") << 0; + QTest::newRow("TemplateTrack ortho") << QStringLiteral("testdata:templates/template-track-ortho.xmap") << 0; + QTest::newRow("OgrTemplate ortho") << QStringLiteral("testdata:templates/template-track-ortho.xmap") << 1; } void ogrTemplateTest()