aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-03-16 15:14:55 +0100
committerEven Rouault <even.rouault@spatialys.com>2019-03-16 15:22:57 +0100
commitd95b0cb8b317d0a8142b664c42928083145194ed (patch)
tree3829861a7c03da12179e4d7cf4458748583acfbc
parenta9886a5e4a64610aa605e98afeb467d1c44ed925 (diff)
downloadPROJ-d95b0cb8b317d0a8142b664c42928083145194ed.tar.gz
PROJ-d95b0cb8b317d0a8142b664c42928083145194ed.zip
createOperation(): fix geocent <--> nadgrids+geoidgrids case (fixes #1323)
-rw-r--r--src/iso19111/coordinateoperation.cpp31
-rw-r--r--src/iso19111/io.cpp20
-rw-r--r--test/unit/test_operation.cpp45
3 files changed, 93 insertions, 3 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 575eae39..240833df 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -11914,11 +11914,40 @@ CoordinateOperationFactory::Private::createOperations(
return horizTransforms;
}
}
+ } else if (compoundSrc && geodDst) {
+ auto datum = geodDst->datum();
+ if (datum) {
+ auto cs =
+ cs::EllipsoidalCS::createLatitudeLongitudeEllipsoidalHeight(
+ common::UnitOfMeasure::DEGREE,
+ common::UnitOfMeasure::METRE);
+ auto intermGeog3DCRS = util::nn_static_pointer_cast<crs::CRS>(
+ crs::GeographicCRS::create(
+ util::PropertyMap()
+ .set(common::IdentifiedObject::NAME_KEY,
+ geodDst->nameStr())
+ .set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY,
+ metadata::Extent::WORLD),
+ NN_NO_CHECK(datum), cs));
+ auto sourceToGeog3DOps =
+ createOperations(sourceCRS, intermGeog3DCRS, context);
+ auto geog3DToTargetOps =
+ createOperations(intermGeog3DCRS, targetCRS, context);
+ if (!geog3DToTargetOps.empty()) {
+ for (const auto &op : sourceToGeog3DOps) {
+ res.emplace_back(
+ ConcatenatedOperation::createComputeMetadata(
+ {op, geog3DToTargetOps.front()},
+ !allowEmptyIntersection));
+ }
+ return res;
+ }
+ }
}
// reverse of previous case
auto compoundDst = dynamic_cast<const crs::CompoundCRS *>(targetCRS.get());
- if (geogSrc && compoundDst) {
+ if (geodSrc && compoundDst) {
return applyInverse(createOperations(targetCRS, sourceCRS, context));
}
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 51f93e2f..d5f38fd5 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -5049,7 +5049,7 @@ const std::string &PROJStringFormatter::toString() const {
first.paramValues[1].keyEquals("z_in") &&
first.paramValues[2].keyEquals("xy_out") &&
first.paramValues[3].keyEquals("z_out") &&
- second.paramValues[0].keyEquals("xy_in=") &&
+ second.paramValues[0].keyEquals("xy_in") &&
second.paramValues[1].keyEquals("xy_out") &&
first.paramValues[0].value == second.paramValues[1].value &&
first.paramValues[2].value == second.paramValues[0].value) {
@@ -5074,6 +5074,22 @@ const std::string &PROJStringFormatter::toString() const {
break;
}
+ // unitconvert (1), axisswap order=2,1, unitconvert(2) ==>
+ // axisswap order=2,1, unitconvert (1), unitconvert(2) which
+ // will get further optimized by previous case
+ if (i + 1 < d->steps_.size() && prevStep.name == "unitconvert" &&
+ curStep.name == "axisswap" && curStepParamCount == 1 &&
+ curStep.paramValues[0].equals("order", "2,1")) {
+ auto iterNext = iterCur;
+ ++iterNext;
+ auto &nextStep = *iterNext;
+ if (nextStep.name == "unitconvert") {
+ std::swap(*iterPrev, *iterCur);
+ changeDone = true;
+ break;
+ }
+ }
+
// axisswap order=2,1 followed by itself is a no-op
if (curStep.name == "axisswap" && prevStep.name == "axisswap" &&
curStepParamCount == 1 && prevStepParamCount == 1 &&
@@ -6707,7 +6723,7 @@ PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) {
auto datum = buildDatum(step, title);
- UnitOfMeasure unit = UnitOfMeasure::METRE;
+ UnitOfMeasure unit = buildUnit(step, "units", "");
if (iUnitConvert >= 0) {
auto &stepUnitConvert = steps_[iUnitConvert];
const std::string *xy_in = &getParamValue(stepUnitConvert, "xy_in");
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index e71ac716..615cbd67 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -6026,6 +6026,51 @@ TEST(operation, compoundCRS_with_boundProjCRS_and_boundVerticalCRS_to_geogCRS) {
// ---------------------------------------------------------------------------
+TEST(operation, geocent_to_compoundCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=geocent +datum=WGS84 +units=m +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
+ "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
+ "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocent_to_compoundCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // WGS84 geocentric
+ auto src = authFactory->createCoordinateReferenceSystem("4978");
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ src, NN_CHECK_ASSERT(dst), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
+ "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
+ "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
TEST(operation, compoundCRS_to_compoundCRS) {
auto compound1 = CompoundCRS::create(
PropertyMap(),