aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2020-05-16 16:20:10 +0200
committerGitHub <noreply@github.com>2020-05-16 16:20:10 +0200
commit2d6b5c0a9a1e0f0f92e69c641a16377ef36f8270 (patch)
tree55fff0406885c1694150e7889bf03415e8c4d35c /src
parent330b2066244f77f89995a1aa195ef4323948a9b9 (diff)
parent960285f9742cd407caef9956b6a6f9d947f03dde (diff)
downloadPROJ-2d6b5c0a9a1e0f0f92e69c641a16377ef36f8270.tar.gz
PROJ-2d6b5c0a9a1e0f0f92e69c641a16377ef36f8270.zip
Merge pull request #2227 from rouault/fix_2225
createOperations(): when converting CompoundCRS<-->Geographic3DCrs, do not use discard change of ellipsoidal height if a Helmert transformation is involved
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/coordinateoperation.cpp106
1 files changed, 61 insertions, 45 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index ad456860..35be415f 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -119,8 +119,6 @@ static const char *BALLPARK_GEOCENTRIC_TRANSLATION =
static const char *NULL_GEOGRAPHIC_OFFSET = "Null geographic offset";
static const char *NULL_GEOCENTRIC_TRANSLATION = "Null geocentric translation";
static const char *BALLPARK_GEOGRAPHIC_OFFSET = "Ballpark geographic offset";
-static const char *BALLPARK_VERTICAL_TRANSFORMATION_PREFIX =
- " (ballpark vertical transformation";
static const char *BALLPARK_VERTICAL_TRANSFORMATION =
" (ballpark vertical transformation)";
static const char *BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT =
@@ -128,6 +126,8 @@ static const char *BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT =
"height correction)";
static const std::string AXIS_ORDER_CHANGE_2D_NAME = "axis order change (2D)";
+static const std::string AXIS_ORDER_CHANGE_3D_NAME =
+ "axis order change (geographic3D horizontal)";
//! @endcond
//! @cond Doxygen_Suppress
@@ -4842,8 +4842,7 @@ Conversion::createHeightDepthReversal(const util::PropertyMap &properties) {
*/
ConversionNNPtr Conversion::createAxisOrderReversal(bool is3D) {
if (is3D) {
- return create(createMapNameEPSGCode(
- "axis order change (geographic3D horizontal)", 15499),
+ return create(createMapNameEPSGCode(AXIS_ORDER_CHANGE_3D_NAME, 15499),
createMethodMapNameEPSGCode(
EPSG_CODE_METHOD_AXIS_ORDER_REVERSAL_3D),
{}, {});
@@ -7829,7 +7828,8 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom,
}
if (starts_with(tokens[i], INVERSE_OF)) {
name += tokens[i].substr(INVERSE_OF.size());
- } else if (tokens[i] == AXIS_ORDER_CHANGE_2D_NAME) {
+ } else if (tokens[i] == AXIS_ORDER_CHANGE_2D_NAME ||
+ tokens[i] == AXIS_ORDER_CHANGE_3D_NAME) {
name += tokens[i];
} else {
name += INVERSE_OF + tokens[i];
@@ -11123,8 +11123,8 @@ struct SortFunction {
// Sorting function
// Return true if a < b
- bool operator()(const CoordinateOperationNNPtr &a,
- const CoordinateOperationNNPtr &b) const {
+ bool compare(const CoordinateOperationNNPtr &a,
+ const CoordinateOperationNNPtr &b) const {
auto iterA = map.find(a.get());
assert(iterA != map.end());
auto iterB = map.find(b.get());
@@ -11249,6 +11249,15 @@ struct SortFunction {
// Arbitrary final criterion
return a_name < b_name;
}
+
+ bool operator()(const CoordinateOperationNNPtr &a,
+ const CoordinateOperationNNPtr &b) const {
+ const bool ret = compare(a, b);
+#if 0
+ std::cerr << a->nameStr() << " < " << b->nameStr() << " : " << ret << std::endl;
+#endif
+ return ret;
+ }
};
// ---------------------------------------------------------------------------
@@ -11264,6 +11273,17 @@ static size_t getStepCount(const CoordinateOperationNNPtr &op) {
// ---------------------------------------------------------------------------
+static bool isNullTransformation(const std::string &name) {
+ if (name.find(" + ") != std::string::npos)
+ return false;
+ return starts_with(name, BALLPARK_GEOCENTRIC_TRANSLATION) ||
+ starts_with(name, BALLPARK_GEOGRAPHIC_OFFSET) ||
+ starts_with(name, NULL_GEOGRAPHIC_OFFSET) ||
+ starts_with(name, NULL_GEOCENTRIC_TRANSLATION);
+}
+
+// ---------------------------------------------------------------------------
+
struct FilterResults {
FilterResults(const std::vector<CoordinateOperationNNPtr> &sourceListIn,
@@ -11514,19 +11534,6 @@ struct FilterResults {
const auto stepCount = getStepCount(op);
- const bool isApprox =
- op->nameStr().find(BALLPARK_VERTICAL_TRANSFORMATION_PREFIX) !=
- std::string::npos;
- const bool isNullTransformation =
- op->nameStr().find(BALLPARK_GEOGRAPHIC_OFFSET) !=
- std::string::npos ||
- op->nameStr().find(NULL_GEOGRAPHIC_OFFSET) !=
- std::string::npos ||
- op->nameStr().find(NULL_GEOCENTRIC_TRANSLATION) !=
- std::string::npos ||
- op->nameStr().find(BALLPARK_GEOCENTRIC_TRANSLATION) !=
- std::string::npos;
-
bool isPROJExportable = false;
auto formatter = io::PROJStringFormatter::create();
try {
@@ -11537,10 +11544,24 @@ struct FilterResults {
} catch (const std::exception &) {
}
+#if 0
+ std::cerr << op->nameStr() << " ";
+ std::cerr << area << " ";
+ std::cerr << getAccuracy(op) << " ";
+ std::cerr << isPROJExportable << " ";
+ std::cerr << hasGrids << " ";
+ std::cerr << gridsAvailable << " ";
+ std::cerr << gridsKnown << " ";
+ std::cerr << stepCount << " ";
+ std::cerr << op->hasBallparkTransformation() << " ";
+ std::cerr << isNullTransformation(op->nameStr()) << " ";
+ std::cerr << std::endl;
+#endif
map[op.get()] = PrecomputedOpCharacteristics(
area, getAccuracy(op), isPROJExportable, hasGrids,
- gridsAvailable, gridsKnown, stepCount, isApprox,
- isNullTransformation);
+ gridsAvailable, gridsKnown, stepCount,
+ op->hasBallparkTransformation(),
+ isNullTransformation(op->nameStr()));
}
// Sort !
@@ -11587,12 +11608,8 @@ struct FilterResults {
// better
if (hasOpThatContainsAreaOfInterestAndNoGrid && res.size() > 1) {
const auto &opLast = res.back();
- const std::string &name = opLast->nameStr();
- if (name.find(BALLPARK_GEOGRAPHIC_OFFSET) != std::string::npos ||
- name.find(NULL_GEOGRAPHIC_OFFSET) != std::string::npos ||
- name.find(NULL_GEOCENTRIC_TRANSLATION) != std::string::npos ||
- name.find(BALLPARK_GEOCENTRIC_TRANSLATION) !=
- std::string::npos) {
+ if (opLast->hasBallparkTransformation() ||
+ isNullTransformation(opLast->nameStr())) {
std::vector<CoordinateOperationNNPtr> resTemp;
for (size_t i = 0; i < res.size() - 1; i++) {
resTemp.emplace_back(res[i]);
@@ -12438,7 +12455,8 @@ static CoordinateOperationNNPtr createHorizVerticalPROJBased(
horizTransform, verticalTransform, geogDst);
const bool horizTransformIsNoOp =
- starts_with(horizTransform->nameStr(), NULL_GEOGRAPHIC_OFFSET);
+ starts_with(horizTransform->nameStr(), NULL_GEOGRAPHIC_OFFSET) &&
+ horizTransform->nameStr().find(" + ") == std::string::npos;
if (horizTransformIsNoOp) {
auto properties = util::PropertyMap();
properties.set(common::IdentifiedObject::NAME_KEY,
@@ -12496,11 +12514,13 @@ static CoordinateOperationNNPtr createHorizVerticalHorizPROJBased(
interpolationGeogCRS);
std::vector<CoordinateOperationNNPtr> ops;
- if (!starts_with(opSrcCRSToGeogCRS->nameStr(), NULL_GEOGRAPHIC_OFFSET)) {
+ if (!(starts_with(opSrcCRSToGeogCRS->nameStr(), NULL_GEOGRAPHIC_OFFSET) &&
+ opSrcCRSToGeogCRS->nameStr().find(" + ") == std::string::npos)) {
ops.emplace_back(opSrcCRSToGeogCRS);
}
ops.emplace_back(verticalTransform);
- if (!starts_with(opGeogCRStoDstCRS->nameStr(), NULL_GEOGRAPHIC_OFFSET)) {
+ if (!(starts_with(opGeogCRStoDstCRS->nameStr(), NULL_GEOGRAPHIC_OFFSET) &&
+ opGeogCRStoDstCRS->nameStr().find(" + ") == std::string::npos)) {
ops.emplace_back(opGeogCRStoDstCRS);
}
@@ -12792,16 +12812,6 @@ 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, NULL_GEOGRAPHIC_OFFSET) ||
- starts_with(name, NULL_GEOCENTRIC_TRANSLATION);
-}
-
-// ---------------------------------------------------------------------------
-
void CoordinateOperationFactory::Private::setCRSs(
CoordinateOperation *co, const crs::CRSNNPtr &sourceCRS,
const crs::CRSNNPtr &targetCRS) {
@@ -14789,10 +14799,16 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog(
if (!componentsSrc[0]->isEquivalentTo(
target2D.get(),
util::IComparable::Criterion::EQUIVALENT)) {
- interpToTargetOps = createOperations(
- NN_NO_CHECK(interpolationGeogCRS),
- targetCRS->demoteTo2D(std::string(), dbContext),
- context);
+ // We do the transformation from the
+ // interpolationCRS
+ // to the target one in 3D (see #2225)
+ // But we don't do that between sourceCRS and
+ // interpolationCRS, as this would mess with an
+ // orthometric elevation.
+ auto interp3D = interpolationGeogCRS->promoteTo3D(
+ std::string(), dbContext);
+ interpToTargetOps =
+ createOperations(interp3D, targetCRS, context);
}
};