aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/proj/crs.hpp2
-rw-r--r--scripts/reference_exported_symbols.txt1
-rw-r--r--src/apps/projinfo.cpp36
-rw-r--r--src/iso19111/crs.cpp64
-rwxr-xr-xtest/cli/testprojinfo5
-rw-r--r--test/cli/testprojinfo_out.dist3
-rw-r--r--test/unit/test_crs.cpp4
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");
}
// ---------------------------------------------------------------------------