aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-10-04 01:13:43 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-10-04 01:13:43 +0200
commitae779eaa8264914a401f585f747a0f87fd5350e9 (patch)
treea82bfb05cf329f05fb2563389b9efe5f002595e9 /src
parent109f75c74ee9e251b9507aeb5f3add109042bd5f (diff)
downloadPROJ-ae779eaa8264914a401f585f747a0f87fd5350e9.tar.gz
PROJ-ae779eaa8264914a401f585f747a0f87fd5350e9.zip
Add a proj_crs_demote_to_2D(). Useful if forced to export a 3D CRS to a best approximate as WKT1 that doesn't support it
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/c_api.cpp42
-rw-r--r--src/iso19111/crs.cpp81
-rw-r--r--src/proj_experimental.h4
3 files changed, 127 insertions, 0 deletions
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index ac3a5f11..4fedbe05 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -3388,6 +3388,48 @@ PJ *proj_crs_create_projected_3D_crs_from_2D(PJ_CONTEXT *ctx,
// ---------------------------------------------------------------------------
+/** \brief Create a 2D CRS from an existing 3D CRS.
+ *
+ * See osgeo::proj::crs::CRS::demoteTo2D().
+ *
+ * The returned object must be unreferenced with proj_destroy() after
+ * use.
+ * It should be used by at most one thread at a time.
+ *
+ * @param ctx PROJ context, or NULL for default context
+ * @param crs_2D_name CRS name. Or NULL (in which case the name of crs_3D
+ * will be used)
+ * @param crs_3D 3D CRS to be "demoted" to 2D. Must not be NULL.
+ *
+ * @return Object that must be unreferenced with
+ * proj_destroy(), or NULL in case of error.
+ * @since 7.0
+ */
+PJ *proj_crs_demote_to_2D(PJ_CONTEXT *ctx, const char *crs_2D_name,
+ const PJ *crs_3D) {
+ SANITIZE_CTX(ctx);
+ auto cpp_3D_crs = dynamic_cast<const CRS *>(crs_3D->iso_obj.get());
+ if (!cpp_3D_crs) {
+ proj_log_error(ctx, __FUNCTION__, "crs_3D is not a CRS");
+ return nullptr;
+ }
+ try {
+ auto dbContext = getDBcontextNoException(ctx, __FUNCTION__);
+ return pj_obj_create(
+ ctx, cpp_3D_crs->demoteTo2D(crs_2D_name ? std::string(crs_2D_name)
+ : cpp_3D_crs->nameStr(),
+ dbContext));
+ } catch (const std::exception &e) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
+ return nullptr;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Instantiate a EngineeringCRS with just a name
*
* The returned object must be unreferenced with proj_destroy() after
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index d0e23f95..b98e5937 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -843,6 +843,49 @@ CRSNNPtr CRS::promoteTo3D(const std::string &newName,
return NN_NO_CHECK(
std::static_pointer_cast<CRS>(shared_from_this().as_nullable()));
}
+// ---------------------------------------------------------------------------
+
+/** \brief Return a variant of this CRS "demoted" to a 2D one, if not already
+ * the case.
+ *
+ *
+ * @param newName Name of the new CRS. If empty, nameStr() will be used.
+ * @param dbContext Database context to look for potentially already registered
+ * 2D CRS. May be nullptr.
+ * @return a new CRS demoted to 2D, or the current one if already 2D or not
+ * applicable.
+ * @since 7.0
+ */
+CRSNNPtr CRS::demoteTo2D(const std::string &newName,
+ const io::DatabaseContextPtr &dbContext) const {
+ const auto geogCRS = dynamic_cast<const GeographicCRS *>(this);
+ if (geogCRS) {
+ return geogCRS->demoteTo2D(newName, dbContext);
+ }
+
+ const auto projCRS = dynamic_cast<const ProjectedCRS *>(this);
+ if (projCRS) {
+ return projCRS->demoteTo2D(newName, dbContext);
+ }
+
+ const auto boundCRS = dynamic_cast<const BoundCRS *>(this);
+ if (boundCRS) {
+ return BoundCRS::create(
+ boundCRS->baseCRS()->demoteTo2D(newName, dbContext),
+ boundCRS->hubCRS(), boundCRS->transformation());
+ }
+
+ const auto compoundCRS = dynamic_cast<const CompoundCRS *>(this);
+ if (compoundCRS) {
+ const auto &components = compoundCRS->componentReferenceSystems();
+ if (components.size() >= 2) {
+ return components[0];
+ }
+ }
+
+ return NN_NO_CHECK(
+ std::static_pointer_cast<CRS>(shared_from_this().as_nullable()));
+}
// ---------------------------------------------------------------------------
@@ -3650,6 +3693,44 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const {
// ---------------------------------------------------------------------------
+/** \brief Return a variant of this CRS "demoted" to a 2D one, if not already
+ * the case.
+ *
+ *
+ * @param newName Name of the new CRS. If empty, nameStr() will be used.
+ * @param dbContext Database context to look for potentially already registered
+ * 2D CRS. May be nullptr.
+ * @return a new CRS demoted to 2D, or the current one if already 2D or not
+ * applicable.
+ * @since 7.0
+ */
+ProjectedCRSNNPtr
+ProjectedCRS::demoteTo2D(const std::string &newName,
+ const io::DatabaseContextPtr &dbContext) const {
+
+ const auto &axisList = coordinateSystem()->axisList();
+ if (axisList.size() == 3) {
+ auto cs = cs::CartesianCS::create(util::PropertyMap(), axisList[0],
+ axisList[1]);
+ const auto &l_baseCRS = baseCRS();
+ const auto geogCRS =
+ dynamic_cast<const GeographicCRS *>(l_baseCRS.get());
+ const auto newBaseCRS =
+ geogCRS ? util::nn_static_pointer_cast<GeodeticCRS>(
+ geogCRS->demoteTo2D(std::string(), dbContext))
+ : l_baseCRS;
+ return ProjectedCRS::create(
+ util::PropertyMap().set(common::IdentifiedObject::NAME_KEY,
+ !newName.empty() ? newName : nameStr()),
+ newBaseCRS, derivingConversionRef(), cs);
+ }
+
+ return NN_NO_CHECK(std::dynamic_pointer_cast<ProjectedCRS>(
+ shared_from_this().as_nullable()));
+}
+
+// ---------------------------------------------------------------------------
+
//! @cond Doxygen_Suppress
std::list<std::pair<CRSNNPtr, int>>
diff --git a/src/proj_experimental.h b/src/proj_experimental.h
index 9a1a6045..63b858d5 100644
--- a/src/proj_experimental.h
+++ b/src/proj_experimental.h
@@ -235,6 +235,10 @@ PJ PROJ_DLL *proj_crs_create_projected_3D_crs_from_2D(PJ_CONTEXT *ctx,
const PJ* projected_2D_crs,
const PJ* geog_3D_crs);
+PJ PROJ_DLL *proj_crs_demote_to_2D(PJ_CONTEXT *ctx,
+ const char* crs_2D_name,
+ const PJ* crs_3D);
+
PJ PROJ_DLL *proj_create_engineering_crs(PJ_CONTEXT *ctx,
const char *crsName);