diff options
| -rw-r--r-- | include/proj/crs.hpp | 2 | ||||
| -rw-r--r-- | scripts/reference_exported_symbols.txt | 1 | ||||
| -rw-r--r-- | src/apps/projinfo.cpp | 36 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 64 | ||||
| -rwxr-xr-x | test/cli/testprojinfo | 5 | ||||
| -rw-r--r-- | test/cli/testprojinfo_out.dist | 3 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 4 |
7 files changed, 93 insertions, 22 deletions
diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index 8c1f9f6f..0f8c5e42 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -142,7 +142,7 @@ class PROJ_GCC_DLL CRS : public common::ObjectUsage, PROJ_INTERNAL bool mustAxisOrderBeSwitchedForVisualization() const; - PROJ_INTERNAL CRSNNPtr normalizeForVisualization() const; + PROJ_FOR_TEST CRSNNPtr normalizeForVisualization() const; PROJ_INTERNAL CRSNNPtr allowNonConformantWKT1Export() const; diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index a4716e96..e1de53d0 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -117,6 +117,7 @@ osgeo::proj::crs::CRS::extractGeographicCRS() const osgeo::proj::crs::CRS::extractVerticalCRS() const osgeo::proj::crs::CRS::getNonDeprecated(dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::io::DatabaseContext> > const&) const osgeo::proj::crs::CRS::identify(std::shared_ptr<osgeo::proj::io::AuthorityFactory> const&) const +osgeo::proj::crs::CRS::normalizeForVisualization() const osgeo::proj::crs::CRS::promoteTo3D(std::string const&, std::shared_ptr<osgeo::proj::io::DatabaseContext> const&) const osgeo::proj::crs::CRS::shallowClone() const osgeo::proj::crs::CRS::stripVerticalComponent() const diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index deb8b190..404007e5 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -257,7 +257,7 @@ static BaseObjectNNPtr buildObject( const std::string &kind, const std::string &context, bool buildBoundCRSToWGS84, CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, - bool promoteTo3D, bool quiet) { + bool promoteTo3D, bool normalizeAxisOrder, bool quiet) { BaseObjectPtr obj; std::string l_user_string(user_string); @@ -405,6 +405,13 @@ static BaseObjectNNPtr buildObject( } } + if (normalizeAxisOrder) { + auto crs = std::dynamic_pointer_cast<CRS>(obj); + if (crs) { + obj = crs->normalizeForVisualization().as_nullable(); + } + } + return NN_NO_CHECK(obj); } @@ -807,12 +814,12 @@ static void outputOperations( CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, const std::vector<std::pair<std::string, std::string>> &pivots, const std::string &authority, bool usePROJGridAlternatives, - bool showSuperseded, bool promoteTo3D, double minimumAccuracy, - const OutputOptions &outputOpt, bool summary) { + bool showSuperseded, bool promoteTo3D, bool normalizeAxisOrder, + double minimumAccuracy, const OutputOptions &outputOpt, bool summary) { auto sourceObj = buildObject(dbContext, sourceCRSStr, "crs", "source CRS", false, CoordinateOperationContext::IntermediateCRSUse::NEVER, - promoteTo3D, outputOpt.quiet); + promoteTo3D, normalizeAxisOrder, outputOpt.quiet); auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceObj); if (!sourceCRS) { std::cerr << "source CRS string is not a CRS" << std::endl; @@ -823,7 +830,7 @@ static void outputOperations( auto targetObj = buildObject(dbContext, targetCRSStr, "crs", "target CRS", false, CoordinateOperationContext::IntermediateCRSUse::NEVER, - promoteTo3D, outputOpt.quiet); + promoteTo3D, normalizeAxisOrder, outputOpt.quiet); auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetObj); if (!targetCRS) { std::cerr << "target CRS string is not a CRS" << std::endl; @@ -957,6 +964,7 @@ int main(int argc, char **argv) { bool identify = false; bool showSuperseded = false; bool promoteTo3D = false; + bool normalizeAxisOrder = false; double minimumAccuracy = -1; bool outputAll = false; bool dumpDbStructure = false; @@ -1224,6 +1232,9 @@ int main(int argc, char **argv) { outputOpt.ballparkAllowed = false; } else if (ci_equal(arg, "--3d")) { promoteTo3D = true; + } else if (ci_equal(arg, "--normalize-axis-order")) { + // Undocumented for now + normalizeAxisOrder = true; } else if (arg == "--output-id" && i + 1 < argc) { i++; const auto tokens = split(argv[i], ':'); @@ -1468,7 +1479,7 @@ int main(int argc, char **argv) { auto obj(buildObject(dbContext, user_string, objectKind, "input string", buildBoundCRSToWGS84, allowUseIntermediateCRS, promoteTo3D, - outputOpt.quiet)); + normalizeAxisOrder, outputOpt.quiet)); if (guessDialect) { auto dialect = WKTParser().guessDialect(user_string); std::cout << "Guessed WKT dialect: "; @@ -1562,12 +1573,13 @@ int main(int argc, char **argv) { } else { auto bboxFilter = makeBboxFilter(dbContext, bboxStr, area, true); try { - outputOperations( - dbContext, sourceCRSStr, targetCRSStr, bboxFilter, - spatialCriterion, spatialCriterionExplicitlySpecified, - crsExtentUse, gridAvailabilityUse, allowUseIntermediateCRS, - pivots, authority, usePROJGridAlternatives, showSuperseded, - promoteTo3D, minimumAccuracy, outputOpt, summary); + outputOperations(dbContext, sourceCRSStr, targetCRSStr, bboxFilter, + spatialCriterion, + spatialCriterionExplicitlySpecified, crsExtentUse, + gridAvailabilityUse, allowUseIntermediateCRS, + pivots, authority, usePROJGridAlternatives, + showSuperseded, promoteTo3D, normalizeAxisOrder, + minimumAccuracy, outputOpt, summary); } catch (const std::exception &e) { std::cerr << "outputOperations() failed with: " << e.what() << std::endl; diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index d7058a56..2d589ad1 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -824,21 +824,58 @@ bool CRS::mustAxisOrderBeSwitchedForVisualization() const { //! @cond Doxygen_Suppress CRSNNPtr CRS::normalizeForVisualization() const { - auto props = util::PropertyMap().set( - common::IdentifiedObject::NAME_KEY, - nameStr() + " (with axis order normalized for visualization)"); + + const auto createProperties = [this](const std::string &newName = + std::string()) { + auto props = util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + !newName.empty() + ? newName + : nameStr() + + " (with axis order normalized for visualization)"); + const auto &l_domains = domains(); + if (!l_domains.empty()) { + auto array = util::ArrayOfBaseObject::create(); + for (const auto &domain : l_domains) { + array->add(domain); + } + if (!array->empty()) { + props.set(common::ObjectUsage::OBJECT_DOMAIN_KEY, array); + } + } + const auto &l_identifiers = identifiers(); + const auto &l_remarks = remarks(); + if (l_identifiers.size() == 1) { + std::string remarks("Axis order reversed compared to "); + remarks += *(l_identifiers[0]->codeSpace()); + remarks += ':'; + remarks += l_identifiers[0]->code(); + if (!l_remarks.empty()) { + remarks += ". "; + remarks += l_remarks; + } + props.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } else if (!l_remarks.empty()) { + props.set(common::IdentifiedObject::REMARKS_KEY, l_remarks); + } + return props; + }; const CompoundCRS *compoundCRS = dynamic_cast<const CompoundCRS *>(this); if (compoundCRS) { const auto &comps = compoundCRS->componentReferenceSystems(); - if (!comps.empty()) { + if (!comps.empty() && + comps[0]->mustAxisOrderBeSwitchedForVisualization()) { std::vector<CRSNNPtr> newComps; newComps.emplace_back(comps[0]->normalizeForVisualization()); + std::string l_name = newComps.back()->nameStr(); for (size_t i = 1; i < comps.size(); i++) { newComps.emplace_back(comps[i]); + l_name += " + "; + l_name += newComps.back()->nameStr(); } return util::nn_static_pointer_cast<CRS>( - CompoundCRS::create(props, newComps)); + CompoundCRS::create(createProperties(l_name), newComps)); } } @@ -852,8 +889,9 @@ CRSNNPtr CRS::normalizeForVisualization() const { : cs::EllipsoidalCS::create(util::PropertyMap(), axisList[1], axisList[0], axisList[2]); - return util::nn_static_pointer_cast<CRS>(GeographicCRS::create( - props, geogCRS->datum(), geogCRS->datumEnsemble(), cs)); + return util::nn_static_pointer_cast<CRS>( + GeographicCRS::create(createProperties(), geogCRS->datum(), + geogCRS->datumEnsemble(), cs)); } } @@ -867,8 +905,9 @@ CRSNNPtr CRS::normalizeForVisualization() const { axisList[0]) : cs::CartesianCS::create(util::PropertyMap(), axisList[1], axisList[0], axisList[2]); - return util::nn_static_pointer_cast<CRS>(ProjectedCRS::create( - props, projCRS->baseCRS(), projCRS->derivingConversion(), cs)); + return util::nn_static_pointer_cast<CRS>( + ProjectedCRS::create(createProperties(), projCRS->baseCRS(), + projCRS->derivingConversion(), cs)); } } @@ -1021,12 +1060,19 @@ CRSNNPtr CRS::promoteTo3D(const std::string &newName, } } const auto &l_identifiers = identifiers(); + const auto &l_remarks = remarks(); if (l_identifiers.size() == 1) { std::string remarks("Promoted to 3D from "); remarks += *(l_identifiers[0]->codeSpace()); remarks += ':'; remarks += l_identifiers[0]->code(); + if (!l_remarks.empty()) { + remarks += ". "; + remarks += l_remarks; + } props.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } else if (!l_remarks.empty()) { + props.set(common::IdentifiedObject::REMARKS_KEY, l_remarks); } return props; }; diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo index ce8cd762..a9bbfa37 100755 --- a/test/cli/testprojinfo +++ b/test/cli/testprojinfo @@ -135,6 +135,11 @@ echo "Testing -s EPSG:32631 -t EPSG:4326+3855 --3d --summary" >> ${OUT} $EXE -s EPSG:32631 -t EPSG:4326+3855 --3d --summary >>${OUT} 2>&1 echo "" >>${OUT} +# Undocumented option: --normalize-axis-order +echo "Testing -s EPSG:4326 -t EPSG:32661 --normalize-axis-order -o PROJ -q --single-line" >> ${OUT} +$EXE -s EPSG:4326 -t EPSG:32661 --normalize-axis-order -o PROJ -q --single-line >>${OUT} 2>&1 +echo "" >>${OUT} + echo "Testing -s EPSG:4936 -t EPSG:4978 --spatial-test intersects --summary where WGS 84 to ETRS89 (2) uses a transformation method not supported by PROJ currently (time-specific Helmert), and thus must be sorted last" >> ${OUT} $EXE -s EPSG:4936 -t EPSG:4978 --spatial-test intersects --summary >>${OUT} 2>&1 echo "" >>${OUT} diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index 4f48b222..596f915c 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -1238,6 +1238,9 @@ unknown id, Inverse of UTM zone 31N + WGS 84 to EGM2008 height (1), 1 m, World. unknown id, Inverse of UTM zone 31N + WGS 84 to EGM2008 height (2), 0.5 m, World. unknown id, Inverse of UTM zone 31N + Inverse of Transformation from EGM2008 height to WGS 84 (ballpark vertical transformation, without ellipsoid height to vertical height correction), unknown accuracy, World, has ballpark transformation +Testing -s EPSG:4326 -t EPSG:32661 --normalize-axis-order -o PROJ -q --single-line ++proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=stere +lat_0=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +ellps=WGS84 + Testing -s EPSG:4936 -t EPSG:4978 --spatial-test intersects --summary where WGS 84 to ETRS89 (2) uses a transformation method not supported by PROJ currently (time-specific Helmert), and thus must be sorted last Candidate operations found: 2 unknown id, Ballpark geocentric translation from ETRS89 to WGS 84, unknown accuracy, World, has ballpark transformation diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 5ff4dd2d..719cd125 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -1002,6 +1002,10 @@ TEST(crs, EPSG_32661_projected_north_pole_north_east) { EXPECT_EQ( opNormalized->exportToPROJString(PROJStringFormatter::create().get()), proj_string_normalized); + + EXPECT_EQ(opNormalized->sourceCRS()->domains().size(), 1U); + EXPECT_EQ(opNormalized->sourceCRS()->remarks(), + "Axis order reversed compared to EPSG:4326"); } // --------------------------------------------------------------------------- |
