From 5c691e7fec7c244b1a1a6b5ef97df2cf69e403df Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 21 Feb 2019 01:04:55 +0100 Subject: projinfo: add information about missing grids --- src/apps/projinfo.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 094587e2..7e401887 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -464,11 +464,42 @@ static void outputObject( } } } + + auto op = dynamic_cast(obj.get()); + if (op && dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) { + try { + auto setGrids = op->gridsNeeded(dbContext); + bool firstWarning = true; + for (const auto &grid : setGrids) { + if (!grid.available) { + if (firstWarning) { + std::cout << std::endl; + firstWarning = false; + } + std::cout << "Grid " << grid.shortName + << " needed but not found on the system."; + if (!grid.packageName.empty()) { + std::cout << " Can be obtained from the " + << grid.packageName << " package"; + if (!grid.url.empty()) { + std::cout << " at " << grid.url; + } + } else if (!grid.url.empty()) { + std::cout << " Can be obtained at " << grid.url; + } + std::cout << std::endl; + } + } + } catch (const std::exception &e) { + std::cerr << "Error in gridsNeeded(): " << e.what() << std::endl; + } + } } // --------------------------------------------------------------------------- -static void outputOperationSummary(const CoordinateOperationNNPtr &op) { +static void outputOperationSummary(const CoordinateOperationNNPtr &op, + const DatabaseContextPtr &dbContext) { auto ids = op->identifiers(); if (!ids.empty()) { std::cout << *(ids[0]->codeSpace()) << ":" << ids[0]->code(); @@ -512,6 +543,18 @@ static void outputOperationSummary(const CoordinateOperationNNPtr &op) { std::cout << ", has ballpark transformation"; } + if (dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) { + try { + auto setGrids = op->gridsNeeded(dbContext); + for (const auto &grid : setGrids) { + if (!grid.available) { + std::cout << ", at least one grid missing"; + break; + } + } + } catch (const std::exception &) { + } + } std::cout << std::endl; } @@ -598,7 +641,7 @@ static void outputOperations( } if (summary) { for (const auto &op : list) { - outputOperationSummary(op); + outputOperationSummary(op, dbContext); } } else { bool first = true; @@ -613,7 +656,7 @@ static void outputOperations( "\xC2\xB0" << (i + 1) << ":" << std::endl << std::endl; - outputOperationSummary(op); + outputOperationSummary(op, dbContext); std::cout << std::endl; outputObject(dbContext, op, allowUseIntermediateCRS, outputOpt); } -- cgit v1.2.3 From 34168532d3f3773e1afa2e560bdfba9bd369a0aa Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 21 Feb 2019 12:47:38 +0100 Subject: Geog2D+Height -> Geog3D of same datum: avoid inserting a useless ballpark horizontal transformation --- src/iso19111/coordinateoperation.cpp | 70 +++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 224b19ef..6e2d7f4f 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -10829,30 +10829,58 @@ static CoordinateOperationNNPtr createHorizVerticalPROJBased( auto exportable = util::nn_make_shared( horizTransform, verticalTransform, geogDst); - bool dummy = false; - auto ops = std::vector{horizTransform, - verticalTransform}; - auto extent = getExtent(ops, true, dummy); - auto properties = util::PropertyMap(); - properties.set(common::IdentifiedObject::NAME_KEY, - computeConcatenatedName(ops)); - - if (extent) { - properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, - NN_NO_CHECK(extent)); + bool horizTransformIsNoOp = horizTransform->sourceCRS()->_isEquivalentTo( + horizTransform->targetCRS().get()); + if (!horizTransformIsNoOp) { + const crs::GeographicCRS *geogSrc = + dynamic_cast( + horizTransform->sourceCRS().get()); + if (geogSrc) { + horizTransformIsNoOp = + geogSrc->is2DPartOf3D(NN_NO_CHECK(geogDst.get())); + } } - std::vector accuracies; - const double accuracy = getAccuracy(ops); - if (accuracy >= 0.0) { - accuracies.emplace_back( - metadata::PositionalAccuracy::create(toString(accuracy))); - } + if (horizTransformIsNoOp) { + auto properties = util::PropertyMap(); + properties.set(common::IdentifiedObject::NAME_KEY, + verticalTransform->nameStr()); + bool dummy = false; + auto extent = getExtent(verticalTransform, true, dummy); + if (extent) { + properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + NN_NO_CHECK(extent)); + } + return createPROJBased( + properties, exportable, sourceCRS, targetCRS, + verticalTransform->coordinateOperationAccuracies(), + verticalTransform->hasBallparkTransformation()); + } else { + bool dummy = false; + auto ops = std::vector{horizTransform, + verticalTransform}; + auto extent = getExtent(ops, true, dummy); + auto properties = util::PropertyMap(); + properties.set(common::IdentifiedObject::NAME_KEY, + computeConcatenatedName(ops)); - return createPROJBased(properties, exportable, sourceCRS, targetCRS, - accuracies, - horizTransform->hasBallparkTransformation() || - verticalTransform->hasBallparkTransformation()); + if (extent) { + properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + NN_NO_CHECK(extent)); + } + + std::vector accuracies; + const double accuracy = getAccuracy(ops); + if (accuracy >= 0.0) { + accuracies.emplace_back( + metadata::PositionalAccuracy::create(toString(accuracy))); + } + + return createPROJBased( + properties, exportable, sourceCRS, targetCRS, accuracies, + horizTransform->hasBallparkTransformation() || + verticalTransform->hasBallparkTransformation()); + } } // --------------------------------------------------------------------------- -- cgit v1.2.3 From 287230f86d89a26574c777bb5e5b498084a84897 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 21 Feb 2019 13:48:28 +0100 Subject: Transformation: reintroduce the term of 'Null geographic offset' for transformations between geographic CRS of same datum (typically 3D to 2D) --- src/iso19111/coordinateoperation.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 6e2d7f4f..7b0adc6f 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -106,6 +106,7 @@ constexpr double UTM_SOUTH_FALSE_NORTHING = 10000000.0; static const std::string INVERSE_OF = "Inverse of "; static const char *BALLPARK_GEOCENTRIC_TRANSLATION = "Ballpark geocentric translation"; +static const char *NULL_GEOGRAPHIC_OFFSET = "Null geographic offset"; static const char *BALLPARK_GEOGRAPHIC_OFFSET = "Ballpark geographic offset"; static const char *BALLPARK_VERTICAL_TRANSFORMATION_PREFIX = " (ballpark vertical transformation"; @@ -7189,6 +7190,8 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, opType = BALLPARK_GEOCENTRIC_TRANSLATION; } else if (starts_with(forwardName, BALLPARK_GEOGRAPHIC_OFFSET)) { opType = BALLPARK_GEOGRAPHIC_OFFSET; + } else if (starts_with(forwardName, NULL_GEOGRAPHIC_OFFSET)) { + opType = NULL_GEOGRAPHIC_OFFSET; } else if (dynamic_cast(op) || starts_with(forwardName, "Transformation from ")) { opType = "Transformation"; @@ -10182,6 +10185,8 @@ struct FilterResults { const bool isNullTransformation = op->nameStr().find(BALLPARK_GEOGRAPHIC_OFFSET) != std::string::npos || + op->nameStr().find(NULL_GEOGRAPHIC_OFFSET) != + std::string::npos || op->nameStr().find(BALLPARK_GEOCENTRIC_TRANSLATION) != std::string::npos; map[op.get()] = PrecomputedOpCharacteristics( @@ -10206,6 +10211,7 @@ struct FilterResults { if (hasOpThatContainsAreaOfInterest && res.size() > 1) { const std::string &name = res.back()->nameStr(); if (name.find(BALLPARK_GEOGRAPHIC_OFFSET) != std::string::npos || + name.find(NULL_GEOGRAPHIC_OFFSET) != std::string::npos || name.find(BALLPARK_GEOCENTRIC_TRANSLATION) != std::string::npos) { std::vector resTemp; @@ -10622,7 +10628,18 @@ static std::vector findsOpsInRegistryWithIntermediate( static TransformationNNPtr createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS) { - std::string name(BALLPARK_GEOGRAPHIC_OFFSET); + + const crs::GeographicCRS *geogSrc = + dynamic_cast(sourceCRS.get()); + const crs::GeographicCRS *geogDst = + dynamic_cast(targetCRS.get()); + const bool isSameDatum = + geogSrc && geogDst && geogSrc->datum() && geogDst->datum() && + geogSrc->datum()->_isEquivalentTo( + geogDst->datum().get(), util::IComparable::Criterion::EQUIVALENT); + + std::string name(isSameDatum ? NULL_GEOGRAPHIC_OFFSET + : BALLPARK_GEOGRAPHIC_OFFSET); name += " from "; name += sourceCRS->nameStr(); name += " to "; @@ -10641,6 +10658,12 @@ createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, sameExtent ? NN_NO_CHECK(sourceCRSExtent) : metadata::Extent::WORLD); const common::Angle angle0(0); + + std::vector accuracies; + if (isSameDatum) { + accuracies.emplace_back(metadata::PositionalAccuracy::create("0")); + } + if (dynamic_cast(sourceCRS.get()) ->coordinateSystem() ->axisList() @@ -10650,10 +10673,11 @@ createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, ->axisList() .size() == 3) { return Transformation::createGeographic3DOffsets( - map, sourceCRS, targetCRS, angle0, angle0, common::Length(0), {}); + map, sourceCRS, targetCRS, angle0, angle0, common::Length(0), + accuracies); } else { return Transformation::createGeographic2DOffsets( - map, sourceCRS, targetCRS, angle0, angle0, {}); + map, sourceCRS, targetCRS, angle0, angle0, accuracies); } } //! @endcond @@ -11175,7 +11199,8 @@ findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, static bool isNullTransformation(const std::string &name) { return starts_with(name, BALLPARK_GEOCENTRIC_TRANSLATION) || - starts_with(name, BALLPARK_GEOGRAPHIC_OFFSET); + starts_with(name, BALLPARK_GEOGRAPHIC_OFFSET) || + starts_with(name, NULL_GEOGRAPHIC_OFFSET); } // --------------------------------------------------------------------------- -- cgit v1.2.3