aboutsummaryrefslogtreecommitdiff
path: root/src/iso19111
diff options
context:
space:
mode:
Diffstat (limited to 'src/iso19111')
-rw-r--r--src/iso19111/c_api.cpp43
-rw-r--r--src/iso19111/factory.cpp82
2 files changed, 125 insertions, 0 deletions
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index ce7f2ae2..f8d9e685 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -9162,3 +9162,46 @@ PROJ_STRING_LIST proj_get_insert_statements(
}
return nullptr;
}
+
+// ---------------------------------------------------------------------------
+
+/** \brief Returns a list of geoid models available for that crs
+ *
+ * The list includes the geoid models connected directly with the crs,
+ * or via "Height Depth Reversal" or "Change of Vertical Unit" transformations.
+ * The returned list is NULL terminated and must be freed with
+ * proj_string_list_destroy().
+ *
+ * @param ctx Context, or NULL for default context.
+ * @param auth_name Authority name (must not be NULL)
+ * @param code Object code (must not be NULL)
+ * @param options should be set to NULL for now
+ * @return list of geoid models names (to be freed with
+ * proj_string_list_destroy()), or NULL in case of error.
+ * @since 8.1
+ */
+PROJ_STRING_LIST
+proj_get_geoid_models_from_database(PJ_CONTEXT *ctx, const char *auth_name,
+ const char *code,
+ const char *const *options) {
+ SANITIZE_CTX(ctx);
+ if (!auth_name || !code) {
+ proj_context_errno_set(ctx, PROJ_ERR_OTHER_API_MISUSE);
+ proj_log_error(ctx, __FUNCTION__, "missing required input");
+ return nullptr;
+ }
+ (void)options;
+ try {
+ const std::string codeStr(code);
+ auto factory = AuthorityFactory::create(getDBcontext(ctx), auth_name);
+ auto geoidModels = factory->getGeoidModels(codeStr);
+ ctx->safeAutoCloseDbIfNeeded();
+ return to_string_list(std::move(geoidModels));
+ } catch (const std::exception &e) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ }
+ ctx->safeAutoCloseDbIfNeeded();
+ return nullptr;
+}
+
+// ---------------------------------------------------------------------------
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index fabf57e1..d95ccbf4 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -5765,6 +5765,88 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes(
// ---------------------------------------------------------------------------
+/** \brief Returns a list of geoid models available for that crs
+ *
+ * The list includes the geoid models connected directly with the crs,
+ * or via "Height Depth Reversal" or "Change of Vertical Unit" transformations
+ *
+ * @param code crs code allocated by authority.
+ * @return list of geoid model names
+ * @throw FactoryException
+ */
+
+std::list<std::string>
+AuthorityFactory::getGeoidModels(const std::string &code) const {
+
+ ListOfParams params;
+ std::string sql;
+ sql += "SELECT DISTINCT GM0.name "
+ " FROM geoid_model GM0 "
+ "INNER JOIN grid_transformation GT0 "
+ " ON GT0.code = GM0.operation_code "
+ " AND GT0.auth_name = GM0.operation_auth_name "
+ " AND GT0.target_crs_code = ? ";
+ params.emplace_back(code);
+ if (d->hasAuthorityRestriction()) {
+ sql += " AND GT0.target_crs_auth_name = ? ";
+ params.emplace_back(d->authority());
+ }
+
+ /// The second part of the query is for CRSs that use that geoid model via
+ /// Height Depth Reversal (EPSG:1068) or Change of Vertical Unit (EPSG:1069)
+ sql += "UNION "
+ "SELECT DISTINCT GM0.name "
+ " FROM geoid_model GM0 "
+ "INNER JOIN grid_transformation GT1 "
+ " ON GT1.code = GM0.operation_code "
+ " AND GT1.auth_name = GM0.operation_auth_name "
+ "INNER JOIN other_transformation OT1 "
+ " ON OT1.source_crs_code = GT1.target_crs_code "
+ " AND OT1.source_crs_auth_name = GT1.target_crs_auth_name "
+ " AND OT1.method_auth_name = 'EPSG' "
+ " AND OT1.method_code IN (1068, 1069, 1104) "
+ " AND OT1.target_crs_code = ? ";
+ params.emplace_back(code);
+ if (d->hasAuthorityRestriction()) {
+ sql += " AND OT1.target_crs_auth_name = ? ";
+ params.emplace_back(d->authority());
+ }
+
+ /// The third part of the query is for CRSs that use that geoid model via
+ /// other_transformation table twice, like transforming depth and feet
+ sql += "UNION "
+ "SELECT DISTINCT GM0.name "
+ " FROM geoid_model GM0 "
+ "INNER JOIN grid_transformation GT1 "
+ " ON GT1.code = GM0.operation_code "
+ " AND GT1.auth_name = GM0.operation_auth_name "
+ "INNER JOIN other_transformation OT1 "
+ " ON OT1.source_crs_code = GT1.target_crs_code "
+ " AND OT1.source_crs_auth_name = GT1.target_crs_auth_name "
+ " AND OT1.method_auth_name = 'EPSG' "
+ " AND OT1.method_code IN (1068, 1069, 1104) "
+ "INNER JOIN other_transformation OT2 "
+ " ON OT2.source_crs_code = OT1.target_crs_code "
+ " AND OT2.source_crs_auth_name = OT1.target_crs_auth_name "
+ " AND OT2.method_code IN (1068, 1069, 1104) "
+ " AND OT2.target_crs_code = ? ";
+ params.emplace_back(code);
+ if (d->hasAuthorityRestriction()) {
+ sql += " AND OT2.target_crs_auth_name = ? ";
+ params.emplace_back(d->authority());
+ }
+ sql += " ORDER BY 1 ";
+
+ auto sqlRes = d->run(sql, params);
+ std::list<std::string> res;
+ for (const auto &row : sqlRes) {
+ res.push_back(row[0]);
+ }
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Returns a list operation::CoordinateOperation between two CRS.
*
* The list is ordered with preferred operations first. No attempt is made