diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-12-14 21:12:43 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-12-14 21:12:43 +0100 |
| commit | 95340fb1d1011d6864d82b60194eb77df9e9e38f (patch) | |
| tree | 30e2d3909d33c04f7966f996f90c971cd7023ade /src/iso19111 | |
| parent | bfc54bbac8550e18d352468032ad0b3d5ca2d328 (diff) | |
| download | PROJ-95340fb1d1011d6864d82b60194eb77df9e9e38f.tar.gz PROJ-95340fb1d1011d6864d82b60194eb77df9e9e38f.zip | |
createOperations(): fix inconsistent chaining exception when transforming from BoundCRS of projected CRS based on NTF Paris to BoundCRS of geog CRS NTF Paris. Fixes https://github.com/OSGeo/gdal/issues/3273
Diffstat (limited to 'src/iso19111')
| -rw-r--r-- | src/iso19111/crs.cpp | 3 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 3 | ||||
| -rw-r--r-- | src/iso19111/operation/concatenatedoperation.cpp | 35 | ||||
| -rw-r--r-- | src/iso19111/operation/coordinateoperationfactory.cpp | 53 |
4 files changed, 55 insertions, 39 deletions
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 573dd6db..9d58f733 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -5188,7 +5188,8 @@ BoundCRSNNPtr BoundCRS::createFromNadgrids(const CRSNNPtr &baseCRSIn, " (with Greenwich prime meridian)"), sourceGeographicCRS->datumNonNull(nullptr)->ellipsoid(), util::optional<std::string>(), datum::PrimeMeridian::GREENWICH), - sourceGeographicCRS->coordinateSystem()); + cs::EllipsoidalCS::createLatitudeLongitude( + common::UnitOfMeasure::DEGREE)); } std::string transformationName = transformationSourceCRS->nameStr(); transformationName += " to WGS84"; diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 86ece49d..dc51c5d9 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -4238,7 +4238,8 @@ createBoundCRSSourceTransformationCRS(const crs::CRSPtr &sourceCRS, sourceGeographicCRS->datum()->ellipsoid(), util::optional<std::string>(), datum::PrimeMeridian::GREENWICH), - sourceGeographicCRS->coordinateSystem()) + cs::EllipsoidalCS::createLatitudeLongitude( + common::UnitOfMeasure::DEGREE)) .as_nullable(); } } else { diff --git a/src/iso19111/operation/concatenatedoperation.cpp b/src/iso19111/operation/concatenatedoperation.cpp index 1c65a24b..ce4b015a 100644 --- a/src/iso19111/operation/concatenatedoperation.cpp +++ b/src/iso19111/operation/concatenatedoperation.cpp @@ -446,6 +446,41 @@ CoordinateOperationNNPtr ConcatenatedOperation::createComputeMetadata( flattenOps.emplace_back(subOp); } } + + // Remove consecutive inverse operations + if (flattenOps.size() > 2) { + std::vector<size_t> indices; + for (size_t i = 0; i < flattenOps.size(); ++i) + indices.push_back(i); + while (true) { + bool bHasChanged = false; + for (size_t i = 0; i + 1 < indices.size(); ++i) { + if (flattenOps[indices[i]]->_isEquivalentTo( + flattenOps[indices[i + 1]]->inverse().get(), + util::IComparable::Criterion::EQUIVALENT) && + flattenOps[indices[i]]->sourceCRS()->_isEquivalentTo( + flattenOps[indices[i + 1]]->targetCRS().get(), + util::IComparable::Criterion::EQUIVALENT)) { + indices.erase(indices.begin() + i, indices.begin() + i + 2); + bHasChanged = true; + break; + } + } + // We bail out if indices.size() == 2, because potentially + // the last 2 remaining ones could auto-cancel, and we would have + // to have a special case for that (and this happens in practice). + if (!bHasChanged || indices.size() <= 2) + break; + } + if (indices.size() < flattenOps.size()) { + std::vector<CoordinateOperationNNPtr> flattenOpsNew; + for (size_t i = 0; i < indices.size(); ++i) { + flattenOpsNew.emplace_back(flattenOps[indices[i]]); + } + flattenOps = std::move(flattenOpsNew); + } + } + if (flattenOps.size() == 1) { return flattenOps[0]; } diff --git a/src/iso19111/operation/coordinateoperationfactory.cpp b/src/iso19111/operation/coordinateoperationfactory.cpp index 1e919416..b8a9bcdf 100644 --- a/src/iso19111/operation/coordinateoperationfactory.cpp +++ b/src/iso19111/operation/coordinateoperationfactory.cpp @@ -4255,47 +4255,26 @@ void CoordinateOperationFactory::Private::createOperationsBoundToBound( auto hubSrcGeog = dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); const auto &hubDst = boundDst->hubCRS(); auto hubDstGeog = dynamic_cast<const crs::GeographicCRS *>(hubDst.get()); - auto geogCRSOfBaseOfBoundSrc = boundSrc->baseCRS()->extractGeographicCRS(); - auto geogCRSOfBaseOfBoundDst = boundDst->baseCRS()->extractGeographicCRS(); if (hubSrcGeog && hubDstGeog && hubSrcGeog->_isEquivalentTo(hubDstGeog, - util::IComparable::Criterion::EQUIVALENT) && - geogCRSOfBaseOfBoundSrc && geogCRSOfBaseOfBoundDst) { - const bool firstIsNoOp = geogCRSOfBaseOfBoundSrc->_isEquivalentTo( - boundSrc->baseCRS().get(), - util::IComparable::Criterion::EQUIVALENT); - const bool lastIsNoOp = geogCRSOfBaseOfBoundDst->_isEquivalentTo( - boundDst->baseCRS().get(), - util::IComparable::Criterion::EQUIVALENT); - auto opsFirst = createOperations( - boundSrc->baseCRS(), NN_NO_CHECK(geogCRSOfBaseOfBoundSrc), context); - auto opsLast = createOperations(NN_NO_CHECK(geogCRSOfBaseOfBoundDst), - boundDst->baseCRS(), context); - if (!opsFirst.empty() && !opsLast.empty()) { - const auto &opSecond = boundSrc->transformation(); - auto opThird = boundDst->transformation()->inverse(); - for (const auto &opFirst : opsFirst) { - for (const auto &opLast : opsLast) { - try { - std::vector<CoordinateOperationNNPtr> ops; - if (!firstIsNoOp) { - ops.push_back(opFirst); - } - ops.push_back(opSecond); - ops.push_back(opThird); - if (!lastIsNoOp) { - ops.push_back(opLast); - } - res.emplace_back( - ConcatenatedOperation::createComputeMetadata( - ops, disallowEmptyIntersection)); - } catch (const InvalidOperationEmptyIntersection &) { - } + util::IComparable::Criterion::EQUIVALENT)) { + auto opsFirst = createOperations(sourceCRS, hubSrc, context); + auto opsLast = createOperations(hubSrc, targetCRS, context); + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsLast) { + try { + std::vector<CoordinateOperationNNPtr> ops; + ops.push_back(opFirst); + ops.push_back(opLast); + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + ops, disallowEmptyIntersection)); + } catch (const InvalidOperationEmptyIntersection &) { } } - if (!res.empty()) { - return; - } + } + if (!res.empty()) { + return; } } |
