aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/coordinateoperation.cpp183
-rw-r--r--src/iso19111/factory.cpp35
2 files changed, 121 insertions, 97 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 6a05bbe8..881a16fd 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -4710,6 +4710,64 @@ Conversion::createGeographicGeocentric(const util::PropertyMap &properties) {
//! @cond Doxygen_Suppress
+static const char *getCRSQualifierStr(const crs::CRSPtr &crs) {
+ auto geod = dynamic_cast<crs::GeodeticCRS *>(crs.get());
+ if (geod) {
+ if (geod->isGeocentric()) {
+ return " (geocentric)";
+ }
+ auto geog = dynamic_cast<crs::GeographicCRS *>(geod);
+ if (geog) {
+ if (geog->coordinateSystem()->axisList().size() == 2) {
+ return " (geog2D)";
+ } else {
+ return " (geog3D)";
+ }
+ }
+ }
+ return "";
+}
+
+// ---------------------------------------------------------------------------
+
+static std::string buildOpName(const char *opType, const crs::CRSPtr &source,
+ const crs::CRSPtr &target) {
+ std::string res(opType);
+ const auto &srcName = source->nameStr();
+ const auto &targetName = target->nameStr();
+ const char *srcQualifier = "";
+ const char *targetQualifier = "";
+ if (srcName == targetName) {
+ srcQualifier = getCRSQualifierStr(source);
+ targetQualifier = getCRSQualifierStr(target);
+ if (strcmp(srcQualifier, targetQualifier) == 0) {
+ srcQualifier = "";
+ targetQualifier = "";
+ }
+ }
+ res += " from ";
+ res += srcName;
+ res += srcQualifier;
+ res += " to ";
+ res += targetName;
+ res += targetQualifier;
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
+ConversionNNPtr
+Conversion::createGeographicGeocentric(const crs::CRSNNPtr &sourceCRS,
+ const crs::CRSNNPtr &targetCRS) {
+ auto properties = util::PropertyMap().set(
+ common::IdentifiedObject::NAME_KEY,
+ buildOpName("Conversion", sourceCRS, targetCRS));
+ auto conv = createGeographicGeocentric(properties);
+ conv->setCRSs(sourceCRS, targetCRS, nullptr);
+ return conv;
+}
+// ---------------------------------------------------------------------------
+
static util::PropertyMap &addDomains(util::PropertyMap &map,
const common::ObjectUsage *obj) {
@@ -7403,52 +7461,6 @@ TransformationNNPtr Transformation::createChangeVerticalUnit(
// ---------------------------------------------------------------------------
-static const char *getCRSQualifierStr(const crs::CRSPtr &crs) {
- auto geod = dynamic_cast<crs::GeodeticCRS *>(crs.get());
- if (geod) {
- if (geod->isGeocentric()) {
- return " (geocentric)";
- }
- auto geog = dynamic_cast<crs::GeographicCRS *>(geod);
- if (geog) {
- if (geog->coordinateSystem()->axisList().size() == 2) {
- return " (geog2D)";
- } else {
- return " (geog3D)";
- }
- }
- }
- return "";
-}
-
-// ---------------------------------------------------------------------------
-
-static std::string buildOpName(const char *opType, const crs::CRSPtr &source,
- const crs::CRSPtr &target) {
- std::string res(opType);
- const auto &srcName = source->nameStr();
- const auto &targetName = target->nameStr();
- const char *srcQualifier = "";
- const char *targetQualifier = "";
- if (srcName == targetName) {
- srcQualifier = getCRSQualifierStr(source);
- targetQualifier = getCRSQualifierStr(target);
- if (strcmp(srcQualifier, targetQualifier) == 0) {
- srcQualifier = "";
- targetQualifier = "";
- }
- }
- res += " from ";
- res += srcName;
- res += srcQualifier;
- res += " to ";
- res += targetName;
- res += targetQualifier;
- return res;
-}
-
-// ---------------------------------------------------------------------------
-
static util::PropertyMap
createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom,
bool approximateInversion) {
@@ -9524,6 +9536,9 @@ ConcatenatedOperationNNPtr ConcatenatedOperation::create(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+
+// ---------------------------------------------------------------------------
+
void ConcatenatedOperation::fixStepsDirection(
const crs::CRSNNPtr &concatOpSourceCRS,
const crs::CRSNNPtr &concatOpTargetCRS,
@@ -9620,14 +9635,47 @@ void ConcatenatedOperation::fixStepsDirection(
nullptr);
}
} else if (!conv && l_sourceCRS && l_targetCRS) {
+
+ const auto isGeographic = [](const crs::CRS *crs) -> bool {
+ return dynamic_cast<const crs::GeographicCRS *>(crs) != nullptr;
+ };
+
+ const auto isGeocentric = [](const crs::CRS *crs) -> bool {
+ auto geodCRS = dynamic_cast<const crs::GeodeticCRS *>(crs);
+ if (geodCRS &&
+ geodCRS->coordinateSystem()->axisList().size() == 3)
+ return true;
+ return false;
+ };
+
// Transformations might be mentioned in their forward directions,
// whereas we should instead use the reverse path.
auto prevOpTarget = (i == 0) ? concatOpSourceCRS.as_nullable()
: operationsInOut[i - 1]->targetCRS();
- if (!compareStepCRS(l_sourceCRS.get(), prevOpTarget.get()) &&
- compareStepCRS(l_targetCRS.get(), prevOpTarget.get())) {
+ if (compareStepCRS(l_sourceCRS.get(), prevOpTarget.get())) {
+ // do nothing
+ } else if (compareStepCRS(l_targetCRS.get(), prevOpTarget.get())) {
op = op->inverse();
}
+ // Below is needed for EPSG:9103 which chains NAD83(2011) geographic
+ // 2D with NAD83(2011) geocentric
+ else if (l_sourceCRS->nameStr() == prevOpTarget->nameStr() &&
+ ((isGeographic(l_sourceCRS.get()) &&
+ isGeocentric(prevOpTarget.get())) ||
+ (isGeocentric(l_sourceCRS.get()) &&
+ isGeographic(prevOpTarget.get())))) {
+ auto newOp(Conversion::createGeographicGeocentric(
+ NN_NO_CHECK(prevOpTarget), NN_NO_CHECK(l_sourceCRS)));
+ operationsInOut.insert(operationsInOut.begin() + i, newOp);
+ } else if (l_targetCRS->nameStr() == prevOpTarget->nameStr() &&
+ ((isGeographic(l_targetCRS.get()) &&
+ isGeocentric(prevOpTarget.get())) ||
+ (isGeocentric(l_targetCRS.get()) &&
+ isGeographic(prevOpTarget.get())))) {
+ auto newOp(Conversion::createGeographicGeocentric(
+ NN_NO_CHECK(prevOpTarget), NN_NO_CHECK(l_targetCRS)));
+ operationsInOut.insert(operationsInOut.begin() + i, newOp);
+ }
}
}
@@ -10290,10 +10338,6 @@ struct CoordinateOperationFactory::Private {
hasPerfectAccuracyResult(const std::vector<CoordinateOperationNNPtr> &res,
const Context &context);
- static ConversionNNPtr
- createGeographicGeocentric(const crs::CRSNNPtr &sourceCRS,
- const crs::CRSNNPtr &targetCRS);
-
static void setCRSs(CoordinateOperation *co, const crs::CRSNNPtr &sourceCRS,
const crs::CRSNNPtr &targetCRS);
};
@@ -11659,18 +11703,6 @@ static CoordinateOperationNNPtr createHorizVerticalHorizPROJBased(
//! @cond Doxygen_Suppress
-ConversionNNPtr CoordinateOperationFactory::Private::createGeographicGeocentric(
- const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS) {
- auto properties = util::PropertyMap().set(
- common::IdentifiedObject::NAME_KEY,
- buildOpName("Conversion", sourceCRS, targetCRS));
- auto conv = Conversion::createGeographicGeocentric(properties);
- conv->setCRSs(sourceCRS, targetCRS, nullptr);
- return conv;
-}
-
-// ---------------------------------------------------------------------------
-
std::vector<CoordinateOperationNNPtr>
CoordinateOperationFactory::Private::createOperationsGeogToGeog(
std::vector<CoordinateOperationNNPtr> &res, const crs::CRSNNPtr &sourceCRS,
@@ -12712,8 +12744,8 @@ CoordinateOperationFactory::Private::createOperations(
if (geodSrc->datum()->_isEquivalentTo(
geodDst->datum().get(),
util::IComparable::Criterion::EQUIVALENT)) {
- res.emplace_back(
- createGeographicGeocentric(sourceCRS, targetCRS));
+ res.emplace_back(Conversion::createGeographicGeocentric(
+ sourceCRS, targetCRS));
} else if (isSrcGeocentric) {
std::string interm_crs_name(geogDst->nameStr());
interm_crs_name += " (geocentric)";
@@ -12729,8 +12761,8 @@ CoordinateOperationFactory::Private::createOperations(
geodSrc->coordinateSystem()))));
auto opFirst =
createBallparkGeocentricTranslation(sourceCRS, interm_crs);
- auto opSecond =
- createGeographicGeocentric(interm_crs, targetCRS);
+ auto opSecond = Conversion::createGeographicGeocentric(
+ interm_crs, targetCRS);
res.emplace_back(ConcatenatedOperation::createComputeMetadata(
{opFirst, opSecond}, !allowEmptyIntersection));
} else {
@@ -13364,9 +13396,7 @@ CoordinateOperationFactory::Private::createOperations(
verticalTransform, interpToTarget,
interpolationGeogCRS, true);
res.emplace_back(op);
- } catch (
- const InvalidOperationEmptyIntersection &) {
- continue;
+ } catch (const std::exception &) {
}
}
}
@@ -13377,10 +13407,13 @@ CoordinateOperationFactory::Private::createOperations(
// involve a grid, because of the rather arbitrary order
// horizontal then vertical applied
for (const auto &horizTransform : horizTransforms) {
- auto op = createHorizVerticalPROJBased(
- sourceCRS, targetCRS, horizTransform,
- verticalTransform);
- res.emplace_back(op);
+ try {
+ auto op = createHorizVerticalPROJBased(
+ sourceCRS, targetCRS, horizTransform,
+ verticalTransform);
+ res.emplace_back(op);
+ } catch (const std::exception &) {
+ }
}
}
}
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index 9be04580..6fef6366 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -3141,8 +3141,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
"source_crs_auth_name, source_crs_code, "
"target_crs_auth_name, target_crs_code, "
"area_of_use_auth_name, area_of_use_code, accuracy, "
- "step1_auth_name, step1_code, step2_auth_name, step2_code, "
- "step3_auth_name, step3_code, operation_version, deprecated FROM "
+ "operation_version, deprecated FROM "
"concatenated_operation WHERE auth_name = ? AND code = ?",
code);
if (res.empty()) {
@@ -3150,6 +3149,13 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
throw NoSuchAuthorityCodeException(
"concatenated_operation not found", d->authority(), code);
}
+
+ auto resSteps = d->runWithCodeParam(
+ "SELECT step_auth_name, step_code FROM "
+ "concatenated_operation_step WHERE operation_auth_name = ? "
+ "AND operation_code = ? ORDER BY step_number",
+ code);
+
try {
const auto &row = res.front();
size_t idx = 0;
@@ -3163,32 +3169,17 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
const auto &area_of_use_auth_name = row[idx++];
const auto &area_of_use_code = row[idx++];
const auto &accuracy = row[idx++];
- const auto &step1_auth_name = row[idx++];
- const auto &step1_code = row[idx++];
- const auto &step2_auth_name = row[idx++];
- const auto &step2_code = row[idx++];
- const auto &step3_auth_name = row[idx++];
- const auto &step3_code = row[idx++];
const auto &operation_version = row[idx++];
const auto &deprecated_str = row[idx++];
const bool deprecated = deprecated_str == "1";
std::vector<operation::CoordinateOperationNNPtr> operations;
- operations.push_back(
- d->createFactory(step1_auth_name)
- ->createCoordinateOperation(step1_code, false,
- usePROJAlternativeGridNames,
- std::string()));
- operations.push_back(
- d->createFactory(step2_auth_name)
- ->createCoordinateOperation(step2_code, false,
- usePROJAlternativeGridNames,
- std::string()));
-
- if (!step3_auth_name.empty()) {
+ for (const auto &rowStep : resSteps) {
+ const auto &step_auth_name = rowStep[0];
+ const auto &step_code = rowStep[1];
operations.push_back(
- d->createFactory(step3_auth_name)
- ->createCoordinateOperation(step3_code, false,
+ d->createFactory(step_auth_name)
+ ->createCoordinateOperation(step_code, false,
usePROJAlternativeGridNames,
std::string()));
}