aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-05-07 11:39:48 +0200
committerGitHub <noreply@github.com>2019-05-07 11:39:48 +0200
commit850050693a25843d6ae69492cfad72f7753e39f7 (patch)
tree4d464df04190ae115e7f54259457286d22580eb9 /src
parent4636df33ed4d2a9bedf19973d58a42858fb816c0 (diff)
parentd4ffaca08a4f2ef3475165c2634561ee9bf01885 (diff)
downloadPROJ-850050693a25843d6ae69492cfad72f7753e39f7.tar.gz
PROJ-850050693a25843d6ae69492cfad72f7753e39f7.zip
Merge pull request #1454 from rouault/fix_ETRS89_3D_to_proj_string_with_geoidgrids_nadgrids
createOperations(): fix case of ETRS89 3D to proj string with nadgrids and geoidgrids
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/coordinateoperation.cpp142
-rw-r--r--src/iso19111/internal.cpp15
-rw-r--r--src/iso19111/io.cpp20
3 files changed, 148 insertions, 29 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 605004b6..348a776a 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -6958,11 +6958,11 @@ TransformationNNPtr Transformation::createNTv2(
static TransformationNNPtr _createGravityRelatedHeightToGeographic3D(
const util::PropertyMap &properties, bool inverse,
const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn,
- const std::string &filename,
+ const crs::CRSPtr &interpolationCRSIn, const std::string &filename,
const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) {
return Transformation::create(
- properties, sourceCRSIn, targetCRSIn, nullptr,
+ properties, sourceCRSIn, targetCRSIn, interpolationCRSIn,
util::PropertyMap().set(
common::IdentifiedObject::NAME_KEY,
inverse ? INVERSE_OF + PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D
@@ -6981,17 +6981,20 @@ static TransformationNNPtr _createGravityRelatedHeightToGeographic3D(
* At minimum the name should be defined.
* @param sourceCRSIn Source CRS.
* @param targetCRSIn Target CRS.
+ * @param interpolationCRSIn Interpolation CRS. (might be null)
* @param filename GRID filename.
* @param accuracies Vector of positional accuracy (might be empty).
* @return new Transformation.
*/
TransformationNNPtr Transformation::createGravityRelatedHeightToGeographic3D(
const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn,
- const crs::CRSNNPtr &targetCRSIn, const std::string &filename,
+ const crs::CRSNNPtr &targetCRSIn, const crs::CRSPtr &interpolationCRSIn,
+ const std::string &filename,
const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) {
return _createGravityRelatedHeightToGeographic3D(
- properties, false, sourceCRSIn, targetCRSIn, filename, accuracies);
+ properties, false, sourceCRSIn, targetCRSIn, interpolationCRSIn,
+ filename, accuracies);
}
// ---------------------------------------------------------------------------
@@ -7302,8 +7305,20 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom,
auto targetCRS = op->targetCRS();
std::string name;
if (!forwardName.empty()) {
- if (starts_with(forwardName, INVERSE_OF)) {
- name = forwardName.substr(INVERSE_OF.size());
+ if (starts_with(forwardName, INVERSE_OF) ||
+ forwardName.find(" + ") != std::string::npos) {
+ auto tokens = split(forwardName, " + ");
+ for (size_t i = tokens.size(); i > 0;) {
+ i--;
+ if (!name.empty()) {
+ name += " + ";
+ }
+ if (starts_with(tokens[i], INVERSE_OF)) {
+ name += tokens[i].substr(INVERSE_OF.size());
+ } else {
+ name += INVERSE_OF + tokens[i];
+ }
+ }
} else if (!sourceCRS || !targetCRS ||
forwardName != buildOpName(opType, sourceCRS, targetCRS)) {
name = INVERSE_OF + forwardName;
@@ -8195,13 +8210,14 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames(
return createGravityRelatedHeightToGeographic3D(
createPropertiesForInverse(self.as_nullable().get(),
true, false),
- targetCRS(), sourceCRS(), projFilename,
- coordinateOperationAccuracies())
+ targetCRS(), sourceCRS(), interpolationCRS(),
+ projFilename, coordinateOperationAccuracies())
->inverseAsTransformation();
} else {
return createGravityRelatedHeightToGeographic3D(
createSimilarPropertiesTransformation(self), sourceCRS(),
- targetCRS(), projFilename, coordinateOperationAccuracies());
+ targetCRS(), interpolationCRS(), projFilename,
+ coordinateOperationAccuracies());
}
}
}
@@ -10972,19 +10988,19 @@ struct MyPROJStringExportableHorizVertical final
// cppcheck-suppress functionStatic
_exportToPROJString(io::PROJStringFormatter *formatter) const override {
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
horizTransform->_exportToPROJString(formatter);
formatter->startInversion();
geogDst->addAngularUnitConvertAndAxisSwap(formatter);
formatter->stopInversion();
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
verticalTransform->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
geogDst->addAngularUnitConvertAndAxisSwap(formatter);
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
}
};
@@ -11016,7 +11032,7 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final
// cppcheck-suppress functionStatic
_exportToPROJString(io::PROJStringFormatter *formatter) const override {
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
opSrcCRSToGeogCRS->_exportToPROJString(formatter);
@@ -11024,17 +11040,17 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final
interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter);
formatter->stopInversion();
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
verticalTransform->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter);
opGeogCRStoDstCRS->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
}
};
@@ -12135,6 +12151,37 @@ CoordinateOperationFactory::Private::createOperations(
}
}
+ auto vertCRSOfBaseOfBoundSrc =
+ dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get());
+ if (vertCRSOfBaseOfBoundSrc && hubSrcGeog &&
+ hubSrcGeog->coordinateSystem()->axisList().size() == 3 &&
+ geogDst->coordinateSystem()->axisList().size() == 3) {
+ auto opsFirst = createOperations(sourceCRS, hubSrc, context);
+ auto opsSecond = createOperations(hubSrc, targetCRS, context);
+ if (!opsFirst.empty() && !opsSecond.empty()) {
+ for (const auto &opFirst : opsFirst) {
+ for (const auto &opLast : opsSecond) {
+ // Exclude artificial transformations from the hub
+ // to the target CRS
+ if (!opLast->hasBallparkTransformation()) {
+ try {
+ res.emplace_back(
+ ConcatenatedOperation::
+ createComputeMetadata(
+ {opFirst, opLast},
+ !allowEmptyIntersection));
+ } catch (
+ const InvalidOperationEmptyIntersection &) {
+ }
+ }
+ }
+ }
+ if (!res.empty()) {
+ return res;
+ }
+ }
+ }
+
return createOperations(boundSrc->baseCRS(), targetCRS, context);
}
@@ -12349,7 +12396,8 @@ CoordinateOperationFactory::Private::createOperations(
const auto &componentsSrc = compoundSrc->componentReferenceSystems();
if (!componentsSrc.empty()) {
std::vector<CoordinateOperationNNPtr> horizTransforms;
- if (componentsSrc[0]->extractGeographicCRS()) {
+ auto srcGeogCRS = componentsSrc[0]->extractGeographicCRS();
+ if (srcGeogCRS) {
horizTransforms =
createOperations(componentsSrc[0], targetCRS, context);
}
@@ -12363,11 +12411,61 @@ CoordinateOperationFactory::Private::createOperations(
for (const auto &horizTransform : horizTransforms) {
for (const auto &verticalTransform : verticalTransforms) {
- auto op = createHorizVerticalPROJBased(
- sourceCRS, targetCRS, horizTransform,
- verticalTransform);
+ crs::GeographicCRSPtr interpolationGeogCRS;
+ auto transformationVerticalTransform =
+ dynamic_cast<const Transformation *>(
+ verticalTransform.get());
+ if (transformationVerticalTransform) {
+ auto interpTransformCRS =
+ transformationVerticalTransform
+ ->interpolationCRS();
+ if (interpTransformCRS) {
+ auto nn_interpTransformCRS =
+ NN_NO_CHECK(interpTransformCRS);
+ if (dynamic_cast<const crs::GeographicCRS *>(
+ nn_interpTransformCRS.get())) {
+ interpolationGeogCRS =
+ util::nn_dynamic_pointer_cast<
+ crs::GeographicCRS>(
+ nn_interpTransformCRS);
+ }
+ }
+ }
+ bool done = false;
+ if (interpolationGeogCRS &&
+ (interpolationGeogCRS->_isEquivalentTo(
+ srcGeogCRS.get(),
+ util::IComparable::Criterion::EQUIVALENT) ||
+ interpolationGeogCRS->is2DPartOf3D(
+ NN_NO_CHECK(srcGeogCRS.get())))) {
+ auto srcToInterp = createOperations(
+ componentsSrc[0],
+ NN_NO_CHECK(interpolationGeogCRS), context);
+ auto interpToCompoundHoriz = createOperations(
+ NN_NO_CHECK(interpolationGeogCRS),
+ componentsSrc[0], context);
+ if (!srcToInterp.empty() &&
+ !interpToCompoundHoriz.empty()) {
+ auto op = createHorizVerticalHorizPROJBased(
+ sourceCRS, componentsSrc[0],
+ srcToInterp.front(), verticalTransform,
+ interpToCompoundHoriz.front(),
+ interpolationGeogCRS);
+ done = true;
+ res.emplace_back(
+ ConcatenatedOperation::
+ createComputeMetadata(
+ {op, horizTransform},
+ !allowEmptyIntersection));
+ }
+ }
+ if (!done) {
+ auto op = createHorizVerticalPROJBased(
+ sourceCRS, targetCRS, horizTransform,
+ verticalTransform);
- res.emplace_back(op);
+ res.emplace_back(op);
+ }
}
}
return res;
diff --git a/src/iso19111/internal.cpp b/src/iso19111/internal.cpp
index 240c98f4..4810202d 100644
--- a/src/iso19111/internal.cpp
+++ b/src/iso19111/internal.cpp
@@ -298,6 +298,21 @@ std::vector<std::string> split(const std::string &str, char separator) {
// ---------------------------------------------------------------------------
+std::vector<std::string> split(const std::string &str,
+ const std::string &separator) {
+ std::vector<std::string> res;
+ size_t lastPos = 0;
+ size_t newPos = 0;
+ while ((newPos = str.find(separator, lastPos)) != std::string::npos) {
+ res.push_back(str.substr(lastPos, newPos - lastPos));
+ lastPos = newPos + separator.size();
+ }
+ res.push_back(str.substr(lastPos));
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
#ifdef _WIN32
// For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index e072a66f..c84ea2f3 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -3818,7 +3818,7 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) {
Transformation::createGravityRelatedHeightToGeographic3D(
PropertyMap().set(IdentifiedObject::NAME_KEY,
transformationName),
- crs, GeographicCRS::EPSG_4979,
+ crs, GeographicCRS::EPSG_4979, nullptr,
stripQuotes(extensionChildren[1]),
std::vector<PositionalAccuracyNNPtr>());
return nn_static_pointer_cast<CRS>(BoundCRS::create(
@@ -4922,7 +4922,7 @@ struct PROJStringFormatter::Private {
};
std::vector<InversionStackElt> inversionStack_{InversionStackElt()};
bool omitProjLongLatIfPossible_ = false;
- bool omitZUnitConversion_ = false;
+ std::vector<bool> omitZUnitConversion_{false};
DatabaseContextPtr dbContext_{};
bool useApproxTMerc_ = false;
bool addNoDefs_ = true;
@@ -5939,15 +5939,21 @@ bool PROJStringFormatter::omitProjLongLatIfPossible() const {
// ---------------------------------------------------------------------------
-void PROJStringFormatter::setOmitZUnitConversion(bool omit) {
- assert(d->omitZUnitConversion_ ^ omit);
- d->omitZUnitConversion_ = omit;
+void PROJStringFormatter::pushOmitZUnitConversion() {
+ d->omitZUnitConversion_.push_back(true);
+}
+
+// ---------------------------------------------------------------------------
+
+void PROJStringFormatter::popOmitZUnitConversion() {
+ assert(d->omitZUnitConversion_.size() > 1);
+ d->omitZUnitConversion_.pop_back();
}
// ---------------------------------------------------------------------------
bool PROJStringFormatter::omitZUnitConversion() const {
- return d->omitZUnitConversion_;
+ return d->omitZUnitConversion_.back();
}
// ---------------------------------------------------------------------------
@@ -6995,7 +7001,7 @@ PROJStringParser::Private::buildBoundOrCompoundCRSIfNeeded(int iStep,
Transformation::createGravityRelatedHeightToGeographic3D(
PropertyMap().set(IdentifiedObject::NAME_KEY,
"unknown to WGS84 ellipsoidal height"),
- crs, GeographicCRS::EPSG_4979, geoidgrids,
+ crs, GeographicCRS::EPSG_4979, nullptr, geoidgrids,
std::vector<PositionalAccuracyNNPtr>());
auto boundvcrs =
BoundCRS::create(vcrs, GeographicCRS::EPSG_4979, transformation);