diff options
| author | Even Rouault <even.rouault@mines-paris.org> | 2018-12-03 17:20:48 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-03 17:20:48 +0100 |
| commit | d0506e19a71888f7f0c3aa8618d919624e754c4d (patch) | |
| tree | 4468cd5ef29f3f7f6ce2ed950b5d1938cfbf84b5 /src | |
| parent | 4794d755a8dea4f4501c61e896e1829bb720e69a (diff) | |
| parent | ba111ac8323ff194039a06db87d1fb17ed8175b3 (diff) | |
| download | PROJ-d0506e19a71888f7f0c3aa8618d919624e754c4d.tar.gz PROJ-d0506e19a71888f7f0c3aa8618d919624e754c4d.zip | |
Merge pull request #1182 from rouault/plug_new_code
Remove data/epsg, IGNF and esri.* files / support legacy +init=epsg:XXXX syntax
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/bin_cs2cs.cmake | 2 | ||||
| -rw-r--r-- | src/c_api.cpp | 4720 | ||||
| -rw-r--r-- | src/coordinateoperation.cpp | 362 | ||||
| -rw-r--r-- | src/coordinatesystem.cpp | 97 | ||||
| -rw-r--r-- | src/crs.cpp | 313 | ||||
| -rw-r--r-- | src/cs2cs.c | 463 | ||||
| -rw-r--r-- | src/cs2cs.cpp | 636 | ||||
| -rw-r--r-- | src/emess.h | 8 | ||||
| -rw-r--r-- | src/factory.cpp | 47 | ||||
| -rw-r--r-- | src/gie.c | 646 | ||||
| -rw-r--r-- | src/io.cpp | 802 | ||||
| -rw-r--r-- | src/lib_proj.cmake | 3 | ||||
| -rw-r--r-- | src/pj_apply_gridshift.c | 2 | ||||
| -rw-r--r-- | src/pj_ctx.c | 3 | ||||
| -rw-r--r-- | src/pj_fwd.c | 9 | ||||
| -rw-r--r-- | src/pj_init.c | 102 | ||||
| -rw-r--r-- | src/pj_transform.c | 6 | ||||
| -rw-r--r-- | src/proj.h | 875 | ||||
| -rw-r--r-- | src/proj_4D_api.c | 234 | ||||
| -rw-r--r-- | src/proj_experimental.h | 831 | ||||
| -rw-r--r-- | src/proj_symbol_rename.h | 12 | ||||
| -rw-r--r-- | src/projects.h | 13 | ||||
| -rw-r--r-- | src/projinfo.cpp | 68 | ||||
| -rw-r--r-- | src/rtodms.c | 7 |
25 files changed, 6611 insertions, 3654 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 81524e82..99158f02 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ @JNI_INCLUDE@ -I$(top_srcdir)/include @SQLITE3_FLAGS@ AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@ -DPROJ_COMPILATION -include_HEADERS = proj.h proj_constants.h proj_api.h geodesic.h \ +include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \ org_proj4_PJ.h proj_symbol_rename.h EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ @@ -19,7 +19,7 @@ EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ proj_SOURCES = proj.c gen_cheb.c p_series.c projinfo_SOURCES = projinfo.cpp -cs2cs_SOURCES = cs2cs.c gen_cheb.c p_series.c +cs2cs_SOURCES = cs2cs.cpp gen_cheb.c p_series.c cct_SOURCES = cct.c proj_strtod.c proj_strtod.h optargpm.h nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h diff --git a/src/bin_cs2cs.cmake b/src/bin_cs2cs.cmake index bdb16e1a..9c013dcc 100644 --- a/src/bin_cs2cs.cmake +++ b/src/bin_cs2cs.cmake @@ -1,4 +1,4 @@ -set(CS2CS_SRC cs2cs.c +set(CS2CS_SRC cs2cs.cpp gen_cheb.c p_series.c) diff --git a/src/c_api.cpp b/src/c_api.cpp index fbba0f51..7a991765 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -39,6 +39,7 @@ #include "proj/common.hpp" #include "proj/coordinateoperation.hpp" +#include "proj/coordinatesystem.hpp" #include "proj/crs.hpp" #include "proj/datum.hpp" #include "proj/io.hpp" @@ -51,11 +52,13 @@ // clang-format off #include "proj_internal.h" #include "proj.h" +#include "proj_experimental.h" #include "projects.h" // clang-format on using namespace NS_PROJ::common; using namespace NS_PROJ::crs; +using namespace NS_PROJ::cs; using namespace NS_PROJ::datum; using namespace NS_PROJ::io; using namespace NS_PROJ::internal; @@ -90,19 +93,16 @@ static void PROJ_NO_INLINE proj_log_debug(PJ_CONTEXT *ctx, const char *function, * Operation. Should be used by at most one thread at a time. */ struct PJ_OBJ { //! @cond Doxygen_Suppress - PJ_CONTEXT *ctx; IdentifiedObjectNNPtr obj; // cached results - std::string lastWKT{}; - std::string lastPROJString{}; - bool gridsNeededAsked = false; - std::vector<GridDescription> gridsNeeded{}; + mutable std::string lastWKT{}; + mutable std::string lastPROJString{}; + mutable bool gridsNeededAsked = false; + mutable std::vector<GridDescription> gridsNeeded{}; - explicit PJ_OBJ(PJ_CONTEXT *ctxIn, const IdentifiedObjectNNPtr &objIn) - : ctx(ctxIn), obj(objIn) {} - static PJ_OBJ *create(PJ_CONTEXT *ctxIn, - const IdentifiedObjectNNPtr &objIn); + explicit PJ_OBJ(const IdentifiedObjectNNPtr &objIn) : obj(objIn) {} + static PJ_OBJ *create(const IdentifiedObjectNNPtr &objIn); PJ_OBJ(const PJ_OBJ &) = delete; PJ_OBJ &operator=(const PJ_OBJ &) = delete; @@ -110,8 +110,8 @@ struct PJ_OBJ { }; //! @cond Doxygen_Suppress -PJ_OBJ *PJ_OBJ::create(PJ_CONTEXT *ctxIn, const IdentifiedObjectNNPtr &objIn) { - return new PJ_OBJ(ctxIn, objIn); +PJ_OBJ *PJ_OBJ::create(const IdentifiedObjectNNPtr &objIn) { + return new PJ_OBJ(objIn); } //! @endcond @@ -120,12 +120,10 @@ PJ_OBJ *PJ_OBJ::create(PJ_CONTEXT *ctxIn, const IdentifiedObjectNNPtr &objIn) { /** \brief Opaque object representing a set of operation results. */ struct PJ_OBJ_LIST { //! @cond Doxygen_Suppress - PJ_CONTEXT *ctx; std::vector<IdentifiedObjectNNPtr> objects; - explicit PJ_OBJ_LIST(PJ_CONTEXT *ctxIn, - std::vector<IdentifiedObjectNNPtr> &&objectsIn) - : ctx(ctxIn), objects(std::move(objectsIn)) {} + explicit PJ_OBJ_LIST(std::vector<IdentifiedObjectNNPtr> &&objectsIn) + : objects(std::move(objectsIn)) {} PJ_OBJ_LIST(const PJ_OBJ_LIST &) = delete; PJ_OBJ_LIST &operator=(const PJ_OBJ_LIST &) = delete; @@ -140,11 +138,11 @@ struct PJ_OBJ_LIST { struct projCppContext { DatabaseContextNNPtr databaseContext; - explicit projCppContext(PJ_CONTEXT *ctxt, const char *dbPath = nullptr, + explicit projCppContext(PJ_CONTEXT *ctx, const char *dbPath = nullptr, const char *const *auxDbPaths = nullptr) : databaseContext(DatabaseContext::create( dbPath ? dbPath : std::string(), toVector(auxDbPaths))) { - databaseContext->attachPJContext(ctxt); + databaseContext->attachPJContext(ctx); } static std::vector<std::string> toVector(const char *const *auxDbPaths) { @@ -250,6 +248,28 @@ const char *proj_context_get_database_path(PJ_CONTEXT *ctx) { // --------------------------------------------------------------------------- +/** \brief Return a metadata from the database. + * + * The returned pointer remains valid while ctx is valid, and until + * proj_context_get_database_metadata() is called. + * + * @param ctx PROJ context, or NULL for default context + * @param key Metadata key. Must not be NULL + * @return value, or nullptr + */ +const char *proj_context_get_database_metadata(PJ_CONTEXT *ctx, + const char *key) { + SANITIZE_CTX(ctx); + try { + return getDBcontext(ctx)->getMetadata(key); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + /** \brief Guess the "dialect" of the WKT string. * * @param ctx PROJ context, or NULL for default context @@ -276,6 +296,43 @@ PJ_GUESSED_WKT_DIALECT proj_context_guess_wkt_dialect(PJ_CONTEXT *ctx, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +static const char *getOptionValue(const char *option, + const char *keyWithEqual) noexcept { + if (ci_starts_with(option, keyWithEqual)) { + return option + strlen(keyWithEqual); + } + return nullptr; +} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief "Clone" an object. + * + * Technically this just increases the reference counter on the object, since + * PJ_OBJ objects are immutable. + * + * The returned object must be unreferenced with proj_obj_unref() after use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object to clone. Must not be NULL. + * @return Object that must be unreferenced with proj_obj_unref(), or NULL in + * case of error. + */ +PJ_OBJ *proj_obj_clone(PJ_CONTEXT *ctx, const PJ_OBJ *obj) { + SANITIZE_CTX(ctx); + try { + return PJ_OBJ::create(obj->obj); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + /** \brief Instanciate an object from a WKT string, PROJ string or object code * (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", * "urn:ogc:def:coordinateOperation:EPSG::1671"). @@ -287,7 +344,17 @@ PJ_GUESSED_WKT_DIALECT proj_context_guess_wkt_dialect(PJ_CONTEXT *ctx, * * @param ctx PROJ context, or NULL for default context * @param text String (must not be NULL) - * @param options should be set to NULL for now + * @param options null-terminated list of options, or NULL. Currently + * supported options are: + * <ul> + * <li>USE_PROJ4_INIT_RULES=YES/NO. Defaults to NO. When set to YES, + * init=epsg:XXXX syntax will be allowed and will be interpreted according to + * PROJ.4 and PROJ.5 rules, that is geodeticCRS will have longitude, latitude + * order and will expect/output coordinates in radians. ProjectedCRS will have + * easting, northing axis order (except the ones with Transverse Mercator South + * Orientated projection). In that mode, the epsg:XXXX syntax will be also + * interprated the same way.</li> + * </ul> * @return Object that must be unreferenced with proj_obj_unref(), or NULL in * case of error. */ @@ -298,10 +365,22 @@ PJ_OBJ *proj_obj_create_from_user_input(PJ_CONTEXT *ctx, const char *text, (void)options; auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); try { + bool usePROJ4InitRules = false; + for (auto iter = options; iter && iter[0]; ++iter) { + const char *value; + if ((value = getOptionValue(*iter, "USE_PROJ4_INIT_RULES="))) { + usePROJ4InitRules = ci_equal(value, "YES"); + } else { + std::string msg("Unknown option :"); + msg += *iter; + proj_log_error(ctx, __FUNCTION__, msg.c_str()); + return nullptr; + } + } auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( - createFromUserInput(text, dbContext)); + createFromUserInput(text, dbContext, usePROJ4InitRules)); if (identifiedObject) { - return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + return PJ_OBJ::create(NN_NO_CHECK(identifiedObject)); } } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); @@ -330,10 +409,15 @@ PJ_OBJ *proj_obj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt, assert(wkt); (void)options; try { + WKTParser parser; + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + if (dbContext) { + parser.attachDatabaseContext(NN_NO_CHECK(dbContext)); + } auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( - WKTParser().createFromWKT(wkt)); + parser.createFromWKT(wkt)); if (identifiedObject) { - return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + return PJ_OBJ::create(NN_NO_CHECK(identifiedObject)); } } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); @@ -363,10 +447,15 @@ PJ_OBJ *proj_obj_create_from_proj_string(PJ_CONTEXT *ctx, (void)options; assert(proj_string); try { + PROJStringParser parser; + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + if (dbContext) { + parser.attachDatabaseContext(NN_NO_CHECK(dbContext)); + } auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( - PROJStringParser().createFromPROJString(proj_string)); + parser.createFromPROJString(proj_string)); if (identifiedObject) { - return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + return PJ_OBJ::create(NN_NO_CHECK(identifiedObject)); } } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); @@ -423,7 +512,7 @@ PJ_OBJ *proj_obj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, .as_nullable(); break; } - return PJ_OBJ::create(ctx, NN_NO_CHECK(obj)); + return PJ_OBJ::create(NN_NO_CHECK(obj)); } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); } @@ -503,6 +592,10 @@ convertPJObjectTypeToObjectType(PJ_OBJ_TYPE type, bool &valid) { cppType = AuthorityFactory::ObjectType::COMPOUND_CRS; break; + case PJ_OBJ_TYPE_ENGINEERING_CRS: + valid = false; + break; + case PJ_OBJ_TYPE_TEMPORAL_CRS: valid = false; break; @@ -586,7 +679,7 @@ PJ_OBJ_LIST *proj_obj_create_from_name(PJ_CONTEXT *ctx, const char *auth_name, for (const auto &obj : res) { objects.push_back(obj); } - return new PJ_OBJ_LIST(ctx, std::move(objects)); + return new PJ_OBJ_LIST(std::move(objects)); } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); } @@ -600,7 +693,7 @@ PJ_OBJ_LIST *proj_obj_create_from_name(PJ_CONTEXT *ctx, const char *auth_name, * @param obj Object (must not be NULL) * @return its type. */ -PJ_OBJ_TYPE proj_obj_get_type(PJ_OBJ *obj) { +PJ_OBJ_TYPE proj_obj_get_type(const PJ_OBJ *obj) { assert(obj); auto ptr = obj->obj.get(); if (dynamic_cast<Ellipsoid *>(ptr)) { @@ -657,6 +750,9 @@ PJ_OBJ_TYPE proj_obj_get_type(PJ_OBJ *obj) { if (dynamic_cast<TemporalCRS *>(ptr)) { return PJ_OBJ_TYPE_TEMPORAL_CRS; } + if (dynamic_cast<EngineeringCRS *>(ptr)) { + return PJ_OBJ_TYPE_ENGINEERING_CRS; + } if (dynamic_cast<BoundCRS *>(ptr)) { return PJ_OBJ_TYPE_BOUND_CRS; } @@ -687,7 +783,7 @@ PJ_OBJ_TYPE proj_obj_get_type(PJ_OBJ *obj) { * @param obj Object (must not be NULL) * @return TRUE if it is deprecated, FALSE otherwise */ -int proj_obj_is_deprecated(PJ_OBJ *obj) { +int proj_obj_is_deprecated(const PJ_OBJ *obj) { assert(obj); return obj->obj->isDeprecated(); } @@ -701,7 +797,7 @@ int proj_obj_is_deprecated(PJ_OBJ *obj) { * @param criterion Comparison criterion * @return TRUE if they are equivalent */ -int proj_obj_is_equivalent_to(PJ_OBJ *obj, PJ_OBJ *other, +int proj_obj_is_equivalent_to(const PJ_OBJ *obj, const PJ_OBJ *other, PJ_COMPARISON_CRITERION criterion) { assert(obj); assert(other); @@ -738,7 +834,7 @@ int proj_obj_is_equivalent_to(PJ_OBJ *obj, PJ_OBJ *other, * * @param obj Object (must not be NULL) */ -int proj_obj_is_crs(PJ_OBJ *obj) { +int proj_obj_is_crs(const PJ_OBJ *obj) { assert(obj); return dynamic_cast<CRS *>(obj->obj.get()) != nullptr; } @@ -752,7 +848,7 @@ int proj_obj_is_crs(PJ_OBJ *obj) { * @param obj Object (must not be NULL) * @return a string, or NULL in case of error or missing name. */ -const char *proj_obj_get_name(PJ_OBJ *obj) { +const char *proj_obj_get_name(const PJ_OBJ *obj) { assert(obj); const auto &desc = obj->obj->name()->description(); if (!desc.has_value()) { @@ -773,7 +869,7 @@ const char *proj_obj_get_name(PJ_OBJ *obj) { * @param index Index of the identifier. 0 = first identifier * @return a string, or NULL in case of error or missing name. */ -const char *proj_obj_get_id_auth_name(PJ_OBJ *obj, int index) { +const char *proj_obj_get_id_auth_name(const PJ_OBJ *obj, int index) { assert(obj); const auto &ids = obj->obj->identifiers(); if (static_cast<size_t>(index) >= ids.size()) { @@ -798,7 +894,7 @@ const char *proj_obj_get_id_auth_name(PJ_OBJ *obj, int index) { * @param index Index of the identifier. 0 = first identifier * @return a string, or NULL in case of error or missing name. */ -const char *proj_obj_get_id_code(PJ_OBJ *obj, int index) { +const char *proj_obj_get_id_code(const PJ_OBJ *obj, int index) { assert(obj); const auto &ids = obj->obj->identifiers(); if (static_cast<size_t>(index) >= ids.size()) { @@ -809,18 +905,6 @@ const char *proj_obj_get_id_code(PJ_OBJ *obj, int index) { // --------------------------------------------------------------------------- -//! @cond Doxygen_Suppress -static const char *getOptionValue(const char *option, - const char *keyWithEqual) noexcept { - if (ci_starts_with(option, keyWithEqual)) { - return option + strlen(keyWithEqual); - } - return nullptr; -} -//! @endcond - -// --------------------------------------------------------------------------- - /** \brief Get a WKT representation of an object. * * The returned string is valid while the input obj parameter is valid, @@ -831,6 +915,7 @@ static const char *getOptionValue(const char *option, * This function may return NULL if the object is not compatible with an * export to the requested type. * + * @param ctx PROJ context, or NULL for default context * @param obj Object (must not be NULL) * @param type WKT version. * @param options null-terminated list of options, or NULL. Currently @@ -846,8 +931,9 @@ static const char *getOptionValue(const char *option, * </ul> * @return a string, or NULL in case of error. */ -const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, - const char *const *options) { +const char *proj_obj_as_wkt(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + PJ_WKT_TYPE type, const char *const *options) { + SANITIZE_CTX(ctx); assert(obj); // Make sure that the C and C++ enumerations match @@ -885,7 +971,8 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, const WKTFormatter::Convention convention = static_cast<WKTFormatter::Convention>(type); try { - auto formatter = WKTFormatter::create(convention); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + auto formatter = WKTFormatter::create(convention, dbContext); for (auto iter = options; iter && iter[0]; ++iter) { const char *value; if ((value = getOptionValue(*iter, "MULTILINE="))) { @@ -902,14 +989,14 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, } else { std::string msg("Unknown option :"); msg += *iter; - proj_log_error(obj->ctx, __FUNCTION__, msg.c_str()); + proj_log_error(ctx, __FUNCTION__, msg.c_str()); return nullptr; } } obj->lastWKT = obj->obj->exportToWKT(formatter.get()); return obj->lastWKT.c_str(); } catch (const std::exception &e) { - proj_log_error(obj->ctx, __FUNCTION__, e.what()); + proj_log_error(ctx, __FUNCTION__, e.what()); return nullptr; } } @@ -928,6 +1015,7 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, * This function may return NULL if the object is not compatible with an * export to the requested type. * + * @param ctx PROJ context, or NULL for default context * @param obj Object (must not be NULL) * @param type PROJ String version. * @param options NULL-terminated list of strings with "KEY=VALUE" format. or @@ -937,14 +1025,15 @@ const char *proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, * use of etmerc by utm conversions) * @return a string, or NULL in case of error. */ -const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type, +const char *proj_obj_as_proj_string(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + PJ_PROJ_STRING_TYPE type, const char *const *options) { + SANITIZE_CTX(ctx); assert(obj); auto exportable = dynamic_cast<const IPROJStringExportable *>(obj->obj.get()); if (!exportable) { - proj_log_error(obj->ctx, __FUNCTION__, - "Object type not exportable to PROJ"); + proj_log_error(ctx, __FUNCTION__, "Object type not exportable to PROJ"); return nullptr; } // Make sure that the C and C++ enumeration match @@ -963,7 +1052,7 @@ const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type, } const PROJStringFormatter::Convention convention = static_cast<PROJStringFormatter::Convention>(type); - auto dbContext = getDBcontextNoException(obj->ctx, __FUNCTION__); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); try { auto formatter = PROJStringFormatter::create(convention, dbContext); if (options != nullptr && options[0] != nullptr) { @@ -976,7 +1065,7 @@ const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type, obj->lastPROJString = exportable->exportToPROJString(formatter.get()); return obj->lastPROJString.c_str(); } catch (const std::exception &e) { - proj_log_error(obj->ctx, __FUNCTION__, e.what()); + proj_log_error(ctx, __FUNCTION__, e.what()); return nullptr; } } @@ -985,29 +1074,34 @@ const char *proj_obj_as_proj_string(PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type, /** \brief Return the area of use of an object. * + * @param ctx PROJ context, or NULL for default context * @param obj Object (must not be NULL) - * @param p_west_lon Pointer to a double to receive the west longitude (in - * degrees). Or NULL. If the returned value is -1000, the bounding box is + * @param out_west_lon_degree Pointer to a double to receive the west longitude + * (in degrees). Or NULL. If the returned value is -1000, the bounding box is * unknown. - * @param p_south_lat Pointer to a double to receive the south latitude (in - * degrees). Or NULL. If the returned value is -1000, the bounding box is + * @param out_south_lat_degree Pointer to a double to receive the south latitude + * (in degrees). Or NULL. If the returned value is -1000, the bounding box is * unknown. - * @param p_east_lon Pointer to a double to receive the east longitude (in - * degrees). Or NULL. If the returned value is -1000, the bounding box is + * @param out_east_lon_degree Pointer to a double to receive the east longitude + * (in degrees). Or NULL. If the returned value is -1000, the bounding box is * unknown. - * @param p_north_lat Pointer to a double to receive the north latitude (in - * degrees). Or NULL. If the returned value is -1000, the bounding box is + * @param out_north_lat_degree Pointer to a double to receive the north latitude + * (in degrees). Or NULL. If the returned value is -1000, the bounding box is * unknown. - * @param p_area_name Pointer to a string to receive the name of the area of + * @param out_area_name Pointer to a string to receive the name of the area of * use. Or NULL. *p_area_name is valid while obj is valid itself. * @return TRUE in case of success, FALSE in case of error or if the area * of use is unknown. */ -int proj_obj_get_area_of_use(PJ_OBJ *obj, double *p_west_lon, - double *p_south_lat, double *p_east_lon, - double *p_north_lat, const char **p_area_name) { - if (p_area_name) { - *p_area_name = nullptr; +int proj_obj_get_area_of_use(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + double *out_west_lon_degree, + double *out_south_lat_degree, + double *out_east_lon_degree, + double *out_north_lat_degree, + const char **out_area_name) { + (void)ctx; + if (out_area_name) { + *out_area_name = nullptr; } auto objectUsage = dynamic_cast<const ObjectUsage *>(obj->obj.get()); if (!objectUsage) { @@ -1022,8 +1116,8 @@ int proj_obj_get_area_of_use(PJ_OBJ *obj, double *p_west_lon, return false; } const auto &desc = extent->description(); - if (desc.has_value() && p_area_name) { - *p_area_name = desc->c_str(); + if (desc.has_value() && out_area_name) { + *out_area_name = desc->c_str(); } const auto &geogElements = extent->geographicElements(); @@ -1031,48 +1125,49 @@ int proj_obj_get_area_of_use(PJ_OBJ *obj, double *p_west_lon, auto bbox = dynamic_cast<const GeographicBoundingBox *>(geogElements[0].get()); if (bbox) { - if (p_west_lon) { - *p_west_lon = bbox->westBoundLongitude(); + if (out_west_lon_degree) { + *out_west_lon_degree = bbox->westBoundLongitude(); } - if (p_south_lat) { - *p_south_lat = bbox->southBoundLatitude(); + if (out_south_lat_degree) { + *out_south_lat_degree = bbox->southBoundLatitude(); } - if (p_east_lon) { - *p_east_lon = bbox->eastBoundLongitude(); + if (out_east_lon_degree) { + *out_east_lon_degree = bbox->eastBoundLongitude(); } - if (p_north_lat) { - *p_north_lat = bbox->northBoundLatitude(); + if (out_north_lat_degree) { + *out_north_lat_degree = bbox->northBoundLatitude(); } return true; } } - if (p_west_lon) { - *p_west_lon = -1000; + if (out_west_lon_degree) { + *out_west_lon_degree = -1000; } - if (p_south_lat) { - *p_south_lat = -1000; + if (out_south_lat_degree) { + *out_south_lat_degree = -1000; } - if (p_east_lon) { - *p_east_lon = -1000; + if (out_east_lon_degree) { + *out_east_lon_degree = -1000; } - if (p_north_lat) { - *p_north_lat = -1000; + if (out_north_lat_degree) { + *out_north_lat_degree = -1000; } return true; } // --------------------------------------------------------------------------- -static const GeodeticCRS *extractGeodeticCRS(PJ_OBJ *crs, const char *fname) { +static const GeodeticCRS *extractGeodeticCRS(PJ_CONTEXT *ctx, const PJ_OBJ *crs, + const char *fname) { assert(crs); auto l_crs = dynamic_cast<const CRS *>(crs->obj.get()); if (!l_crs) { - proj_log_error(crs->ctx, fname, "Object is not a CRS"); + proj_log_error(ctx, fname, "Object is not a CRS"); return nullptr; } auto geodCRS = l_crs->extractGeodeticCRSRaw(); if (!geodCRS) { - proj_log_error(crs->ctx, fname, "CRS has no geodetic CRS"); + proj_log_error(ctx, fname, "CRS has no geodetic CRS"); } return geodCRS; } @@ -1085,18 +1180,19 @@ static const GeodeticCRS *extractGeodeticCRS(PJ_OBJ *crs, const char *fname) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param crs Objet of type CRS (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_crs_get_geodetic_crs(PJ_OBJ *crs) { - auto geodCRS = extractGeodeticCRS(crs, __FUNCTION__); +PJ_OBJ *proj_obj_crs_get_geodetic_crs(PJ_CONTEXT *ctx, const PJ_OBJ *crs) { + SANITIZE_CTX(ctx); + auto geodCRS = extractGeodeticCRS(ctx, crs, __FUNCTION__); if (!geodCRS) { return nullptr; } - return PJ_OBJ::create(crs->ctx, - NN_NO_CHECK(nn_dynamic_pointer_cast<IdentifiedObject>( - geodCRS->shared_from_this()))); + return PJ_OBJ::create(NN_NO_CHECK(nn_dynamic_pointer_cast<IdentifiedObject>( + geodCRS->shared_from_this()))); } // --------------------------------------------------------------------------- @@ -1107,24 +1203,75 @@ PJ_OBJ *proj_obj_crs_get_geodetic_crs(PJ_OBJ *crs) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param crs Objet of type CRS (must not be NULL) * @param index Index of the CRS component (typically 0 = horizontal, 1 = * vertical) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_crs_get_sub_crs(PJ_OBJ *crs, int index) { +PJ_OBJ *proj_obj_crs_get_sub_crs(PJ_CONTEXT *ctx, const PJ_OBJ *crs, + int index) { + SANITIZE_CTX(ctx); assert(crs); auto l_crs = dynamic_cast<CompoundCRS *>(crs->obj.get()); if (!l_crs) { - proj_log_error(crs->ctx, __FUNCTION__, "Object is not a CompoundCRS"); + proj_log_error(ctx, __FUNCTION__, "Object is not a CompoundCRS"); return nullptr; } const auto &components = l_crs->componentReferenceSystems(); if (static_cast<size_t>(index) >= components.size()) { return nullptr; } - return PJ_OBJ::create(crs->ctx, components[index]); + return PJ_OBJ::create(components[index]); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns a BoundCRS + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param base_crs Base CRS (must not be NULL) + * @param hub_crs Hub CRS (must not be NULL) + * @param transformation Transformation (must not be NULL) + * @return Object that must be unreferenced with proj_obj_unref(), or NULL + * in case of error. + */ +PJ_OBJ *proj_obj_crs_create_bound_crs(PJ_CONTEXT *ctx, const PJ_OBJ *base_crs, + const PJ_OBJ *hub_crs, + const PJ_OBJ *transformation) { + SANITIZE_CTX(ctx); + assert(base_crs); + assert(hub_crs); + assert(transformation); + auto l_base_crs = util::nn_dynamic_pointer_cast<CRS>(base_crs->obj); + if (!l_base_crs) { + proj_log_error(ctx, __FUNCTION__, "base_crs is not a CRS"); + return nullptr; + } + auto l_hub_crs = util::nn_dynamic_pointer_cast<CRS>(hub_crs->obj); + if (!l_hub_crs) { + proj_log_error(ctx, __FUNCTION__, "hub_crs is not a CRS"); + return nullptr; + } + auto l_transformation = + util::nn_dynamic_pointer_cast<Transformation>(transformation->obj); + if (!l_transformation) { + proj_log_error(ctx, __FUNCTION__, "transformation is not a CRS"); + return nullptr; + } + try { + return PJ_OBJ::create(BoundCRS::create(NN_NO_CHECK(l_base_crs), + NN_NO_CHECK(l_hub_crs), + NN_NO_CHECK(l_transformation))); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } } // --------------------------------------------------------------------------- @@ -1139,20 +1286,28 @@ PJ_OBJ *proj_obj_crs_get_sub_crs(PJ_OBJ *crs, int index) { * This is the same as method * osgeo::proj::crs::CRS::createBoundCRSToWGS84IfPossible() * + * @param ctx PROJ context, or NULL for default context * @param crs Objet of type CRS (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_crs_create_bound_crs_to_WGS84(PJ_OBJ *crs) { +PJ_OBJ *proj_obj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx, + const PJ_OBJ *crs) { + SANITIZE_CTX(ctx); assert(crs); auto l_crs = dynamic_cast<const CRS *>(crs->obj.get()); if (!l_crs) { - proj_log_error(crs->ctx, __FUNCTION__, "Object is not a CRS"); + proj_log_error(ctx, __FUNCTION__, "Object is not a CRS"); + return nullptr; + } + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + try { + return PJ_OBJ::create( + l_crs->createBoundCRSToWGS84IfPossible(dbContext)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); return nullptr; } - auto dbContext = getDBcontextNoException(crs->ctx, __FUNCTION__); - return PJ_OBJ::create(crs->ctx, - l_crs->createBoundCRSToWGS84IfPossible(dbContext)); } // --------------------------------------------------------------------------- @@ -1163,24 +1318,26 @@ PJ_OBJ *proj_obj_crs_create_bound_crs_to_WGS84(PJ_OBJ *crs) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param obj Objet of type CRS or GeodeticReferenceFrame (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_get_ellipsoid(PJ_OBJ *obj) { +PJ_OBJ *proj_obj_get_ellipsoid(PJ_CONTEXT *ctx, const PJ_OBJ *obj) { + SANITIZE_CTX(ctx); auto ptr = obj->obj.get(); if (dynamic_cast<const CRS *>(ptr)) { - auto geodCRS = extractGeodeticCRS(obj, __FUNCTION__); + auto geodCRS = extractGeodeticCRS(ctx, obj, __FUNCTION__); if (geodCRS) { - return PJ_OBJ::create(obj->ctx, geodCRS->ellipsoid()); + return PJ_OBJ::create(geodCRS->ellipsoid()); } } else { auto datum = dynamic_cast<const GeodeticReferenceFrame *>(ptr); if (datum) { - return PJ_OBJ::create(obj->ctx, datum->ellipsoid()); + return PJ_OBJ::create(datum->ellipsoid()); } } - proj_log_error(obj->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a CRS or GeodeticReferenceFrame"); return nullptr; } @@ -1193,25 +1350,27 @@ PJ_OBJ *proj_obj_get_ellipsoid(PJ_OBJ *obj) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param crs Objet of type CRS (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_crs_get_horizontal_datum(PJ_OBJ *crs) { - auto geodCRS = extractGeodeticCRS(crs, __FUNCTION__); +PJ_OBJ *proj_obj_crs_get_horizontal_datum(PJ_CONTEXT *ctx, const PJ_OBJ *crs) { + SANITIZE_CTX(ctx); + auto geodCRS = extractGeodeticCRS(ctx, crs, __FUNCTION__); if (!geodCRS) { return nullptr; } const auto &datum = geodCRS->datum(); if (datum) { - return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(datum)); + return PJ_OBJ::create(NN_NO_CHECK(datum)); } const auto &datumEnsemble = geodCRS->datumEnsemble(); if (datumEnsemble) { - return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(datumEnsemble)); + return PJ_OBJ::create(NN_NO_CHECK(datumEnsemble)); } - proj_log_error(crs->ctx, __FUNCTION__, "CRS has no datum"); + proj_log_error(ctx, __FUNCTION__, "CRS has no datum"); return nullptr; } @@ -1219,42 +1378,48 @@ PJ_OBJ *proj_obj_crs_get_horizontal_datum(PJ_OBJ *crs) { /** \brief Return ellipsoid parameters. * + * @param ctx PROJ context, or NULL for default context * @param ellipsoid Object of type Ellipsoid (must not be NULL) - * @param pSemiMajorMetre Pointer to a value to store the semi-major axis in + * @param out_semi_major_metre Pointer to a value to store the semi-major axis + * in * metre. or NULL - * @param pSemiMinorMetre Pointer to a value to store the semi-minor axis in + * @param out_semi_minor_metre Pointer to a value to store the semi-minor axis + * in * metre. or NULL - * @param pIsSemiMinorComputed Pointer to a boolean value to indicate if the + * @param out_is_semi_minor_computed Pointer to a boolean value to indicate if + * the * semi-minor value was computed. If FALSE, its value comes from the * definition. or NULL - * @param pInverseFlattening Pointer to a value to store the inverse + * @param out_inv_flattening Pointer to a value to store the inverse * flattening. or NULL * @return TRUE in case of success. */ -int proj_obj_ellipsoid_get_parameters(PJ_OBJ *ellipsoid, - double *pSemiMajorMetre, - double *pSemiMinorMetre, - int *pIsSemiMinorComputed, - double *pInverseFlattening) { +int proj_obj_ellipsoid_get_parameters(PJ_CONTEXT *ctx, const PJ_OBJ *ellipsoid, + double *out_semi_major_metre, + double *out_semi_minor_metre, + int *out_is_semi_minor_computed, + double *out_inv_flattening) { + SANITIZE_CTX(ctx); assert(ellipsoid); auto l_ellipsoid = dynamic_cast<const Ellipsoid *>(ellipsoid->obj.get()); if (!l_ellipsoid) { - proj_log_error(ellipsoid->ctx, __FUNCTION__, - "Object is not a Ellipsoid"); + proj_log_error(ctx, __FUNCTION__, "Object is not a Ellipsoid"); return FALSE; } - if (pSemiMajorMetre) { - *pSemiMajorMetre = l_ellipsoid->semiMajorAxis().getSIValue(); + if (out_semi_major_metre) { + *out_semi_major_metre = l_ellipsoid->semiMajorAxis().getSIValue(); } - if (pSemiMinorMetre) { - *pSemiMinorMetre = l_ellipsoid->computeSemiMinorAxis().getSIValue(); + if (out_semi_minor_metre) { + *out_semi_minor_metre = + l_ellipsoid->computeSemiMinorAxis().getSIValue(); } - if (pIsSemiMinorComputed) { - *pIsSemiMinorComputed = !(l_ellipsoid->semiMinorAxis().has_value()); + if (out_is_semi_minor_computed) { + *out_is_semi_minor_computed = + !(l_ellipsoid->semiMinorAxis().has_value()); } - if (pInverseFlattening) { - *pInverseFlattening = l_ellipsoid->computedInverseFlattening(); + if (out_inv_flattening) { + *out_inv_flattening = l_ellipsoid->computedInverseFlattening(); } return TRUE; } @@ -1267,25 +1432,27 @@ int proj_obj_ellipsoid_get_parameters(PJ_OBJ *ellipsoid, * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param obj Objet of type CRS or GeodeticReferenceFrame (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error. */ -PJ_OBJ *proj_obj_get_prime_meridian(PJ_OBJ *obj) { +PJ_OBJ *proj_obj_get_prime_meridian(PJ_CONTEXT *ctx, const PJ_OBJ *obj) { + SANITIZE_CTX(ctx); auto ptr = obj->obj.get(); if (dynamic_cast<CRS *>(ptr)) { - auto geodCRS = extractGeodeticCRS(obj, __FUNCTION__); + auto geodCRS = extractGeodeticCRS(ctx, obj, __FUNCTION__); if (geodCRS) { - return PJ_OBJ::create(obj->ctx, geodCRS->primeMeridian()); + return PJ_OBJ::create(geodCRS->primeMeridian()); } } else { auto datum = dynamic_cast<const GeodeticReferenceFrame *>(ptr); if (datum) { - return PJ_OBJ::create(obj->ctx, datum->primeMeridian()); + return PJ_OBJ::create(datum->primeMeridian()); } } - proj_log_error(obj->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a CRS or GeodeticReferenceFrame"); return nullptr; } @@ -1294,69 +1461,77 @@ PJ_OBJ *proj_obj_get_prime_meridian(PJ_OBJ *obj) { /** \brief Return prime meridian parameters. * + * @param ctx PROJ context, or NULL for default context * @param prime_meridian Object of type PrimeMeridian (must not be NULL) - * @param pLongitude Pointer to a value to store the longitude of the prime + * @param out_longitude Pointer to a value to store the longitude of the prime * meridian, in its native unit. or NULL - * @param pLongitudeUnitConvFactor Pointer to a value to store the conversion + * @param out_unit_conv_factor Pointer to a value to store the conversion * factor of the prime meridian longitude unit to radian. or NULL - * @param pLongitudeUnitName Pointer to a string value to store the unit name. + * @param out_unit_name Pointer to a string value to store the unit name. * or NULL * @return TRUE in case of success. */ -int proj_obj_prime_meridian_get_parameters(PJ_OBJ *prime_meridian, - double *pLongitude, - double *pLongitudeUnitConvFactor, - const char **pLongitudeUnitName) { +int proj_obj_prime_meridian_get_parameters(PJ_CONTEXT *ctx, + const PJ_OBJ *prime_meridian, + double *out_longitude, + double *out_unit_conv_factor, + const char **out_unit_name) { + SANITIZE_CTX(ctx); assert(prime_meridian); auto l_pm = dynamic_cast<const PrimeMeridian *>(prime_meridian->obj.get()); if (!l_pm) { - proj_log_error(prime_meridian->ctx, __FUNCTION__, - "Object is not a PrimeMeridian"); + proj_log_error(ctx, __FUNCTION__, "Object is not a PrimeMeridian"); return false; } const auto &longitude = l_pm->longitude(); - if (pLongitude) { - *pLongitude = longitude.value(); + if (out_longitude) { + *out_longitude = longitude.value(); } const auto &unit = longitude.unit(); - if (pLongitudeUnitConvFactor) { - *pLongitudeUnitConvFactor = unit.conversionToSI(); + if (out_unit_conv_factor) { + *out_unit_conv_factor = unit.conversionToSI(); } - if (pLongitudeUnitName) { - *pLongitudeUnitName = unit.name().c_str(); + if (out_unit_name) { + *out_unit_name = unit.name().c_str(); } return true; } // --------------------------------------------------------------------------- -/** \brief Return the base CRS of a BoundCRS or the source CRS of a - * CoordinateOperation. +/** \brief Return the base CRS of a BoundCRS or a DerivedCRS/ProjectedCRS, or + * the source CRS of a CoordinateOperation. * * The returned object must be unreferenced with proj_obj_unref() after * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param obj Objet of type BoundCRS or CoordinateOperation (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error, or missing source CRS. */ -PJ_OBJ *proj_obj_get_source_crs(PJ_OBJ *obj) { +PJ_OBJ *proj_obj_get_source_crs(PJ_CONTEXT *ctx, const PJ_OBJ *obj) { + SANITIZE_CTX(ctx); assert(obj); auto ptr = obj->obj.get(); auto boundCRS = dynamic_cast<const BoundCRS *>(ptr); if (boundCRS) { - return PJ_OBJ::create(obj->ctx, boundCRS->baseCRS()); + return PJ_OBJ::create(boundCRS->baseCRS()); + } + auto derivedCRS = dynamic_cast<const DerivedCRS *>(ptr); + if (derivedCRS) { + return PJ_OBJ::create(derivedCRS->baseCRS()); } auto co = dynamic_cast<const CoordinateOperation *>(ptr); if (co) { auto sourceCRS = co->sourceCRS(); if (sourceCRS) { - return PJ_OBJ::create(obj->ctx, NN_NO_CHECK(sourceCRS)); + return PJ_OBJ::create(NN_NO_CHECK(sourceCRS)); } return nullptr; } - proj_log_error(obj->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a BoundCRS or a CoordinateOperation"); return nullptr; } @@ -1370,26 +1545,28 @@ PJ_OBJ *proj_obj_get_source_crs(PJ_OBJ *obj) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param obj Objet of type BoundCRS or CoordinateOperation (must not be NULL) * @return Object that must be unreferenced with proj_obj_unref(), or NULL * in case of error, or missing target CRS. */ -PJ_OBJ *proj_obj_get_target_crs(PJ_OBJ *obj) { +PJ_OBJ *proj_obj_get_target_crs(PJ_CONTEXT *ctx, const PJ_OBJ *obj) { + SANITIZE_CTX(ctx); assert(obj); auto ptr = obj->obj.get(); auto boundCRS = dynamic_cast<const BoundCRS *>(ptr); if (boundCRS) { - return PJ_OBJ::create(obj->ctx, boundCRS->hubCRS()); + return PJ_OBJ::create(boundCRS->hubCRS()); } auto co = dynamic_cast<const CoordinateOperation *>(ptr); if (co) { auto targetCRS = co->targetCRS(); if (targetCRS) { - return PJ_OBJ::create(obj->ctx, NN_NO_CHECK(targetCRS)); + return PJ_OBJ::create(NN_NO_CHECK(targetCRS)); } return nullptr; } - proj_log_error(obj->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a BoundCRS or a CoordinateOperation"); return nullptr; } @@ -1415,36 +1592,40 @@ PJ_OBJ *proj_obj_get_target_crs(PJ_OBJ *obj) { * This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and * CompoundCRS. * + * @param ctx PROJ context, or NULL for default context * @param obj Object of type CRS. Must not be NULL * @param auth_name Authority name, or NULL for all authorities * @param options Placeholder for future options. Should be set to NULL. - * @param confidence Output parameter. Pointer to an array of integers that will - * be allocated by the function and filled with the confidence values + * @param out_confidence Output parameter. Pointer to an array of integers that + * will be allocated by the function and filled with the confidence values * (0-100). There are as many elements in this array as * proj_obj_list_get_count() * returns on the return value of this function. *confidence should be * released with proj_free_int_list(). * @return a list of matching reference CRS, or nullptr in case of error. */ -PJ_OBJ_LIST *proj_obj_identify(PJ_OBJ *obj, const char *auth_name, - const char *const *options, int **confidence) { +PJ_OBJ_LIST *proj_obj_identify(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + const char *auth_name, + const char *const *options, + int **out_confidence) { + SANITIZE_CTX(ctx); assert(obj); (void)options; - if (confidence) { - *confidence = nullptr; + if (out_confidence) { + *out_confidence = nullptr; } auto ptr = obj->obj.get(); auto crs = dynamic_cast<const CRS *>(ptr); if (!crs) { - proj_log_error(obj->ctx, __FUNCTION__, "Object is not a CRS"); + proj_log_error(ctx, __FUNCTION__, "Object is not a CRS"); } else { int *confidenceTemp = nullptr; try { - auto factory = AuthorityFactory::create(getDBcontext(obj->ctx), + auto factory = AuthorityFactory::create(getDBcontext(ctx), auth_name ? auth_name : ""); auto res = crs->identify(factory); std::vector<IdentifiedObjectNNPtr> objects; - confidenceTemp = confidence ? new int[res.size()] : nullptr; + confidenceTemp = out_confidence ? new int[res.size()] : nullptr; size_t i = 0; for (const auto &pair : res) { objects.push_back(pair.first); @@ -1453,16 +1634,15 @@ PJ_OBJ_LIST *proj_obj_identify(PJ_OBJ *obj, const char *auth_name, ++i; } } - auto ret = internal::make_unique<PJ_OBJ_LIST>(obj->ctx, - std::move(objects)); - if (confidence) { - *confidence = confidenceTemp; + auto ret = internal::make_unique<PJ_OBJ_LIST>(std::move(objects)); + if (out_confidence) { + *out_confidence = confidenceTemp; confidenceTemp = nullptr; } return ret.release(); } catch (const std::exception &e) { delete[] confidenceTemp; - proj_log_error(obj->ctx, __FUNCTION__, e.what()); + proj_log_error(ctx, __FUNCTION__, e.what()); } } return nullptr; @@ -1567,19 +1747,22 @@ void proj_free_string_list(PROJ_STRING_LIST list) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param crs Objet of type DerivedCRS or BoundCRSs (must not be NULL) - * @param pMethodName Pointer to a string value to store the method + * @param out_method_name Pointer to a string value to store the method * (projection) name. or NULL - * @param pMethodAuthorityName Pointer to a string value to store the method + * @param out_method_auth_name Pointer to a string value to store the method * authority name. or NULL - * @param pMethodCode Pointer to a string value to store the method + * @param out_method_code Pointer to a string value to store the method * code. or NULL * @return Object of type SingleOperation that must be unreferenced with * proj_obj_unref(), or NULL in case of error. */ -PJ_OBJ *proj_obj_crs_get_coordoperation(PJ_OBJ *crs, const char **pMethodName, - const char **pMethodAuthorityName, - const char **pMethodCode) { +PJ_OBJ *proj_obj_crs_get_coordoperation(PJ_CONTEXT *ctx, const PJ_OBJ *crs, + const char **out_method_name, + const char **out_method_auth_name, + const char **out_method_code) { + SANITIZE_CTX(ctx); assert(crs); SingleOperationPtr co; @@ -1591,7 +1774,7 @@ PJ_OBJ *proj_obj_crs_get_coordoperation(PJ_OBJ *crs, const char **pMethodName, if (boundCRS) { co = boundCRS->transformation().as_nullable(); } else { - proj_log_error(crs->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a DerivedCRS or BoundCRS"); return nullptr; } @@ -1599,24 +1782,24 @@ PJ_OBJ *proj_obj_crs_get_coordoperation(PJ_OBJ *crs, const char **pMethodName, const auto &method = co->method(); const auto &method_ids = method->identifiers(); - if (pMethodName) { - *pMethodName = method->name()->description()->c_str(); + if (out_method_name) { + *out_method_name = method->name()->description()->c_str(); } - if (pMethodAuthorityName) { + if (out_method_auth_name) { if (!method_ids.empty()) { - *pMethodAuthorityName = method_ids[0]->codeSpace()->c_str(); + *out_method_auth_name = method_ids[0]->codeSpace()->c_str(); } else { - *pMethodAuthorityName = nullptr; + *out_method_auth_name = nullptr; } } - if (pMethodCode) { + if (out_method_code) { if (!method_ids.empty()) { - *pMethodCode = method_ids[0]->code().c_str(); + *out_method_code = method_ids[0]->code().c_str(); } else { - *pMethodCode = nullptr; + *out_method_code = nullptr; } } - return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(co)); + return PJ_OBJ::create(NN_NO_CHECK(co)); } // --------------------------------------------------------------------------- @@ -1630,8 +1813,9 @@ static PropertyMap createPropertyMapName(const char *name) { // --------------------------------------------------------------------------- static UnitOfMeasure createLinearUnit(const char *name, double convFactor) { - return name == nullptr ? UnitOfMeasure::METRE - : UnitOfMeasure(name, convFactor); + return name == nullptr + ? UnitOfMeasure::METRE + : UnitOfMeasure(name, convFactor, UnitOfMeasure::Type::LINEAR); } // --------------------------------------------------------------------------- @@ -1641,75 +1825,117 @@ static UnitOfMeasure createAngularUnit(const char *name, double convFactor) { ? UnitOfMeasure::DEGREE : ci_equal(name, "grad") ? UnitOfMeasure::GRAD - : UnitOfMeasure(name, convFactor)) + : UnitOfMeasure(name, convFactor, + UnitOfMeasure::Type::ANGULAR)) : UnitOfMeasure::DEGREE; } + +// --------------------------------------------------------------------------- + +static GeodeticReferenceFrameNNPtr createGeodeticReferenceFrame( + PJ_CONTEXT *ctx, const char *datum_name, const char *ellps_name, + double semi_major_metre, double inv_flattening, + const char *prime_meridian_name, double prime_meridian_offset, + const char *angular_units, double angular_units_conv) { + const UnitOfMeasure angUnit( + createAngularUnit(angular_units, angular_units_conv)); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + auto body = Ellipsoid::guessBodyName(dbContext, semi_major_metre); + auto ellpsName = createPropertyMapName(ellps_name); + auto ellps = inv_flattening != 0.0 + ? Ellipsoid::createFlattenedSphere( + ellpsName, Length(semi_major_metre), + Scale(inv_flattening), body) + : Ellipsoid::createSphere(ellpsName, + Length(semi_major_metre), body); + auto pm = PrimeMeridian::create( + PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + prime_meridian_name + ? prime_meridian_name + : prime_meridian_offset == 0.0 + ? (ellps->celestialBody() == Ellipsoid::EARTH + ? "Greenwich" + : "Reference meridian") + : "unnamed"), + Angle(prime_meridian_offset, angUnit)); + + std::string datumName(datum_name ? datum_name : "unnamed"); + if (datumName == "WGS_1984") { + datumName = GeodeticReferenceFrame::EPSG_6326->nameStr(); + } else if (datumName.find('_') != std::string::npos) { + // Likely coming from WKT1 + if (dbContext) { + auto authFactory = + AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); + auto res = authFactory->createObjectsFromName( + datumName, + {AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, true, + 1); + if (!res.empty()) { + const auto &refDatum = res.front(); + if (metadata::Identifier::isEquivalentName( + datumName.c_str(), refDatum->nameStr().c_str())) { + datumName = refDatum->nameStr(); + } + } + } + } + + return GeodeticReferenceFrame::create( + createPropertyMapName(datumName.c_str()), ellps, + util::optional<std::string>(), pm); +} + //! @endcond // --------------------------------------------------------------------------- -/** \brief Create a GeographicCRS 2D from its definition. +/** \brief Create a GeographicCRS. * * The returned object must be unreferenced with proj_obj_unref() after * use. * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param geogName Name of the GeographicCRS. Or NULL - * @param datumName Name of the GeodeticReferenceFrame. Or NULL - * @param ellipsoidName Name of the Ellipsoid. Or NULL - * @param semiMajorMetre Ellipsoid semi-major axis, in metres. - * @param invFlattening Ellipsoid inverse flattening. Or 0 for a sphere. - * @param primeMeridianName Name of the PrimeMeridian. Or NULL - * @param primeMeridianOffset Offset of the prime meridian, expressed in the + * @param crs_name Name of the GeographicCRS. Or NULL + * @param datum_name Name of the GeodeticReferenceFrame. Or NULL + * @param ellps_name Name of the Ellipsoid. Or NULL + * @param semi_major_metre Ellipsoid semi-major axis, in metres. + * @param inv_flattening Ellipsoid inverse flattening. Or 0 for a sphere. + * @param prime_meridian_name Name of the PrimeMeridian. Or NULL + * @param prime_meridian_offset Offset of the prime meridian, expressed in the * specified angular units. - * @param angularUnits Name of the angular units. Or NULL for Degree - * @param angularUnitsConv Conversion factor from the angular unit to radian. Or - * 0 for Degree if angularUnits == NULL. Otherwise should be not NULL - * @param latLongOrder TRUE for Latitude Longitude axis order. + * @param pm_angular_units Name of the angular units. Or NULL for Degree + * @param pm_angular_units_conv Conversion factor from the angular unit to + * radian. + * Or + * 0 for Degree if pm_angular_units == NULL. Otherwise should be not NULL + * @param ellipsoidal_cs Coordinate system. Must not be NULL. * * @return Object of type GeographicCRS that must be unreferenced with * proj_obj_unref(), or NULL in case of error. */ PJ_OBJ *proj_obj_create_geographic_crs( - PJ_CONTEXT *ctx, const char *geogName, const char *datumName, - const char *ellipsoidName, double semiMajorMetre, double invFlattening, - const char *primeMeridianName, double primeMeridianOffset, - const char *angularUnits, double angularUnitsConv, int latLongOrder) { + PJ_CONTEXT *ctx, const char *crs_name, const char *datum_name, + const char *ellps_name, double semi_major_metre, double inv_flattening, + const char *prime_meridian_name, double prime_meridian_offset, + const char *pm_angular_units, double pm_angular_units_conv, + PJ_OBJ *ellipsoidal_cs) { SANITIZE_CTX(ctx); + auto cs = util::nn_dynamic_pointer_cast<EllipsoidalCS>(ellipsoidal_cs->obj); + if (!cs) { + return nullptr; + } try { - const UnitOfMeasure angUnit( - createAngularUnit(angularUnits, angularUnitsConv)); - auto dbContext = getDBcontext(ctx); - auto body = Ellipsoid::guessBodyName(dbContext, semiMajorMetre); - auto ellpsName = createPropertyMapName(ellipsoidName); - auto ellps = - invFlattening != 0.0 - ? Ellipsoid::createFlattenedSphere(ellpsName, - Length(semiMajorMetre), - Scale(invFlattening), body) - : Ellipsoid::createSphere(ellpsName, Length(semiMajorMetre), - body); - auto pm = PrimeMeridian::create( - PropertyMap().set( - common::IdentifiedObject::NAME_KEY, - primeMeridianName - ? primeMeridianName - : primeMeridianOffset == 0.0 - ? (ellps->celestialBody() == Ellipsoid::EARTH - ? "Greenwich" - : "Reference meridian") - : "unnamed"), - Angle(primeMeridianOffset, angUnit)); - auto datum = GeodeticReferenceFrame::create( - createPropertyMapName(datumName), ellps, - util::optional<std::string>(), pm); - auto geogCRS = GeographicCRS::create( - createPropertyMapName(geogName), datum, - latLongOrder ? cs::EllipsoidalCS::createLatitudeLongitude(angUnit) - : cs::EllipsoidalCS::createLongitudeLatitude(angUnit)); - return PJ_OBJ::create(ctx, geogCRS); + auto datum = createGeodeticReferenceFrame( + ctx, datum_name, ellps_name, semi_major_metre, inv_flattening, + prime_meridian_name, prime_meridian_offset, pm_angular_units, + pm_angular_units_conv); + auto geogCRS = GeographicCRS::create(createPropertyMapName(crs_name), + datum, NN_NO_CHECK(cs)); + return PJ_OBJ::create(geogCRS); } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); } @@ -1718,22 +1944,775 @@ PJ_OBJ *proj_obj_create_geographic_crs( // --------------------------------------------------------------------------- +/** \brief Create a GeographicCRS. + * + * The returned object must be unreferenced with proj_obj_unref() 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_name Name of the GeographicCRS. Or NULL + * @param datum Datum. Must not be NULL. + * @param ellipsoidal_cs Coordinate system. Must not be NULL. + * + * @return Object of type GeographicCRS that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_create_geographic_crs_from_datum(PJ_CONTEXT *ctx, + const char *crs_name, + PJ_OBJ *datum, + PJ_OBJ *ellipsoidal_cs) { + + SANITIZE_CTX(ctx); + auto l_datum = + util::nn_dynamic_pointer_cast<GeodeticReferenceFrame>(datum->obj); + if (!l_datum) { + proj_log_error(ctx, __FUNCTION__, + "datum is not a GeodeticReferenceFrame"); + return nullptr; + } + auto cs = util::nn_dynamic_pointer_cast<EllipsoidalCS>(ellipsoidal_cs->obj); + if (!cs) { + return nullptr; + } + try { + auto geogCRS = + GeographicCRS::create(createPropertyMapName(crs_name), + NN_NO_CHECK(l_datum), NN_NO_CHECK(cs)); + return PJ_OBJ::create(geogCRS); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Create a GeodeticCRS of geocentric type. + * + * The returned object must be unreferenced with proj_obj_unref() 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_name Name of the GeographicCRS. Or NULL + * @param datum_name Name of the GeodeticReferenceFrame. Or NULL + * @param ellps_name Name of the Ellipsoid. Or NULL + * @param semi_major_metre Ellipsoid semi-major axis, in metres. + * @param inv_flattening Ellipsoid inverse flattening. Or 0 for a sphere. + * @param prime_meridian_name Name of the PrimeMeridian. Or NULL + * @param prime_meridian_offset Offset of the prime meridian, expressed in the + * specified angular units. + * @param angular_units Name of the angular units. Or NULL for Degree + * @param angular_units_conv Conversion factor from the angular unit to radian. + * Or + * 0 for Degree if angular_units == NULL. Otherwise should be not NULL + * @param linear_units Name of the linear units. Or NULL for Metre + * @param linear_units_conv Conversion factor from the linear unit to metre. Or + * 0 for Metre if linear_units == NULL. Otherwise should be not NULL + * + * @return Object of type GeodeticCRS that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_create_geocentric_crs( + PJ_CONTEXT *ctx, const char *crs_name, const char *datum_name, + const char *ellps_name, double semi_major_metre, double inv_flattening, + const char *prime_meridian_name, double prime_meridian_offset, + const char *angular_units, double angular_units_conv, + const char *linear_units, double linear_units_conv) { + + SANITIZE_CTX(ctx); + try { + const UnitOfMeasure linearUnit( + createLinearUnit(linear_units, linear_units_conv)); + auto datum = createGeodeticReferenceFrame( + ctx, datum_name, ellps_name, semi_major_metre, inv_flattening, + prime_meridian_name, prime_meridian_offset, angular_units, + angular_units_conv); + + auto geodCRS = + GeodeticCRS::create(createPropertyMapName(crs_name), datum, + cs::CartesianCS::createGeocentric(linearUnit)); + return PJ_OBJ::create(geodCRS); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Create a GeodeticCRS of geocentric type. + * + * The returned object must be unreferenced with proj_obj_unref() 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_name Name of the GeographicCRS. Or NULL + * @param datum Datum. Must not be NULL. + * @param linear_units Name of the linear units. Or NULL for Metre + * @param linear_units_conv Conversion factor from the linear unit to metre. Or + * 0 for Metre if linear_units == NULL. Otherwise should be not NULL + * + * @return Object of type GeodeticCRS that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_create_geocentric_crs_from_datum(PJ_CONTEXT *ctx, + const char *crs_name, + const PJ_OBJ *datum, + const char *linear_units, + double linear_units_conv) { + SANITIZE_CTX(ctx); + try { + const UnitOfMeasure linearUnit( + createLinearUnit(linear_units, linear_units_conv)); + auto l_datum = + util::nn_dynamic_pointer_cast<GeodeticReferenceFrame>(datum->obj); + if (!l_datum) { + proj_log_error(ctx, __FUNCTION__, + "datum is not a GeodeticReferenceFrame"); + return nullptr; + } + auto geodCRS = GeodeticCRS::create( + createPropertyMapName(crs_name), NN_NO_CHECK(l_datum), + cs::CartesianCS::createGeocentric(linearUnit)); + return PJ_OBJ::create(geodCRS); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return a copy of the object with its name changed + * + * Currently, only implemented on CRS objects. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type CRS. Must not be NULL + * @param name New name. Must not be NULL + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ PROJ_DLL *proj_obj_alter_name(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + const char *name) { + SANITIZE_CTX(ctx); + auto crs = dynamic_cast<const CRS *>(obj->obj.get()); + if (!crs) { + return nullptr; + } + try { + return PJ_OBJ::create(crs->alterName(name)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return a copy of the CRS with its geodetic CRS changed + * + * Currently, when obj is a GeodeticCRS, it returns a clone of new_geod_crs + * When obj is a ProjectedCRS, it replaces its base CRS with new_geod_crs. + * When obj is a CompoundCRS, it replaces the GeodeticCRS part of the horizontal + * CRS with new_geod_crs. + * In other cases, it returns a clone of obj. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type CRS. Must not be NULL + * @param new_geod_crs Object of type GeodeticCRS. Must not be NULL + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_crs_alter_geodetic_crs(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + const PJ_OBJ *new_geod_crs) { + SANITIZE_CTX(ctx); + auto l_new_geod_crs = + util::nn_dynamic_pointer_cast<GeodeticCRS>(new_geod_crs->obj); + if (!l_new_geod_crs) { + proj_log_error(ctx, __FUNCTION__, "new_geod_crs is not a GeodeticCRS"); + return nullptr; + } + + auto crs = dynamic_cast<const CRS *>(obj->obj.get()); + if (!crs) { + proj_log_error(ctx, __FUNCTION__, "obj is not a CRS"); + return nullptr; + } + + try { + return PJ_OBJ::create( + crs->alterGeodeticCRS(NN_NO_CHECK(l_new_geod_crs))); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return a copy of the CRS with its angular units changed + * + * The CRS must be or contain a GeographicCRS. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type CRS. Must not be NULL + * @param angular_units Name of the angular units. Or NULL for Degree + * @param angular_units_conv Conversion factor from the angular unit to radian. + * Or + * 0 for Degree if angular_units == NULL. Otherwise should be not NULL + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_crs_alter_cs_angular_unit(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + const char *angular_units, + double angular_units_conv) { + + SANITIZE_CTX(ctx); + auto geodCRS = proj_obj_crs_get_geodetic_crs(ctx, obj); + if (!geodCRS) { + return nullptr; + } + auto geogCRS = dynamic_cast<const GeographicCRS *>(geodCRS->obj.get()); + if (!geogCRS) { + proj_obj_unref(geodCRS); + return nullptr; + } + + PJ_OBJ *geogCRSAltered = nullptr; + try { + const UnitOfMeasure angUnit( + createAngularUnit(angular_units, angular_units_conv)); + geogCRSAltered = PJ_OBJ::create(GeographicCRS::create( + createPropertyMapName(proj_obj_get_name(geodCRS)), geogCRS->datum(), + geogCRS->datumEnsemble(), + geogCRS->coordinateSystem()->alterAngularUnit(angUnit))); + proj_obj_unref(geodCRS); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + proj_obj_unref(geodCRS); + return nullptr; + } + + auto ret = proj_obj_crs_alter_geodetic_crs(ctx, obj, geogCRSAltered); + proj_obj_unref(geogCRSAltered); + return ret; +} + +// --------------------------------------------------------------------------- + +/** \brief Return a copy of the CRS with the linear units of its coordinate + * system changed + * + * The CRS must be or contain a ProjectedCRS, VerticalCRS or a GeocentricCRS. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type CRS. Must not be NULL + * @param linear_units Name of the linear units. Or NULL for Metre + * @param linear_units_conv Conversion factor from the linear unit to metre. Or + * 0 for Metre if linear_units == NULL. Otherwise should be not NULL + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_crs_alter_cs_linear_unit(PJ_CONTEXT *ctx, const PJ_OBJ *obj, + const char *linear_units, + double linear_units_conv) { + SANITIZE_CTX(ctx); + auto crs = dynamic_cast<const CRS *>(obj->obj.get()); + if (!crs) { + return nullptr; + } + + try { + const UnitOfMeasure linearUnit( + createLinearUnit(linear_units, linear_units_conv)); + return PJ_OBJ::create(crs->alterCSLinearUnit(linearUnit)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return a copy of the CRS with the lineaer units of the parameters + * of its conversion modified. + * + * The CRS must be or contain a ProjectedCRS, VerticalCRS or a GeocentricCRS. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type ProjectedCRS. Must not be NULL + * @param linear_units Name of the linear units. Or NULL for Metre + * @param linear_units_conv Conversion factor from the linear unit to metre. Or + * 0 for Metre if linear_units == NULL. Otherwise should be not NULL + * @param convert_to_new_unit TRUE if exisiting values should be converted from + * their current unit to the new unit. If FALSE, their value will be left + * unchanged and the unit overriden (so the resulting CRS will not be + * equivalent to the original one for reprojection purposes). + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ *proj_obj_crs_alter_parameters_linear_unit(PJ_CONTEXT *ctx, + const PJ_OBJ *obj, + const char *linear_units, + double linear_units_conv, + int convert_to_new_unit) { + SANITIZE_CTX(ctx); + auto crs = dynamic_cast<const ProjectedCRS *>(obj->obj.get()); + if (!crs) { + return nullptr; + } + + try { + const UnitOfMeasure linearUnit( + createLinearUnit(linear_units, linear_units_conv)); + return PJ_OBJ::create(crs->alterParametersLinearUnit( + linearUnit, convert_to_new_unit == TRUE)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a EngineeringCRS with just a name + * + * The returned object must be unreferenced with proj_obj_unref() 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_name CRS name. Or NULL. + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ +PJ_OBJ PROJ_DLL *proj_obj_create_engineering_crs(PJ_CONTEXT *ctx, + const char *crs_name) { + SANITIZE_CTX(ctx); + try { + return PJ_OBJ::create(EngineeringCRS::create( + createPropertyMapName(crs_name), + EngineeringDatum::create(PropertyMap()), + CartesianCS::createEastingNorthing(UnitOfMeasure::METRE))); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a Conversion + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param name Conversion name. Or NULL. + * @param auth_name Conversion authority name. Or NULL. + * @param code Conversion code. Or NULL. + * @param method_name Method name. Or NULL. + * @param method_auth_name Method authority name. Or NULL. + * @param method_code Method code. Or NULL. + * @param param_count Number of parameters (size of params argument) + * @param params Parameter descriptions (array of size param_count) + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_conversion(PJ_CONTEXT *ctx, const char *name, + const char *auth_name, const char *code, + const char *method_name, + const char *method_auth_name, + const char *method_code, int param_count, + const PJ_PARAM_DESCRIPTION *params) { + SANITIZE_CTX(ctx); + try { + PropertyMap propConv; + propConv.set(common::IdentifiedObject::NAME_KEY, + name ? name : "unnamed"); + if (auth_name && code) { + propConv.set(metadata::Identifier::CODESPACE_KEY, auth_name) + .set(metadata::Identifier::CODE_KEY, code); + } + PropertyMap propMethod; + propMethod.set(common::IdentifiedObject::NAME_KEY, + method_name ? method_name : "unnamed"); + if (method_auth_name && method_code) { + propMethod + .set(metadata::Identifier::CODESPACE_KEY, method_auth_name) + .set(metadata::Identifier::CODE_KEY, method_code); + } + std::vector<OperationParameterNNPtr> parameters; + std::vector<ParameterValueNNPtr> values; + for (int i = 0; i < param_count; i++) { + PropertyMap propParam; + propParam.set(common::IdentifiedObject::NAME_KEY, + params[i].name ? params[i].name : "unnamed"); + if (params[i].auth_name && params[i].code) { + propParam + .set(metadata::Identifier::CODESPACE_KEY, + params[i].auth_name) + .set(metadata::Identifier::CODE_KEY, params[i].code); + } + parameters.emplace_back(OperationParameter::create(propParam)); + auto unit_type = UnitOfMeasure::Type::UNKNOWN; + switch (params[i].unit_type) { + case PJ_UT_ANGULAR: + unit_type = UnitOfMeasure::Type::ANGULAR; + break; + case PJ_UT_LINEAR: + unit_type = UnitOfMeasure::Type::LINEAR; + break; + case PJ_UT_SCALE: + unit_type = UnitOfMeasure::Type::SCALE; + break; + case PJ_UT_TIME: + unit_type = UnitOfMeasure::Type::TIME; + break; + case PJ_UT_PARAMETRIC: + unit_type = UnitOfMeasure::Type::PARAMETRIC; + break; + } + + Measure measure( + params[i].value, + params[i].unit_type == PJ_UT_ANGULAR + ? createAngularUnit(params[i].unit_name, + params[i].unit_conv_factor) + : params[i].unit_type == PJ_UT_LINEAR + ? createLinearUnit(params[i].unit_name, + params[i].unit_conv_factor) + : UnitOfMeasure( + params[i].unit_name ? params[i].unit_name + : "unnamed", + params[i].unit_conv_factor, unit_type)); + values.emplace_back(ParameterValue::create(measure)); + } + return PJ_OBJ::create( + Conversion::create(propConv, propMethod, parameters, values)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress -static PJ_OBJ *proj_obj_create_projected_crs(PJ_OBJ *geodetic_crs, - const char *crs_name, - const ConversionNNPtr &conv, - const UnitOfMeasure &linearUnit) { - assert(geodetic_crs); - auto geogCRS = +static CoordinateSystemAxisNNPtr createAxis(const PJ_AXIS_DESCRIPTION &axis) { + const auto dir = + axis.direction ? AxisDirection::valueOf(axis.direction) : nullptr; + if (dir == nullptr) + throw Exception("invalid value for axis direction"); + auto unit_type = UnitOfMeasure::Type::UNKNOWN; + switch (axis.unit_type) { + case PJ_UT_ANGULAR: + unit_type = UnitOfMeasure::Type::ANGULAR; + break; + case PJ_UT_LINEAR: + unit_type = UnitOfMeasure::Type::LINEAR; + break; + case PJ_UT_SCALE: + unit_type = UnitOfMeasure::Type::SCALE; + break; + case PJ_UT_TIME: + unit_type = UnitOfMeasure::Type::TIME; + break; + case PJ_UT_PARAMETRIC: + unit_type = UnitOfMeasure::Type::PARAMETRIC; + break; + } + auto unit = + axis.unit_type == PJ_UT_ANGULAR + ? createAngularUnit(axis.unit_name, axis.unit_conv_factor) + : axis.unit_type == PJ_UT_LINEAR + ? createLinearUnit(axis.unit_name, axis.unit_conv_factor) + : UnitOfMeasure(axis.unit_name ? axis.unit_name : "unnamed", + axis.unit_conv_factor, unit_type); + + return CoordinateSystemAxis::create( + createPropertyMapName(axis.name), + axis.abbreviation ? axis.abbreviation : std::string(), *dir, unit); +} + +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a CoordinateSystem. + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param type Coordinate system type. + * @param axis_count Number of axis + * @param axis Axis description (array of size axis_count) + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_cs(PJ_CONTEXT *ctx, PJ_COORDINATE_SYSTEM_TYPE type, + int axis_count, const PJ_AXIS_DESCRIPTION *axis) { + try { + switch (type) { + case PJ_CS_TYPE_UNKNOWN: + return nullptr; + + case PJ_CS_TYPE_CARTESIAN: { + if (axis_count == 2) { + return PJ_OBJ::create(CartesianCS::create( + PropertyMap(), createAxis(axis[0]), createAxis(axis[1]))); + } else if (axis_count == 3) { + return PJ_OBJ::create(CartesianCS::create( + PropertyMap(), createAxis(axis[0]), createAxis(axis[1]), + createAxis(axis[2]))); + } + break; + } + + case PJ_CS_TYPE_ELLIPSOIDAL: { + if (axis_count == 2) { + return PJ_OBJ::create(EllipsoidalCS::create( + PropertyMap(), createAxis(axis[0]), createAxis(axis[1]))); + } else if (axis_count == 3) { + return PJ_OBJ::create(EllipsoidalCS::create( + PropertyMap(), createAxis(axis[0]), createAxis(axis[1]), + createAxis(axis[2]))); + } + break; + } + + case PJ_CS_TYPE_VERTICAL: { + if (axis_count == 1) { + return PJ_OBJ::create( + VerticalCS::create(PropertyMap(), createAxis(axis[0]))); + } + break; + } + + case PJ_CS_TYPE_SPHERICAL: { + if (axis_count == 3) { + return PJ_OBJ::create(EllipsoidalCS::create( + PropertyMap(), createAxis(axis[0]), createAxis(axis[1]), + createAxis(axis[2]))); + } + break; + } + + case PJ_CS_TYPE_PARAMETRIC: { + if (axis_count == 1) { + return PJ_OBJ::create( + ParametricCS::create(PropertyMap(), createAxis(axis[0]))); + } + break; + } + + case PJ_CS_TYPE_ORDINAL: { + std::vector<CoordinateSystemAxisNNPtr> axisVector; + for (int i = 0; i < axis_count; i++) { + axisVector.emplace_back(createAxis(axis[i])); + } + + return PJ_OBJ::create(OrdinalCS::create(PropertyMap(), axisVector)); + } + + case PJ_CS_TYPE_DATETIMETEMPORAL: { + if (axis_count == 1) { + return PJ_OBJ::create(DateTimeTemporalCS::create( + PropertyMap(), createAxis(axis[0]))); + } + break; + } + + case PJ_CS_TYPE_TEMPORALCOUNT: { + if (axis_count == 1) { + return PJ_OBJ::create(TemporalCountCS::create( + PropertyMap(), createAxis(axis[0]))); + } + break; + } + + case PJ_CS_TYPE_TEMPORALMEASURE: { + if (axis_count == 1) { + return PJ_OBJ::create(TemporalMeasureCS::create( + PropertyMap(), createAxis(axis[0]))); + } + break; + } + } + + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } + proj_log_error(ctx, __FUNCTION__, "Wrong value for axis_count"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a CartesiansCS 2D + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param type Coordinate system type. + * @param unit_name Unit name. + * @param unit_conv_factor Unit conversion factor to SI. + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_cartesian_2D_cs(PJ_CONTEXT *ctx, + PJ_CARTESIAN_CS_2D_TYPE type, + const char *unit_name, + double unit_conv_factor) { + try { + switch (type) { + case PJ_CART2D_EASTING_NORTHING: + return PJ_OBJ::create(CartesianCS::createEastingNorthing( + createLinearUnit(unit_name, unit_conv_factor))); + + case PJ_CART2D_NORTHING_EASTING: + return PJ_OBJ::create(CartesianCS::createNorthingEasting( + createLinearUnit(unit_name, unit_conv_factor))); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a Ellipsoidal 2D + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param type Coordinate system type. + * @param unit_name Unit name. + * @param unit_conv_factor Unit conversion factor to SI. + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx, + PJ_ELLIPSOIDAL_CS_2D_TYPE type, + const char *unit_name, + double unit_conv_factor) { + try { + switch (type) { + case PJ_ELLPS2D_LONGITUDE_LATITUDE: + return PJ_OBJ::create(EllipsoidalCS::createLongitudeLatitude( + createAngularUnit(unit_name, unit_conv_factor))); + + case PJ_ELLPS2D_LATITUDE_LONGITUDE: + return PJ_OBJ::create(EllipsoidalCS::createLatitudeLongitude( + createAngularUnit(unit_name, unit_conv_factor))); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS + * + * The returned object must be unreferenced with proj_obj_unref() 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_name CRS name. Or NULL + * @param geodetic_crs Base GeodeticCRS. Must not be NULL. + * @param conversion Conversion. Must not be NULL. + * @param coordinate_system Cartesian coordinate system. Must not be NULL. + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_projected_crs(PJ_CONTEXT *ctx, const char *crs_name, + const PJ_OBJ *geodetic_crs, + const PJ_OBJ *conversion, + const PJ_OBJ *coordinate_system) { + SANITIZE_CTX(ctx); + auto geodCRS = util::nn_dynamic_pointer_cast<GeodeticCRS>(geodetic_crs->obj); - if (!geogCRS) { + if (!geodCRS) { + return nullptr; + } + auto conv = util::nn_dynamic_pointer_cast<Conversion>(conversion->obj); + if (!conv) { return nullptr; } - auto crs = ProjectedCRS::create( - createPropertyMapName(crs_name), NN_NO_CHECK(geogCRS), conv, - cs::CartesianCS::createEastingNorthing(linearUnit)); - return PJ_OBJ::create(geodetic_crs->ctx, crs); + auto cs = + util::nn_dynamic_pointer_cast<CartesianCS>(coordinate_system->obj); + if (!cs) { + return nullptr; + } + try { + return PJ_OBJ::create(ProjectedCRS::create( + createPropertyMapName(crs_name), NN_NO_CHECK(geodCRS), + NN_NO_CHECK(conv), NN_NO_CHECK(cs))); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +static PJ_OBJ *proj_obj_create_conversion(const ConversionNNPtr &conv) { + return PJ_OBJ::create(conv); } //! @endcond @@ -1747,15 +2726,18 @@ static PJ_OBJ *proj_obj_create_projected_crs(PJ_OBJ *geodetic_crs, * * See osgeo::proj::operation::Conversion::createUTM(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_UTM(PJ_OBJ *geodetic_crs, - const char *crs_name, int zone, - int north) { - const auto &linearUnit = UnitOfMeasure::METRE; - auto conv = Conversion::createUTM(PropertyMap(), zone, north != 0); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_utm(PJ_CONTEXT *ctx, int zone, int north) { + SANITIZE_CTX(ctx); + try { + auto conv = Conversion::createUTM(PropertyMap(), zone, north != 0); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1764,23 +2746,31 @@ PJ_OBJ *proj_obj_create_projected_crs_UTM(PJ_OBJ *geodetic_crs, * * See osgeo::proj::operation::Conversion::createTransverseMercator(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_TransverseMercator( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createTransverseMercator( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_transverse_mercator( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createTransverseMercator( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1790,23 +2780,31 @@ PJ_OBJ *proj_obj_create_projected_crs_TransverseMercator( * See * osgeo::proj::operation::Conversion::createGaussSchreiberTransverseMercator(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_GaussSchreiberTransverseMercator( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGaussSchreiberTransverseMercator( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_gauss_schreiber_transverse_mercator( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGaussSchreiberTransverseMercator( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1816,23 +2814,31 @@ PJ_OBJ *proj_obj_create_projected_crs_GaussSchreiberTransverseMercator( * See * osgeo::proj::operation::Conversion::createTransverseMercatorSouthOriented(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_TransverseMercatorSouthOriented( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createTransverseMercatorSouthOriented( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_transverse_mercator_south_oriented( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createTransverseMercatorSouthOriented( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1841,26 +2847,34 @@ PJ_OBJ *proj_obj_create_projected_crs_TransverseMercatorSouthOriented( * * See osgeo::proj::operation::Conversion::createTwoPointEquidistant(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_TwoPointEquidistant( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstPoint, - double longitudeFirstPoint, double latitudeSecondPoint, - double longitudeSeconPoint, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createTwoPointEquidistant( - PropertyMap(), Angle(latitudeFirstPoint, angUnit), - Angle(longitudeFirstPoint, angUnit), - Angle(latitudeSecondPoint, angUnit), - Angle(longitudeSeconPoint, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_two_point_equidistant( + PJ_CONTEXT *ctx, double latitude_first_point, double longitude_first_point, + double latitude_second_point, double longitude_secon_point, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createTwoPointEquidistant( + PropertyMap(), Angle(latitude_first_point, angUnit), + Angle(longitude_first_point, angUnit), + Angle(latitude_second_point, angUnit), + Angle(longitude_secon_point, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1869,22 +2883,30 @@ PJ_OBJ *proj_obj_create_projected_crs_TwoPointEquidistant( * * See osgeo::proj::operation::Conversion::createTunisiaMappingGrid(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_TunisiaMappingGrid( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createTunisiaMappingGrid( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_tunisia_mapping_grid( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createTunisiaMappingGrid( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1893,28 +2915,35 @@ PJ_OBJ *proj_obj_create_projected_crs_TunisiaMappingGrid( * * See osgeo::proj::operation::Conversion::createAlbersEqualArea(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_AlbersEqualArea( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFalseOrigin, - double longitudeFalseOrigin, double latitudeFirstParallel, - double latitudeSecondParallel, double eastingFalseOrigin, - double northingFalseOrigin, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createAlbersEqualArea( - PropertyMap(), Angle(latitudeFalseOrigin, angUnit), - Angle(longitudeFalseOrigin, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(eastingFalseOrigin, linearUnit), - Length(northingFalseOrigin, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_albers_equal_area( + PJ_CONTEXT *ctx, double latitude_false_origin, + double longitude_false_origin, double latitude_first_parallel, + double latitude_second_parallel, double easting_false_origin, + double northing_false_origin, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createAlbersEqualArea( + PropertyMap(), Angle(latitude_false_origin, angUnit), + Angle(longitude_false_origin, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(easting_false_origin, linearUnit), + Length(northing_false_origin, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1923,23 +2952,31 @@ PJ_OBJ *proj_obj_create_projected_crs_AlbersEqualArea( * * See osgeo::proj::operation::Conversion::createLambertConicConformal_1SP(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_1SP( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertConicConformal_1SP( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_lambert_conic_conformal_1sp( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertConicConformal_1SP( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1948,28 +2985,35 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_1SP( * * See osgeo::proj::operation::Conversion::createLambertConicConformal_2SP(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFalseOrigin, - double longitudeFalseOrigin, double latitudeFirstParallel, - double latitudeSecondParallel, double eastingFalseOrigin, - double northingFalseOrigin, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertConicConformal_2SP( - PropertyMap(), Angle(latitudeFalseOrigin, angUnit), - Angle(longitudeFalseOrigin, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(eastingFalseOrigin, linearUnit), - Length(northingFalseOrigin, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_lambert_conic_conformal_2sp( + PJ_CONTEXT *ctx, double latitude_false_origin, + double longitude_false_origin, double latitude_first_parallel, + double latitude_second_parallel, double easting_false_origin, + double northing_false_origin, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertConicConformal_2SP( + PropertyMap(), Angle(latitude_false_origin, angUnit), + Angle(longitude_false_origin, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(easting_false_origin, linearUnit), + Length(northing_false_origin, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -1979,28 +3023,36 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP( * See * osgeo::proj::operation::Conversion::createLambertConicConformal_2SP_Michigan(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP_Michigan( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFalseOrigin, - double longitudeFalseOrigin, double latitudeFirstParallel, - double latitudeSecondParallel, double eastingFalseOrigin, - double northingFalseOrigin, double ellipsoidScalingFactor, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertConicConformal_2SP_Michigan( - PropertyMap(), Angle(latitudeFalseOrigin, angUnit), - Angle(longitudeFalseOrigin, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(eastingFalseOrigin, linearUnit), - Length(northingFalseOrigin, linearUnit), Scale(ellipsoidScalingFactor)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_lambert_conic_conformal_2sp_michigan( + PJ_CONTEXT *ctx, double latitude_false_origin, + double longitude_false_origin, double latitude_first_parallel, + double latitude_second_parallel, double easting_false_origin, + double northing_false_origin, double ellipsoid_scaling_factor, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertConicConformal_2SP_Michigan( + PropertyMap(), Angle(latitude_false_origin, angUnit), + Angle(longitude_false_origin, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(easting_false_origin, linearUnit), + Length(northing_false_origin, linearUnit), + Scale(ellipsoid_scaling_factor)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2010,28 +3062,35 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP_Michigan( * See * osgeo::proj::operation::Conversion::createLambertConicConformal_2SP_Belgium(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP_Belgium( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFalseOrigin, - double longitudeFalseOrigin, double latitudeFirstParallel, - double latitudeSecondParallel, double eastingFalseOrigin, - double northingFalseOrigin, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertConicConformal_2SP_Belgium( - PropertyMap(), Angle(latitudeFalseOrigin, angUnit), - Angle(longitudeFalseOrigin, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(eastingFalseOrigin, linearUnit), - Length(northingFalseOrigin, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_lambert_conic_conformal_2sp_belgium( + PJ_CONTEXT *ctx, double latitude_false_origin, + double longitude_false_origin, double latitude_first_parallel, + double latitude_second_parallel, double easting_false_origin, + double northing_false_origin, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertConicConformal_2SP_Belgium( + PropertyMap(), Angle(latitude_false_origin, angUnit), + Angle(longitude_false_origin, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(easting_false_origin, linearUnit), + Length(northing_false_origin, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2040,23 +3099,31 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertConicConformal_2SP_Belgium( * * See osgeo::proj::operation::Conversion::createAzimuthalEquidistant(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_AzimuthalEquidistant( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeNatOrigin, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createAzimuthalEquidistant( - PropertyMap(), Angle(latitudeNatOrigin, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_azimuthal_equidistant( + PJ_CONTEXT *ctx, double latitude_nat_origin, double longitude_nat_origin, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createAzimuthalEquidistant( + PropertyMap(), Angle(latitude_nat_origin, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2065,23 +3132,31 @@ PJ_OBJ *proj_obj_create_projected_crs_AzimuthalEquidistant( * * See osgeo::proj::operation::Conversion::createGuamProjection(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_GuamProjection( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeNatOrigin, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGuamProjection( - PropertyMap(), Angle(latitudeNatOrigin, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_guam_projection( + PJ_CONTEXT *ctx, double latitude_nat_origin, double longitude_nat_origin, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGuamProjection( + PropertyMap(), Angle(latitude_nat_origin, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2090,23 +3165,31 @@ PJ_OBJ *proj_obj_create_projected_crs_GuamProjection( * * See osgeo::proj::operation::Conversion::createBonne(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Bonne( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeNatOrigin, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createBonne( - PropertyMap(), Angle(latitudeNatOrigin, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_bonne( + PJ_CONTEXT *ctx, double latitude_nat_origin, double longitude_nat_origin, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createBonne( + PropertyMap(), Angle(latitude_nat_origin, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2116,23 +3199,31 @@ PJ_OBJ *proj_obj_create_projected_crs_Bonne( * See * osgeo::proj::operation::Conversion::createLambertCylindricalEqualAreaSpherical(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_LambertCylindricalEqualAreaSpherical( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstParallel, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertCylindricalEqualAreaSpherical( - PropertyMap(), Angle(latitudeFirstParallel, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_lambert_cylindrical_equal_area_spherical( + PJ_CONTEXT *ctx, double latitude_first_parallel, + double longitude_nat_origin, double false_easting, double false_northing, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertCylindricalEqualAreaSpherical( + PropertyMap(), Angle(latitude_first_parallel, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2141,23 +3232,31 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertCylindricalEqualAreaSpherical( * * See osgeo::proj::operation::Conversion::createLambertCylindricalEqualArea(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_LambertCylindricalEqualArea( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstParallel, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertCylindricalEqualArea( - PropertyMap(), Angle(latitudeFirstParallel, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_lambert_cylindrical_equal_area( + PJ_CONTEXT *ctx, double latitude_first_parallel, + double longitude_nat_origin, double false_easting, double false_northing, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertCylindricalEqualArea( + PropertyMap(), Angle(latitude_first_parallel, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2166,22 +3265,30 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertCylindricalEqualArea( * * See osgeo::proj::operation::Conversion::createCassiniSoldner(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_CassiniSoldner( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createCassiniSoldner( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_cassini_soldner( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createCassiniSoldner( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2190,25 +3297,34 @@ PJ_OBJ *proj_obj_create_projected_crs_CassiniSoldner( * * See osgeo::proj::operation::Conversion::createEquidistantConic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EquidistantConic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double latitudeFirstParallel, - double latitudeSecondParallel, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEquidistantConic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_equidistant_conic( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double latitude_first_parallel, double latitude_second_parallel, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEquidistantConic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2217,22 +3333,32 @@ PJ_OBJ *proj_obj_create_projected_crs_EquidistantConic( * * See osgeo::proj::operation::Conversion::createEckertI(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertI( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertI( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_i(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertI( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2241,22 +3367,30 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertI( * * See osgeo::proj::operation::Conversion::createEckertII(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertII( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertII( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_ii( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertII( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2265,22 +3399,30 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertII( * * See osgeo::proj::operation::Conversion::createEckertIII(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertIII( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertIII( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_iii( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertIII( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2289,22 +3431,30 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertIII( * * See osgeo::proj::operation::Conversion::createEckertIV(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertIV( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertIV( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_iv( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertIV( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2313,22 +3463,32 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertIV( * * See osgeo::proj::operation::Conversion::createEckertV(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertV( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertV( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_v(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertV( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2337,22 +3497,30 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertV( * * See osgeo::proj::operation::Conversion::createEckertVI(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EckertVI( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEckertVI( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_eckert_vi( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEckertVI( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2361,23 +3529,31 @@ PJ_OBJ *proj_obj_create_projected_crs_EckertVI( * * See osgeo::proj::operation::Conversion::createEquidistantCylindrical(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EquidistantCylindrical( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstParallel, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEquidistantCylindrical( - PropertyMap(), Angle(latitudeFirstParallel, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_equidistant_cylindrical( + PJ_CONTEXT *ctx, double latitude_first_parallel, + double longitude_nat_origin, double false_easting, double false_northing, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEquidistantCylindrical( + PropertyMap(), Angle(latitude_first_parallel, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2387,23 +3563,31 @@ PJ_OBJ *proj_obj_create_projected_crs_EquidistantCylindrical( * See * osgeo::proj::operation::Conversion::createEquidistantCylindricalSpherical(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_EquidistantCylindricalSpherical( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstParallel, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEquidistantCylindricalSpherical( - PropertyMap(), Angle(latitudeFirstParallel, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_equidistant_cylindrical_spherical( + PJ_CONTEXT *ctx, double latitude_first_parallel, + double longitude_nat_origin, double false_easting, double false_northing, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEquidistantCylindricalSpherical( + PropertyMap(), Angle(latitude_first_parallel, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2412,22 +3596,32 @@ PJ_OBJ *proj_obj_create_projected_crs_EquidistantCylindricalSpherical( * * See osgeo::proj::operation::Conversion::createGall(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Gall( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGall( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_gall(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = + Conversion::createGall(PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2436,22 +3630,30 @@ PJ_OBJ *proj_obj_create_projected_crs_Gall( * * See osgeo::proj::operation::Conversion::createGoodeHomolosine(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_GoodeHomolosine( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGoodeHomolosine( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_goode_homolosine( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGoodeHomolosine( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2460,22 +3662,30 @@ PJ_OBJ *proj_obj_create_projected_crs_GoodeHomolosine( * * See osgeo::proj::operation::Conversion::createInterruptedGoodeHomolosine(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_InterruptedGoodeHomolosine( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createInterruptedGoodeHomolosine( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_interrupted_goode_homolosine( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createInterruptedGoodeHomolosine( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2485,22 +3695,30 @@ PJ_OBJ *proj_obj_create_projected_crs_InterruptedGoodeHomolosine( * * See osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepX(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_GeostationarySatelliteSweepX( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double height, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGeostationarySatelliteSweepX( - PropertyMap(), Angle(centerLong, angUnit), Length(height, linearUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_geostationary_satellite_sweep_x( + PJ_CONTEXT *ctx, double center_long, double height, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGeostationarySatelliteSweepX( + PropertyMap(), Angle(center_long, angUnit), + Length(height, linearUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2510,22 +3728,30 @@ PJ_OBJ *proj_obj_create_projected_crs_GeostationarySatelliteSweepX( * * See osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepY(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_GeostationarySatelliteSweepY( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double height, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGeostationarySatelliteSweepY( - PropertyMap(), Angle(centerLong, angUnit), Length(height, linearUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_geostationary_satellite_sweep_y( + PJ_CONTEXT *ctx, double center_long, double height, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGeostationarySatelliteSweepY( + PropertyMap(), Angle(center_long, angUnit), + Length(height, linearUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2534,22 +3760,30 @@ PJ_OBJ *proj_obj_create_projected_crs_GeostationarySatelliteSweepY( * * See osgeo::proj::operation::Conversion::createGnomonic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Gnomonic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createGnomonic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_gnomonic( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createGnomonic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2559,26 +3793,35 @@ PJ_OBJ *proj_obj_create_projected_crs_Gnomonic( * See * osgeo::proj::operation::Conversion::createHotineObliqueMercatorVariantA(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_HotineObliqueMercatorVariantA( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeProjectionCentre, - double longitudeProjectionCentre, double azimuthInitialLine, - double angleFromRectifiedToSkrewGrid, double scale, double falseEasting, - double falseNorthing, const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createHotineObliqueMercatorVariantA( - PropertyMap(), Angle(latitudeProjectionCentre, angUnit), - Angle(longitudeProjectionCentre, angUnit), - Angle(azimuthInitialLine, angUnit), - Angle(angleFromRectifiedToSkrewGrid, angUnit), Scale(scale), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_hotine_oblique_mercator_variant_a( + PJ_CONTEXT *ctx, double latitude_projection_centre, + double longitude_projection_centre, double azimuth_initial_line, + double angle_from_rectified_to_skrew_grid, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createHotineObliqueMercatorVariantA( + PropertyMap(), Angle(latitude_projection_centre, angUnit), + Angle(longitude_projection_centre, angUnit), + Angle(azimuth_initial_line, angUnit), + Angle(angle_from_rectified_to_skrew_grid, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2588,28 +3831,35 @@ PJ_OBJ *proj_obj_create_projected_crs_HotineObliqueMercatorVariantA( * See * osgeo::proj::operation::Conversion::createHotineObliqueMercatorVariantB(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_HotineObliqueMercatorVariantB( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeProjectionCentre, - double longitudeProjectionCentre, double azimuthInitialLine, - double angleFromRectifiedToSkrewGrid, double scale, - double eastingProjectionCentre, double northingProjectionCentre, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createHotineObliqueMercatorVariantB( - PropertyMap(), Angle(latitudeProjectionCentre, angUnit), - Angle(longitudeProjectionCentre, angUnit), - Angle(azimuthInitialLine, angUnit), - Angle(angleFromRectifiedToSkrewGrid, angUnit), Scale(scale), - Length(eastingProjectionCentre, linearUnit), - Length(northingProjectionCentre, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_hotine_oblique_mercator_variant_b( + PJ_CONTEXT *ctx, double latitude_projection_centre, + double longitude_projection_centre, double azimuth_initial_line, + double angle_from_rectified_to_skrew_grid, double scale, + double easting_projection_centre, double northing_projection_centre, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createHotineObliqueMercatorVariantB( + PropertyMap(), Angle(latitude_projection_centre, angUnit), + Angle(longitude_projection_centre, angUnit), + Angle(azimuth_initial_line, angUnit), + Angle(angle_from_rectified_to_skrew_grid, angUnit), Scale(scale), + Length(easting_projection_centre, linearUnit), + Length(northing_projection_centre, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2619,28 +3869,38 @@ PJ_OBJ *proj_obj_create_projected_crs_HotineObliqueMercatorVariantB( * See * osgeo::proj::operation::Conversion::createHotineObliqueMercatorTwoPointNaturalOrigin(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ PJ_OBJ * -proj_obj_create_projected_crs_HotineObliqueMercatorTwoPointNaturalOrigin( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeProjectionCentre, - double latitudePoint1, double longitudePoint1, double latitudePoint2, - double longitudePoint2, double scale, double eastingProjectionCentre, - double northingProjectionCentre, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createHotineObliqueMercatorTwoPointNaturalOrigin( - PropertyMap(), Angle(latitudeProjectionCentre, angUnit), - Angle(latitudePoint1, angUnit), Angle(longitudePoint1, angUnit), - Angle(latitudePoint2, angUnit), Angle(longitudePoint2, angUnit), - Scale(scale), Length(eastingProjectionCentre, linearUnit), - Length(northingProjectionCentre, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +proj_obj_create_conversion_hotine_oblique_mercator_two_point_natural_origin( + PJ_CONTEXT *ctx, double latitude_projection_centre, double latitude_point1, + double longitude_point1, double latitude_point2, double longitude_point2, + double scale, double easting_projection_centre, + double northing_projection_centre, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = + Conversion::createHotineObliqueMercatorTwoPointNaturalOrigin( + PropertyMap(), Angle(latitude_projection_centre, angUnit), + Angle(latitude_point1, angUnit), + Angle(longitude_point1, angUnit), + Angle(latitude_point2, angUnit), + Angle(longitude_point2, angUnit), Scale(scale), + Length(easting_projection_centre, linearUnit), + Length(northing_projection_centre, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2650,25 +3910,33 @@ proj_obj_create_projected_crs_HotineObliqueMercatorTwoPointNaturalOrigin( * See * osgeo::proj::operation::Conversion::createInternationalMapWorldPolyconic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_InternationalMapWorldPolyconic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double latitudeFirstParallel, double latitudeSecondParallel, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createInternationalMapWorldPolyconic( - PropertyMap(), Angle(centerLong, angUnit), - Angle(latitudeFirstParallel, angUnit), - Angle(latitudeSecondParallel, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_international_map_world_polyconic( + PJ_CONTEXT *ctx, double center_long, double latitude_first_parallel, + double latitude_second_parallel, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createInternationalMapWorldPolyconic( + PropertyMap(), Angle(center_long, angUnit), + Angle(latitude_first_parallel, angUnit), + Angle(latitude_second_parallel, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2677,27 +3945,37 @@ PJ_OBJ *proj_obj_create_projected_crs_InternationalMapWorldPolyconic( * * See osgeo::proj::operation::Conversion::createKrovakNorthOriented(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_KrovakNorthOriented( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeProjectionCentre, - double longitudeOfOrigin, double colatitudeConeAxis, - double latitudePseudoStandardParallel, - double scaleFactorPseudoStandardParallel, double falseEasting, - double falseNorthing, const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createKrovakNorthOriented( - PropertyMap(), Angle(latitudeProjectionCentre, angUnit), - Angle(longitudeOfOrigin, angUnit), Angle(colatitudeConeAxis, angUnit), - Angle(latitudePseudoStandardParallel, angUnit), - Scale(scaleFactorPseudoStandardParallel), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_krovak_north_oriented( + PJ_CONTEXT *ctx, double latitude_projection_centre, + double longitude_of_origin, double colatitude_cone_axis, + double latitude_pseudo_standard_parallel, + double scale_factor_pseudo_standard_parallel, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createKrovakNorthOriented( + PropertyMap(), Angle(latitude_projection_centre, angUnit), + Angle(longitude_of_origin, angUnit), + Angle(colatitude_cone_axis, angUnit), + Angle(latitude_pseudo_standard_parallel, angUnit), + Scale(scale_factor_pseudo_standard_parallel), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2706,27 +3984,37 @@ PJ_OBJ *proj_obj_create_projected_crs_KrovakNorthOriented( * * See osgeo::proj::operation::Conversion::createKrovak(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_Krovak( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeProjectionCentre, - double longitudeOfOrigin, double colatitudeConeAxis, - double latitudePseudoStandardParallel, - double scaleFactorPseudoStandardParallel, double falseEasting, - double falseNorthing, const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createKrovak( - PropertyMap(), Angle(latitudeProjectionCentre, angUnit), - Angle(longitudeOfOrigin, angUnit), Angle(colatitudeConeAxis, angUnit), - Angle(latitudePseudoStandardParallel, angUnit), - Scale(scaleFactorPseudoStandardParallel), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_krovak( + PJ_CONTEXT *ctx, double latitude_projection_centre, + double longitude_of_origin, double colatitude_cone_axis, + double latitude_pseudo_standard_parallel, + double scale_factor_pseudo_standard_parallel, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createKrovak( + PropertyMap(), Angle(latitude_projection_centre, angUnit), + Angle(longitude_of_origin, angUnit), + Angle(colatitude_cone_axis, angUnit), + Angle(latitude_pseudo_standard_parallel, angUnit), + Scale(scale_factor_pseudo_standard_parallel), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2735,23 +4023,31 @@ PJ_OBJ *proj_obj_create_projected_crs_Krovak( * * See osgeo::proj::operation::Conversion::createLambertAzimuthalEqualArea(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_LambertAzimuthalEqualArea( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeNatOrigin, - double longitudeNatOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createLambertAzimuthalEqualArea( - PropertyMap(), Angle(latitudeNatOrigin, angUnit), - Angle(longitudeNatOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_lambert_azimuthal_equal_area( + PJ_CONTEXT *ctx, double latitude_nat_origin, double longitude_nat_origin, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createLambertAzimuthalEqualArea( + PropertyMap(), Angle(latitude_nat_origin, angUnit), + Angle(longitude_nat_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2760,22 +4056,30 @@ PJ_OBJ *proj_obj_create_projected_crs_LambertAzimuthalEqualArea( * * See osgeo::proj::operation::Conversion::createMillerCylindrical(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_MillerCylindrical( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createMillerCylindrical( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_miller_cylindrical( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createMillerCylindrical( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2784,23 +4088,31 @@ PJ_OBJ *proj_obj_create_projected_crs_MillerCylindrical( * * See osgeo::proj::operation::Conversion::createMercatorVariantA(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_MercatorVariantA( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createMercatorVariantA( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_mercator_variant_a( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createMercatorVariantA( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2809,23 +4121,30 @@ PJ_OBJ *proj_obj_create_projected_crs_MercatorVariantA( * * See osgeo::proj::operation::Conversion::createMercatorVariantB(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_MercatorVariantB( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeFirstParallel, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createMercatorVariantB( - PropertyMap(), Angle(latitudeFirstParallel, angUnit), - Angle(centerLong, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_mercator_variant_b( + PJ_CONTEXT *ctx, double latitude_first_parallel, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createMercatorVariantB( + PropertyMap(), Angle(latitude_first_parallel, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2835,22 +4154,30 @@ PJ_OBJ *proj_obj_create_projected_crs_MercatorVariantB( * See * osgeo::proj::operation::Conversion::createPopularVisualisationPseudoMercator(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_PopularVisualisationPseudoMercator( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createPopularVisualisationPseudoMercator( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_popular_visualisation_pseudo_mercator( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createPopularVisualisationPseudoMercator( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2859,22 +4186,30 @@ PJ_OBJ *proj_obj_create_projected_crs_PopularVisualisationPseudoMercator( * * See osgeo::proj::operation::Conversion::createMollweide(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Mollweide( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createMollweide( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_mollweide( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createMollweide( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2883,22 +4218,30 @@ PJ_OBJ *proj_obj_create_projected_crs_Mollweide( * * See osgeo::proj::operation::Conversion::createNewZealandMappingGrid(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_NewZealandMappingGrid( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createNewZealandMappingGrid( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_new_zealand_mapping_grid( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createNewZealandMappingGrid( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2907,23 +4250,31 @@ PJ_OBJ *proj_obj_create_projected_crs_NewZealandMappingGrid( * * See osgeo::proj::operation::Conversion::createObliqueStereographic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_ObliqueStereographic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createObliqueStereographic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_oblique_stereographic( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createObliqueStereographic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2932,22 +4283,30 @@ PJ_OBJ *proj_obj_create_projected_crs_ObliqueStereographic( * * See osgeo::proj::operation::Conversion::createOrthographic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Orthographic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createOrthographic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_orthographic( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createOrthographic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2956,22 +4315,30 @@ PJ_OBJ *proj_obj_create_projected_crs_Orthographic( * * See osgeo::proj::operation::Conversion::createAmericanPolyconic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_AmericanPolyconic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createAmericanPolyconic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_american_polyconic( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createAmericanPolyconic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -2980,23 +4347,31 @@ PJ_OBJ *proj_obj_create_projected_crs_AmericanPolyconic( * * See osgeo::proj::operation::Conversion::createPolarStereographicVariantA(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_PolarStereographicVariantA( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createPolarStereographicVariantA( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_polar_stereographic_variant_a( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createPolarStereographicVariantA( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3005,23 +4380,31 @@ PJ_OBJ *proj_obj_create_projected_crs_PolarStereographicVariantA( * * See osgeo::proj::operation::Conversion::createPolarStereographicVariantB(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_PolarStereographicVariantB( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeStandardParallel, - double longitudeOfOrigin, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createPolarStereographicVariantB( - PropertyMap(), Angle(latitudeStandardParallel, angUnit), - Angle(longitudeOfOrigin, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_polar_stereographic_variant_b( + PJ_CONTEXT *ctx, double latitude_standard_parallel, + double longitude_of_origin, double false_easting, double false_northing, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createPolarStereographicVariantB( + PropertyMap(), Angle(latitude_standard_parallel, angUnit), + Angle(longitude_of_origin, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3030,22 +4413,32 @@ PJ_OBJ *proj_obj_create_projected_crs_PolarStereographicVariantB( * * See osgeo::proj::operation::Conversion::createRobinson(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Robinson( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createRobinson( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_robinson(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createRobinson( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3054,22 +4447,30 @@ PJ_OBJ *proj_obj_create_projected_crs_Robinson( * * See osgeo::proj::operation::Conversion::createSinusoidal(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Sinusoidal( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createSinusoidal( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_sinusoidal( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createSinusoidal( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3078,23 +4479,31 @@ PJ_OBJ *proj_obj_create_projected_crs_Sinusoidal( * * See osgeo::proj::operation::Conversion::createStereographic(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_Stereographic( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double scale, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createStereographic( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Scale(scale), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_stereographic( + PJ_CONTEXT *ctx, double center_lat, double center_long, double scale, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createStereographic( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Scale(scale), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3103,22 +4512,30 @@ PJ_OBJ *proj_obj_create_projected_crs_Stereographic( * * See osgeo::proj::operation::Conversion::createVanDerGrinten(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_VanDerGrinten( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createVanDerGrinten( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_van_der_grinten( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createVanDerGrinten( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3127,22 +4544,32 @@ PJ_OBJ *proj_obj_create_projected_crs_VanDerGrinten( * * See osgeo::proj::operation::Conversion::createWagnerI(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerI( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerI( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_i(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerI( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3151,22 +4578,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerI( * * See osgeo::proj::operation::Conversion::createWagnerII(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerII( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerII( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_ii( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerII( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3175,23 +4610,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerII( * * See osgeo::proj::operation::Conversion::createWagnerIII(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerIII( - PJ_OBJ *geodetic_crs, const char *crs_name, double latitudeTrueScale, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerIII( - PropertyMap(), Angle(latitudeTrueScale, angUnit), - Angle(centerLong, angUnit), Length(falseEasting, linearUnit), - Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_iii( + PJ_CONTEXT *ctx, double latitude_true_scale, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerIII( + PropertyMap(), Angle(latitude_true_scale, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3200,22 +4642,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerIII( * * See osgeo::proj::operation::Conversion::createWagnerIV(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerIV( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerIV( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_iv( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerIV( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3224,22 +4674,32 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerIV( * * See osgeo::proj::operation::Conversion::createWagnerV(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerV( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerV( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_v(PJ_CONTEXT *ctx, double center_long, + double false_easting, + double false_northing, + const char *ang_unit_name, + double ang_unit_conv_factor, + const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerV( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3248,22 +4708,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerV( * * See osgeo::proj::operation::Conversion::createWagnerVI(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerVI( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerVI( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_vi( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerVI( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3272,22 +4740,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerVI( * * See osgeo::proj::operation::Conversion::createWagnerVII(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_WagnerVII( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createWagnerVII( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_wagner_vii( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createWagnerVII( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3297,22 +4773,30 @@ PJ_OBJ *proj_obj_create_projected_crs_WagnerVII( * See * osgeo::proj::operation::Conversion::createQuadrilateralizedSphericalCube(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_QuadrilateralizedSphericalCube( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLat, - double centerLong, double falseEasting, double falseNorthing, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createQuadrilateralizedSphericalCube( - PropertyMap(), Angle(centerLat, angUnit), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_quadrilateralized_spherical_cube( + PJ_CONTEXT *ctx, double center_lat, double center_long, + double false_easting, double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createQuadrilateralizedSphericalCube( + PropertyMap(), Angle(center_lat, angUnit), + Angle(center_long, angUnit), Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3321,23 +4805,30 @@ PJ_OBJ *proj_obj_create_projected_crs_QuadrilateralizedSphericalCube( * * See osgeo::proj::operation::Conversion::createSphericalCrossTrackHeight(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). */ -PJ_OBJ *proj_obj_create_projected_crs_SphericalCrossTrackHeight( - PJ_OBJ *geodetic_crs, const char *crs_name, double pegPointLat, - double pegPointLong, double pegPointHeading, double pegPointHeight, - const char *angUnitName, double angUnitConvFactor, - const char *linearUnitName, double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createSphericalCrossTrackHeight( - PropertyMap(), Angle(pegPointLat, angUnit), - Angle(pegPointLong, angUnit), Angle(pegPointHeading, angUnit), - Length(pegPointHeight, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); +PJ_OBJ *proj_obj_create_conversion_spherical_cross_track_height( + PJ_CONTEXT *ctx, double peg_point_lat, double peg_point_long, + double peg_point_heading, double peg_point_height, + const char *ang_unit_name, double ang_unit_conv_factor, + const char *linear_unit_name, double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createSphericalCrossTrackHeight( + PropertyMap(), Angle(peg_point_lat, angUnit), + Angle(peg_point_long, angUnit), Angle(peg_point_heading, angUnit), + Length(peg_point_height, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } // --------------------------------------------------------------------------- @@ -3346,22 +4837,30 @@ PJ_OBJ *proj_obj_create_projected_crs_SphericalCrossTrackHeight( * * See osgeo::proj::operation::Conversion::createEqualEarth(). * - * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). - * Angular parameters are expressed in (angUnitName, angUnitConvFactor). - */ -PJ_OBJ *proj_obj_create_projected_crs_EqualEarth( - PJ_OBJ *geodetic_crs, const char *crs_name, double centerLong, - double falseEasting, double falseNorthing, const char *angUnitName, - double angUnitConvFactor, const char *linearUnitName, - double linearUnitConvFactor) { - UnitOfMeasure linearUnit( - createLinearUnit(linearUnitName, linearUnitConvFactor)); - UnitOfMeasure angUnit(createAngularUnit(angUnitName, angUnitConvFactor)); - auto conv = Conversion::createEqualEarth( - PropertyMap(), Angle(centerLong, angUnit), - Length(falseEasting, linearUnit), Length(falseNorthing, linearUnit)); - return proj_obj_create_projected_crs(geodetic_crs, crs_name, conv, - linearUnit); + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ_OBJ *proj_obj_create_conversion_equal_earth( + PJ_CONTEXT *ctx, double center_long, double false_easting, + double false_northing, const char *ang_unit_name, + double ang_unit_conv_factor, const char *linear_unit_name, + double linear_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure linearUnit( + createLinearUnit(linear_unit_name, linear_unit_conv_factor)); + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createEqualEarth( + PropertyMap(), Angle(center_long, angUnit), + Length(false_easting, linearUnit), + Length(false_northing, linearUnit)); + return proj_obj_create_conversion(conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; } /* END: Generated by scripts/create_c_api_projections.py*/ @@ -3371,21 +4870,23 @@ PJ_OBJ *proj_obj_create_projected_crs_EqualEarth( * a PROJ pipeline, checking in particular that referenced grids are * available. * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type CoordinateOperation or derived classes * (must not be NULL) * @return TRUE or FALSE. */ -int proj_coordoperation_is_instanciable(PJ_OBJ *coordoperation) { +int proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation) { assert(coordoperation); auto op = dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); if (!op) { - proj_log_error(coordoperation->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateOperation"); return 0; } - auto dbContext = getDBcontextNoException(coordoperation->ctx, __FUNCTION__); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); try { return op->isPROJInstanciable(dbContext) ? 1 : 0; } catch (const std::exception &) { @@ -3397,16 +4898,18 @@ int proj_coordoperation_is_instanciable(PJ_OBJ *coordoperation) { /** \brief Return the number of parameters of a SingleOperation * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type SingleOperation or derived classes * (must not be NULL) */ -int proj_coordoperation_get_param_count(PJ_OBJ *coordoperation) { +int proj_coordoperation_get_param_count(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation) { + SANITIZE_CTX(ctx); assert(coordoperation); auto op = dynamic_cast<const SingleOperation *>(coordoperation->obj.get()); if (!op) { - proj_log_error(coordoperation->ctx, __FUNCTION__, - "Object is not a SingleOperation"); + proj_log_error(ctx, __FUNCTION__, "Object is not a SingleOperation"); return 0; } return static_cast<int>(op->parameterValues().size()); @@ -3416,20 +4919,22 @@ int proj_coordoperation_get_param_count(PJ_OBJ *coordoperation) { /** \brief Return the index of a parameter of a SingleOperation * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type SingleOperation or derived classes * (must not be NULL) * @param name Parameter name. Must not be NULL * @return index (>=0), or -1 in case of error. */ -int proj_coordoperation_get_param_index(PJ_OBJ *coordoperation, +int proj_coordoperation_get_param_index(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation, const char *name) { + SANITIZE_CTX(ctx); assert(coordoperation); assert(name); auto op = dynamic_cast<const SingleOperation *>(coordoperation->obj.get()); if (!op) { - proj_log_error(coordoperation->ctx, __FUNCTION__, - "Object is not a SingleOperation"); + proj_log_error(ctx, __FUNCTION__, "Object is not a SingleOperation"); return -1; } int index = 0; @@ -3446,64 +4951,66 @@ int proj_coordoperation_get_param_index(PJ_OBJ *coordoperation, /** \brief Return a parameter of a SingleOperation * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type SingleOperation or derived classes * (must not be NULL) * @param index Parameter index. - * @param pName Pointer to a string value to store the parameter name. or NULL - * @param pNameAuthorityName Pointer to a string value to store the parameter + * @param out_name Pointer to a string value to store the parameter name. or + * NULL + * @param out_auth_name Pointer to a string value to store the parameter * authority name. or NULL - * @param pNameCode Pointer to a string value to store the parameter + * @param out_code Pointer to a string value to store the parameter * code. or NULL - * @param pValue Pointer to a double value to store the parameter + * @param out_value Pointer to a double value to store the parameter * value (if numeric). or NULL - * @param pValueString Pointer to a string value to store the parameter + * @param out_value_string Pointer to a string value to store the parameter * value (if of type string). or NULL - * @param pValueUnitConvFactor Pointer to a double value to store the parameter + * @param out_unit_conv_factor Pointer to a double value to store the parameter * unit conversion factor. or NULL - * @param pValueUnitName Pointer to a string value to store the parameter + * @param out_unit_name Pointer to a string value to store the parameter * unit name. or NULL * @return TRUE in case of success. */ -int proj_coordoperation_get_param(PJ_OBJ *coordoperation, int index, - const char **pName, - const char **pNameAuthorityName, - const char **pNameCode, double *pValue, - const char **pValueString, - double *pValueUnitConvFactor, - const char **pValueUnitName) { +int proj_coordoperation_get_param(PJ_CONTEXT *ctx, const PJ_OBJ *coordoperation, + int index, const char **out_name, + const char **out_auth_name, + const char **out_code, double *out_value, + const char **out_value_string, + double *out_unit_conv_factor, + const char **out_unit_name) { + SANITIZE_CTX(ctx); assert(coordoperation); auto op = dynamic_cast<const SingleOperation *>(coordoperation->obj.get()); if (!op) { - proj_log_error(coordoperation->ctx, __FUNCTION__, - "Object is not a SingleOperation"); + proj_log_error(ctx, __FUNCTION__, "Object is not a SingleOperation"); return false; } const auto ¶meters = op->method()->parameters(); const auto &values = op->parameterValues(); if (static_cast<size_t>(index) >= parameters.size() || static_cast<size_t>(index) >= values.size()) { - proj_log_error(coordoperation->ctx, __FUNCTION__, "Invalid index"); + proj_log_error(ctx, __FUNCTION__, "Invalid index"); return false; } const auto ¶m = parameters[index]; const auto ¶m_ids = param->identifiers(); - if (pName) { - *pName = param->name()->description()->c_str(); + if (out_name) { + *out_name = param->name()->description()->c_str(); } - if (pNameAuthorityName) { + if (out_auth_name) { if (!param_ids.empty()) { - *pNameAuthorityName = param_ids[0]->codeSpace()->c_str(); + *out_auth_name = param_ids[0]->codeSpace()->c_str(); } else { - *pNameAuthorityName = nullptr; + *out_auth_name = nullptr; } } - if (pNameCode) { + if (out_code) { if (!param_ids.empty()) { - *pNameCode = param_ids[0]->code().c_str(); + *out_code = param_ids[0]->code().c_str(); } else { - *pNameCode = nullptr; + *out_code = nullptr; } } @@ -3514,38 +5021,38 @@ int proj_coordoperation_get_param(PJ_OBJ *coordoperation, int index, if (opParamValue) { paramValue = opParamValue->parameterValue().as_nullable(); } - if (pValue) { - *pValue = 0; + if (out_value) { + *out_value = 0; if (paramValue) { if (paramValue->type() == ParameterValue::Type::MEASURE) { - *pValue = paramValue->value().value(); + *out_value = paramValue->value().value(); } } } - if (pValueString) { - *pValueString = nullptr; + if (out_value_string) { + *out_value_string = nullptr; if (paramValue) { if (paramValue->type() == ParameterValue::Type::FILENAME) { - *pValueString = paramValue->valueFile().c_str(); + *out_value_string = paramValue->valueFile().c_str(); } else if (paramValue->type() == ParameterValue::Type::STRING) { - *pValueString = paramValue->stringValue().c_str(); + *out_value_string = paramValue->stringValue().c_str(); } } } - if (pValueUnitConvFactor) { - *pValueUnitConvFactor = 0; + if (out_unit_conv_factor) { + *out_unit_conv_factor = 0; if (paramValue) { if (paramValue->type() == ParameterValue::Type::MEASURE) { - *pValueUnitConvFactor = + *out_unit_conv_factor = paramValue->value().unit().conversionToSI(); } } } - if (pValueUnitName) { - *pValueUnitName = nullptr; + if (out_unit_name) { + *out_unit_name = nullptr; if (paramValue) { if (paramValue->type() == ParameterValue::Type::MEASURE) { - *pValueUnitName = paramValue->value().unit().name().c_str(); + *out_unit_name = paramValue->value().unit().name().c_str(); } } } @@ -3557,20 +5064,23 @@ int proj_coordoperation_get_param(PJ_OBJ *coordoperation, int index, /** \brief Return the number of grids used by a CoordinateOperation * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type CoordinateOperation or derived classes * (must not be NULL) */ -int proj_coordoperation_get_grid_used_count(PJ_OBJ *coordoperation) { +int proj_coordoperation_get_grid_used_count(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation) { + SANITIZE_CTX(ctx); assert(coordoperation); auto co = dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); if (!co) { - proj_log_error(coordoperation->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateOperation"); return 0; } - auto dbContext = getDBcontextNoException(coordoperation->ctx, __FUNCTION__); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); try { if (!coordoperation->gridsNeededAsked) { coordoperation->gridsNeededAsked = true; @@ -3581,7 +5091,7 @@ int proj_coordoperation_get_grid_used_count(PJ_OBJ *coordoperation) { } return static_cast<int>(coordoperation->gridsNeeded.size()); } catch (const std::exception &e) { - proj_log_error(coordoperation->ctx, __FUNCTION__, e.what()); + proj_log_error(ctx, __FUNCTION__, e.what()); return 0; } } @@ -3590,65 +5100,68 @@ int proj_coordoperation_get_grid_used_count(PJ_OBJ *coordoperation) { /** \brief Return a parameter of a SingleOperation * + * @param ctx PROJ context, or NULL for default context * @param coordoperation Objet of type SingleOperation or derived classes * (must not be NULL) * @param index Parameter index. - * @param pShortName Pointer to a string value to store the grid short name. or - * NULL - * @param pFullName Pointer to a string value to store the grid full filename. + * @param out_short_name Pointer to a string value to store the grid short name. * or NULL - * @param pPackageName Pointer to a string value to store the package name where + * @param out_full_name Pointer to a string value to store the grid full + * filename. or NULL + * @param out_package_name Pointer to a string value to store the package name + * where * the grid might be found. or NULL - * @param pURL Pointer to a string value to store the grid URL or the + * @param out_url Pointer to a string value to store the grid URL or the * package URL where the grid might be found. or NULL - * @param pDirectDownload Pointer to a int (boolean) value to store whether - * *pURL can be downloaded directly. or NULL - * @param pOpenLicense Pointer to a int (boolean) value to store whether + * @param out_direct_download Pointer to a int (boolean) value to store whether + * *out_url can be downloaded directly. or NULL + * @param out_open_license Pointer to a int (boolean) value to store whether * the grid is released with an open license. or NULL - * @param pAvailable Pointer to a int (boolean) value to store whether the grid - * is available at runtime. or NULL + * @param out_available Pointer to a int (boolean) value to store whether the + * grid is available at runtime. or NULL * @return TRUE in case of success. */ -int proj_coordoperation_get_grid_used(PJ_OBJ *coordoperation, int index, - const char **pShortName, - const char **pFullName, - const char **pPackageName, - const char **pURL, int *pDirectDownload, - int *pOpenLicense, int *pAvailable) { - const int count = proj_coordoperation_get_grid_used_count(coordoperation); +int proj_coordoperation_get_grid_used( + PJ_CONTEXT *ctx, const PJ_OBJ *coordoperation, int index, + const char **out_short_name, const char **out_full_name, + const char **out_package_name, const char **out_url, + int *out_direct_download, int *out_open_license, int *out_available) { + SANITIZE_CTX(ctx); + const int count = + proj_coordoperation_get_grid_used_count(ctx, coordoperation); if (index < 0 || index >= count) { - proj_log_error(coordoperation->ctx, __FUNCTION__, "Invalid index"); + proj_log_error(ctx, __FUNCTION__, "Invalid index"); return false; } const auto &gridDesc = coordoperation->gridsNeeded[index]; - if (pShortName) { - *pShortName = gridDesc.shortName.c_str(); + if (out_short_name) { + *out_short_name = gridDesc.shortName.c_str(); } - if (pFullName) { - *pFullName = gridDesc.fullName.c_str(); + if (out_full_name) { + *out_full_name = gridDesc.fullName.c_str(); } - if (pPackageName) { - *pPackageName = gridDesc.packageName.c_str(); + if (out_package_name) { + *out_package_name = gridDesc.packageName.c_str(); } - if (pURL) { - *pURL = gridDesc.url.c_str(); + if (out_url) { + *out_url = gridDesc.url.c_str(); } - if (pDirectDownload) { - *pDirectDownload = gridDesc.directDownload; + if (out_direct_download) { + *out_direct_download = gridDesc.directDownload; } - if (pOpenLicense) { - *pOpenLicense = gridDesc.openLicense; + if (out_open_license) { + *out_open_license = gridDesc.openLicense; } - if (pAvailable) { - *pAvailable = gridDesc.available; + if (out_available) { + *out_available = gridDesc.available; } return true; @@ -3659,12 +5172,11 @@ int proj_coordoperation_get_grid_used(PJ_OBJ *coordoperation, int index, /** \brief Opaque object representing an operation factory context. */ struct PJ_OPERATION_FACTORY_CONTEXT { //! @cond Doxygen_Suppress - PJ_CONTEXT *ctx; CoordinateOperationContextNNPtr operationContext; explicit PJ_OPERATION_FACTORY_CONTEXT( - PJ_CONTEXT *ctxIn, CoordinateOperationContextNNPtr &&operationContextIn) - : ctx(ctxIn), operationContext(std::move(operationContextIn)) {} + CoordinateOperationContextNNPtr &&operationContextIn) + : operationContext(std::move(operationContextIn)) {} PJ_OPERATION_FACTORY_CONTEXT(const PJ_OPERATION_FACTORY_CONTEXT &) = delete; PJ_OPERATION_FACTORY_CONTEXT & @@ -3700,12 +5212,12 @@ proj_create_operation_factory_context(PJ_CONTEXT *ctx, const char *authority) { auto operationContext = CoordinateOperationContext::create(authFactory, nullptr, 0.0); return new PJ_OPERATION_FACTORY_CONTEXT( - ctx, std::move(operationContext)); + std::move(operationContext)); } else { auto operationContext = CoordinateOperationContext::create(nullptr, nullptr, 0.0); return new PJ_OPERATION_FACTORY_CONTEXT( - ctx, std::move(operationContext)); + std::move(operationContext)); } } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); @@ -3720,22 +5232,29 @@ proj_create_operation_factory_context(PJ_CONTEXT *ctx, const char *authority) { * This method should be called one and exactly one for each function * returning a PJ_OPERATION_FACTORY_CONTEXT* * - * @param ctxt Object, or NULL. + * @param ctx Object, or NULL. */ -void proj_operation_factory_context_unref(PJ_OPERATION_FACTORY_CONTEXT *ctxt) { - delete ctxt; +void proj_operation_factory_context_unref(PJ_OPERATION_FACTORY_CONTEXT *ctx) { + delete ctx; } // --------------------------------------------------------------------------- /** \brief Set the desired accuracy of the resulting coordinate transformations. - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param accuracy Accuracy in meter (or 0 to disable the filter). */ void proj_operation_factory_context_set_desired_accuracy( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, double accuracy) { - assert(ctxt); - ctxt->operationContext->setDesiredAccuracy(accuracy); + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + double accuracy) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + factory_ctx->operationContext->setDesiredAccuracy(accuracy); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } } // --------------------------------------------------------------------------- @@ -3743,21 +5262,29 @@ void proj_operation_factory_context_set_desired_accuracy( /** \brief Set the desired area of interest for the resulting coordinate * transformations. * - * For an area of interest crossing the anti-meridian, west_lon will be - * greater than east_lon. + * For an area of interest crossing the anti-meridian, west_lon_degree will be + * greater than east_lon_degree. * - * @param ctxt Operation factory context. must not be NULL - * @param west_lon West longitude (in degrees). - * @param south_lat South latitude (in degrees). - * @param east_lon East longitude (in degrees). - * @param north_lat North latitude (in degrees). + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL + * @param west_lon_degree West longitude (in degrees). + * @param south_lat_degree South latitude (in degrees). + * @param east_lon_degree East longitude (in degrees). + * @param north_lat_degree North latitude (in degrees). */ void proj_operation_factory_context_set_area_of_interest( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, double west_lon, double south_lat, - double east_lon, double north_lat) { - assert(ctxt); - ctxt->operationContext->setAreaOfInterest( - Extent::createFromBBOX(west_lon, south_lat, east_lon, north_lat)); + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + double west_lon_degree, double south_lat_degree, double east_lon_degree, + double north_lat_degree) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + factory_ctx->operationContext->setAreaOfInterest( + Extent::createFromBBOX(west_lon_degree, south_lat_degree, + east_lon_degree, north_lat_degree)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } } // --------------------------------------------------------------------------- @@ -3768,32 +5295,40 @@ void proj_operation_factory_context_set_area_of_interest( * * The default is PJ_CRS_EXTENT_SMALLEST. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param use How source and target CRS extent should be used. */ void proj_operation_factory_context_set_crs_extent_use( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, PROJ_CRS_EXTENT_USE use) { - assert(ctxt); - switch (use) { - case PJ_CRS_EXTENT_NONE: - ctxt->operationContext->setSourceAndTargetCRSExtentUse( - CoordinateOperationContext::SourceTargetCRSExtentUse::NONE); - break; + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + PROJ_CRS_EXTENT_USE use) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + switch (use) { + case PJ_CRS_EXTENT_NONE: + factory_ctx->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::NONE); + break; - case PJ_CRS_EXTENT_BOTH: - ctxt->operationContext->setSourceAndTargetCRSExtentUse( - CoordinateOperationContext::SourceTargetCRSExtentUse::BOTH); - break; + case PJ_CRS_EXTENT_BOTH: + factory_ctx->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::BOTH); + break; - case PJ_CRS_EXTENT_INTERSECTION: - ctxt->operationContext->setSourceAndTargetCRSExtentUse( - CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION); - break; + case PJ_CRS_EXTENT_INTERSECTION: + factory_ctx->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse:: + INTERSECTION); + break; - case PJ_CRS_EXTENT_SMALLEST: - ctxt->operationContext->setSourceAndTargetCRSExtentUse( - CoordinateOperationContext::SourceTargetCRSExtentUse::SMALLEST); - break; + case PJ_CRS_EXTENT_SMALLEST: + factory_ctx->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::SMALLEST); + break; + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); } } @@ -3806,22 +5341,31 @@ void proj_operation_factory_context_set_crs_extent_use( * * The default is PROJ_SPATIAL_CRITERION_STRICT_CONTAINMENT. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param criterion patial criterion to use */ void PROJ_DLL proj_operation_factory_context_set_spatial_criterion( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, PROJ_SPATIAL_CRITERION criterion) { - assert(ctxt); - switch (criterion) { - case PROJ_SPATIAL_CRITERION_STRICT_CONTAINMENT: - ctxt->operationContext->setSpatialCriterion( - CoordinateOperationContext::SpatialCriterion::STRICT_CONTAINMENT); - break; + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + PROJ_SPATIAL_CRITERION criterion) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + switch (criterion) { + case PROJ_SPATIAL_CRITERION_STRICT_CONTAINMENT: + factory_ctx->operationContext->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion:: + STRICT_CONTAINMENT); + break; - case PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION: - ctxt->operationContext->setSpatialCriterion( - CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); - break; + case PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION: + factory_ctx->operationContext->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion:: + PARTIAL_INTERSECTION); + break; + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); } } @@ -3831,29 +5375,37 @@ void PROJ_DLL proj_operation_factory_context_set_spatial_criterion( * * The default is USE_FOR_SORTING. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param use how grid availability is used. */ void PROJ_DLL proj_operation_factory_context_set_grid_availability_use( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, PROJ_GRID_AVAILABILITY_USE use) { - assert(ctxt); - switch (use) { - case PROJ_GRID_AVAILABILITY_USED_FOR_SORTING: - ctxt->operationContext->setGridAvailabilityUse( - CoordinateOperationContext::GridAvailabilityUse::USE_FOR_SORTING); - break; + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + PROJ_GRID_AVAILABILITY_USE use) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + switch (use) { + case PROJ_GRID_AVAILABILITY_USED_FOR_SORTING: + factory_ctx->operationContext->setGridAvailabilityUse( + CoordinateOperationContext::GridAvailabilityUse:: + USE_FOR_SORTING); + break; - case PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID: - ctxt->operationContext->setGridAvailabilityUse( - CoordinateOperationContext::GridAvailabilityUse:: - DISCARD_OPERATION_IF_MISSING_GRID); - break; + case PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID: + factory_ctx->operationContext->setGridAvailabilityUse( + CoordinateOperationContext::GridAvailabilityUse:: + DISCARD_OPERATION_IF_MISSING_GRID); + break; - case PROJ_GRID_AVAILABILITY_IGNORED: - ctxt->operationContext->setGridAvailabilityUse( - CoordinateOperationContext::GridAvailabilityUse:: - IGNORE_GRID_AVAILABILITY); - break; + case PROJ_GRID_AVAILABILITY_IGNORED: + factory_ctx->operationContext->setGridAvailabilityUse( + CoordinateOperationContext::GridAvailabilityUse:: + IGNORE_GRID_AVAILABILITY); + break; + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); } } @@ -3864,13 +5416,21 @@ void PROJ_DLL proj_operation_factory_context_set_grid_availability_use( * * The default is true. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param usePROJNames whether PROJ alternative grid names should be used */ void proj_operation_factory_context_set_use_proj_alternative_grid_names( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, int usePROJNames) { - assert(ctxt); - ctxt->operationContext->setUsePROJAlternativeGridNames(usePROJNames != 0); + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + int usePROJNames) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + factory_ctx->operationContext->setUsePROJAlternativeGridNames( + usePROJNames != 0); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } } // --------------------------------------------------------------------------- @@ -3892,13 +5452,19 @@ void proj_operation_factory_context_set_use_proj_alternative_grid_names( * * The default is true. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param allow whether intermediate CRS may be used. */ void proj_operation_factory_context_set_allow_use_intermediate_crs( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, int allow) { - assert(ctxt); - ctxt->operationContext->setAllowUseIntermediateCRS(allow != 0); + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, int allow) { + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + factory_ctx->operationContext->setAllowUseIntermediateCRS(allow != 0); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } } // --------------------------------------------------------------------------- @@ -3906,21 +5472,27 @@ void proj_operation_factory_context_set_allow_use_intermediate_crs( /** \brief Restrict the potential pivot CRSs that can be used when trying to * build a coordinate operation between two CRS that have no direct operation. * - * @param ctxt Operation factory context. must not be NULL + * @param ctx PROJ context, or NULL for default context + * @param factory_ctx Operation factory context. must not be NULL * @param list_of_auth_name_codes an array of strings NLL terminated, * with the format { "auth_name1", "code1", "auth_name2", "code2", ... NULL } */ void proj_operation_factory_context_set_allowed_intermediate_crs( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, const char *const *list_of_auth_name_codes) { - assert(ctxt); - std::vector<std::pair<std::string, std::string>> pivots; - for (auto iter = list_of_auth_name_codes; iter && iter[0] && iter[1]; - iter += 2) { - pivots.emplace_back(std::pair<std::string, std::string>( - std::string(iter[0]), std::string(iter[1]))); + SANITIZE_CTX(ctx); + assert(factory_ctx); + try { + std::vector<std::pair<std::string, std::string>> pivots; + for (auto iter = list_of_auth_name_codes; iter && iter[0] && iter[1]; + iter += 2) { + pivots.emplace_back(std::pair<std::string, std::string>( + std::string(iter[0]), std::string(iter[1]))); + } + factory_ctx->operationContext->setIntermediateCRS(pivots); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); } - ctxt->operationContext->setIntermediateCRS(pivots); } // --------------------------------------------------------------------------- @@ -3935,29 +5507,29 @@ void proj_operation_factory_context_set_allowed_intermediate_crs( * by increasing accuracy. Operations with unknown accuracy are sorted last, * whatever their area. * + * @param ctx PROJ context, or NULL for default context * @param source_crs source CRS. Must not be NULL. * @param target_crs source CRS. Must not be NULL. * @param operationContext Search context. Must not be NULL. * @return a result set that must be unreferenced with * proj_obj_list_unref(), or NULL in case of error. */ -PJ_OBJ_LIST * -proj_obj_create_operations(PJ_OBJ *source_crs, PJ_OBJ *target_crs, - PJ_OPERATION_FACTORY_CONTEXT *operationContext) { +PJ_OBJ_LIST *proj_obj_create_operations( + PJ_CONTEXT *ctx, const PJ_OBJ *source_crs, const PJ_OBJ *target_crs, + const PJ_OPERATION_FACTORY_CONTEXT *operationContext) { + SANITIZE_CTX(ctx); assert(source_crs); assert(target_crs); assert(operationContext); auto sourceCRS = nn_dynamic_pointer_cast<CRS>(source_crs->obj); if (!sourceCRS) { - proj_log_error(operationContext->ctx, __FUNCTION__, - "source_crs is not a CRS"); + proj_log_error(ctx, __FUNCTION__, "source_crs is not a CRS"); return nullptr; } auto targetCRS = nn_dynamic_pointer_cast<CRS>(target_crs->obj); if (!targetCRS) { - proj_log_error(operationContext->ctx, __FUNCTION__, - "target_crs is not a CRS"); + proj_log_error(ctx, __FUNCTION__, "target_crs is not a CRS"); return nullptr; } @@ -3970,9 +5542,9 @@ proj_obj_create_operations(PJ_OBJ *source_crs, PJ_OBJ *target_crs, for (const auto &op : ops) { objects.emplace_back(op); } - return new PJ_OBJ_LIST(operationContext->ctx, std::move(objects)); + return new PJ_OBJ_LIST(std::move(objects)); } catch (const std::exception &e) { - proj_log_error(operationContext->ctx, __FUNCTION__, e.what()); + proj_log_error(ctx, __FUNCTION__, e.what()); return nullptr; } } @@ -3983,7 +5555,7 @@ proj_obj_create_operations(PJ_OBJ *source_crs, PJ_OBJ *target_crs, * * @param result Objet of type PJ_OBJ_LIST (must not be NULL) */ -int proj_obj_list_get_count(PJ_OBJ_LIST *result) { +int proj_obj_list_get_count(const PJ_OBJ_LIST *result) { assert(result); return static_cast<int>(result->objects.size()); } @@ -3996,19 +5568,22 @@ int proj_obj_list_get_count(PJ_OBJ_LIST *result) { * use. * It should be used by at most one thread at a time. * + * @param ctx PROJ context, or NULL for default context * @param result Objet of type PJ_OBJ_LIST (must not be NULL) * @param index Index * @return a new object that must be unreferenced with proj_obj_unref(), * or nullptr in case of error. */ -PJ_OBJ *proj_obj_list_get(PJ_OBJ_LIST *result, int index) { +PJ_OBJ *proj_obj_list_get(PJ_CONTEXT *ctx, const PJ_OBJ_LIST *result, + int index) { + SANITIZE_CTX(ctx); assert(result); if (index < 0 || index >= proj_obj_list_get_count(result)) { - proj_log_error(result->ctx, __FUNCTION__, "Invalid index"); + proj_log_error(ctx, __FUNCTION__, "Invalid index"); return nullptr; } - return PJ_OBJ::create(result->ctx, result->objects[index]); + return PJ_OBJ::create(result->objects[index]); } // --------------------------------------------------------------------------- @@ -4026,14 +5601,18 @@ void proj_obj_list_unref(PJ_OBJ_LIST *result) { delete result; } /** \brief Return the accuracy (in metre) of a coordinate operation. * + * @param ctx PROJ context, or NULL for default context + * @param coordoperation Coordinate operation. Must not be NULL. * @return the accuracy, or a negative value if unknown or in case of error. */ -double proj_coordoperation_get_accuracy(PJ_OBJ *coordoperation) { +double proj_coordoperation_get_accuracy(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation) { + SANITIZE_CTX(ctx); assert(coordoperation); auto co = dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); if (!co) { - proj_log_error(coordoperation->ctx, __FUNCTION__, + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateOperation"); return -1; } @@ -4047,3 +5626,176 @@ double proj_coordoperation_get_accuracy(PJ_OBJ *coordoperation) { } return -1; } + +// --------------------------------------------------------------------------- + +/** \brief Returns the datum of a SingleCRS. + * + * The returned object must be unreferenced with proj_obj_unref() 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 Objet of type SingleCRS (must not be NULL) + * @return Object that must be unreferenced with proj_obj_unref(), or NULL + * in case of error (or if there is no datum) + */ +PJ_OBJ *proj_obj_crs_get_datum(PJ_CONTEXT *ctx, const PJ_OBJ *crs) { + SANITIZE_CTX(ctx); + assert(crs); + auto l_crs = dynamic_cast<const SingleCRS *>(crs->obj.get()); + if (!l_crs) { + proj_log_error(ctx, __FUNCTION__, "Object is not a SingleCRS"); + return nullptr; + } + const auto &datum = l_crs->datum(); + if (!datum) { + return nullptr; + } + return PJ_OBJ::create(NN_NO_CHECK(datum)); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the coordinate system of a SingleCRS. + * + * The returned object must be unreferenced with proj_obj_unref() 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 Objet of type SingleCRS (must not be NULL) + * @return Object that must be unreferenced with proj_obj_unref(), or NULL + * in case of error. + */ +PJ_OBJ *proj_obj_crs_get_coordinate_system(PJ_CONTEXT *ctx, const PJ_OBJ *crs) { + SANITIZE_CTX(ctx); + assert(crs); + auto l_crs = dynamic_cast<const SingleCRS *>(crs->obj.get()); + if (!l_crs) { + proj_log_error(ctx, __FUNCTION__, "Object is not a SingleCRS"); + return nullptr; + } + return PJ_OBJ::create(l_crs->coordinateSystem()); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the type of the coordinate system. + * + * @param ctx PROJ context, or NULL for default context + * @param cs Objet of type CoordinateSystem (must not be NULL) + * @return type, or PJ_CS_TYPE_UNKNOWN in case of error. + */ +PJ_COORDINATE_SYSTEM_TYPE proj_obj_cs_get_type(PJ_CONTEXT *ctx, + const PJ_OBJ *cs) { + SANITIZE_CTX(ctx); + assert(cs); + auto l_cs = dynamic_cast<const CoordinateSystem *>(cs->obj.get()); + if (!l_cs) { + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateSystem"); + return PJ_CS_TYPE_UNKNOWN; + } + if (dynamic_cast<const CartesianCS *>(l_cs)) { + return PJ_CS_TYPE_CARTESIAN; + } + if (dynamic_cast<const EllipsoidalCS *>(l_cs)) { + return PJ_CS_TYPE_ELLIPSOIDAL; + } + if (dynamic_cast<const VerticalCS *>(l_cs)) { + return PJ_CS_TYPE_VERTICAL; + } + if (dynamic_cast<const SphericalCS *>(l_cs)) { + return PJ_CS_TYPE_SPHERICAL; + } + if (dynamic_cast<const OrdinalCS *>(l_cs)) { + return PJ_CS_TYPE_ORDINAL; + } + if (dynamic_cast<const ParametricCS *>(l_cs)) { + return PJ_CS_TYPE_PARAMETRIC; + } + if (dynamic_cast<const DateTimeTemporalCS *>(l_cs)) { + return PJ_CS_TYPE_DATETIMETEMPORAL; + } + if (dynamic_cast<const TemporalCountCS *>(l_cs)) { + return PJ_CS_TYPE_TEMPORALCOUNT; + } + if (dynamic_cast<const TemporalMeasureCS *>(l_cs)) { + return PJ_CS_TYPE_TEMPORALMEASURE; + } + return PJ_CS_TYPE_UNKNOWN; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the number of axis of the coordinate system. + * + * @param ctx PROJ context, or NULL for default context + * @param cs Objet of type CoordinateSystem (must not be NULL) + * @return number of axis, or -1 in case of error. + */ +int proj_obj_cs_get_axis_count(PJ_CONTEXT *ctx, const PJ_OBJ *cs) { + SANITIZE_CTX(ctx); + assert(cs); + auto l_cs = dynamic_cast<const CoordinateSystem *>(cs->obj.get()); + if (!l_cs) { + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateSystem"); + return -1; + } + return static_cast<int>(l_cs->axisList().size()); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns information on an axis + * + * @param ctx PROJ context, or NULL for default context + * @param cs Objet of type CoordinateSystem (must not be NULL) + * @param index Index of the coordinate system (between 0 and + * proj_obj_cs_get_axis_count() - 1) + * @param out_name Pointer to a string value to store the axis name. or NULL + * @param out_abbrev Pointer to a string value to store the axis abbreviation. + * or NULL + * @param out_direction Pointer to a string value to store the axis direction. + * or NULL + * @param out_unit_conv_factor Pointer to a double value to store the axis + * unit conversion factor. or NULL + * @param out_unit_name Pointer to a string value to store the axis + * unit name. or NULL + * @return TRUE in case of success + */ +int proj_obj_cs_get_axis_info(PJ_CONTEXT *ctx, const PJ_OBJ *cs, int index, + const char **out_name, const char **out_abbrev, + const char **out_direction, + double *out_unit_conv_factor, + const char **out_unit_name) { + SANITIZE_CTX(ctx); + assert(cs); + auto l_cs = dynamic_cast<const CoordinateSystem *>(cs->obj.get()); + if (!l_cs) { + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateSystem"); + return false; + } + const auto &axisList = l_cs->axisList(); + if (index < 0 || static_cast<size_t>(index) >= axisList.size()) { + proj_log_error(ctx, __FUNCTION__, "Invalid index"); + return false; + } + const auto &axis = axisList[index]; + if (out_name) { + *out_name = axis->nameStr().c_str(); + } + if (out_abbrev) { + *out_abbrev = axis->abbreviation().c_str(); + } + if (out_direction) { + *out_direction = axis->direction().toString().c_str(); + } + if (out_unit_conv_factor) { + *out_unit_conv_factor = axis->unit().conversionToSI(); + } + if (out_unit_name) { + *out_unit_name = axis->unit().name().c_str(); + } + return true; +} diff --git a/src/coordinateoperation.cpp b/src/coordinateoperation.cpp index 42cc806e..bbe84698 100644 --- a/src/coordinateoperation.cpp +++ b/src/coordinateoperation.cpp @@ -149,6 +149,8 @@ static std::set<std::string> buildSetEquivalentParameters() { {"latitude_of_point_2", "Latitude_Of_2nd_Point", nullptr}, {"longitude_of_point_2", "Longitude_Of_2nd_Point", nullptr}, + {"satellite_height", "height", nullptr}, + {EPSG_NAME_PARAMETER_FALSE_EASTING, EPSG_NAME_PARAMETER_EASTING_FALSE_ORIGIN, EPSG_NAME_PARAMETER_EASTING_PROJECTION_CENTRE, nullptr}, @@ -160,7 +162,8 @@ static std::set<std::string> buildSetEquivalentParameters() { {WKT1_LATITUDE_OF_ORIGIN, WKT1_LATITUDE_OF_CENTER, EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, EPSG_NAME_PARAMETER_LATITUDE_FALSE_ORIGIN, - EPSG_NAME_PARAMETER_LATITUDE_PROJECTION_CENTRE, nullptr}, + EPSG_NAME_PARAMETER_LATITUDE_PROJECTION_CENTRE, "Central_Parallel", + nullptr}, {WKT1_CENTRAL_MERIDIAN, WKT1_LONGITUDE_OF_CENTER, EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, @@ -1898,6 +1901,58 @@ ConversionNNPtr Conversion::shallowClone() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +ConversionNNPtr +Conversion::alterParametersLinearUnit(const common::UnitOfMeasure &unit, + bool convertToNewUnit) const { + + std::vector<GeneralParameterValueNNPtr> newValues; + bool changesDone = false; + for (const auto &genOpParamvalue : parameterValues()) { + bool updated = false; + auto opParamvalue = dynamic_cast<const OperationParameterValue *>( + genOpParamvalue.get()); + if (opParamvalue) { + const auto ¶mValue = opParamvalue->parameterValue(); + if (paramValue->type() == ParameterValue::Type::MEASURE) { + const auto &measure = paramValue->value(); + if (measure.unit().type() == + common::UnitOfMeasure::Type::LINEAR) { + if (!measure.unit()._isEquivalentTo( + unit, util::IComparable::Criterion::EQUIVALENT)) { + const double newValue = + convertToNewUnit ? measure.convertToUnit(unit) + : measure.value(); + newValues.emplace_back(OperationParameterValue::create( + opParamvalue->parameter(), + ParameterValue::create( + common::Measure(newValue, unit)))); + updated = true; + } + } + } + } + if (updated) { + changesDone = true; + } else { + newValues.emplace_back(genOpParamvalue); + } + } + if (changesDone) { + auto conv = create(util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, "unknown"), + method(), newValues); + conv->setCRSs(this, false); + return conv; + } else { + return NN_NO_CHECK( + util::nn_dynamic_pointer_cast<Conversion>(shared_from_this())); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Instanciate a Conversion from a vector of GeneralParameterValue. * * @param properties See \ref general_properties. At minimum the name should be @@ -5471,6 +5526,12 @@ Transformation::~Transformation() = default; // --------------------------------------------------------------------------- +Transformation::Transformation(const Transformation &other) + : CoordinateOperation(other), SingleOperation(other), + d(internal::make_unique<Private>(*other.d)) {} + +// --------------------------------------------------------------------------- + /** \brief Return the source crs::CRS of the transformation. * * @return the source CRS. @@ -5492,6 +5553,17 @@ const crs::CRSNNPtr &Transformation::targetCRS() PROJ_CONST_DEFN { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +TransformationNNPtr Transformation::shallowClone() const { + auto conv = Transformation::nn_make_shared<Transformation>(*this); + conv->assignSelf(conv); + conv->setCRSs(this, false); + return conv; +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress /** \brief Return the TOWGS84 parameters of the transformation. * * If this transformation uses Coordinate Frame Rotation, Position Vector @@ -7595,6 +7667,8 @@ void Transformation::_exportToPROJString( "Transformation cannot be exported as a PROJ.4 string"); } + formatter->setCoordinateOperationOptimizations(true); + bool positionVectorConvention = true; bool sevenParamsTransform = false; bool threeParamsTransform = false; @@ -8220,6 +8294,32 @@ bool SingleOperation::exportToPROJStringGeneric( if (isAxisOrderReversal(methodEPSGCode)) { formatter->addStep("axisswap"); formatter->addParam("order", "2,1"); + auto sourceCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(sourceCRS().get()); + auto targetCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(targetCRS().get()); + if (sourceCRSGeog && targetCRSGeog) { + const auto &unitSrc = + sourceCRSGeog->coordinateSystem()->axisList()[0]->unit(); + const auto &unitDst = + targetCRSGeog->coordinateSystem()->axisList()[0]->unit(); + if (!unitSrc._isEquivalentTo( + unitDst, util::IComparable::Criterion::EQUIVALENT)) { + formatter->addStep("unitconvert"); + auto projUnit = unitSrc.exportToPROJString(); + if (projUnit.empty()) { + formatter->addParam("xy_in", unitSrc.conversionToSI()); + } else { + formatter->addParam("xy_in", projUnit); + } + projUnit = unitDst.exportToPROJString(); + if (projUnit.empty()) { + formatter->addParam("xy_out", unitDst.conversionToSI()); + } else { + formatter->addParam("xy_out", projUnit); + } + } + } return true; } @@ -9228,6 +9328,7 @@ struct FilterAndSort { // Precompute a number of parameters for each operation that will be // useful for the sorting. std::map<CoordinateOperation *, PrecomputedOpCharacteristics> map; + const auto gridAvailabilityUse = context->getGridAvailabilityUse(); for (const auto &op : res) { bool dummy = false; auto extentOp = getExtent(op, true, dummy); @@ -9260,14 +9361,20 @@ struct FilterAndSort { bool gridsAvailable = true; bool gridsKnown = true; if (context->getAuthorityFactory() && - context->getGridAvailabilityUse() == - CoordinateOperationContext::GridAvailabilityUse:: - USE_FOR_SORTING) { + (gridAvailabilityUse == + CoordinateOperationContext::GridAvailabilityUse:: + USE_FOR_SORTING || + gridAvailabilityUse == + CoordinateOperationContext::GridAvailabilityUse:: + IGNORE_GRID_AVAILABILITY)) { const auto gridsNeeded = op->gridsNeeded( context->getAuthorityFactory()->databaseContext()); for (const auto &gridDesc : gridsNeeded) { hasGrids = true; - if (!gridDesc.available) { + if (gridAvailabilityUse == + CoordinateOperationContext::GridAvailabilityUse:: + USE_FOR_SORTING && + !gridDesc.available) { gridsAvailable = false; } if (gridDesc.packageName.empty()) { @@ -10130,6 +10237,72 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( const auto candidatesDstGeod( findCandidateGeodCRSForDatum(authFactory, geodDst->datum())); + auto createTransformations = [&](const crs::CRSNNPtr &candidateSrcGeod, + const crs::CRSNNPtr &candidateDstGeod, + const CoordinateOperationNNPtr &opFirst, + bool isNullFirst) { + const auto opsSecond = + createOperations(candidateSrcGeod, candidateDstGeod, context); + const auto opsThird = + createOperations(candidateDstGeod, targetCRS, context); + assert(!opsThird.empty()); + + for (auto &opSecond : opsSecond) { + // Check that it is not a transformation synthetized by + // ourselves + if (!hasIdentifiers(opSecond)) { + continue; + } + // And even if it is a referenced transformation, check that + // it is not a trivial one + auto so = dynamic_cast<const SingleOperation *>(opSecond.get()); + if (so && isAxisOrderReversal(so->method()->getEPSGCode())) { + continue; + } + + std::vector<CoordinateOperationNNPtr> subOps; + if (isNullFirst) { + opSecond->setCRSs( + sourceCRS, NN_CHECK_ASSERT(opSecond->targetCRS()), nullptr); + } else { + subOps.emplace_back(opFirst); + } + if (isNullTransformation(opsThird[0]->nameStr())) { + opSecond->setCRSs(NN_CHECK_ASSERT(opSecond->sourceCRS()), + targetCRS, nullptr); + subOps.emplace_back(opSecond); + } else { + subOps.emplace_back(opSecond); + subOps.emplace_back(opsThird[0]); + } + res.emplace_back(ConcatenatedOperation::createComputeMetadata( + subOps, !allowEmptyIntersection)); + } + }; + + // Start in priority with candidates that have exactly the same name as + // the sourcCRS and targetCRS. Typically for the case of init=IGNF:XXXX + for (const auto &candidateSrcGeod : candidatesSrcGeod) { + if (candidateSrcGeod->nameStr() == sourceCRS->nameStr()) { + for (const auto &candidateDstGeod : candidatesDstGeod) { + if (candidateDstGeod->nameStr() == targetCRS->nameStr()) { + const auto opsFirst = + createOperations(sourceCRS, candidateSrcGeod, context); + assert(!opsFirst.empty()); + const bool isNullFirst = + isNullTransformation(opsFirst[0]->nameStr()); + createTransformations(candidateSrcGeod, candidateDstGeod, + opsFirst[0], isNullFirst); + if (!res.empty()) { + return; + } + break; + } + } + break; + } + } + for (const auto &candidateSrcGeod : candidatesSrcGeod) { const auto opsFirst = createOperations(sourceCRS, candidateSrcGeod, context); @@ -10137,44 +10310,8 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( const bool isNullFirst = isNullTransformation(opsFirst[0]->nameStr()); for (const auto &candidateDstGeod : candidatesDstGeod) { - const auto opsSecond = - createOperations(candidateSrcGeod, candidateDstGeod, context); - const auto opsThird = - createOperations(candidateDstGeod, targetCRS, context); - assert(!opsThird.empty()); - - for (auto &opSecond : opsSecond) { - // Check that it is not a transformation synthetized by - // ourselves - if (!hasIdentifiers(opSecond)) { - continue; - } - // And even if it is a referenced transformation, check that - // it is not a trivial one - auto so = dynamic_cast<const SingleOperation *>(opSecond.get()); - if (so && isAxisOrderReversal(so->method()->getEPSGCode())) { - continue; - } - - std::vector<CoordinateOperationNNPtr> subOps; - if (isNullFirst) { - opSecond->setCRSs(sourceCRS, - NN_CHECK_ASSERT(opSecond->targetCRS()), - nullptr); - } else { - subOps.emplace_back(opsFirst[0]); - } - if (isNullTransformation(opsThird[0]->nameStr())) { - opSecond->setCRSs(NN_CHECK_ASSERT(opSecond->sourceCRS()), - targetCRS, nullptr); - subOps.emplace_back(opSecond); - } else { - subOps.emplace_back(opSecond); - subOps.emplace_back(opsThird[0]); - } - res.emplace_back(ConcatenatedOperation::createComputeMetadata( - subOps, !allowEmptyIntersection)); - } + createTransformations(candidateSrcGeod, candidateDstGeod, + opsFirst[0], isNullFirst); } if (!res.empty()) { return; @@ -10235,6 +10372,56 @@ CoordinateOperationFactory::Private::createOperations( std::vector<CoordinateOperationNNPtr> res; const bool allowEmptyIntersection = true; + const auto &sourceProj4Ext = sourceCRS->getExtensionProj4(); + const auto &targetProj4Ext = targetCRS->getExtensionProj4(); + if (!sourceProj4Ext.empty() || !targetProj4Ext.empty()) { + + auto sourceProjExportable = + dynamic_cast<io::IPROJStringExportable *>(sourceCRS.get()); + auto targetProjExportable = + dynamic_cast<io::IPROJStringExportable *>(targetCRS.get()); + if (!sourceProjExportable) { + throw InvalidOperation("Source CRS is not PROJ exportable"); + } + if (!targetProjExportable) { + throw InvalidOperation("Target CRS is not PROJ exportable"); + } + auto projFormatter = io::PROJStringFormatter::create( + io::PROJStringFormatter::Convention::PROJ_4); + projFormatter->startInversion(); + sourceProjExportable->_exportToPROJString(projFormatter.get()); + + auto geogSrc = + dynamic_cast<const crs::GeographicCRS *>(sourceCRS.get()); + if (geogSrc) { + auto proj5Formatter = io::PROJStringFormatter::create( + io::PROJStringFormatter::Convention::PROJ_5); + geogSrc->addAngularUnitConvertAndAxisSwap(proj5Formatter.get()); + projFormatter->ingestPROJString(proj5Formatter->toString()); + } + + projFormatter->stopInversion(); + + targetProjExportable->_exportToPROJString(projFormatter.get()); + + auto geogDst = + dynamic_cast<const crs::GeographicCRS *>(targetCRS.get()); + if (geogDst) { + auto proj5Formatter = io::PROJStringFormatter::create( + io::PROJStringFormatter::Convention::PROJ_5); + geogDst->addAngularUnitConvertAndAxisSwap(proj5Formatter.get()); + projFormatter->ingestPROJString(proj5Formatter->toString()); + } + + const auto PROJString = projFormatter->toString(); + auto properties = util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + buildTransfName(sourceCRS->nameStr(), targetCRS->nameStr())); + res.emplace_back(SingleOperation::createPROJBased( + properties, PROJString, sourceCRS, targetCRS, {})); + return res; + } + auto geodSrc = dynamic_cast<const crs::GeodeticCRS *>(sourceCRS.get()); auto geodDst = dynamic_cast<const crs::GeodeticCRS *>(targetCRS.get()); @@ -10291,7 +10478,9 @@ CoordinateOperationFactory::Private::createOperations( const auto &dstDatum = geodDst->datum(); const bool dstHasDatumWithId = dstDatum && !dstDatum->identifiers().empty(); - if (srcHasDatumWithId && dstHasDatumWithId) { + if (srcHasDatumWithId && dstHasDatumWithId && + !srcDatum->_isEquivalentTo( + dstDatum.get(), util::IComparable::Criterion::EQUIVALENT)) { createOperationsWithDatumPivot(res, sourceCRS, targetCRS, geodSrc, geodDst, context); doFilterAndCheckPerfectOp = !res.empty(); @@ -10417,11 +10606,10 @@ CoordinateOperationFactory::Private::createOperations( dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); auto geogCRSOfBaseOfBoundSrc = boundSrc->baseCRS()->extractGeographicCRS(); - if (hubSrcGeog && + if (hubSrcGeog && geogCRSOfBaseOfBoundSrc && (hubSrcGeog->_isEquivalentTo( geogDst, util::IComparable::Criterion::EQUIVALENT) || - hubSrcGeog->is2DPartOf3D(NN_NO_CHECK(geogDst))) && - geogCRSOfBaseOfBoundSrc) { + hubSrcGeog->is2DPartOf3D(NN_NO_CHECK(geogDst)))) { if (boundSrc->baseCRS() == geogCRSOfBaseOfBoundSrc) { // Optimization to avoid creating a useless concatenated // operation @@ -10445,6 +10633,86 @@ CoordinateOperationFactory::Private::createOperations( return res; } } + // If the datum are equivalent, this is also fine + } else if (geogCRSOfBaseOfBoundSrc && hubSrcGeog->datum() && + geogDst->datum() && + hubSrcGeog->datum()->_isEquivalentTo( + geogDst->datum().get(), + util::IComparable::Criterion::EQUIVALENT)) { + auto opsFirst = + createOperations(boundSrc->baseCRS(), + NN_NO_CHECK(geogCRSOfBaseOfBoundSrc), context); + auto opsLast = createOperations(hubSrc, targetCRS, context); + if (!opsFirst.empty() && !opsLast.empty()) { + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsLast) { + try { + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + {opFirst, boundSrc->transformation(), + opLast}, + !allowEmptyIntersection)); + } catch (const InvalidOperationEmptyIntersection &) { + } + } + } + if (!res.empty()) { + return res; + } + } + // Consider WGS 84 and NAD83 as equivalent in that context if the + // geogCRSOfBaseOfBoundSrc ellipsoid is Clarke66 (for NAD27) + // Case of "+proj=latlong +ellps=clrk66 + // +nadgrids=ntv1_can.dat,conus" + // to "+proj=latlong +datum=NAD83" + } else if (geogCRSOfBaseOfBoundSrc && hubSrcGeog->datum() && + geogDst->datum() && + geogCRSOfBaseOfBoundSrc->ellipsoid()->_isEquivalentTo( + datum::Ellipsoid::CLARKE_1866.get(), + util::IComparable::Criterion::EQUIVALENT) && + hubSrcGeog->datum()->_isEquivalentTo( + datum::GeodeticReferenceFrame::EPSG_6326.get(), + util::IComparable::Criterion::EQUIVALENT) && + geogDst->datum()->_isEquivalentTo( + datum::GeodeticReferenceFrame::EPSG_6269.get(), + util::IComparable::Criterion::EQUIVALENT)) { + auto nnGeogCRSOfBaseOfBoundSrc = + NN_NO_CHECK(geogCRSOfBaseOfBoundSrc); + if (boundSrc->baseCRS()->_isEquivalentTo( + nnGeogCRSOfBaseOfBoundSrc.get(), + util::IComparable::Criterion::EQUIVALENT)) { + auto transf = boundSrc->transformation()->shallowClone(); + transf->setProperties(util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + buildTransfName(boundSrc->baseCRS()->nameStr(), + targetCRS->nameStr()))); + transf->setCRSs(boundSrc->baseCRS(), targetCRS, nullptr); + res.emplace_back(transf); + return res; + } else { + auto opsFirst = createOperations( + boundSrc->baseCRS(), nnGeogCRSOfBaseOfBoundSrc, context); + auto transf = boundSrc->transformation()->shallowClone(); + transf->setProperties(util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + buildTransfName(nnGeogCRSOfBaseOfBoundSrc->nameStr(), + targetCRS->nameStr()))); + transf->setCRSs(nnGeogCRSOfBaseOfBoundSrc, targetCRS, nullptr); + if (!opsFirst.empty()) { + for (const auto &opFirst : opsFirst) { + try { + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + {opFirst, transf}, + !allowEmptyIntersection)); + } catch (const InvalidOperationEmptyIntersection &) { + } + } + if (!res.empty()) { + return res; + } + } + } } if (hubSrcGeog && diff --git a/src/coordinatesystem.cpp b/src/coordinatesystem.cpp index f8d2d2b3..f1220878 100644 --- a/src/coordinatesystem.cpp +++ b/src/coordinatesystem.cpp @@ -416,6 +416,16 @@ bool CoordinateSystemAxis::_isEquivalentTo( // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +CoordinateSystemAxisNNPtr +CoordinateSystemAxis::alterUnit(const common::UnitOfMeasure &newUnit) const { + return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY, name()), + abbreviation(), direction(), newUnit, meridian()); +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress struct CoordinateSystem::Private { std::vector<CoordinateSystemAxisNNPtr> axisList{}; @@ -738,6 +748,43 @@ EllipsoidalCS::AxisOrder EllipsoidalCS::axisOrder() const { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +EllipsoidalCSNNPtr EllipsoidalCS::alterAngularUnit( + const common::UnitOfMeasure &angularUnit) const { + const auto &l_axisList = CoordinateSystem::getPrivate()->axisList; + if (l_axisList.size() == 2) { + return EllipsoidalCS::create(util::PropertyMap(), + l_axisList[0]->alterUnit(angularUnit), + l_axisList[1]->alterUnit(angularUnit)); + } else { + assert(l_axisList.size() == 3); + return EllipsoidalCS::create( + util::PropertyMap(), l_axisList[0]->alterUnit(angularUnit), + l_axisList[1]->alterUnit(angularUnit), l_axisList[2]); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +EllipsoidalCSNNPtr +EllipsoidalCS::alterLinearUnit(const common::UnitOfMeasure &linearUnit) const { + const auto &l_axisList = CoordinateSystem::getPrivate()->axisList; + if (l_axisList.size() == 2) { + return EllipsoidalCS::create(util::PropertyMap(), l_axisList[0], + l_axisList[1]); + } else { + assert(l_axisList.size() == 3); + return EllipsoidalCS::create(util::PropertyMap(), l_axisList[0], + l_axisList[1], + l_axisList[2]->alterUnit(linearUnit)); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress VerticalCS::~VerticalCS() = default; //! @endcond @@ -788,6 +835,16 @@ VerticalCS::createGravityRelatedHeight(const common::UnitOfMeasure &unit) { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +VerticalCSNNPtr VerticalCS::alterUnit(const common::UnitOfMeasure &unit) const { + const auto &l_axisList = CoordinateSystem::getPrivate()->axisList; + return VerticalCS::nn_make_shared<VerticalCS>( + l_axisList[0]->alterUnit(unit)); +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress CartesianCS::~CartesianCS() = default; //! @endcond @@ -863,6 +920,27 @@ CartesianCS::createEastingNorthing(const common::UnitOfMeasure &unit) { // --------------------------------------------------------------------------- +/** \brief Instanciate a CartesianCS with a Northing (first) and Easting + * (second) axis. + * + * @param unit Linear unit of the axes. + * @return a new CartesianCS. + */ +CartesianCSNNPtr +CartesianCS::createNorthingEasting(const common::UnitOfMeasure &unit) { + return create(util::PropertyMap(), + CoordinateSystemAxis::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, + AxisName::Northing), + AxisAbbreviation::N, AxisDirection::NORTH, unit), + CoordinateSystemAxis::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, + AxisName::Easting), + AxisAbbreviation::E, AxisDirection::EAST, unit)); +} + +// --------------------------------------------------------------------------- + /** \brief Instanciate a CartesianCS with the three geocentric axes. * * @param unit Liinear unit of the axes. @@ -888,6 +966,25 @@ CartesianCS::createGeocentric(const common::UnitOfMeasure &unit) { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +CartesianCSNNPtr +CartesianCS::alterUnit(const common::UnitOfMeasure &unit) const { + const auto &l_axisList = CoordinateSystem::getPrivate()->axisList; + if (l_axisList.size() == 2) { + return CartesianCS::create(util::PropertyMap(), + l_axisList[0]->alterUnit(unit), + l_axisList[1]->alterUnit(unit)); + } else { + assert(l_axisList.size() == 3); + return CartesianCS::create( + util::PropertyMap(), l_axisList[0]->alterUnit(unit), + l_axisList[1]->alterUnit(unit), l_axisList[2]->alterUnit(unit)); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress OrdinalCS::~OrdinalCS() = default; //! @endcond diff --git a/src/crs.cpp b/src/crs.cpp index a204a037..31682644 100644 --- a/src/crs.cpp +++ b/src/crs.cpp @@ -45,6 +45,7 @@ #include "proj/internal/internal.hpp" #include "proj/internal/io_internal.hpp" +#include <algorithm> #include <cassert> #include <cstring> #include <iostream> @@ -88,6 +89,20 @@ namespace crs { struct CRS::Private { BoundCRSPtr canonicalBoundCRS_{}; std::string extensionProj4_{}; + bool implicitCS_ = false; + + void setImplicitCS(const util::PropertyMap &properties) { + auto oIter = properties.find("IMPLICIT_CS"); + if (oIter != properties.end()) { + if (auto genVal = util::nn_dynamic_pointer_cast<util::BoxedValue>( + oIter->second)) { + if (genVal->type() == util::BoxedValue::Type::BOOLEAN && + genVal->booleanValue()) { + implicitCS_ = true; + } + } + } + } }; //! @endcond @@ -170,6 +185,14 @@ const GeodeticCRS *CRS::extractGeodeticCRSRaw() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +const std::string &CRS::getExtensionProj4() const noexcept { + return d->extensionProj4_; +} +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Return the GeographicCRS of the CRS. * * Returns the GeographicCRS contained in a CRS. This works currently with @@ -189,6 +212,97 @@ GeographicCRSPtr CRS::extractGeographicCRS() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +static util::PropertyMap createPropertyMapName(const std::string &name) { + return util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, name); +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +CRSNNPtr CRS::alterGeodeticCRS(const GeodeticCRSNNPtr &newGeodCRS) const { + auto geodCRS = dynamic_cast<const GeodeticCRS *>(this); + if (geodCRS) { + return newGeodCRS; + } + + auto projCRS = dynamic_cast<const ProjectedCRS *>(this); + if (projCRS) { + return ProjectedCRS::create( + createPropertyMapName(nameStr()), newGeodCRS, + projCRS->derivingConversionRef(), projCRS->coordinateSystem()); + } + + auto compoundCRS = dynamic_cast<const CompoundCRS *>(this); + if (compoundCRS) { + std::vector<CRSNNPtr> components; + for (const auto &subCrs : compoundCRS->componentReferenceSystems()) { + components.emplace_back(subCrs->alterGeodeticCRS(newGeodCRS)); + } + return CompoundCRS::create(createPropertyMapName(nameStr()), + components); + } + + return NN_NO_CHECK( + std::dynamic_pointer_cast<CRS>(shared_from_this().as_nullable())); +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +CRSNNPtr CRS::alterCSLinearUnit(const common::UnitOfMeasure &unit) const { + { + auto projCRS = dynamic_cast<const ProjectedCRS *>(this); + if (projCRS) { + return ProjectedCRS::create( + createPropertyMapName(projCRS->nameStr().c_str()), + projCRS->baseCRS(), projCRS->derivingConversionRef(), + projCRS->coordinateSystem()->alterUnit(unit)); + } + } + + { + auto geodCRS = dynamic_cast<const GeodeticCRS *>(this); + if (geodCRS && geodCRS->isGeocentric()) { + auto cs = dynamic_cast<const cs::CartesianCS *>( + geodCRS->coordinateSystem().get()); + assert(cs); + return GeodeticCRS::create( + createPropertyMapName(geodCRS->nameStr().c_str()), + geodCRS->datum(), geodCRS->datumEnsemble(), + cs->alterUnit(unit)); + } + } + + { + auto geogCRS = dynamic_cast<const GeographicCRS *>(this); + if (geogCRS && geogCRS->coordinateSystem()->axisList().size() == 3) { + return GeographicCRS::create( + createPropertyMapName(geogCRS->nameStr().c_str()), + geogCRS->datum(), geogCRS->datumEnsemble(), + geogCRS->coordinateSystem()->alterLinearUnit(unit)); + } + } + + { + auto vertCRS = dynamic_cast<const VerticalCRS *>(this); + if (vertCRS) { + return VerticalCRS::create( + createPropertyMapName(vertCRS->nameStr().c_str()), + vertCRS->datum(), vertCRS->datumEnsemble(), + vertCRS->coordinateSystem()->alterUnit(unit)); + } + } + + return NN_NO_CHECK( + std::dynamic_pointer_cast<CRS>(shared_from_this().as_nullable())); +} +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Return the VerticalCRS of the CRS. * * Returns the VerticalCRS contained in a CRS. This works currently with @@ -383,6 +497,19 @@ CRSNNPtr CRS::shallowClone() const { return _shallowClone(); } // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress + +CRSNNPtr CRS::alterName(const std::string &newName) const { + auto crs = shallowClone(); + crs->setProperties( + util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, newName)); + return crs; +} + +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Identify the CRS with reference CRSs. * * The candidate CRSs are either hard-coded, or looked in the database when @@ -748,6 +875,7 @@ GeodeticCRS::create(const util::PropertyMap &properties, crs->setProperties(properties); properties.getStringValue("EXTENSION_PROJ4", crs->CRS::getPrivate()->extensionProj4_); + return crs; } @@ -853,7 +981,16 @@ void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { if (!isWKT2) { unit._exportToWKT(formatter); } + + const auto oldAxisOutputRule = formatter->outputAxis(); + if (oldAxisOutputRule == + io::WKTFormatter::OutputAxisRule::WKT1_GDAL_EPSG_STYLE && + isGeocentric()) { + formatter->setOutputAxis(io::WKTFormatter::OutputAxisRule::YES); + } cs->_exportToWKT(formatter); + formatter->setOutputAxis(oldAxisOutputRule); + ObjectUsage::baseExportToWKT(formatter); if (!isWKT2 && !formatter->useESRIDialect()) { @@ -1062,6 +1199,12 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { std::list<Pair> res; const auto &thisName(nameStr()); + const bool l_implicitCS = CRS::getPrivate()->implicitCS_; + const auto crsCriterion = + l_implicitCS + ? util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS + : util::IComparable::Criterion::EQUIVALENT; + const GeographicCRSNNPtr candidatesCRS[] = {GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4267, GeographicCRS::EPSG_4269}; @@ -1069,8 +1212,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const bool nameEquivalent = metadata::Identifier::isEquivalentName( thisName.c_str(), crs->nameStr().c_str()); const bool nameEqual = thisName == crs->nameStr(); - const bool isEq = _isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT); + const bool isEq = _isEquivalentTo(crs.get(), crsCriterion); if (nameEquivalent && isEq && (!authorityFactory || nameEqual)) { res.emplace_back(util::nn_static_pointer_cast<GeodeticCRS>(crs), nameEqual ? 100 : 90); @@ -1105,15 +1247,13 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisDatum(datum()); auto searchByDatum = [this, &authorityFactory, &res, &thisDatum, - &geodetic_crs_type]() { + &geodetic_crs_type, crsCriterion]() { for (const auto &id : thisDatum->identifiers()) { try { auto tempRes = authorityFactory->createGeodeticCRSFromDatum( *id->codeSpace(), id->code(), geodetic_crs_type); for (const auto &crs : tempRes) { - if (_isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + if (_isEquivalentTo(crs.get(), crsCriterion)) { res.emplace_back(crs, 70); } } @@ -1124,7 +1264,8 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisEllipsoid(ellipsoid()); auto searchByEllipsoid = [this, &authorityFactory, &res, &thisDatum, - &thisEllipsoid, &geodetic_crs_type]() { + &thisEllipsoid, &geodetic_crs_type, + l_implicitCS]() { const auto ellipsoids = thisEllipsoid->identifiers().empty() ? authorityFactory->createEllipsoidFromExisting( @@ -1146,11 +1287,11 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { crsDatum->primeMeridian()->_isEquivalentTo( thisDatum->primeMeridian().get(), util::IComparable::Criterion::EQUIVALENT) && - coordinateSystem()->_isEquivalentTo( - crs->coordinateSystem().get(), - util::IComparable::Criterion::EQUIVALENT) - - ) { + (!l_implicitCS || + coordinateSystem()->_isEquivalentTo( + crs->coordinateSystem().get(), + util::IComparable::Criterion:: + EQUIVALENT))) { res.emplace_back(crs, 60); } } @@ -1181,14 +1322,14 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { authorityFactory->databaseContext(), *id->codeSpace()) ->createGeodeticCRS(id->code()); - bool match = _isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT); + bool match = _isEquivalentTo(crs.get(), crsCriterion); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { } } } else { + bool gotAbove25Pct = false; for (int ipass = 0; ipass < 2; ipass++) { const bool approximateMatch = ipass == 1; auto objects = authorityFactory->createObjectsFromName( @@ -1198,9 +1339,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { auto crs = util::nn_dynamic_pointer_cast<GeodeticCRS>(obj); assert(crs); auto crsNN = NN_NO_CHECK(crs); - if (_isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + if (_isEquivalentTo(crs.get(), crsCriterion)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); @@ -1210,6 +1349,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { metadata::Identifier::isEquivalentName( thisName.c_str(), crs->nameStr().c_str()); res.emplace_back(crsNN, eqName ? 90 : 70); + gotAbove25Pct = true; } else { res.emplace_back(crsNN, 25); } @@ -1218,7 +1358,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { break; } } - if (res.empty() && thisDatum) { + if (!gotAbove25Pct && thisDatum) { if (!thisDatum->identifiers().empty()) { searchByDatum(); } else { @@ -1446,6 +1586,7 @@ GeographicCRS::create(const util::PropertyMap &properties, crs->setProperties(properties); properties.getStringValue("EXTENSION_PROJ4", crs->CRS::getPrivate()->extensionProj4_); + crs->CRS::getPrivate()->setImplicitCS(properties); return crs; } @@ -2274,6 +2415,63 @@ const cs::CartesianCSNNPtr &ProjectedCRS::coordinateSystem() PROJ_CONST_DEFN { void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; + const auto &l_identifiers = identifiers(); + // Try to perfectly round-trip ESRI projectedCRS if the current object + // perfectly matches the database definition + const auto &dbContext = formatter->databaseContext(); + + auto l_name = nameStr(); + std::string l_alias; + if (formatter->useESRIDialect() && dbContext) { + l_alias = dbContext->getAliasFromOfficialName(l_name, "projected_crs", + "ESRI"); + } + + if (!isWKT2 && formatter->useESRIDialect() && !l_identifiers.empty() && + *(l_identifiers[0]->codeSpace()) == "ESRI" && dbContext) { + try { + const auto definition = dbContext->getTextDefinition( + "projected_crs", "ESRI", l_identifiers[0]->code()); + if (starts_with(definition, "PROJCS")) { + auto crsFromFromDef = io::WKTParser() + .attachDatabaseContext(dbContext) + .createFromWKT(definition); + if (_isEquivalentTo( + dynamic_cast<IComparable *>(crsFromFromDef.get()), + util::IComparable::Criterion::EQUIVALENT)) { + formatter->ingestWKTNode( + io::WKTNode::createFrom(definition)); + return; + } + } + } catch (const std::exception &) { + } + } else if (!isWKT2 && formatter->useESRIDialect() && !l_alias.empty()) { + try { + auto res = + io::AuthorityFactory::create(NN_NO_CHECK(dbContext), "ESRI") + ->createObjectsFromName( + l_alias, + {io::AuthorityFactory::ObjectType::PROJECTED_CRS}, + false); + if (res.size() == 1) { + const auto definition = dbContext->getTextDefinition( + "projected_crs", "ESRI", + res.front()->identifiers()[0]->code()); + if (starts_with(definition, "PROJCS")) { + if (_isEquivalentTo( + dynamic_cast<IComparable *>(res.front().get()), + util::IComparable::Criterion::EQUIVALENT)) { + formatter->ingestWKTNode( + io::WKTNode::createFrom(definition)); + return; + } + } + } + } catch (const std::exception &) { + } + } + const auto &l_coordinateSystem = d->coordinateSystem(); const auto &axisList = l_coordinateSystem->axisList(); @@ -2292,7 +2490,7 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { if (!isWKT2 && !formatter->useESRIDialect() && starts_with(nameStr(), "Popular Visualisation CRS / Mercator")) { - formatter->startNode(io::WKTConstants::PROJCS, !identifiers().empty()); + formatter->startNode(io::WKTConstants::PROJCS, !l_identifiers.empty()); formatter->addQuotedString(nameStr()); formatter->setTOWGS84Parameters({0, 0, 0, 0, 0, 0, 0}); baseCRS()->_exportToWKT(formatter); @@ -2332,21 +2530,13 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { formatter->startNode(isWKT2 ? io::WKTConstants::PROJCRS : io::WKTConstants::PROJCS, - !identifiers().empty()); - auto l_name = nameStr(); + !l_identifiers.empty()); + if (formatter->useESRIDialect()) { - bool aliasFound = false; - const auto &dbContext = formatter->databaseContext(); - if (dbContext) { - auto l_alias = dbContext->getAliasFromOfficialName( - l_name, "projected_crs", "ESRI"); - if (!l_alias.empty()) { - l_name = l_alias; - aliasFound = true; - } - } - if (!aliasFound) { + if (l_alias.empty()) { l_name = io::WKTFormatter::morphNameToESRI(l_name); + } else { + l_name = l_alias; } } if (!isWKT2 && !formatter->useESRIDialect() && isDeprecated()) { @@ -2461,6 +2651,7 @@ ProjectedCRS::create(const util::PropertyMap &properties, crs->setDerivingConversionCRS(); properties.getStringValue("EXTENSION_PROJ4", crs->CRS::getPrivate()->extensionProj4_); + crs->CRS::getPrivate()->setImplicitCS(properties); return crs; } @@ -2477,6 +2668,19 @@ bool ProjectedCRS::_isEquivalentTo( // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +ProjectedCRSNNPtr +ProjectedCRS::alterParametersLinearUnit(const common::UnitOfMeasure &unit, + bool convertToNewUnit) const { + return create(createPropertyMapName(nameStr()), baseCRS(), + derivingConversionRef()->alterParametersLinearUnit( + unit, convertToNewUnit), + coordinateSystem()); +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter, bool axisSpecFound) const { const auto &axisList = d->coordinateSystem()->axisList(); @@ -2702,7 +2906,8 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { *id->codeSpace()) ->createProjectedCRS(id->code()); bool match = _isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT); + crs.get(), util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { @@ -2723,13 +2928,27 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { foundEquivalentName |= eqName; if (_isEquivalentTo( crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); return res; } res.emplace_back(crsNN, eqName ? 90 : 70); + } else if (crs->nameStr() == thisName && + CRS::getPrivate()->implicitCS_ && + l_baseCRS->_isEquivalentTo( + crs->baseCRS().get(), + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) && + derivingConversionRef()->_isEquivalentTo( + crs->derivingConversionRef().get(), + util::IComparable::Criterion::EQUIVALENT) && + objects.size() == 1) { + res.clear(); + res.emplace_back(crsNN, 100); + return res; } else { res.emplace_back(crsNN, 25); } @@ -2791,7 +3010,8 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { } if (_isEquivalentTo(crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)) { res.emplace_back(crs, unsignificantName ? 90 : 70); } else if (ellipsoid->_isEquivalentTo( crs->baseCRS()->ellipsoid().get(), @@ -3529,9 +3749,26 @@ BoundCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const { } } catch (const std::exception &) { } + bool foundOp = false; for (const auto &op : ops) { std::string opTransfPROJString; bool opTransfPROJStringValid = false; + if (op->nameStr().find("Null geographic") == 0) { + if (isTOWGS84Compatible()) { + auto params = + transformation()->getTOWGS84Parameters(); + if (params == + std::vector<double>{0, 0, 0, 0, 0, 0, 0}) { + res.emplace_back(create(candidateBaseCRS, + d->hubCRS_, + transformation()), + pair.second); + foundOp = true; + break; + } + } + continue; + } try { opTransfPROJString = op->exportToPROJString( io::PROJStringFormatter::create().get()); @@ -3548,9 +3785,15 @@ BoundCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const { NN_NO_CHECK(util::nn_dynamic_pointer_cast< operation::Transformation>(op))), pair.second); + foundOp = true; break; } } + if (!foundOp) { + res.emplace_back( + create(candidateBaseCRS, d->hubCRS_, transformation()), + std::min(70, pair.second)); + } } } } diff --git a/src/cs2cs.c b/src/cs2cs.c deleted file mode 100644 index d9e37528..00000000 --- a/src/cs2cs.c +++ /dev/null @@ -1,463 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Mainline program sort of like ``proj'' for converting between - * two coordinate systems. - * Author: Frank Warmerdam, warmerda@home.com - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include <ctype.h> -#include <locale.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "proj.h" -#include "projects.h" -#include "emess.h" - -#define MAX_LINE 1000 -#define MAX_PARGS 100 - -static projPJ fromProj, toProj; - -static int -reversein = 0, /* != 0 reverse input arguments */ -reverseout = 0, /* != 0 reverse output arguments */ -echoin = 0, /* echo input data to output line */ -tag = '#'; /* beginning of line tag character */ - static char -*oform = (char *)0, /* output format for x-y or decimal degrees */ - oform_buffer[16], /* buffer for oform when using -d */ -*oterr = "*\t*", /* output line for unprojectable input */ -*usage = -"%s\nusage: %s [ -dDeEfIlrstvwW [args] ] [ +opts[=arg] ]\n" -" [+to [+opts[=arg] [ files ]\n"; - -static double (*informat)(const char *, - char **); /* input data deformatter function */ - - -/************************************************************************/ -/* process() */ -/* */ -/* File processing function. */ -/************************************************************************/ -static void process(FILE *fid) - -{ - char line[MAX_LINE+3], *s, pline[40]; - projUV data; - - for (;;) { - double z; - - ++emess_dat.File_line; - if (!(s = fgets(line, MAX_LINE, fid))) - break; - if (!strchr(s, '\n')) { /* overlong line */ - int c; - (void)strcat(s, "\n"); - /* gobble up to newline */ - while ((c = fgetc(fid)) != EOF && c != '\n') ; - } - if (*s == tag) { - fputs(line, stdout); - continue; - } - - if (reversein) { - data.v = (*informat)(s, &s); - data.u = (*informat)(s, &s); - } else { - data.u = (*informat)(s, &s); - data.v = (*informat)(s, &s); - } - - z = strtod( s, &s ); - - if (data.v == HUGE_VAL) - data.u = HUGE_VAL; - - if (!*s && (s > line)) --s; /* assumed we gobbled \n */ - - if ( echoin) { - char t; - t = *s; - *s = '\0'; - (void)fputs(line, stdout); - *s = t; - putchar('\t'); - } - - if (data.u != HUGE_VAL) { - if( pj_transform( fromProj, toProj, 1, 0, - &(data.u), &(data.v), &z ) != 0 ) - { - data.u = HUGE_VAL; - data.v = HUGE_VAL; - emess(-3,"pj_transform(): %s", pj_strerrno(pj_errno)); - } - } - - if (data.u == HUGE_VAL) /* error output */ - fputs(oterr, stdout); - - else if (pj_is_latlong(toProj) && !oform) { /*ascii DMS output */ - if (reverseout) { - fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - putchar('\t'); - fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - } else { - fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - putchar('\t'); - fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - } - - } else { /* x-y or decimal degree ascii output */ - if ( proj_angular_output(toProj, PJ_FWD) ) { - data.v *= RAD_TO_DEG; - data.u *= RAD_TO_DEG; - } - if (reverseout) { - printf(oform,data.v); putchar('\t'); - printf(oform,data.u); - } else { - printf(oform,data.u); putchar('\t'); - printf(oform,data.v); - } - } - - putchar(' '); - if( oform != NULL ) - printf( oform, z ); - else - printf( "%.3f", z ); - if( s ) - printf( "%s", s ); - else - printf( "\n" ); - } -} - -/************************************************************************/ -/* main() */ -/************************************************************************/ - -int main(int argc, char **argv) -{ - char *arg, **eargv = argv, *from_argv[MAX_PARGS], *to_argv[MAX_PARGS]; - FILE *fid; - int from_argc=0, to_argc=0, eargc = 0, mon = 0; - int have_to_flag = 0, inverse = 0, i; - int use_env_locale = 0; - - /* This is just to check that pj_init() is locale-safe */ - /* Used by nad/testvarious */ - if( getenv("PROJ_USE_ENV_LOCALE") != NULL ) - use_env_locale = 1; - - if ((emess_dat.Prog_name = strrchr(*argv,DIR_CHAR)) != NULL) - ++emess_dat.Prog_name; - else emess_dat.Prog_name = *argv; - inverse = ! strncmp(emess_dat.Prog_name, "inv", 3); - if (argc <= 1 ) { - (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name); - exit (0); - } - /* process run line arguments */ - while (--argc > 0) { /* collect run line arguments */ - if(**++argv == '-') for(arg = *argv;;) { - switch(*++arg) { - case '\0': /* position of "stdin" */ - if (arg[-1] == '-') eargv[eargc++] = "-"; - break; - case 'v': /* monitor dump of initialization */ - mon = 1; - continue; - case 'I': /* alt. method to spec inverse */ - inverse = 1; - continue; - case 'E': /* echo ascii input to ascii output */ - echoin = 1; - continue; - case 't': /* set col. one char */ - if (arg[1]) tag = *++arg; - else emess(1,"missing -t col. 1 tag"); - continue; - case 'l': /* list projections, ellipses or units */ - if (!arg[1] || arg[1] == 'p' || arg[1] == 'P') { - /* list projections */ - const struct PJ_LIST *lp; - int do_long = arg[1] == 'P', c; - const char *str; - - for (lp = proj_list_operations() ; lp->id ; ++lp) { - (void)printf("%s : ", lp->id); - if (do_long) /* possibly multiline description */ - (void)puts(*lp->descr); - else { /* first line, only */ - str = *lp->descr; - while ((c = *str++) && c != '\n') - putchar(c); - putchar('\n'); - } - } - } else if (arg[1] == '=') { /* list projection 'descr' */ - const struct PJ_LIST *lp; - - arg += 2; - for (lp = proj_list_operations() ; lp->id ; ++lp) - if (!strcmp(lp->id, arg)) { - (void)printf("%9s : %s\n", lp->id, *lp->descr); - break; - } - } else if (arg[1] == 'e') { /* list ellipses */ - const struct PJ_ELLPS *le; - - for (le = proj_list_ellps(); le->id ; ++le) - (void)printf("%9s %-16s %-16s %s\n", - le->id, le->major, le->ell, le->name); - } else if (arg[1] == 'u') { /* list units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units(); lu->id ; ++lu) - (void)printf("%12s %-20s %s\n", - lu->id, lu->to_meter, lu->name); - } else if (arg[1] == 'd') { /* list datums */ - const struct PJ_DATUMS *ld; - - printf("__datum_id__ __ellipse___ __definition/comments______________________________\n" ); - for (ld = pj_get_datums_ref(); ld->id ; ++ld) - { - printf("%12s %-12s %-30s\n", - ld->id, ld->ellipse_id, ld->defn); - if( ld->comments != NULL && strlen(ld->comments) > 0 ) - printf( "%25s %s\n", " ", ld->comments ); - } - } else if( arg[1] == 'm') { /* list prime meridians */ - const struct PJ_PRIME_MERIDIANS *lpm; - - for (lpm = proj_list_prime_meridians(); lpm->id ; ++lpm) - (void)printf("%12s %-30s\n", - lpm->id, lpm->defn); - } else - emess(1,"invalid list option: l%c",arg[1]); - exit(0); - /* cppcheck-suppress duplicateBreak */ - continue; /* artificial */ - case 'e': /* error line alternative */ - if (--argc <= 0) - noargument: - emess(1,"missing argument for -%c",*arg); - oterr = *++argv; - continue; - case 'W': /* specify seconds precision */ - case 'w': /* -W for constant field width */ - { - char c = arg[1]; - if (c != 0 && isdigit(c)) { - set_rtodms(c - '0', *arg == 'W'); - ++arg; - } else - emess(1,"-W argument missing or non-digit"); - continue; - } - case 'f': /* alternate output format degrees or xy */ - if (--argc <= 0) goto noargument; - oform = *++argv; - continue; - case 'r': /* reverse input */ - reversein = 1; - continue; - case 's': /* reverse output */ - reverseout = 1; - continue; - case 'D': /* set debug level */ - if (--argc <= 0) goto noargument; - pj_ctx_set_debug( pj_get_default_ctx(), atoi(*++argv)); - continue; - case 'd': - if (--argc <= 0) goto noargument; - sprintf(oform_buffer, "%%.%df", atoi(*++argv)); - oform = oform_buffer; - break; - default: - emess(1, "invalid option: -%c",*arg); - break; - } - break; - - } else if (strcmp(*argv,"+to") == 0 ) { - have_to_flag = 1; - - } else if (**argv == '+') { /* + argument */ - if( have_to_flag ) - { - if( to_argc < MAX_PARGS ) - to_argv[to_argc++] = *argv + 1; - else - emess(1,"overflowed + argument table"); - } - else - { - if (from_argc < MAX_PARGS) - from_argv[from_argc++] = *argv + 1; - else - emess(1,"overflowed + argument table"); - } - } else /* assumed to be input file name(s) */ - eargv[eargc++] = *argv; - } - if (eargc == 0 ) /* if no specific files force sysin */ - eargv[eargc++] = "-"; - - /* - * If the user has requested inverse, then just reverse the - * coordinate systems. - */ - if( inverse ) - { - int argcount; - - for( i = 0; i < MAX_PARGS; i++ ) - { - arg = from_argv[i]; - from_argv[i] = to_argv[i]; - to_argv[i] = arg; - } - - argcount = from_argc; - from_argc = to_argc; - to_argc = argcount; - } - - if( use_env_locale ) - { - /* Set locale from environment */ - setlocale(LC_ALL, ""); - } - - if( from_argc == 0 && to_argc != 0 ) - { - /* we will generate the from proj as the latlong of the +to in a bit */ - } - else if (!(fromProj = pj_init(from_argc, from_argv))) - { - printf( "Using from definition: " ); - for( i = 0; i < from_argc; i++ ) - printf( "%s ", from_argv[i] ); - printf( "\n" ); - - emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); - } - - if( to_argc == 0 ) - { - if (!(toProj = pj_latlong_from_proj( fromProj ))) - { - printf( "Using to definition: " ); - for( i = 0; i < to_argc; i++ ) - printf( "%s ", to_argv[i] ); - printf( "\n" ); - - emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); - } - } - else if (!(toProj = pj_init(to_argc, to_argv))) - { - printf( "Using to definition: " ); - for( i = 0; i < to_argc; i++ ) - printf( "%s ", to_argv[i] ); - printf( "\n" ); - - emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); - } - - if( from_argc == 0 && toProj != NULL) - { - if (!(fromProj = pj_latlong_from_proj( toProj ))) - { - printf( "Using to definition: " ); - for( i = 0; i < to_argc; i++ ) - printf( "%s ", to_argv[i] ); - printf( "\n" ); - - emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); - } - } - - if( use_env_locale ) - { - /* Restore C locale to avoid issues in parsing/outputting numbers*/ - setlocale(LC_ALL, "C"); - } - - if (mon) { - printf( "%c ---- From Coordinate System ----\n", tag ); - pj_pr_list(fromProj); - printf( "%c ---- To Coordinate System ----\n", tag ); - pj_pr_list(toProj); - } - - /* set input formatting control */ - if( !fromProj->is_latlong ) - informat = strtod; - else { - informat = dmstor; - } - - if( !toProj->is_latlong && !oform ) - oform = "%.2f"; - - /* process input file list */ - for ( ; eargc-- ; ++eargv) { - if (**eargv == '-') { - fid = stdin; - emess_dat.File_name = "<stdin>"; - - } else { - if ((fid = fopen(*eargv, "rt")) == NULL) { - emess(-2, *eargv, "input file"); - continue; - } - emess_dat.File_name = *eargv; - } - emess_dat.File_line = 0; - process(fid); - fclose(fid); - emess_dat.File_name = 0; - } - - pj_free( fromProj ); - pj_free( toProj ); - - pj_deallocate_grids(); - - exit(0); /* normal completion */ -} diff --git a/src/cs2cs.cpp b/src/cs2cs.cpp new file mode 100644 index 00000000..a8d126cf --- /dev/null +++ b/src/cs2cs.cpp @@ -0,0 +1,636 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Mainline program sort of like ``proj'' for converting between + * two coordinate systems. + * Author: Frank Warmerdam, warmerda@home.com + * + ****************************************************************************** + * Copyright (c) 2000, Frank Warmerdam + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#define FROM_PROJ_CPP + +#include <ctype.h> +#include <locale.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cassert> +#include <string> + +#include <proj/internal/internal.hpp> + +// PROJ include order is sensitive +// clang-format off +#include "proj.h" +#include "projects.h" +#include "emess.h" +// clang-format on + +#define MAX_LINE 1000 + +static PJ *transformation = nullptr; + +static bool srcIsGeog = false; +static double srcToRadians = 0.0; + +static bool destIsGeog = false; +static double destToRadians = 0.0; +static bool destIsLatLong = false; + +static int reversein = 0, /* != 0 reverse input arguments */ + reverseout = 0, /* != 0 reverse output arguments */ + echoin = 0, /* echo input data to output line */ + tag = '#'; /* beginning of line tag character */ + +static const char *oform = + nullptr; /* output format for x-y or decimal degrees */ +static char oform_buffer[16]; /* buffer for oform when using -d */ +static const char *oterr = "*\t*"; /* output line for unprojectable input */ +static const char *usage = + "%s\nusage: %s [ -dDeEfIlrstvwW [args] ] [ +opts[=arg] ]\n" + " [+to [+opts[=arg] [ files ]\n"; + +static double (*informat)(const char *, + char **); /* input data deformatter function */ + +/************************************************************************/ +/* process() */ +/* */ +/* File processing function. */ +/************************************************************************/ +static void process(FILE *fid) + +{ + char line[MAX_LINE + 3], *s, pline[40]; + projUV data; + + for (;;) { + double z; + + ++emess_dat.File_line; + if (!(s = fgets(line, MAX_LINE, fid))) + break; + if (!strchr(s, '\n')) { /* overlong line */ + int c; + (void)strcat(s, "\n"); + /* gobble up to newline */ + while ((c = fgetc(fid)) != EOF && c != '\n') + ; + } + if (*s == tag) { + fputs(line, stdout); + continue; + } + + if (reversein) { + data.v = (*informat)(s, &s); + data.u = (*informat)(s, &s); + } else { + data.u = (*informat)(s, &s); + data.v = (*informat)(s, &s); + } + + z = strtod(s, &s); + + if (data.v == HUGE_VAL) + data.u = HUGE_VAL; + + if (!*s && (s > line)) + --s; /* assumed we gobbled \n */ + + if (echoin) { + char t; + t = *s; + *s = '\0'; + (void)fputs(line, stdout); + *s = t; + putchar('\t'); + } + + if (data.u != HUGE_VAL) { + + if (srcIsGeog) { + /* dmstor gives values to radians. Convert now to the SRS unit + */ + data.u /= srcToRadians; + data.v /= srcToRadians; + } + + PJ_COORD coord; + coord.xyzt.x = data.u; + coord.xyzt.y = data.v; + coord.xyzt.z = z; + coord.xyzt.t = HUGE_VAL; + coord = proj_trans(transformation, PJ_FWD, coord); + data.u = coord.xyz.x; + data.v = coord.xyz.y; + z = coord.xyz.z; + } + + if (data.u == HUGE_VAL) /* error output */ + fputs(oterr, stdout); + + else if (destIsGeog && !oform) { /*ascii DMS output */ + + // rtodms() expect radians: convert from the output SRS unit + data.u *= destToRadians; + data.v *= destToRadians; + + if (destIsLatLong) { + if (reverseout) { + fputs(rtodms(pline, data.v, 'E', 'W'), stdout); + putchar('\t'); + fputs(rtodms(pline, data.u, 'N', 'S'), stdout); + } else { + fputs(rtodms(pline, data.u, 'N', 'S'), stdout); + putchar('\t'); + fputs(rtodms(pline, data.v, 'E', 'W'), stdout); + } + } else if (reverseout) { + fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + putchar('\t'); + fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + } else { + fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + putchar('\t'); + fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + } + + } else { /* x-y or decimal degree ascii output */ + if (destIsGeog) { + data.v *= destToRadians * RAD_TO_DEG; + data.u *= destToRadians * RAD_TO_DEG; + } + if (reverseout) { + printf(oform, data.v); + putchar('\t'); + printf(oform, data.u); + } else { + printf(oform, data.u); + putchar('\t'); + printf(oform, data.v); + } + } + + putchar(' '); + if (oform != nullptr) + printf(oform, z); + else + printf("%.3f", z); + if (s) + printf("%s", s); + else + printf("\n"); + } +} + +/************************************************************************/ +/* instanciate_crs() */ +/************************************************************************/ + +static PJ_OBJ *instanciate_crs(const std::string &definition, + const char *const *optionsImportCRS, + bool &isGeog, double &toRadians, + bool &isLatFirst) { + PJ_OBJ *crs = proj_obj_create_from_user_input(nullptr, definition.c_str(), + optionsImportCRS); + if (!crs) { + return nullptr; + } + + isGeog = false; + toRadians = 0.0; + isLatFirst = false; + + auto type = proj_obj_get_type(crs); + if (type == PJ_OBJ_TYPE_BOUND_CRS) { + auto base = proj_obj_get_source_crs(nullptr, crs); + proj_obj_unref(crs); + crs = base; + type = proj_obj_get_type(crs); + } + if (type == PJ_OBJ_TYPE_GEOGRAPHIC_2D_CRS || + type == PJ_OBJ_TYPE_GEOGRAPHIC_3D_CRS) { + auto cs = proj_obj_crs_get_coordinate_system(nullptr, crs); + assert(cs); + + isGeog = true; + const char *axisName = ""; + proj_obj_cs_get_axis_info(nullptr, cs, 0, + &axisName, // name, + nullptr, // abbrev + nullptr, // direction + &toRadians, + nullptr // unit name + ); + isLatFirst = + NS_PROJ::internal::ci_find(std::string(axisName), "latitude") != + std::string::npos; + + proj_obj_unref(cs); + } + + return crs; +} + +/************************************************************************/ +/* get_geog_crs_proj_string_from_proj_crs() */ +/************************************************************************/ + +static std::string get_geog_crs_proj_string_from_proj_crs(PJ_OBJ *src, + double &toRadians, + bool &isLatFirst) { + auto srcType = proj_obj_get_type(src); + if (srcType == PJ_OBJ_TYPE_BOUND_CRS) { + auto base = proj_obj_get_source_crs(nullptr, src); + assert(base); + proj_obj_unref(src); + src = base; + srcType = proj_obj_get_type(src); + } + if (srcType != PJ_OBJ_TYPE_PROJECTED_CRS) { + return std::string(); + } + + auto base = proj_obj_get_source_crs(nullptr, src); + assert(base); + auto baseType = proj_obj_get_type(base); + if (baseType != PJ_OBJ_TYPE_GEOGRAPHIC_2D_CRS && + baseType != PJ_OBJ_TYPE_GEOGRAPHIC_3D_CRS) { + proj_obj_unref(base); + return std::string(); + } + + auto cs = proj_obj_crs_get_coordinate_system(nullptr, base); + assert(cs); + + const char *axisName = ""; + proj_obj_cs_get_axis_info(nullptr, cs, 0, + &axisName, // name, + nullptr, // abbrev + nullptr, // direction + &toRadians, + nullptr // unit name + ); + isLatFirst = NS_PROJ::internal::ci_find(std::string(axisName), + "latitude") != std::string::npos; + + proj_obj_unref(cs); + + auto retCStr = proj_obj_as_proj_string(nullptr, base, PJ_PROJ_5, nullptr); + std::string ret(retCStr ? retCStr : ""); + proj_obj_unref(base); + return ret; +} + +/************************************************************************/ +/* main() */ +/************************************************************************/ + +int main(int argc, char **argv) { + char *arg; + char **eargv = argv; + std::string fromStr; + std::string toStr; + FILE *fid; + int eargc = 0, mon = 0; + int have_to_flag = 0, inverse = 0; + int use_env_locale = 0; + + /* This is just to check that pj_init() is locale-safe */ + /* Used by nad/testvarious */ + if (getenv("PROJ_USE_ENV_LOCALE") != nullptr) + use_env_locale = 1; + + /* Enable compatibility mode for init=epsg:XXXX by default */ + if (getenv("PROJ_USE_PROJ4_INIT_RULES") == nullptr) { + proj_context_use_proj4_init_rules(nullptr, true); + } + + if ((emess_dat.Prog_name = strrchr(*argv, DIR_CHAR)) != nullptr) + ++emess_dat.Prog_name; + else + emess_dat.Prog_name = *argv; + inverse = !strncmp(emess_dat.Prog_name, "inv", 3); + if (argc <= 1) { + (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name); + exit(0); + } + + // First pass to check if we have "cs2cs [-bla]* <SRC> <DEST>" syntax + int countNonOptionArg = 0; + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (argv[i][1] == '\0') { + countNonOptionArg++; + } + } else { + if (strcmp(argv[i], "+to") == 0) { + countNonOptionArg = -1; + break; + } + countNonOptionArg++; + } + } + const bool isSrcDestSyntax = (countNonOptionArg == 2); + + /* process run line arguments */ + while (--argc > 0) { /* collect run line arguments */ + if (**++argv == '-') { + for (arg = *argv;;) { + switch (*++arg) { + case '\0': /* position of "stdin" */ + if (arg[-1] == '-') + eargv[eargc++] = const_cast<char *>("-"); + break; + case 'v': /* monitor dump of initialization */ + mon = 1; + continue; + case 'I': /* alt. method to spec inverse */ + inverse = 1; + continue; + case 'E': /* echo ascii input to ascii output */ + echoin = 1; + continue; + case 't': /* set col. one char */ + if (arg[1]) + tag = *++arg; + else + emess(1, "missing -t col. 1 tag"); + continue; + case 'l': /* list projections, ellipses or units */ + if (!arg[1] || arg[1] == 'p' || arg[1] == 'P') { + /* list projections */ + const struct PJ_LIST *lp; + int do_long = arg[1] == 'P', c; + const char *str; + + for (lp = proj_list_operations(); lp->id; ++lp) { + (void)printf("%s : ", lp->id); + if (do_long) /* possibly multiline description */ + (void)puts(*lp->descr); + else { /* first line, only */ + str = *lp->descr; + while ((c = *str++) && c != '\n') + putchar(c); + putchar('\n'); + } + } + } else if (arg[1] == '=') { /* list projection 'descr' */ + const struct PJ_LIST *lp; + + arg += 2; + for (lp = proj_list_operations(); lp->id; ++lp) + if (!strcmp(lp->id, arg)) { + (void)printf("%9s : %s\n", lp->id, *lp->descr); + break; + } + } else if (arg[1] == 'e') { /* list ellipses */ + const struct PJ_ELLPS *le; + + for (le = proj_list_ellps(); le->id; ++le) + (void)printf("%9s %-16s %-16s %s\n", le->id, + le->major, le->ell, le->name); + } else if (arg[1] == 'u') { /* list units */ + const struct PJ_UNITS *lu; + + for (lu = proj_list_units(); lu->id; ++lu) + (void)printf("%12s %-20s %s\n", lu->id, + lu->to_meter, lu->name); + } else if (arg[1] == 'd') { /* list datums */ + const struct PJ_DATUMS *ld; + + printf("__datum_id__ __ellipse___ " + "__definition/" + "comments______________________________\n"); + for (ld = pj_get_datums_ref(); ld->id; ++ld) { + printf("%12s %-12s %-30s\n", ld->id, ld->ellipse_id, + ld->defn); + if (ld->comments != nullptr && + strlen(ld->comments) > 0) + printf("%25s %s\n", " ", ld->comments); + } + } else if (arg[1] == 'm') { /* list prime meridians */ + const struct PJ_PRIME_MERIDIANS *lpm; + + for (lpm = proj_list_prime_meridians(); lpm->id; ++lpm) + (void)printf("%12s %-30s\n", lpm->id, lpm->defn); + } else + emess(1, "invalid list option: l%c", arg[1]); + exit(0); + /* cppcheck-suppress duplicateBreak */ + continue; /* artificial */ + case 'e': /* error line alternative */ + if (--argc <= 0) + noargument: + emess(1, "missing argument for -%c", *arg); + oterr = *++argv; + continue; + case 'W': /* specify seconds precision */ + case 'w': /* -W for constant field width */ + { + char c = arg[1]; + if (c != 0 && isdigit(c)) { + set_rtodms(c - '0', *arg == 'W'); + ++arg; + } else + emess(1, "-W argument missing or non-digit"); + continue; + } + case 'f': /* alternate output format degrees or xy */ + if (--argc <= 0) + goto noargument; + oform = *++argv; + continue; + case 'r': /* reverse input */ + reversein = 1; + continue; + case 's': /* reverse output */ + reverseout = 1; + continue; + case 'D': /* set debug level */ + if (--argc <= 0) + goto noargument; + pj_ctx_set_debug(pj_get_default_ctx(), atoi(*++argv)); + continue; + case 'd': + if (--argc <= 0) + goto noargument; + sprintf(oform_buffer, "%%.%df", atoi(*++argv)); + oform = oform_buffer; + break; + default: + emess(1, "invalid option: -%c", *arg); + break; + } + break; + } + } else if (isSrcDestSyntax) { + if (fromStr.empty()) + fromStr = *argv; + else + toStr = *argv; + } else if (strcmp(*argv, "+to") == 0) { + have_to_flag = 1; + + } else if (**argv == '+') { /* + argument */ + if (have_to_flag) { + if (!toStr.empty()) + toStr += ' '; + toStr += *argv; + } else { + if (!fromStr.empty()) + fromStr += ' '; + fromStr += *argv; + } + } else if (!have_to_flag) { + fromStr = *argv; + } else if (toStr.empty()) { + toStr = *argv; + } else /* assumed to be input file name(s) */ + eargv[eargc++] = *argv; + } + if (eargc == 0) /* if no specific files force sysin */ + eargv[eargc++] = const_cast<char *>("-"); + + /* + * If the user has requested inverse, then just reverse the + * coordinate systems. + */ + if (inverse) { + std::swap(fromStr, toStr); + } + + if (use_env_locale) { + /* Set locale from environment */ + setlocale(LC_ALL, ""); + } + + if (fromStr.empty() && toStr.empty()) { + emess(3, "missing source and target coordinate systems"); + } + + const char *const optionsProj4Mode[] = {"USE_PROJ4_INIT_RULES=YES", + nullptr}; + const char *const *optionsImportCRS = + proj_context_get_use_proj4_init_rules(nullptr, TRUE) ? optionsProj4Mode + : nullptr; + + PJ_OBJ *src = nullptr; + if (!fromStr.empty()) { + bool ignored; + src = instanciate_crs(fromStr, optionsImportCRS, srcIsGeog, + srcToRadians, ignored); + if (!src) { + emess(3, "cannot instanciate source coordinate system"); + } + } + + PJ_OBJ *dst = nullptr; + if (!toStr.empty()) { + dst = instanciate_crs(toStr, optionsImportCRS, destIsGeog, + destToRadians, destIsLatLong); + if (!dst) { + emess(3, "cannot instanciate target coordinate system"); + } + } + + if (toStr.empty()) { + assert(src); + toStr = get_geog_crs_proj_string_from_proj_crs(src, destToRadians, + destIsLatLong); + if (toStr.empty()) { + emess(3, + "missing target CRS and source CRS is not a projected CRS"); + } + destIsGeog = true; + } else if (fromStr.empty()) { + assert(dst); + bool ignored; + fromStr = + get_geog_crs_proj_string_from_proj_crs(dst, srcToRadians, ignored); + if (fromStr.empty()) { + emess(3, + "missing source CRS and target CRS is not a projected CRS"); + } + srcIsGeog = true; + } + + proj_obj_unref(src); + proj_obj_unref(dst); + + transformation = proj_create_crs_to_crs(nullptr, fromStr.c_str(), + toStr.c_str(), nullptr); + if (!transformation) { + emess(3, "cannot initialize transformation\ncause: %s", + pj_strerrno(pj_errno)); + } + + if (use_env_locale) { + /* Restore C locale to avoid issues in parsing/outputting numbers*/ + setlocale(LC_ALL, "C"); + } + + if (mon) { + printf("%c ---- From Coordinate System ----\n", tag); + printf("%s\n", fromStr.c_str()); + printf("%c ---- To Coordinate System ----\n", tag); + printf("%s\n", toStr.c_str()); + } + + /* set input formatting control */ + if (!srcIsGeog) + informat = strtod; + else { + informat = dmstor; + } + + if (!destIsGeog && !oform) + oform = "%.2f"; + + /* process input file list */ + for (; eargc--; ++eargv) { + if (**eargv == '-') { + fid = stdin; + emess_dat.File_name = const_cast<char *>("<stdin>"); + + } else { + if ((fid = fopen(*eargv, "rt")) == nullptr) { + emess(-2, *eargv, "input file"); + continue; + } + emess_dat.File_name = *eargv; + } + emess_dat.File_line = 0; + process(fid); + fclose(fid); + emess_dat.File_name = nullptr; + } + + proj_destroy(transformation); + + pj_deallocate_grids(); + + exit(0); /* normal completion */ +} diff --git a/src/emess.h b/src/emess.h index 82526776..cb6b38f4 100644 --- a/src/emess.h +++ b/src/emess.h @@ -2,6 +2,10 @@ #ifndef EMESS_H #define EMESS_H +#ifdef __cplusplus +extern "C" { +#endif + struct EMESS { char *File_name, /* input file name */ *Prog_name; /* name of program */ @@ -26,4 +30,8 @@ extern struct EMESS PROJ_DLL emess_dat; void PROJ_DLL emess(int, const char *, ...); +#ifdef __cplusplus +} +#endif + #endif /* end EMESS_H */ diff --git a/src/factory.cpp b/src/factory.cpp index 3c360d13..91d0c478 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -157,6 +157,8 @@ struct DatabaseContext::Private { }; private: + friend class DatabaseContext; + std::string databasePath_{}; bool close_handle_ = true; sqlite3 *sqlite_handle_{}; @@ -164,6 +166,7 @@ struct DatabaseContext::Private { PJ_CONTEXT *pjCtxt_ = nullptr; int recLevel_ = 0; bool detach_ = false; + std::string lastMetadataValue_{}; void closeDB(); @@ -704,6 +707,22 @@ const std::string &DatabaseContext::getPath() const { return d->getPath(); } // --------------------------------------------------------------------------- +/** \brief Return a metadata item. + * + * Value remains valid while this is alive and to the next call to getMetadata + */ +const char *DatabaseContext::getMetadata(const char *key) const { + auto res = + d->run("SELECT value FROM metadata WHERE key = ?", {std::string(key)}); + if (res.empty()) { + return nullptr; + } + d->lastMetadataValue_ = res[0][0]; + return d->lastMetadataValue_.c_str(); +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress DatabaseContextNNPtr DatabaseContext::create(void *sqlite_handle) { @@ -833,6 +852,29 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName, return res[0][0]; } +// --------------------------------------------------------------------------- + +/** \brief Return the 'text_definition' column of a table for an object + * + * @param tableName Table name/category. + * @param authName Authority name of the object. + * @param code Code of the object + * @return Text definition (or empty) + * @throw FactoryException + */ +std::string DatabaseContext::getTextDefinition(const std::string &tableName, + const std::string &authName, + const std::string &code) const { + std::string sql("SELECT text_definition FROM \""); + sql += replaceAll(tableName, "\"", "\"\""); + sql += "\" WHERE auth_name = ? AND code = ?"; + auto res = d->run(sql, {authName, code}); + if (res.empty()) { + return std::string(); + } + return res[0][0]; +} + //! @endcond // --------------------------------------------------------------------------- @@ -3788,6 +3830,11 @@ AuthorityFactory::createObjectsFromName( break; } } + if (res.empty() && !deprecated) { + return createObjectsFromName(searchedName + " (deprecated)", + allowedObjectTypes, approximateMatch, + limitResultCount); + } auto sortLambda = [](const common::IdentifiedObjectNNPtr &a, const common::IdentifiedObjectNNPtr &b) { @@ -148,8 +148,9 @@ static ffio *ffio_destroy (ffio *G); static ffio *ffio_create (const char **tags, size_t n_tags, size_t max_record_size); static const char *gie_tags[] = { - "<gie>", "operation", "accept", "expect", "roundtrip", "banner", "verbose", - "direction", "tolerance", "ignore", "require_grid", "builtins", "echo", "skip", "</gie>" + "<gie>", "operation", "use_proj4_init_rules", + "accept", "expect", "roundtrip", "banner", "verbose", + "direction", "tolerance", "ignore", "require_grid", "echo", "skip", "</gie>" }; static const size_t n_gie_tags = sizeof gie_tags / sizeof gie_tags[0]; @@ -186,6 +187,7 @@ typedef struct { size_t operation_lineno; size_t dimensions_given, dimensions_given_at_last_accept; double tolerance; + int use_proj4_init_rules; int ignore; int skip_test; const char *curr_file; @@ -196,8 +198,6 @@ ffio *F = 0; static gie_ctx T; int tests=0, succs=0, succ_fails=0, fail_fails=0, succ_rtps=0, fail_rtps=0; -int succ_builtins=0, fail_builtins=0; - static const char delim[] = {"-------------------------------------------------------------------------------\n"}; @@ -245,6 +245,7 @@ int main (int argc, char **argv) { T.verbosity = 1; T.tolerance = 5e-4; T.ignore = 5555; /* Error code that will not be issued by proj_create() */ + T.use_proj4_init_rules = FALSE; o = opt_parse (argc, argv, "hlvq", "o", longflags, longkeys); if (0==o) @@ -312,7 +313,6 @@ int main (int argc, char **argv) { if (T.verbosity > 1) { fprintf (T.fout, "Failing roundtrips: %4d, Succeeding roundtrips: %4d\n", fail_rtps, succ_rtps); fprintf (T.fout, "Failing failures: %4d, Succeeding failures: %4d\n", fail_fails, succ_fails); - fprintf (T.fout, "Failing builtins: %4d, Succeeding builtins: %4d\n", fail_builtins, succ_builtins); fprintf (T.fout, "Internal counters: %4.4d(%4.4d)\n", tests, succs); fprintf (T.fout, "%s", delim); } @@ -369,17 +369,6 @@ static int another_failing_roundtrip (void) { return another_failure (); } -static int another_succeeding_builtin (void) { - succ_builtins++; - return another_success (); -} - -static int another_failing_builtin (void) { - fail_builtins++; - return another_failure (); -} - - static int process_file (const char *fname) { FILE *f; @@ -512,6 +501,12 @@ static int tolerance (const char *args) { return 0; } + +static int use_proj4_init_rules (const char *args) { + T.use_proj4_init_rules = strcmp(args, "true") == 0; + return 0; +} + static int ignore (const char *args) { T.ignore = errno_from_err_const (column (args, 1)); return 0; @@ -597,6 +592,7 @@ either a conversion or a transformation) if (T.P) proj_destroy (T.P); proj_errno_reset (0); + proj_context_use_proj4_init_rules(0, T.use_proj4_init_rules); T.P = proj_create (0, F->args); @@ -606,57 +602,6 @@ either a conversion or a transformation) return 0; } - - - -static int unitconvert_selftest (void); -static int cart_selftest (void); -static int horner_selftest (void); - -/*****************************************************************************/ -static int builtins (const char *args) { -/***************************************************************************** -There are still a few tests that cannot be described using gie -primitives. Instead, they are implemented as builtins, and invoked -using the "builtins" command verb. -******************************************************************************/ - int i; - if (T.verbosity > 1) { - finish_previous_operation (args); - banner ("builtins: unitconvert, horner, cart"); - } - T.op_ok = 0; - T.op_ko = 0; - T.op_skip = 0; - i = unitconvert_selftest (); - if (i!=0) { - fprintf (T.fout, "unitconvert_selftest fails with %d\n", i); - another_failing_builtin(); - } - else - another_succeeding_builtin (); - - - i = cart_selftest (); - if (i!=0) { - fprintf (T.fout, "cart_selftest fails with %d\n", i); - another_failing_builtin(); - } - else - another_succeeding_builtin (); - - i = horner_selftest (); - if (i!=0) { - fprintf (T.fout, "horner_selftest fails with %d\n", i); - another_failing_builtin(); - } - else - another_succeeding_builtin (); - - return 0; -} - - static PJ_COORD torad_coord (PJ *P, PJ_DIRECTION dir, PJ_COORD a) { size_t i, n; char *axis = "enut"; @@ -1064,9 +1009,10 @@ static int dispatch (const char *cmnd, const char *args) { if (0==strcmp (cmnd, "tolerance")) return tolerance (args); if (0==strcmp (cmnd, "ignore")) return ignore (args); if (0==strcmp (cmnd, "require_grid")) return require_grid (args); - if (0==strcmp (cmnd, "builtins")) return builtins (args); if (0==strcmp (cmnd, "echo")) return echo (args); if (0==strcmp (cmnd, "skip")) return skip (args); + if (0==strcmp (cmnd, "use_proj4_init_rules")) + return use_proj4_init_rules (args); return 0; } @@ -1508,567 +1454,3 @@ whitespace etc. The block is stored in G->args. Returns 1 on success, 0 otherwis pj_shrink (G->args); return 1; } - - - - - -static const char tc32_utm32[] = { - " +proj=horner" - " +ellps=intl" - " +range=500000" - " +fwd_origin=877605.269066,6125810.306769" - " +inv_origin=877605.760036,6125811.281773" - " +deg=4" - " +fwd_v=6.1258112678e+06,9.9999971567e-01,1.5372750011e-10,5.9300860915e-15,2.2609497633e-19,4.3188227445e-05,2.8225130416e-10,7.8740007114e-16,-1.7453997279e-19,1.6877465415e-10,-1.1234649773e-14,-1.7042333358e-18,-7.9303467953e-15,-5.2906832535e-19,3.9984284847e-19" - " +fwd_u=8.7760574982e+05,9.9999752475e-01,2.8817299305e-10,5.5641310680e-15,-1.5544700949e-18,-4.1357045890e-05,4.2106213519e-11,2.8525551629e-14,-1.9107771273e-18,3.3615590093e-10,2.4380247154e-14,-2.0241230315e-18,1.2429019719e-15,5.3886155968e-19,-1.0167505000e-18" - " +inv_v=6.1258103208e+06,1.0000002826e+00,-1.5372762184e-10,-5.9304261011e-15,-2.2612705361e-19,-4.3188331419e-05,-2.8225549995e-10,-7.8529116371e-16,1.7476576773e-19,-1.6875687989e-10,1.1236475299e-14,1.7042518057e-18,7.9300735257e-15,5.2881862699e-19,-3.9990736798e-19" - " +inv_u=8.7760527928e+05,1.0000024735e+00,-2.8817540032e-10,-5.5627059451e-15,1.5543637570e-18,4.1357152105e-05,-4.2114813612e-11,-2.8523713454e-14,1.9109017837e-18,-3.3616407783e-10,-2.4382678126e-14,2.0245020199e-18,-1.2441377565e-15,-5.3885232238e-19,1.0167203661e-18" -}; - - -static const char sb_utm32[] = { - " +proj=horner" - " +ellps=intl" - " +range=500000" - " +tolerance=0.0005" - " +fwd_origin=4.94690026817276e+05,6.13342113183056e+06" - " +inv_origin=6.19480258923588e+05,6.13258568148837e+06" - " +deg=3" - " +fwd_c=6.13258562111350e+06,6.19480105709997e+05,9.99378966275206e-01,-2.82153291753490e-02,-2.27089979140026e-10,-1.77019590701470e-09,1.08522286274070e-14,2.11430298751604e-15" - " +inv_c=6.13342118787027e+06,4.94690181709311e+05,9.99824464710368e-01,2.82279070814774e-02,7.66123542220864e-11,1.78425334628927e-09,-1.05584823306400e-14,-3.32554258683744e-15" -}; - -static int horner_selftest (void) { - PJ *P; - PJ_COORD a, b, c; - double dist; - - /* Real polynonia relating the technical coordinate system TC32 to "System 45 Bornholm" */ - P = proj_create (PJ_DEFAULT_CTX, tc32_utm32); - if (0==P) - return 10; - - a = b = proj_coord (0,0,0,0); - a.uv.v = 6125305.4245; - a.uv.u = 878354.8539; - c = a; - - /* Check roundtrip precision for 1 iteration each way, starting in forward direction */ - dist = proj_roundtrip (P, PJ_FWD, 1, &c); - if (dist > 0.01) - return 1; - proj_destroy(P); - - /* The complex polynomial transformation between the "System Storebaelt" and utm32/ed50 */ - P = proj_create (PJ_DEFAULT_CTX, sb_utm32); - if (0==P) - return 11; - - /* Test value: utm32_ed50(620000, 6130000) = sb_ed50(495136.8544, 6130821.2945) */ - a = b = c = proj_coord (0,0,0,0); - a.uv.v = 6130821.2945; - a.uv.u = 495136.8544; - c.uv.v = 6130000.0000; - c.uv.u = 620000.0000; - - /* Forward projection */ - b = proj_trans (P, PJ_FWD, a); - dist = proj_xy_dist (b, c); - if (dist > 0.001) - return 2; - - /* Inverse projection */ - b = proj_trans (P, PJ_INV, c); - dist = proj_xy_dist (b, a); - if (dist > 0.001) - return 3; - - /* Check roundtrip precision for 1 iteration each way */ - dist = proj_roundtrip (P, PJ_FWD, 1, &a); - if (dist > 0.01) - return 4; - - proj_destroy(P); - return 0; -} - - - - - - - - - - - - -/* Testing quite a bit of the pj_obs_api as a side effect (inspired by pj_obs_api_test.c) */ -static int cart_selftest (void) { - PJ_CONTEXT *ctx; - PJ *P; - PJ_COORD a, b, obs[2]; - PJ_COORD coord[2]; - - PJ_INFO info; - PJ_PROJ_INFO pj_info; - PJ_GRID_INFO grid_info; - PJ_INIT_INFO init_info; - - PJ_FACTORS factors; - - const PJ_OPERATIONS *oper_list; - const PJ_ELLPS *ellps_list; - const PJ_UNITS *unit_list; - const PJ_PRIME_MERIDIANS *pm_list; - - int err; - size_t n, sz; - double dist, h, t; - char *args[3] = {"proj=utm", "zone=32", "ellps=GRS80"}; - char arg[50] = {"+proj=utm; +zone=32; +ellps=GRS80"}; - char buf[40]; - - /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (PJ_DEFAULT_CTX, arg); - if (0==P) - return 1; - - - /* Clean up */ - proj_destroy (P); - - /* Same projection, now using argc/argv style initialization */ - P = proj_create_argv (PJ_DEFAULT_CTX, 3, args); - if (0==P) - return 2; - - /* zero initialize everything, then set (longitude, latitude) to (12, 55) */ - a = proj_coord (0,0,0,0); - /* a.lp: The coordinate part of a, interpreted as a classic LP pair */ - a.lp.lam = PJ_TORAD(12); - a.lp.phi = PJ_TORAD(55); - - /* Forward projection */ - b = proj_trans (P, PJ_FWD, a); - - /* Inverse projection */ - a = proj_trans (P, PJ_INV, b); - - /* Null projection */ - a = proj_trans (P, PJ_IDENT, a); - - /* Forward again, to get two linear items for comparison */ - a = proj_trans (P, PJ_FWD, a); - - dist = proj_xy_dist (a, b); - if (dist > 2e-9) - return 3; - - /* Clear any previous error */ - proj_errno_reset (P); - - /* Invalid projection */ - a = proj_trans (P, 42, a); - if (a.lpz.lam!=HUGE_VAL) - return 4; - err = proj_errno (P); - if (0==err) - return 5; - - /* Clear error again */ - proj_errno_reset (P); - - /* Clean up */ - proj_destroy (P); - - /* Now do some 3D transformations */ - P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); - if (0==P) - return 6; - - /* zero initialize everything, then set (longitude, latitude, height) to (12, 55, 100) */ - a = b = proj_coord (0,0,0,0); - a.lpz.lam = PJ_TORAD(12); - a.lpz.phi = PJ_TORAD(55); - a.lpz.z = 100; - - /* Forward projection: 3D-Cartesian-to-Ellipsoidal */ - b = proj_trans (P, PJ_FWD, a); - - /* Check roundtrip precision for 10000 iterations each way */ - dist = proj_roundtrip (P, PJ_FWD, 10000, &a); - dist += proj_roundtrip (P, PJ_INV, 10000, &b); - if (dist > 4e-9) - return 7; - - - /* Test at the North Pole */ - a = b = proj_coord (0,0,0,0); - a.lpz.lam = PJ_TORAD(0); - a.lpz.phi = PJ_TORAD(90); - a.lpz.z = 100; - - /* Forward projection: Ellipsoidal-to-3D-Cartesian */ - dist = proj_roundtrip (P, PJ_FWD, 1, &a); - if (dist > 1e-9) - return 8; - - /* Test at the South Pole */ - a = b = proj_coord (0,0,0,0); - a.lpz.lam = PJ_TORAD(0); - a.lpz.phi = PJ_TORAD(-90); - a.lpz.z = 100; - b = a; - - /* Forward projection: Ellipsoidal-to-3D-Cartesian */ - dist = proj_roundtrip (P, PJ_FWD, 1, &a); - if (dist > 1e-9) - return 9; - - - /* Inverse projection: 3D-Cartesian-to-Ellipsoidal */ - b = proj_trans (P, PJ_INV, b); - - /* Move p to another context */ - ctx = proj_context_create (); - if (ctx==pj_get_default_ctx()) - return 10; - proj_context_set (P, ctx); - if (ctx != P->ctx) - return 11; - b = proj_trans (P, PJ_FWD, b); - - /* Move it back to the default context */ - proj_context_set (P, 0); - if (pj_get_default_ctx() != P->ctx) - return 12; - proj_context_destroy (ctx); - - /* We go on with the work - now back on the default context */ - b = proj_trans (P, PJ_INV, b); - proj_destroy (P); - - - /* Testing proj_trans_generic () */ - - /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (PJ_DEFAULT_CTX, "+proj=utm +zone=32 +ellps=GRS80"); - if (0==P) - return 13; - - obs[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0); - obs[1] = proj_coord (PJ_TORAD(12), PJ_TORAD(56), 50, 0); - sz = sizeof (PJ_COORD); - - /* Forward projection */ - a = proj_trans (P, PJ_FWD, obs[0]); - b = proj_trans (P, PJ_FWD, obs[1]); - - n = proj_trans_generic ( - P, PJ_FWD, - &(obs[0].lpz.lam), sz, 2, - &(obs[0].lpz.phi), sz, 2, - &(obs[0].lpz.z), sz, 2, - 0, sz, 0 - ); - if (2!=n) - return 14; - if (a.lpz.lam != obs[0].lpz.lam) return 15; - if (a.lpz.phi != obs[0].lpz.phi) return 16; - if (a.lpz.z != obs[0].lpz.z) return 17; - if (b.lpz.lam != obs[1].lpz.lam) return 18; - if (b.lpz.phi != obs[1].lpz.phi) return 19; - if (b.lpz.z != obs[1].lpz.z) return 20; - - /* now test the case of constant z */ - obs[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0); - obs[1] = proj_coord (PJ_TORAD(12), PJ_TORAD(56), 50, 0); - h = 27; - t = 33; - n = proj_trans_generic ( - P, PJ_FWD, - &(obs[0].lpz.lam), sz, 2, - &(obs[0].lpz.phi), sz, 2, - &h, 0, 1, - &t, 0, 1 - ); - if (2!=n) - return 21; - if (a.lpz.lam != obs[0].lpz.lam) return 22; - if (a.lpz.phi != obs[0].lpz.phi) return 23; - if (45 != obs[0].lpz.z) return 24; - if (b.lpz.lam != obs[1].lpz.lam) return 25; - if (b.lpz.phi != obs[1].lpz.phi) return 26; - if (50 != obs[1].lpz.z) return 27; /* NOTE: unchanged */ - if (50==h) return 28; - - /* test proj_trans_array () */ - - coord[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0); - coord[1] = proj_coord (PJ_TORAD(12), PJ_TORAD(56), 50, 0); - if (proj_trans_array (P, PJ_FWD, 2, coord)) - return 40; - - if (a.lpz.lam != coord[0].lpz.lam) return 41; - if (a.lpz.phi != coord[0].lpz.phi) return 42; - if (a.lpz.z != coord[0].lpz.z) return 43; - if (b.lpz.lam != coord[1].lpz.lam) return 44; - if (b.lpz.phi != coord[1].lpz.phi) return 45; - if (b.lpz.z != coord[1].lpz.z) return 46; - - /* Clean up after proj_trans_* tests */ - proj_destroy (P); - - /* test proj_create_crs_to_crs() */ - P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "epsg:25832", "epsg:25833", NULL); - if (P==0) - return 50; - - a.xy.x = 700000.0; - a.xy.y = 6000000.0; - b.xy.x = 307788.8761171057; - b.xy.y = 5999669.3036037628; - - a = proj_trans(P, PJ_FWD, a); - if (dist > 1e-7) - return 51; - proj_destroy(P); - - /* let's make sure that only entries in init-files results in a usable PJ */ - P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84", NULL); - if (P != 0) { - proj_destroy(P); - return 52; - } - proj_destroy(P); - - /* ********************************************************************** */ - /* Test info functions */ - /* ********************************************************************** */ - - /* proj_info() */ - /* this one is difficult to test, since the output changes with the setup */ - info = proj_info(); - - if (info.version[0] != '\0' ) { - char tmpstr[64]; - sprintf(tmpstr, "%d.%d.%d", info.major, info.minor, info.patch); - if (strcmp(info.version, tmpstr)) return 55; - } - if (info.release[0] == '\0') return 56; - if (getenv ("HOME") || getenv ("PROJ_LIB")) - if (info.searchpath[0] == '\0') return 57; - - /* proj_pj_info() */ - P = proj_create(PJ_DEFAULT_CTX, "+proj=august"); /* august has no inverse */ - if (proj_pj_info(P).has_inverse) { proj_destroy(P); return 60; } - proj_destroy(P); - - P = proj_create(PJ_DEFAULT_CTX, arg); - pj_info = proj_pj_info(P); - if ( !pj_info.has_inverse ) { proj_destroy(P); return 61; } - pj_shrink (arg); - if ( strcmp(pj_info.definition, arg) ) { proj_destroy(P); return 62; } - if ( strcmp(pj_info.id, "utm") ) { proj_destroy(P); return 63; } - - proj_destroy(P); - - /* proj_grid_info() */ - grid_info = proj_grid_info("null"); - if ( strlen(grid_info.filename) == 0 ) return 64; - if ( strcmp(grid_info.gridname, "null") ) return 65; - grid_info = proj_grid_info("nonexistinggrid"); - if ( strlen(grid_info.filename) > 0 ) return 66; - - /* proj_init_info() */ - init_info = proj_init_info("unknowninit"); - if ( strlen(init_info.filename) != 0 ) return 67; - - init_info = proj_init_info("epsg"); - /* Need to allow for "Unknown" until all commonly distributed EPSG-files comes with a metadata section */ - if ( strcmp(init_info.origin, "EPSG") && strcmp(init_info.origin, "Unknown") ) return 69; - if ( strcmp(init_info.name, "epsg") ) return 68; - - - /* test proj_rtodms() and proj_dmstor() */ - if (strcmp("180dN", proj_rtodms(buf, M_PI, 'N', 'S'))) - return 70; - - if (proj_dmstor(&buf[0], NULL) != M_PI) - return 71; - - if (strcmp("114d35'29.612\"S", proj_rtodms(buf, -2.0, 'N', 'S'))) - return 72; - - /* we can't expect perfect numerical accuracy so testing with a tolerance */ - if (fabs(-2.0 - proj_dmstor(&buf[0], NULL)) > 1e-7) - return 73; - - - /* test proj_derivatives_retrieve() and proj_factors_retrieve() */ - P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); - a = proj_coord (0,0,0,0); - a.lp.lam = PJ_TORAD(12); - a.lp.phi = PJ_TORAD(55); - - factors = proj_factors(P, a); - if (proj_errno(P)) - return 85; /* factors not created correctly */ - - /* check a few key characteristics of the Mercator projection */ - if (factors.angular_distortion != 0.0) return 86; /* angular distortion should be 0 */ - if (factors.meridian_parallel_angle != M_PI_2) return 87; /* Meridian/parallel angle should be 90 deg */ - if (factors.meridian_convergence != 0.0) return 88; /* meridian convergence should be 0 */ - - proj_destroy(P); - - /* Check that proj_list_* functions work by looping through them */ - n = 0; - for (oper_list = proj_list_operations(); oper_list->id; ++oper_list) n++; - if (n == 0) return 90; - - n = 0; - for (ellps_list = proj_list_ellps(); ellps_list->id; ++ellps_list) n++; - if (n == 0) return 91; - - n = 0; - for (unit_list = proj_list_units(); unit_list->id; ++unit_list) n++; - if (n == 0) return 92; - - n = 0; - for (pm_list = proj_list_prime_meridians(); pm_list->id; ++pm_list) n++; - if (n == 0) return 93; - - - /* check io-predicates */ - - /* angular in on fwd, linear out */ - P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); - if (0==P) return 0; - if (!proj_angular_input (P, PJ_FWD)) return 100; - if ( proj_angular_input (P, PJ_INV)) return 101; - if ( proj_angular_output (P, PJ_FWD)) return 102; - if (!proj_angular_output (P, PJ_INV)) return 103; - P->inverted = 1; - if ( proj_angular_input (P, PJ_FWD)) return 104; - if (!proj_angular_input (P, PJ_INV)) return 105; - if (!proj_angular_output (P, PJ_FWD)) return 106; - if ( proj_angular_output (P, PJ_INV)) return 107; - proj_destroy(P); - - /* angular in and out */ - P = proj_create(PJ_DEFAULT_CTX, - "+proj=molodensky +a=6378160 +rf=298.25 " - "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " - "+abridged " - ); - if (0==P) return 0; - if (!proj_angular_input (P, PJ_FWD)) return 108; - if (!proj_angular_input (P, PJ_INV)) return 109; - if (!proj_angular_output (P, PJ_FWD)) return 110; - if (!proj_angular_output (P, PJ_INV)) return 111; - P->inverted = 1; - if (!proj_angular_input (P, PJ_FWD)) return 112; - if (!proj_angular_input (P, PJ_INV)) return 113; - if (!proj_angular_output (P, PJ_FWD)) return 114; - if (!proj_angular_output (P, PJ_INV)) return 115; - proj_destroy(P); - - /* linear in and out */ - P = proj_create(PJ_DEFAULT_CTX, - " +proj=helmert" - " +x=0.0127 +y=0.0065 +z=-0.0209 +s=0.00195" - " +rx=-0.00039 +ry=0.00080 +rz=-0.00114" - " +dx=-0.0029 +dy=-0.0002 +dz=-0.0006 +ds=0.00001" - " +drx=-0.00011 +dry=-0.00019 +drz=0.00007" - " +t_epoch=1988.0 +transpose +no_defs" - ); - if (0==P) return 0; - if (proj_angular_input (P, PJ_FWD)) return 116; - if (proj_angular_input (P, PJ_INV)) return 117; - if (proj_angular_output (P, PJ_FWD)) return 118; - if (proj_angular_output (P, PJ_INV)) return 119; - P->inverted = 1; - if (proj_angular_input (P, PJ_FWD)) return 120; - if (proj_angular_input (P, PJ_INV)) return 121; - if (proj_angular_output (P, PJ_FWD)) return 122; - if (proj_angular_output (P, PJ_INV)) return 123; - - /* We specified "no_defs" but didn't give any ellipsoid info */ - /* pj_init_ctx should default to WGS84 */ - if (P->a != 6378137.0) return 124; - if (P->f != 1.0/298.257223563) return 125; - proj_destroy(P); - - /* Test that pj_fwd* and pj_inv* returns NaNs when receiving NaN input */ - P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); - if (0==P) return 0; - a = proj_coord(NAN, NAN, NAN, NAN); - a = proj_trans(P, PJ_FWD, a); - if ( !( isnan(a.v[0]) && isnan(a.v[1]) && isnan(a.v[2]) && isnan(a.v[3]) ) ) - return 126; - a = proj_coord(NAN, NAN, NAN, NAN); - a = proj_trans(P, PJ_INV, a); - if ( !( isnan(a.v[0]) && isnan(a.v[1]) && isnan(a.v[2]) && isnan(a.v[3]) ) ) - return 127; - proj_destroy(P); - - return 0; -} - - - - -static int test_time(const char* args, double tol, double t_in, double t_exp) { - PJ_COORD in, out; - PJ *P = proj_create(PJ_DEFAULT_CTX, args); - int ret = 0; - - if (P == 0) - return 5; - - in = proj_coord(0.0, 0.0, 0.0, t_in); - - out = proj_trans(P, PJ_FWD, in); - if (fabs(out.xyzt.t - t_exp) > tol) { - proj_log_error(P, "out: %10.10g, expect: %10.10g", out.xyzt.t, t_exp); - ret = 1; - } - out = proj_trans(P, PJ_INV, out); - if (fabs(out.xyzt.t - t_in) > tol) { - proj_log_error(P, "out: %10.10g, expect: %10.10g", out.xyzt.t, t_in); - ret = 2; - } - pj_free(P); - - proj_log_level(NULL, 0); - return ret; -} - -static int unitconvert_selftest (void) { - int ret = 0; - char args1[] = "+proj=unitconvert +t_in=decimalyear +t_out=decimalyear"; - double in1 = 2004.25; - - char args2[] = "+proj=unitconvert +t_in=gps_week +t_out=gps_week"; - double in2 = 1782.0; - - char args3[] = "+proj=unitconvert +t_in=mjd +t_out=mjd"; - double in3 = 57390.0; - - char args4[] = "+proj=unitconvert +t_in=gps_week +t_out=decimalyear"; - double in4 = 1877.71428, exp4 = 2016.0; - - char args5[] = "+proj=unitconvert +t_in=yyyymmdd +t_out=yyyymmdd"; - double in5 = 20170131; - - ret = test_time(args1, 1e-6, in1, in1); if (ret) return ret + 10; - ret = test_time(args2, 1e-6, in2, in2); if (ret) return ret + 20; - ret = test_time(args3, 1e-6, in3, in3); if (ret) return ret + 30; - ret = test_time(args4, 1e-6, in4, exp4); if (ret) return ret + 40; - ret = test_time(args5, 1e-6, in5, in5); if (ret) return ret + 50; - - return 0; -} @@ -373,7 +373,7 @@ void WKTFormatter::startNode(const std::string &keyword, bool hasId) { if (!d->stackHasChild_.empty()) { d->startNewChild(); } else if (!d->result_.empty()) { - d->result_ += ","; + d->result_ += ','; if (d->params_.multiLine_ && !keyword.empty()) { d->addNewLine(); } @@ -390,7 +390,7 @@ void WKTFormatter::startNode(const std::string &keyword, bool hasId) { if (!keyword.empty()) { d->result_ += keyword; - d->result_ += "["; + d->result_ += '['; } d->indentLevel_++; d->stackHasChild_.push_back(false); @@ -428,7 +428,7 @@ void WKTFormatter::endNode() { d->stackEmptyKeyword_.pop_back(); d->stackHasChild_.pop_back(); if (!emptyKeyword) - d->result_ += "]"; + d->result_ += ']'; } // --------------------------------------------------------------------------- @@ -443,7 +443,7 @@ WKTFormatter &WKTFormatter::simulCurNodeHasId() { void WKTFormatter::Private::startNewChild() { assert(!stackHasChild_.empty()); if (stackHasChild_.back()) { - result_ += ","; + result_ += ','; } stackHasChild_.back() = true; } @@ -456,9 +456,9 @@ void WKTFormatter::addQuotedString(const char *str) { void WKTFormatter::addQuotedString(const std::string &str) { d->startNewChild(); - d->result_ += "\""; + d->result_ += '"'; d->result_ += replaceAll(str, "\"", "\"\""); - d->result_ += "\""; + d->result_ += '"'; } // --------------------------------------------------------------------------- @@ -719,6 +719,20 @@ std::string WKTFormatter::morphNameToESRI(const std::string &name) { return ret; } +// --------------------------------------------------------------------------- + +void WKTFormatter::ingestWKTNode(const WKTNodeNNPtr &node) { + startNode(node->value(), true); + for (const auto &child : node->children()) { + if (!child->children().empty()) { + ingestWKTNode(child); + } else { + add(child->value()); + } + } + endNode(); +} + #ifdef unused // --------------------------------------------------------------------------- @@ -991,7 +1005,7 @@ WKTNodeNNPtr WKTNode::createFrom(const std::string &wkt, size_t indexStart, if (!inString) { inString = true; closingStringMarker = endPrintedQuote; - value += "\""; + value += '"'; i += 2; continue; } @@ -1000,7 +1014,7 @@ WKTNodeNNPtr WKTNode::createFrom(const std::string &wkt, size_t indexStart, wkt.substr(i, 3) == endPrintedQuote) { inString = false; closingStringMarker.clear(); - value += "\""; + value += '"'; i += 2; continue; } @@ -1038,6 +1052,10 @@ WKTNodeNNPtr WKTNode::createFrom(const std::string &wkt, size_t indexStart, assert(indexEndChild > i); i = indexEndChild; i = skipSpace(wkt, i); + if (i < wkt.size() && wkt[i] == ',') { + ++i; + i = skipSpace(wkt, i); + } } if (i == wkt.size() || (wkt[i] != ']' && wkt[i] != ')')) { throw ParsingException("missing ]"); @@ -1065,7 +1083,7 @@ static std::string escapeIfQuotedString(const std::string &str) { if (str.size() > 2 && str[0] == '"' && str.back() == '"') { std::string res("\""); res += replaceAll(str.substr(1, str.size() - 2), "\"", "\"\""); - res += "\""; + res += '"'; return res; } else { return str; @@ -1084,7 +1102,7 @@ std::string WKTNode::toString() const { bool first = true; for (auto &child : d->children_) { if (!first) { - str += ","; + str += ','; } first = false; str += child->toString(); @@ -1166,6 +1184,7 @@ struct WKTParser::Private { MeridianNNPtr buildMeridian(const WKTNodeNNPtr &node); CoordinateSystemAxisNNPtr buildAxis(const WKTNodeNNPtr &node, const UnitOfMeasure &unitIn, + const UnitOfMeasure::Type &unitType, bool isGeocentric, int expectedOrderNum); @@ -1198,8 +1217,8 @@ struct WKTParser::Private { static bool hasWebMercPROJ4String(const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode); - static bool projectionHasParameter(const WKTNodeNNPtr &projCRSNode, - const char *paramName); + static std::string projectionGetParameter(const WKTNodeNNPtr &projCRSNode, + const char *paramName); ConversionNNPtr buildProjection(const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, @@ -1924,6 +1943,37 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( .set(Identifier::AUTHORITY_KEY, authNameFromAlias))); properties.set(IdentifiedObject::IDENTIFIERS_KEY, identifiers); } + } else if (name.find('_') != std::string::npos) { + // Likely coming from WKT1 + if (dbContext_) { + auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), + std::string()); + auto res = authFactory->createObjectsFromName( + name, {AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, + true, 1); + if (!res.empty()) { + const auto &refDatum = res.front(); + if (metadata::Identifier::isEquivalentName( + name.c_str(), refDatum->nameStr().c_str())) { + properties.set(IdentifiedObject::NAME_KEY, + refDatum->nameStr()); + if (properties.find(Identifier::CODESPACE_KEY) == + properties.end() && + refDatum->identifiers().size() == 1) { + const auto &id = refDatum->identifiers()[0]; + auto identifiers = ArrayOfBaseObject::create(); + identifiers->add(Identifier::create( + id->code(), PropertyMap() + .set(Identifier::CODESPACE_KEY, + *id->codeSpace()) + .set(Identifier::AUTHORITY_KEY, + *id->codeSpace()))); + properties.set(IdentifiedObject::IDENTIFIERS_KEY, + identifiers); + } + } + } + } } auto ellipsoid = buildEllipsoid(ellipsoidNode); @@ -2039,10 +2089,17 @@ MeridianNNPtr WKTParser::Private::buildMeridian(const WKTNodeNNPtr &node) { // --------------------------------------------------------------------------- +PROJ_NO_RETURN static void ThrowParsingExceptionMissingUNIT() { + throw ParsingException("buildCS: missing UNIT"); +} + +// --------------------------------------------------------------------------- + CoordinateSystemAxisNNPtr WKTParser::Private::buildAxis(const WKTNodeNNPtr &node, - const UnitOfMeasure &unitIn, bool isGeocentric, - int expectedOrderNum) { + const UnitOfMeasure &unitIn, + const UnitOfMeasure::Type &unitType, + bool isGeocentric, int expectedOrderNum) { const auto *nodeP = node->GP(); const auto &children = nodeP->children(); if (children.size() < 2) { @@ -2128,7 +2185,8 @@ WKTParser::Private::buildAxis(const WKTNodeNNPtr &node, abbreviation = AxisAbbreviation::Y; direction = &AxisDirection::GEOCENTRIC_Y; } else if (isGeocentric && axisName == AxisName::Geocentric_Z && - dirString == AxisDirectionWKT1::NORTH.toString()) { + (dirString == AxisDirectionWKT1::NORTH.toString() || + dirString == AxisDirectionWKT1::OTHER.toString())) { abbreviation = AxisAbbreviation::Z; direction = &AxisDirection::GEOCENTRIC_Z; } else if (dirString == AxisDirectionWKT1::OTHER.toString()) { @@ -2146,6 +2204,11 @@ WKTParser::Private::buildAxis(const WKTNodeNNPtr &node, // If no unit in the AXIS node, use the one potentially coming from // the CS. unit = unitIn; + if (unit == UnitOfMeasure::NONE && + unitType != UnitOfMeasure::Type::NONE && + unitType != UnitOfMeasure::Type::TIME) { + ThrowParsingExceptionMissingUNIT(); + } } auto &meridianNode = nodeP->lookForChild(WKTConstants::MERIDIAN); @@ -2165,10 +2228,6 @@ PROJ_NO_RETURN static void ThrowParsingException(const std::string &msg) { throw ParsingException(msg); } -PROJ_NO_RETURN static void ThrowParsingExceptionMissingUNIT() { - throw ParsingException("buildCS: missing UNIT"); -} - static ParsingException buildParsingExceptionInvalidAxisCount(const std::string &csType) { return ParsingException( @@ -2331,8 +2390,7 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */ "and number of AXIS are inconsistent"); } - UnitOfMeasure unit = buildUnitInSubNode( - parentNode, + const auto unitType = ci_equal(csType, "ellipsoidal") ? UnitOfMeasure::Type::ANGULAR : ci_equal(csType, "ordinal") @@ -2347,13 +2405,14 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */ ci_equal(csType, "TemporalCount") || ci_equal(csType, "TemporalMeasure")) ? UnitOfMeasure::Type::TIME - : UnitOfMeasure::Type::UNKNOWN); + : UnitOfMeasure::Type::UNKNOWN; + UnitOfMeasure unit = buildUnitInSubNode(parentNode, unitType); std::vector<CoordinateSystemAxisNNPtr> axisList; for (int i = 0; i < axisCount; i++) { axisList.emplace_back( buildAxis(parentNode->GP()->lookForChild(WKTConstants::AXIS, i), - unit, isGeocentric, i + 1)); + unit, unitType, isGeocentric, i + 1)); }; const PropertyMap &csMap = emptyPropertyMap; @@ -2476,6 +2535,11 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) { auto props = buildProperties(node); addExtensionProj4ToProp(nodeP, props); + // No explicit AXIS node ? (WKT1) + if (isNull(nodeP->lookForChild(WKTConstants::AXIS))) { + props.set("IMPLICIT_CS", true); + } + auto datum = !isNull(datumNode) ? buildGeodeticReferenceFrame(datumNode, primeMeridian, dynamicNode) @@ -2819,7 +2883,7 @@ bool WKTParser::Private::hasWebMercPROJ4String( projCRSNode->countChildrenOfName("center_latitude") == 0) { // Hack to detect the hacky way of encodign webmerc in GDAL WKT1 - // with a EXTENSION["PROJ", "+proj=merc +a=6378137 +b=6378137 + // with a EXTENSION["PROJ4", "+proj=merc +a=6378137 +b=6378137 // +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m // +nadgrids=@null +wktext +no_defs"] node if (extensionNode && extensionNode->GP()->childrenSize() == 2 && @@ -3034,19 +3098,20 @@ WKTParser::Private::buildProjection(const WKTNodeNNPtr &projCRSNode, // --------------------------------------------------------------------------- -bool WKTParser::Private::projectionHasParameter(const WKTNodeNNPtr &projCRSNode, - const char *paramName) { +std::string +WKTParser::Private::projectionGetParameter(const WKTNodeNNPtr &projCRSNode, + const char *paramName) { for (const auto &childNode : projCRSNode->GP()->children()) { if (ci_equal(childNode->GP()->value(), WKTConstants::PARAMETER)) { const auto &childNodeChildren = childNode->GP()->children(); if (childNodeChildren.size() == 2 && metadata::Identifier::isEquivalentName( stripQuotes(childNodeChildren[0]).c_str(), paramName)) { - return true; + return childNodeChildren[1]->GP()->value(); } } } - return false; + return std::string(); } // --------------------------------------------------------------------------- @@ -3068,10 +3133,12 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( bool gdal_3026_hack = false; if (metadata::Identifier::isEquivalentName(wkt1ProjectionName.c_str(), "Mercator_1SP") && - !projectionHasParameter(projCRSNode, "center_latitude")) { + projectionGetParameter(projCRSNode, "center_latitude").empty()) { // Hack for https://trac.osgeo.org/gdal/ticket/3026 - if (projectionHasParameter(projCRSNode, "latitude_of_origin")) { + std::string lat0( + projectionGetParameter(projCRSNode, "latitude_of_origin")); + if (!lat0.empty() && lat0 != "0" && lat0 != "0.0") { wkt1ProjectionName = "Mercator_2SP"; gdal_3026_hack = true; } else { @@ -3173,11 +3240,11 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( projCRSNode->countChildrenOfName(WKTConstants::AXIS) == 2 && &buildAxis( projCRSNode->GP()->lookForChild(WKTConstants::AXIS, 0), - defaultLinearUnit, false, + defaultLinearUnit, UnitOfMeasure::Type::LINEAR, false, 1)->direction() == &AxisDirection::SOUTH && &buildAxis( projCRSNode->GP()->lookForChild(WKTConstants::AXIS, 1), - defaultLinearUnit, false, + defaultLinearUnit, UnitOfMeasure::Type::LINEAR, false, 2)->direction() == &AxisDirection::WEST) { mapping = getMapping(EPSG_CODE_METHOD_KROVAK); } @@ -3255,6 +3322,17 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( // --------------------------------------------------------------------------- +static ProjectedCRSNNPtr createPseudoMercator(const PropertyMap &props) { + auto conversion = Conversion::createPopularVisualisationPseudoMercator( + PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), Angle(0), + Angle(0), Length(0), Length(0)); + return ProjectedCRS::create( + props, GeographicCRS::EPSG_4326, conversion, + CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)); +} + +// --------------------------------------------------------------------------- + ProjectedCRSNNPtr WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { @@ -3264,16 +3342,6 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { if (isNull(conversionNode) && isNull(projectionNode)) { ThrowMissing(WKTConstants::CONVERSION); } - if (isNull(conversionNode) && hasWebMercPROJ4String(node, projectionNode)) { - auto conversion = Conversion::createPopularVisualisationPseudoMercator( - PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), Angle(0), - Angle(0), Length(0), Length(0)); - return ProjectedCRS::create( - PropertyMap().set(IdentifiedObject::NAME_KEY, - "WGS 84 / Pseudo-Mercator"), - GeographicCRS::EPSG_4326, conversion, - CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)); - } auto &baseGeodCRSNode = nodeP->lookForChild(WKTConstants::BASEGEODCRS, @@ -3284,6 +3352,50 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { } auto baseGeodCRS = buildGeodeticCRS(baseGeodCRSNode); + auto props = buildProperties(node); + + const std::string projCRSName = stripQuotes(nodeP->children()[0]); + if (esriStyle_ && dbContext_) { + // It is likely that the ESRI definition of EPSG:32661 (UPS North) & + // EPSG:32761 (UPS South) uses the easting-northing order, instead + // of the EPSG northing-easting order + // so don't substitue names to avoid confusion. + if (projCRSName == "UPS_North") { + props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS North (E,N)"); + } else if (projCRSName == "UPS_South") { + props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS South (E,N)"); + } else { + std::string outTableName; + std::string authNameFromAlias; + std::string codeFromAlias; + auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), + std::string()); + auto officialName = authFactory->getOfficialNameFromAlias( + projCRSName, "projected_crs", "ESRI", outTableName, + authNameFromAlias, codeFromAlias); + if (!officialName.empty()) { + props.set(IdentifiedObject::NAME_KEY, officialName); + } + } + } + + if (isNull(conversionNode) && hasWebMercPROJ4String(node, projectionNode)) { + toWGS84Parameters_.clear(); + return createPseudoMercator(props); + } + + // WGS_84_Pseudo_Mercator: Particular case for corrupted ESRI WKT generated + // by older GDAL versions + // https://trac.osgeo.org/gdal/changeset/30732 + // WGS_1984_Web_Mercator: deprecated ESRI:102113 + if (metadata::Identifier::isEquivalentName(projCRSName.c_str(), + "WGS_84_Pseudo_Mercator") || + metadata::Identifier::isEquivalentName(projCRSName.c_str(), + "WGS_1984_Web_Mercator")) { + toWGS84Parameters_.clear(); + return createPseudoMercator(props); + } + auto linearUnit = buildUnitInSubNode(node, UnitOfMeasure::Type::LINEAR); auto angularUnit = baseGeodCRS->coordinateSystem()->axisList()[0]->unit(); @@ -3301,6 +3413,11 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); auto cartesianCS = nn_dynamic_pointer_cast<CartesianCS>(cs); + // No explicit AXIS node ? (WKT1) + if (isNull(nodeP->lookForChild(WKTConstants::AXIS))) { + props.set("IMPLICIT_CS", true); + } + if (isNull(csNode) && node->countChildrenOfName(WKTConstants::AXIS) == 0) { const auto methodCode = conversion->method()->getEPSGCode(); // Krovak south oriented ? @@ -3367,33 +3484,6 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { ThrowNotExpectedCSType("Cartesian"); } - auto props = buildProperties(node); - if (esriStyle_ && dbContext_) { - auto projCRSName = stripQuotes(nodeP->children()[0]); - - // It is likely that the ESRI definition of EPSG:32661 (UPS North) & - // EPSG:32761 (UPS South) uses the easting-northing order, instead - // of the EPSG northing-easting order - // so don't substitue names to avoid confusion. - if (projCRSName == "UPS_North") { - props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS North (E,N)"); - } else if (projCRSName == "UPS_South") { - props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS South (E,N)"); - } else { - std::string outTableName; - std::string authNameFromAlias; - std::string codeFromAlias; - auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), - std::string()); - auto officialName = authFactory->getOfficialNameFromAlias( - projCRSName, "projected_crs", "ESRI", outTableName, - authNameFromAlias, codeFromAlias); - if (!officialName.empty()) { - props.set(IdentifiedObject::NAME_KEY, officialName); - } - } - } - addExtensionProj4ToProp(nodeP, props); return ProjectedCRS::create(props, baseGeodCRS, conversion, @@ -4066,10 +4156,22 @@ BaseObjectNNPtr WKTParser::Private::build(const WKTNodeNNPtr &node) { * determine the appropriate best match.</li> * </ul> * + * @param text One of the above mentionned text format + * @param dbContext Database context, or nullptr (in which case database + * lookups will not work) + * @param usePROJ4InitRules When set to true, + * init=epsg:XXXX syntax will be allowed and will be interpreted according to + * PROJ.4 and PROJ.5 rules, that is geodeticCRS will have longitude, latitude + * order and will expect/output coordinates in radians. ProjectedCRS will have + * easting, northing axis order (except the ones with Transverse Mercator South + * Orientated projection). In that mode, the epsg:XXXX syntax will be also + * interprated the same way. * @throw ParsingException */ BaseObjectNNPtr createFromUserInput(const std::string &text, - const DatabaseContextPtr &dbContext) { + const DatabaseContextPtr &dbContext, + bool usePROJ4InitRules) { + for (const auto &wktConstants : WKTConstants::constants()) { if (ci_starts_with(text, wktConstants)) { return WKTParser().attachDatabaseContext(dbContext).createFromWKT( @@ -4085,6 +4187,7 @@ BaseObjectNNPtr createFromUserInput(const std::string &text, strncmp(textWithoutPlusPrefix, "title=", strlen("title=")) == 0) { return PROJStringParser() .attachDatabaseContext(dbContext) + .setUsePROJ4InitRules(usePROJ4InitRules) .createFromPROJString(text); } @@ -4093,9 +4196,23 @@ BaseObjectNNPtr createFromUserInput(const std::string &text, if (!dbContext) { throw ParsingException("no database context specified"); } - auto factory = - AuthorityFactory::create(NN_NO_CHECK(dbContext), tokens[0]); - return factory->createCoordinateReferenceSystem(tokens[1]); + DatabaseContextNNPtr dbContextNNPtr(NN_NO_CHECK(dbContext)); + const auto &authName = tokens[0]; + const auto &code = tokens[1]; + auto factory = AuthorityFactory::create(dbContextNNPtr, authName); + try { + return factory->createCoordinateReferenceSystem(code); + } catch (...) { + const auto authorities = dbContextNNPtr->getAuthorities(); + for (const auto &authCandidate : authorities) { + if (ci_equal(authCandidate, authName)) { + return AuthorityFactory::create(dbContextNNPtr, + authCandidate) + ->createCoordinateReferenceSystem(code); + } + } + throw; + } } // urn:ogc:def:crs:EPSG::4326 @@ -4395,6 +4512,7 @@ struct PROJStringFormatter::Private { bool useETMercForTMerc_ = false; bool useETMercForTMercSet_ = false; bool addNoDefs_ = true; + bool coordOperationOptimizations_ = false; std::string result_{}; @@ -4477,6 +4595,12 @@ const std::string &PROJStringFormatter::toString() const { step.paramValues[6].equals("s", "0") && step.paramValues[7].keyEquals("convention")))) { iter = d->steps_.erase(iter); + } else if (d->coordOperationOptimizations_ && + step.name == "unitconvert" && paramCount == 2 && + step.paramValues[0].keyEquals("xy_in") && + step.paramValues[1].keyEquals("xy_out") && + step.paramValues[0].value == step.paramValues[1].value) { + iter = d->steps_.erase(iter); } else { ++iter; } @@ -4694,6 +4818,24 @@ const std::string &PROJStringFormatter::toString() const { break; } + // axisswap order=2,1, unitconvert, axisswap order=2,1 -> can + // suppress axisswap + if (i + 1 < d->steps_.size() && prevStep.name == "axisswap" && + curStep.name == "unitconvert" && prevStepParamCount == 1 && + prevStep.paramValues[0].equals("order", "2,1")) { + auto iterNext = iterCur; + ++iterNext; + auto &nextStep = *iterNext; + if (nextStep.name == "axisswap" && + nextStep.paramValues.size() == 1 && + nextStep.paramValues[0].equals("order", "2,1")) { + d->steps_.erase(iterPrev); + d->steps_.erase(iterNext); + changeDone = true; + break; + } + } + // for practical purposes WGS84 and GRS80 ellipsoids are // equivalents (cartesian transform between both lead to differences // of the order of 1e-14 deg..). @@ -4880,6 +5022,12 @@ bool PROJStringFormatter::getUseETMercForTMerc(bool &settingSetOut) const { // --------------------------------------------------------------------------- +void PROJStringFormatter::setCoordinateOperationOptimizations(bool enable) { + d->coordOperationOptimizations_ = enable; +} + +// --------------------------------------------------------------------------- + void PROJStringFormatter::Private::appendToResult(const char *str) { if (!result_.empty()) { result_ += " "; @@ -4939,11 +5087,13 @@ PROJStringSyntaxParser(const std::string &projString, std::vector<Step> &steps, } prevWasStep = false; } else if (starts_with(word, "proj=")) { + auto stepName = word.substr(strlen("proj=")); if (prevWasInit) { - throw ParsingException("+init= found at unexpected place"); + steps.back() = Step(); + prevWasInit = false; + } else { + steps.push_back(Step()); } - auto stepName = word.substr(strlen("proj=")); - steps.push_back(Step()); steps.back().name = stepName; steps.back().inverted = inverted; prevWasStep = false; @@ -4996,7 +5146,7 @@ void PROJStringFormatter::ingestPROJString( std::string vto_meter; PROJStringSyntaxParser(str, steps, d->globalParamValues_, title, vunits, vto_meter); - d->steps_.insert(d->steps_.begin(), steps.begin(), steps.end()); + d->steps_.insert(d->steps_.end(), steps.begin(), steps.end()); } // --------------------------------------------------------------------------- @@ -5137,7 +5287,7 @@ void PROJStringFormatter::addParam(const char *paramName, std::string paramValue; for (size_t i = 0; i < vals.size(); ++i) { if (i > 0) { - paramValue += ","; + paramValue += ','; } paramValue += formatToString(vals[i]); } @@ -5261,6 +5411,7 @@ const DatabaseContextPtr &PROJStringFormatter::databaseContext() const { struct PROJStringParser::Private { DatabaseContextPtr dbContext_{}; + bool usePROJ4InitRules_ = false; std::vector<std::string> warningList_{}; std::string projString_{}; @@ -5368,6 +5519,22 @@ PROJStringParser::attachDatabaseContext(const DatabaseContextPtr &dbContext) { // --------------------------------------------------------------------------- +/** \brief Set how init=epsg:XXXX syntax should be interpreted. + * + * @param enable When set to true, + * init=epsg:XXXX syntax will be allowed and will be interpreted according to + * PROJ.4 and PROJ.5 rules, that is geodeticCRS will have longitude, latitude + * order and will expect/output coordinates in radians. ProjectedCRS will have + * easting, northing axis order (except the ones with Transverse Mercator South + * Orientated projection). + */ +PROJStringParser &PROJStringParser::setUsePROJ4InitRules(bool enable) { + d->usePROJ4InitRules_ = enable; + return *this; +} + +// --------------------------------------------------------------------------- + /** \brief Return the list of warnings found during parsing. */ std::vector<std::string> PROJStringParser::warningList() const { @@ -5571,11 +5738,12 @@ PROJStringParser::Private::buildPrimeMeridian(const Step &step) { PrimeMeridianNNPtr pm = PrimeMeridian::GREENWICH; const auto &pmStr = getParamValue(step, "pm"); if (!pmStr.empty()) { - try { - double pmValue = c_locale_stod(pmStr); + char *end; + double pmValue = dmstor(pmStr.c_str(), &end) * RAD_TO_DEG; + if (pmValue != HUGE_VAL && *end == '\0') { pm = PrimeMeridian::create(createMapWithUnknownName(), Angle(pmValue)); - } catch (const std::invalid_argument &) { + } else { bool found = false; if (pmStr == "paris") { found = true; @@ -5588,9 +5756,8 @@ PROJStringParser::Private::buildPrimeMeridian(const Step &step) { found = true; std::string name = static_cast<char>(::toupper(pmStr[0])) + pmStr.substr(1); - double pmValue = - dmstor(proj_prime_meridians[i].defn, nullptr) * - RAD_TO_DEG; + pmValue = dmstor(proj_prime_meridians[i].defn, nullptr) * + RAD_TO_DEG; pm = PrimeMeridian::create( PropertyMap().set(IdentifiedObject::NAME_KEY, name), Angle(pmValue)); @@ -5619,12 +5786,20 @@ PROJStringParser::Private::buildDatum(const Step &step, const auto &ellpsStr = getParamValue(step, "ellps"); const auto &datumStr = getParamValue(step, "datum"); + const auto &RStr = getParamValue(step, "R"); const auto &aStr = getParamValue(step, "a"); const auto &bStr = getParamValue(step, "b"); const auto &rfStr = getParamValue(step, "rf"); const auto &fStr = getParamValue(step, "f"); - const auto &RStr = getParamValue(step, "R"); + const auto &esStr = getParamValue(step, "es"); + const auto &eStr = getParamValue(step, "e"); + double a = -1.0; + double b = -1.0; + double rf = -1.0; const util::optional<std::string> optionalEmptyString{}; + const bool numericParamPresent = + !RStr.empty() || !aStr.empty() || !bStr.empty() || !rfStr.empty() || + !fStr.empty() || !esStr.empty() || !eStr.empty(); PrimeMeridianNNPtr pm(buildPrimeMeridian(step)); PropertyMap grfMap; @@ -5647,104 +5822,151 @@ PROJStringParser::Private::buildDatum(const Step &step, } }; + // R take precedence + if (!RStr.empty()) { + double R; + try { + R = c_locale_stod(RStr); + } catch (const std::invalid_argument &) { + throw ParsingException("Invalid R value"); + } + auto ellipsoid = Ellipsoid::createSphere(createMapWithUnknownName(), + Length(R), guessBodyName(R)); + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() ? "unknown" : title.c_str()), + ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); + } + if (!datumStr.empty()) { - if (datumStr == "WGS84") { - return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6326); - } else if (datumStr == "NAD83") { - return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6269); - } else if (datumStr == "NAD27") { - return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6267); - } else { + auto l_datum = [&datumStr, &overridePmIfNeeded, &grfMap, + &optionalEmptyString, &pm]() { + if (datumStr == "WGS84") { + return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6326); + } else if (datumStr == "NAD83") { + return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6269); + } else if (datumStr == "NAD27") { + return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6267); + } else { - for (const auto &datumDesc : datumDescs) { - if (datumStr == datumDesc.projName) { - (void)datumDesc.gcsName; // to please cppcheck - (void)datumDesc.gcsCode; // to please cppcheck - auto ellipsoid = Ellipsoid::createFlattenedSphere( - grfMap - .set(IdentifiedObject::NAME_KEY, - datumDesc.ellipsoidName) - .set(Identifier::CODESPACE_KEY, Identifier::EPSG) - .set(Identifier::CODE_KEY, datumDesc.ellipsoidCode), - Length(datumDesc.a), Scale(datumDesc.rf)); - return GeodeticReferenceFrame::create( - grfMap - .set(IdentifiedObject::NAME_KEY, - datumDesc.datumName) - .set(Identifier::CODESPACE_KEY, Identifier::EPSG) - .set(Identifier::CODE_KEY, datumDesc.datumCode), - ellipsoid, optionalEmptyString, pm); + for (const auto &datumDesc : datumDescs) { + if (datumStr == datumDesc.projName) { + (void)datumDesc.gcsName; // to please cppcheck + (void)datumDesc.gcsCode; // to please cppcheck + auto ellipsoid = Ellipsoid::createFlattenedSphere( + grfMap + .set(IdentifiedObject::NAME_KEY, + datumDesc.ellipsoidName) + .set(Identifier::CODESPACE_KEY, + Identifier::EPSG) + .set(Identifier::CODE_KEY, + datumDesc.ellipsoidCode), + Length(datumDesc.a), Scale(datumDesc.rf)); + return GeodeticReferenceFrame::create( + grfMap + .set(IdentifiedObject::NAME_KEY, + datumDesc.datumName) + .set(Identifier::CODESPACE_KEY, + Identifier::EPSG) + .set(Identifier::CODE_KEY, datumDesc.datumCode), + ellipsoid, optionalEmptyString, pm); + } } } + throw ParsingException("unknown datum " + datumStr); + }(); + if (!numericParamPresent) { + return l_datum; } - throw ParsingException("unknown datum " + datumStr); + a = l_datum->ellipsoid()->semiMajorAxis().getSIValue(); + rf = l_datum->ellipsoid()->computedInverseFlattening(); } else if (!ellpsStr.empty()) { - if (ellpsStr == "WGS84") { - return GeodeticReferenceFrame::create( - grfMap.set(IdentifiedObject::NAME_KEY, - title.empty() ? "Unknown based on WGS84 ellipsoid" - : title.c_str()), - Ellipsoid::WGS84, optionalEmptyString, pm); - } else if (ellpsStr == "GRS80") { - return GeodeticReferenceFrame::create( - grfMap.set(IdentifiedObject::NAME_KEY, - title.empty() ? "Unknown based on GRS80 ellipsoid" - : title.c_str()), - Ellipsoid::GRS1980, optionalEmptyString, pm); - } else { - auto proj_ellps = proj_list_ellps(); - for (int i = 0; proj_ellps[i].id != nullptr; i++) { - if (ellpsStr == proj_ellps[i].id) { - assert(strncmp(proj_ellps[i].major, "a=", 2) == 0); - const double a_iter = - c_locale_stod(proj_ellps[i].major + 2); - EllipsoidPtr ellipsoid; - PropertyMap ellpsMap; - if (strncmp(proj_ellps[i].ell, "b=", 2) == 0) { - const double b_iter = - c_locale_stod(proj_ellps[i].ell + 2); - ellipsoid = Ellipsoid::createTwoAxis( - ellpsMap.set(IdentifiedObject::NAME_KEY, - proj_ellps[i].name), - Length(a_iter), Length(b_iter)) - .as_nullable(); - } else { - assert(strncmp(proj_ellps[i].ell, "rf=", 3) == 0); - const double rf_iter = - c_locale_stod(proj_ellps[i].ell + 3); - ellipsoid = Ellipsoid::createFlattenedSphere( - ellpsMap.set(IdentifiedObject::NAME_KEY, - proj_ellps[i].name), - Length(a_iter), Scale(rf_iter)) - .as_nullable(); + auto l_datum = [&ellpsStr, &title, &grfMap, &optionalEmptyString, + &pm]() { + if (ellpsStr == "WGS84") { + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() + ? "Unknown based on WGS84 ellipsoid" + : title.c_str()), + Ellipsoid::WGS84, optionalEmptyString, pm); + } else if (ellpsStr == "GRS80") { + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() + ? "Unknown based on GRS80 ellipsoid" + : title.c_str()), + Ellipsoid::GRS1980, optionalEmptyString, pm); + } else { + auto proj_ellps = proj_list_ellps(); + for (int i = 0; proj_ellps[i].id != nullptr; i++) { + if (ellpsStr == proj_ellps[i].id) { + assert(strncmp(proj_ellps[i].major, "a=", 2) == 0); + const double a_iter = + c_locale_stod(proj_ellps[i].major + 2); + EllipsoidPtr ellipsoid; + PropertyMap ellpsMap; + if (strncmp(proj_ellps[i].ell, "b=", 2) == 0) { + const double b_iter = + c_locale_stod(proj_ellps[i].ell + 2); + ellipsoid = + Ellipsoid::createTwoAxis( + ellpsMap.set(IdentifiedObject::NAME_KEY, + proj_ellps[i].name), + Length(a_iter), Length(b_iter)) + .as_nullable(); + } else { + assert(strncmp(proj_ellps[i].ell, "rf=", 3) == 0); + const double rf_iter = + c_locale_stod(proj_ellps[i].ell + 3); + ellipsoid = + Ellipsoid::createFlattenedSphere( + ellpsMap.set(IdentifiedObject::NAME_KEY, + proj_ellps[i].name), + Length(a_iter), Scale(rf_iter)) + .as_nullable(); + } + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() + ? std::string("Unknown based on ") + + proj_ellps[i].name + + " ellipsoid" + : title), + NN_NO_CHECK(ellipsoid), optionalEmptyString, pm); } - return GeodeticReferenceFrame::create( - grfMap.set(IdentifiedObject::NAME_KEY, - title.empty() - ? std::string("Unknown based on ") + - proj_ellps[i].name + " ellipsoid" - : title), - NN_NO_CHECK(ellipsoid), optionalEmptyString, pm); } + throw ParsingException("unknown ellipsoid " + ellpsStr); } - throw ParsingException("unknown ellipsoid " + ellpsStr); + }(); + if (!numericParamPresent) { + return l_datum; + } + a = l_datum->ellipsoid()->semiMajorAxis().getSIValue(); + if (l_datum->ellipsoid()->semiMinorAxis().has_value()) { + b = l_datum->ellipsoid()->semiMinorAxis()->getSIValue(); + } else { + rf = l_datum->ellipsoid()->computedInverseFlattening(); } } - else if (!aStr.empty() && !bStr.empty()) { - double a; + if (!aStr.empty()) { try { a = c_locale_stod(aStr); } catch (const std::invalid_argument &) { throw ParsingException("Invalid a value"); } - double b; - try { - b = c_locale_stod(bStr); - } catch (const std::invalid_argument &) { - throw ParsingException("Invalid b value"); + } + + if (a > 0 && (b > 0 || !bStr.empty())) { + if (!bStr.empty()) { + try { + b = c_locale_stod(bStr); + } catch (const std::invalid_argument &) { + throw ParsingException("Invalid b value"); + } } auto ellipsoid = Ellipsoid::createTwoAxis(createMapWithUnknownName(), Length(a), @@ -5756,18 +5978,13 @@ PROJStringParser::Private::buildDatum(const Step &step, ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); } - else if (!aStr.empty() && !rfStr.empty()) { - double a; - try { - a = c_locale_stod(aStr); - } catch (const std::invalid_argument &) { - throw ParsingException("Invalid a value"); - } - double rf; - try { - rf = c_locale_stod(rfStr); - } catch (const std::invalid_argument &) { - throw ParsingException("Invalid rf value"); + else if (a > 0 && (rf >= 0 || !rfStr.empty())) { + if (!rfStr.empty()) { + try { + rf = c_locale_stod(rfStr); + } catch (const std::invalid_argument &) { + throw ParsingException("Invalid rf value"); + } } auto ellipsoid = Ellipsoid::createFlattenedSphere( createMapWithUnknownName(), Length(a), Scale(rf), @@ -5779,13 +5996,7 @@ PROJStringParser::Private::buildDatum(const Step &step, ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); } - else if (!aStr.empty() && !fStr.empty()) { - double a; - try { - a = c_locale_stod(aStr); - } catch (const std::invalid_argument &) { - throw ParsingException("Invalid a value"); - } + else if (a > 0 && !fStr.empty()) { double f; try { f = c_locale_stod(fStr); @@ -5802,23 +6013,52 @@ PROJStringParser::Private::buildDatum(const Step &step, ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); } - else if (!RStr.empty()) { - double R; + else if (a > 0 && !eStr.empty()) { + double e; try { - R = c_locale_stod(RStr); + e = c_locale_stod(eStr); } catch (const std::invalid_argument &) { - throw ParsingException("Invalid R value"); + throw ParsingException("Invalid e value"); } - auto ellipsoid = Ellipsoid::createSphere(createMapWithUnknownName(), - Length(R), guessBodyName(R)); + double alpha = asin(e); /* angular eccentricity */ + double f = 1 - cos(alpha); /* = 1 - sqrt (1 - es); */ + auto ellipsoid = Ellipsoid::createFlattenedSphere( + createMapWithUnknownName(), Length(a), + Scale(f != 0.0 ? 1.0 / f : 0.0), guessBodyName(a)) + ->identify(); + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() ? "unknown" : title.c_str()), + ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); + } + + else if (a > 0 && !esStr.empty()) { + double es; + try { + es = c_locale_stod(esStr); + } catch (const std::invalid_argument &) { + throw ParsingException("Invalid es value"); + } + double f = 1 - sqrt(1 - es); + auto ellipsoid = Ellipsoid::createFlattenedSphere( + createMapWithUnknownName(), Length(a), + Scale(f != 0.0 ? 1.0 / f : 0.0), guessBodyName(a)) + ->identify(); return GeodeticReferenceFrame::create( grfMap.set(IdentifiedObject::NAME_KEY, title.empty() ? "unknown" : title.c_str()), ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); } - if (!aStr.empty() && bStr.empty() && rfStr.empty()) { - throw ParsingException("a found, but b, f or rf missing"); + // If only a is specified, create a sphere + if (a > 0 && bStr.empty() && rfStr.empty() && eStr.empty() && + esStr.empty()) { + auto ellipsoid = Ellipsoid::createSphere(createMapWithUnknownName(), + Length(a), guessBodyName(a)); + return GeodeticReferenceFrame::create( + grfMap.set(IdentifiedObject::NAME_KEY, + title.empty() ? "unknown" : title.c_str()), + ellipsoid, optionalEmptyString, fixupPrimeMeridan(ellipsoid, pm)); } if (!bStr.empty() && aStr.empty()) { @@ -5833,6 +6073,14 @@ PROJStringParser::Private::buildDatum(const Step &step, throw ParsingException("f found, but a missing"); } + if (!eStr.empty() && aStr.empty()) { + throw ParsingException("e found, but a missing"); + } + + if (!esStr.empty() && aStr.empty()) { + throw ParsingException("es found, but a missing"); + } + return overridePmIfNeeded(GeodeticReferenceFrame::EPSG_6326); } @@ -6002,6 +6250,22 @@ PROJStringParser::Private::buildEllipsoidalCS(int iStep, int iUnitConvert, // --------------------------------------------------------------------------- +static double getNumericValue(const std::string ¶mValue, + bool *pHasError = nullptr) { + try { + double value = c_locale_stod(paramValue); + if (pHasError) + *pHasError = false; + return value; + } catch (const std::invalid_argument &) { + if (pHasError) + *pHasError = true; + return 0.0; + } +} + +// --------------------------------------------------------------------------- + GeographicCRSNNPtr PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert, int iAxisSwap, bool ignoreVUnits, @@ -6015,7 +6279,10 @@ PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert, auto props = PropertyMap().set(IdentifiedObject::NAME_KEY, title.empty() ? "unknown" : title); - if (l_isGeographicStep && hasParamValue(step, "wktext")) { + if (l_isGeographicStep && + (hasParamValue(step, "wktext") || + hasParamValue(step, "lon_wrap") | hasParamValue(step, "geoc") || + getNumericValue(getParamValue(step, "lon_0")) != 0.0)) { props.set("EXTENSION_PROJ4", projString_); } @@ -6152,22 +6419,6 @@ static double getAngularValue(const std::string ¶mValue, // --------------------------------------------------------------------------- -static double getNumericValue(const std::string ¶mValue, - bool *pHasError = nullptr) { - try { - double value = c_locale_stod(paramValue); - if (pHasError) - *pHasError = false; - return value; - } catch (const std::invalid_argument &) { - if (pHasError) - *pHasError = true; - return 0.0; - } -} - -// --------------------------------------------------------------------------- - CRSNNPtr PROJStringParser::Private::buildProjectedCRS( int iStep, GeographicCRSNNPtr geogCRS, int iUnitConvert, int iAxisSwap) { auto &step = steps_[iStep]; @@ -6223,7 +6474,10 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( mapping = getMapping(PROJ_WKT2_NAME_METHOD_GEOSTATIONARY_SATELLITE_SWEEP_Y); } else if (step.name == "omerc") { - if (hasParamValue(step, "no_uoff") || hasParamValue(step, "no_off")) { + if (hasParamValue(step, "no_rot")) { + mapping = nullptr; + } else if (hasParamValue(step, "no_uoff") || + hasParamValue(step, "no_off")) { mapping = getMapping(EPSG_CODE_METHOD_HOTINE_OBLIQUE_MERCATOR_VARIANT_A); } else if (hasParamValue(step, "lat_1") && @@ -6777,6 +7031,21 @@ PROJStringParser::Private::buildMolodenskyTransformation( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +static const metadata::ExtentPtr nullExtent{}; + +static const metadata::ExtentPtr &getExtent(const crs::CRS *crs) { + const auto &domains = crs->domains(); + if (!domains.empty()) { + return domains[0]->domainOfValidity(); + } + return nullExtent; +} + +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Instanciate a sub-class of BaseObject from a PROJ string. * @throw ParsingException */ @@ -6785,6 +7054,9 @@ PROJStringParser::createFromPROJString(const std::string &projString) { std::string vunits; std::string vto_meter; + d->steps_.clear(); + d->title_.clear(); + d->globalParamValues_.clear(); d->projString_ = projString; PROJStringSyntaxParser(projString, d->steps_, d->globalParamValues_, d->title_, vunits, vto_meter); @@ -6821,6 +7093,117 @@ PROJStringParser::createFromPROJString(const std::string &projString) { : -1)); } + // +init=xxxx:yyyy syntax + if (d->steps_.size() == 1 && d->steps_[0].isInit && + d->steps_[0].paramValues.size() == 0) { + + // Those used to come from a text init file + // We only support them in compatibility mode + const std::string &stepName = d->steps_[0].name; + if (ci_starts_with(stepName, "epsg:") || + ci_starts_with(stepName, "IGNF:")) { + bool usePROJ4InitRules = d->usePROJ4InitRules_; + if (!usePROJ4InitRules) { + PJ_CONTEXT *ctx = proj_context_create(); + if (ctx) { + usePROJ4InitRules = proj_context_get_use_proj4_init_rules( + ctx, FALSE) == TRUE; + proj_context_destroy(ctx); + } + } + if (!usePROJ4InitRules) { + throw ParsingException("init=epsg:/init=IGNF: syntax not " + "supported in non-PROJ4 emulation mode"); + } + + PJ_CONTEXT *ctx = proj_context_create(); + char unused[256]; + std::string initname(stepName); + initname.resize(initname.find(':')); + int file_found = + pj_find_file(ctx, initname.c_str(), unused, sizeof(unused)); + proj_context_destroy(ctx); + if (!file_found) { + auto obj = createFromUserInput(stepName, d->dbContext_, true); + auto crs = dynamic_cast<CRS *>(obj.get()); + if (crs) { + PropertyMap properties; + properties.set(IdentifiedObject::NAME_KEY, crs->nameStr()); + const auto &extent = getExtent(crs); + if (extent) { + properties.set( + common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + NN_NO_CHECK(extent)); + } + auto geogCRS = dynamic_cast<GeographicCRS *>(crs); + if (geogCRS) { + // Override with longitude latitude in radian + return GeographicCRS::create( + properties, geogCRS->datum(), + geogCRS->datumEnsemble(), + EllipsoidalCS::createLongitudeLatitude( + UnitOfMeasure::RADIAN)); + } + auto projCRS = dynamic_cast<ProjectedCRS *>(crs); + if (projCRS) { + // Override with easting northing order + const auto &conv = projCRS->derivingConversionRef(); + if (conv->method()->getEPSGCode() != + EPSG_CODE_METHOD_TRANSVERSE_MERCATOR_SOUTH_ORIENTATED) { + return ProjectedCRS::create( + properties, projCRS->baseCRS(), conv, + CartesianCS::createEastingNorthing( + projCRS->coordinateSystem() + ->axisList()[0] + ->unit())); + } + } + } + return obj; + } + } + + paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); + if (!init) { + throw ParsingException("out of memory"); + } + PJ_CONTEXT *ctx = proj_context_create(); + if (!ctx) { + pj_dealloc(init); + throw ParsingException("out of memory"); + } + paralist *list = pj_expand_init(ctx, init); + proj_context_destroy(ctx); + if (!list) { + pj_dealloc(init); + throw ParsingException("cannot expand " + projString); + } + std::string expanded; + bool first = true; + bool has_init_term = false; + for (auto t = list; t;) { + if (!expanded.empty()) { + expanded += ' '; + } + if (first) { + // first parameter is the init= itself + first = false; + } else if (starts_with(t->param, "init=")) { + has_init_term = true; + } else { + expanded += t->param; + } + + auto n = t->next; + pj_dealloc(t); + t = n; + } + + if (!has_init_term) { + return createFromPROJString(expanded); + } + } + int iFirstGeogStep = -1; int iSecondGeogStep = -1; int iProjStep = -1; @@ -7003,6 +7386,7 @@ PROJStringParser::createFromPROJString(const std::string &projString) { throw ParsingException("out of memory"); } proj_log_func(pj_context, &logger, Logger::log); + proj_context_use_proj4_init_rules(pj_context, d->usePROJ4InitRules_); auto pj = proj_create(pj_context, projString.c_str()); bool valid = pj != nullptr; proj_destroy(pj); diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index 6fe84944..9e6f51fd 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -32,7 +32,7 @@ elseif(USE_THREAD AND NOT Threads_FOUND) message(FATAL_ERROR "No thread library found and thread/mutex support is required by USE_THREAD option") endif() -option(ENABLE_LTO "Build library with LTO optimization (if available)." ON) +option(ENABLE_LTO "Build library with LTO optimization (if available)." OFF) if(ENABLE_LTO) if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") include (CheckCXXSourceCompiles) @@ -265,6 +265,7 @@ set(SRC_LIBPROJ_CPP set(HEADERS_LIBPROJ proj_api.h proj.h + proj_experimental.h proj_constants.h geodesic.h ) diff --git a/src/pj_apply_gridshift.c b/src/pj_apply_gridshift.c index 31e0124e..45ce5c8e 100644 --- a/src/pj_apply_gridshift.c +++ b/src/pj_apply_gridshift.c @@ -349,7 +349,7 @@ LP proj_hgrid_apply(PJ *P, LP lp, PJ_DIRECTION direction) { out = nad_cvt(lp, inverse, ct); if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) - pj_ctx_set_errno(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); return out; diff --git a/src/pj_ctx.c b/src/pj_ctx.c index 6626d5ee..1c99e921 100644 --- a/src/pj_ctx.c +++ b/src/pj_ctx.c @@ -85,6 +85,8 @@ projCtx pj_get_default_ctx() default_context.app_data = NULL; default_context.fileapi = pj_get_default_fileapi(); default_context.cpp_context = NULL; + default_context.use_proj4_init_rules = -1; + default_context.epsg_file_exists = -1; if( getenv("PROJ_DEBUG") != NULL ) { @@ -114,6 +116,7 @@ projCtx pj_ctx_alloc() memcpy( ctx, pj_get_default_ctx(), sizeof(projCtx_t) ); ctx->last_errno = 0; ctx->cpp_context = NULL; + ctx->use_proj4_init_rules = -1; return ctx; } diff --git a/src/pj_fwd.c b/src/pj_fwd.c index 1a970374..38443f07 100644 --- a/src/pj_fwd.c +++ b/src/pj_fwd.c @@ -103,7 +103,6 @@ static PJ_COORD fwd_prepare (PJ *P, PJ_COORD coo) { } - static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { switch (OUTPUT_UNITS) { @@ -138,6 +137,14 @@ static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { case PJ_IO_UNITS_ANGULAR: coo.lpz.z = P->vfr_meter * (coo.lpz.z + P->z0); + + if( P->is_long_wrap_set ) { + if( coo.lpz.lam != HUGE_VAL ) { + coo.lpz.lam = P->long_wrap_center + + adjlon(coo.lpz.lam - P->long_wrap_center); + } + } + break; } diff --git a/src/pj_init.c b/src/pj_init.c index fcc03537..bc81235e 100644 --- a/src/pj_init.c +++ b/src/pj_init.c @@ -43,7 +43,6 @@ #include "projects.h" - /**************************************************************************************/ static paralist *string_to_paralist (PJ_CONTEXT *ctx, char *definition) { /*************************************************************************************** @@ -81,14 +80,15 @@ static paralist *string_to_paralist (PJ_CONTEXT *ctx, char *definition) { /**************************************************************************************/ -static char *get_init_string (PJ_CONTEXT *ctx, char *name) { +static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { /*************************************************************************************** Read a section of an init file. Return its contents as a plain character string. It is the duty of the caller to free the memory allocated for the string. ***************************************************************************************/ #define MAX_LINE_LENGTH 1000 size_t current_buffer_size = 5 * (MAX_LINE_LENGTH + 1); - char *fname, *section, *key; + char *fname, *section; + const char *key; char *buffer = 0; char *line = 0; PAFile fid; @@ -228,11 +228,12 @@ static char *get_init_string (PJ_CONTEXT *ctx, char *name) { /************************************************************************/ -static paralist *get_init(PJ_CONTEXT *ctx, char *key) { +static paralist *get_init(PJ_CONTEXT *ctx, const char *key, int allow_init_epsg) { /************************************************************************* Expand key from buffer or (if not in buffer) from init file *************************************************************************/ - char *xkey, *definition; + const char *xkey; + char *definition = 0; paralist *init_items = 0; /* support "init=file:section", "+init=file:section", and "file:section" format */ @@ -248,10 +249,68 @@ Expand key from buffer or (if not in buffer) from init file if (init_items) return init_items; - /* If not, we must read it from file */ - pj_log (ctx, PJ_LOG_TRACE, - "get_init: searching on in init files for [%s]", xkey); - definition = get_init_string (ctx, xkey); + if( (strncmp(xkey, "epsg:", 5) == 0 || strncmp(xkey, "IGNF:", 5) == 0) ) { + char unused[256]; + char initname[5]; + int exists; + + memcpy(initname, xkey, 4); + initname[4] = 0; + + if( strncmp(xkey, "epsg:", 5) == 0 ) { + exists = ctx->epsg_file_exists; + if( exists < 0 ) { + exists = pj_find_file(ctx, initname, unused, sizeof(unused)); + ctx->epsg_file_exists = exists; + } + } else { + exists = pj_find_file(ctx, initname, unused, sizeof(unused)); + } + + if( !exists ) { + const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", NULL }; + char szInitStr[7 + 64]; + PJ_OBJ* src; + const char* proj_string; + + pj_ctx_set_errno( ctx, 0 ); + + if( !allow_init_epsg ) { + pj_log (ctx, PJ_LOG_TRACE, "%s expansion disallowed", xkey); + return 0; + } + if( strlen(xkey) > 64 ) { + return 0; + } + strcpy(szInitStr, "+init="); + strcat(szInitStr, xkey); + + src = proj_obj_create_from_user_input(ctx, szInitStr, optionsProj4Mode); + if( !src ) { + return 0; + } + + proj_string = proj_obj_as_proj_string(ctx, src, PJ_PROJ_4, NULL); + if( !proj_string ) { + proj_obj_unref(src); + return 0; + } + definition = (char*)calloc(1, strlen(proj_string)+1); + if( definition ) { + strcpy(definition, proj_string); + } + + proj_obj_unref(src); + } + } + + if( !definition ) { + /* If not, we must read it from file */ + pj_log (ctx, PJ_LOG_TRACE, + "get_init: searching on in init files for [%s]", xkey); + definition = get_init_string (ctx, xkey); + } + if (0==definition) return 0; init_items = string_to_paralist (ctx, definition); @@ -271,7 +330,7 @@ Expand key from buffer or (if not in buffer) from init file -static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, char *key) { +static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, const char *key, int allow_init_epsg) { paralist *defaults, *last = 0; char keystring[ID_TAG_MAX + 20]; paralist *next, *proj; @@ -303,7 +362,7 @@ static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, strcpy (keystring, "proj_def.dat:"); strcat (keystring, key); - defaults = get_init (ctx, keystring); + defaults = get_init (ctx, keystring, allow_init_epsg); /* Defaults are optional - so we don't care if we cannot open the file */ pj_ctx_set_errno (ctx, err); @@ -340,7 +399,7 @@ static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, } /*****************************************************************************/ -paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init) { +static paralist *pj_expand_init_internal(PJ_CONTEXT *ctx, paralist *init, int allow_init_epsg) { /****************************************************************************** Append expansion of <key> to the paralist <init>. The expansion is appended, rather than inserted at <init>'s place, since <init> may contain @@ -367,7 +426,7 @@ Note that 'init=foo:bar' stays in the list. It is ignored after expansion. if (0==init) return 0; - expn = get_init(ctx, init->param); + expn = get_init(ctx, init->param, allow_init_epsg); /* Nothing in expansion? */ if (0==expn) @@ -381,6 +440,9 @@ Note that 'init=foo:bar' stays in the list. It is ignored after expansion. return init; } +paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init) { + return pj_expand_init_internal(ctx, init, TRUE); +} /************************************************************************/ @@ -496,6 +558,14 @@ static PJ_CONSTRUCTOR locate_constructor (const char *name) { PJ * pj_init_ctx(projCtx ctx, int argc, char **argv) { + /* Legacy interface: allow init=epsg:XXXX syntax by default */ + int allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, TRUE); + return pj_init_ctx_with_allow_init_epsg(ctx, argc, argv, allow_init_epsg); +} + + +PJ * +pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_init_epsg) { const char *s; char *name; PJ_CONSTRUCTOR proj; @@ -558,7 +628,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { /* problem when '+init's are expanded as late as possible. */ init = pj_param_exists (start, "init"); if (init && n_pipelines == 0) { - init = pj_expand_init (ctx, init); + init = pj_expand_init_internal (ctx, init, allow_init_epsg); if (!init) return pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); } @@ -580,8 +650,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { /* Append general and projection specific defaults to the definition list */ - append_defaults_to_paralist (ctx, start, "general"); - append_defaults_to_paralist (ctx, start, name); + append_defaults_to_paralist (ctx, start, "general", allow_init_epsg); + append_defaults_to_paralist (ctx, start, name, allow_init_epsg); /* Allocate projection structure */ diff --git a/src/pj_transform.c b/src/pj_transform.c index f6210822..6982676e 100644 --- a/src/pj_transform.c +++ b/src/pj_transform.c @@ -195,7 +195,7 @@ static int geographic_to_projected (PJ *P, long n, int dist, double *x, double * if (P->is_geocent) return 0; - if(P->fwd3d != NULL) + if(P->fwd3d != NULL && !(z == NULL && P->is_latlong)) { /* Three dimensions must be defined */ if ( z == NULL) @@ -292,6 +292,8 @@ static int projected_to_geographic (PJ *P, long n, int dist, double *x, double * /* Nothing to do? */ if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) return 0; + if (P->is_geocent) + return 0; /* Check first if projection is invertible. */ if( (P->inv3d == NULL) && (P->inv == NULL)) @@ -303,7 +305,7 @@ static int projected_to_geographic (PJ *P, long n, int dist, double *x, double * } /* If invertible - First try inv3d if defined */ - if (P->inv3d != NULL) + if (P->inv3d != NULL && !(z == NULL && P->is_latlong)) { /* Three dimensions must be defined */ if ( z == NULL) @@ -335,18 +335,23 @@ typedef struct projCtx_t PJ_CONTEXT; PJ_CONTEXT PROJ_DLL *proj_context_create (void); PJ_CONTEXT PROJ_DLL *proj_context_destroy (PJ_CONTEXT *ctx); +void PROJ_DLL proj_context_use_proj4_init_rules(PJ_CONTEXT *ctx, int enable); +int PROJ_DLL proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_legacy_code_path); /* Manage the transformation definition object PJ */ PJ PROJ_DLL *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ PROJ_DLL *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); -PJ PROJ_DLL *proj_create_crs_to_crs(PJ_CONTEXT *ctx, const char *srid_from, const char *srid_to, PJ_AREA *area); +PJ PROJ_DLL *proj_create_crs_to_crs(PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area); PJ PROJ_DLL *proj_destroy (PJ *P); -/* Setter-functions for the opaque PJ_AREA struct */ -/* Uncomment these when implementing support for area-based transformations. -void proj_area_bbox(PJ_AREA *area, LP ll, LP ur); -void proj_area_description(PJ_AREA *area, const char *descr); -*/ + +PJ_AREA PROJ_DLL *proj_area_create(void); +void PROJ_DLL proj_area_set_bbox(PJ_AREA *area, + double west_lon_degree, + double south_lat_degree, + double east_lon_degree, + double north_lat_degree); +void PROJ_DLL proj_area_destroy(PJ_AREA* area); /* Apply transformation to observation - in forward or inverse direction */ enum PJ_DIRECTION { @@ -438,6 +443,11 @@ char PROJ_DLL * proj_rtodms(char *s, double r, int pos, int neg); /* Binding in C of C++ API */ /* ------------------------------------------------------------------------- */ +/** + * \defgroup basic_cpp_binding Binding in C of basic methods from the C++ API + * @{ + */ + /*! @cond Doxygen_Suppress */ typedef struct PJ_OBJ PJ_OBJ; /*! @endcond */ @@ -453,6 +463,10 @@ int PROJ_DLL proj_context_set_database_path(PJ_CONTEXT *ctx, const char PROJ_DLL *proj_context_get_database_path(PJ_CONTEXT *ctx); +const char PROJ_DLL *proj_context_get_database_metadata(PJ_CONTEXT* ctx, + const char* key); + + /** \brief Guessed WKT "dialect". */ typedef enum { @@ -504,9 +518,13 @@ PJ_OBJ PROJ_DLL *proj_obj_create_from_database(PJ_CONTEXT *ctx, void PROJ_DLL proj_obj_unref(PJ_OBJ *obj); +PJ_OBJ PROJ_DLL *proj_obj_clone(PJ_CONTEXT *ctx, const PJ_OBJ *obj); + /** \brief Object type. */ typedef enum { + PJ_OBJ_TYPE_UNKNOWN, + PJ_OBJ_TYPE_ELLIPSOID, PJ_OBJ_TYPE_GEODETIC_REFERENCE_FRAME, @@ -531,6 +549,7 @@ typedef enum PJ_OBJ_TYPE_PROJECTED_CRS, PJ_OBJ_TYPE_COMPOUND_CRS, PJ_OBJ_TYPE_TEMPORAL_CRS, + PJ_OBJ_TYPE_ENGINEERING_CRS, PJ_OBJ_TYPE_BOUND_CRS, PJ_OBJ_TYPE_OTHER_CRS, @@ -538,8 +557,6 @@ typedef enum PJ_OBJ_TYPE_TRANSFORMATION, PJ_OBJ_TYPE_CONCATENATED_OPERATION, PJ_OBJ_TYPE_OTHER_COORDINATE_OPERATION, - - PJ_OBJ_TYPE_UNKNOWN } PJ_OBJ_TYPE; PJ_OBJ_LIST PROJ_DLL *proj_obj_create_from_name(PJ_CONTEXT *ctx, @@ -551,614 +568,9 @@ PJ_OBJ_LIST PROJ_DLL *proj_obj_create_from_name(PJ_CONTEXT *ctx, size_t limitResultCount, const char* const *options); -PJ_OBJ PROJ_DLL *proj_obj_create_geographic_crs( - PJ_CONTEXT *ctx, - const char *geogName, - const char *datumName, - const char *ellipsoidName, - double semiMajorMetre, double invFlattening, - const char *primeMeridianName, - double primeMeridianOffset, - const char *angularUnits, - double angularUnitsConv, - int latLongOrder); - -/* BEGIN: Generated by scripts/create_c_api_projections.py*/ -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_UTM( - PJ_OBJ* geodetic_crs, const char* crs_name, - int zone, - int north -); +PJ_OBJ_TYPE PROJ_DLL proj_obj_get_type(const PJ_OBJ *obj); -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_TransverseMercator( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_GaussSchreiberTransverseMercator( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_TransverseMercatorSouthOriented( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_TwoPointEquidistant( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstPoint, - double longitudeFirstPoint, - double latitudeSecondPoint, - double longitudeSeconPoint, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_TunisiaMappingGrid( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_AlbersEqualArea( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFalseOrigin, - double longitudeFalseOrigin, - double latitudeFirstParallel, - double latitudeSecondParallel, - double eastingFalseOrigin, - double northingFalseOrigin, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertConicConformal_1SP( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertConicConformal_2SP( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFalseOrigin, - double longitudeFalseOrigin, - double latitudeFirstParallel, - double latitudeSecondParallel, - double eastingFalseOrigin, - double northingFalseOrigin, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertConicConformal_2SP_Michigan( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFalseOrigin, - double longitudeFalseOrigin, - double latitudeFirstParallel, - double latitudeSecondParallel, - double eastingFalseOrigin, - double northingFalseOrigin, - double ellipsoidScalingFactor, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertConicConformal_2SP_Belgium( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFalseOrigin, - double longitudeFalseOrigin, - double latitudeFirstParallel, - double latitudeSecondParallel, - double eastingFalseOrigin, - double northingFalseOrigin, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_AzimuthalEquidistant( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeNatOrigin, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_GuamProjection( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeNatOrigin, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Bonne( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeNatOrigin, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertCylindricalEqualAreaSpherical( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstParallel, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertCylindricalEqualArea( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstParallel, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_CassiniSoldner( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EquidistantConic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double latitudeFirstParallel, - double latitudeSecondParallel, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertI( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertII( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertIII( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertIV( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertV( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EckertVI( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EquidistantCylindrical( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstParallel, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EquidistantCylindricalSpherical( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstParallel, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Gall( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_GoodeHomolosine( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_InterruptedGoodeHomolosine( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_GeostationarySatelliteSweepX( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double height, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_GeostationarySatelliteSweepY( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double height, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Gnomonic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_HotineObliqueMercatorVariantA( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeProjectionCentre, - double longitudeProjectionCentre, - double azimuthInitialLine, - double angleFromRectifiedToSkrewGrid, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_HotineObliqueMercatorVariantB( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeProjectionCentre, - double longitudeProjectionCentre, - double azimuthInitialLine, - double angleFromRectifiedToSkrewGrid, - double scale, - double eastingProjectionCentre, - double northingProjectionCentre, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_HotineObliqueMercatorTwoPointNaturalOrigin( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeProjectionCentre, - double latitudePoint1, - double longitudePoint1, - double latitudePoint2, - double longitudePoint2, - double scale, - double eastingProjectionCentre, - double northingProjectionCentre, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_InternationalMapWorldPolyconic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double latitudeFirstParallel, - double latitudeSecondParallel, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_KrovakNorthOriented( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeProjectionCentre, - double longitudeOfOrigin, - double colatitudeConeAxis, - double latitudePseudoStandardParallel, - double scaleFactorPseudoStandardParallel, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Krovak( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeProjectionCentre, - double longitudeOfOrigin, - double colatitudeConeAxis, - double latitudePseudoStandardParallel, - double scaleFactorPseudoStandardParallel, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_LambertAzimuthalEqualArea( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeNatOrigin, - double longitudeNatOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_MillerCylindrical( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_MercatorVariantA( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_MercatorVariantB( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeFirstParallel, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_PopularVisualisationPseudoMercator( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Mollweide( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_NewZealandMappingGrid( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_ObliqueStereographic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Orthographic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_AmericanPolyconic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_PolarStereographicVariantA( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_PolarStereographicVariantB( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeStandardParallel, - double longitudeOfOrigin, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Robinson( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Sinusoidal( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_Stereographic( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double scale, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_VanDerGrinten( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerI( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerII( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerIII( - PJ_OBJ* geodetic_crs, const char* crs_name, - double latitudeTrueScale, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerIV( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerV( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerVI( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_WagnerVII( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_QuadrilateralizedSphericalCube( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLat, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_SphericalCrossTrackHeight( - PJ_OBJ* geodetic_crs, const char* crs_name, - double pegPointLat, - double pegPointLong, - double pegPointHeading, - double pegPointHeight, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs_EqualEarth( - PJ_OBJ* geodetic_crs, const char* crs_name, - double centerLong, - double falseEasting, - double falseNorthing, - const char* angUnitName, double angUnitConvFactor, - const char* linearUnitName, double linearUnitConvFactor); - -/* END: Generated by scripts/create_c_api_projections.py*/ - -PJ_OBJ_TYPE PROJ_DLL proj_obj_get_type(PJ_OBJ *obj); - -int PROJ_DLL proj_obj_is_deprecated(PJ_OBJ *obj); +int PROJ_DLL proj_obj_is_deprecated(const PJ_OBJ *obj); /** Comparison criterion. */ typedef enum @@ -1182,23 +594,24 @@ typedef enum PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, } PJ_COMPARISON_CRITERION; -int PROJ_DLL proj_obj_is_equivalent_to(PJ_OBJ *obj, PJ_OBJ* other, +int PROJ_DLL proj_obj_is_equivalent_to(const PJ_OBJ *obj, const PJ_OBJ* other, PJ_COMPARISON_CRITERION criterion); -int PROJ_DLL proj_obj_is_crs(PJ_OBJ *obj); +int PROJ_DLL proj_obj_is_crs(const PJ_OBJ *obj); -const char PROJ_DLL* proj_obj_get_name(PJ_OBJ *obj); +const char PROJ_DLL* proj_obj_get_name(const PJ_OBJ *obj); -const char PROJ_DLL* proj_obj_get_id_auth_name(PJ_OBJ *obj, int index); +const char PROJ_DLL* proj_obj_get_id_auth_name(const PJ_OBJ *obj, int index); -const char PROJ_DLL* proj_obj_get_id_code(PJ_OBJ *obj, int index); +const char PROJ_DLL* proj_obj_get_id_code(const PJ_OBJ *obj, int index); -int PROJ_DLL proj_obj_get_area_of_use(PJ_OBJ *obj, - double* p_west_lon, - double* p_south_lat, - double* p_east_lon, - double* p_north_lat, - const char **p_area_name); +int PROJ_DLL proj_obj_get_area_of_use(PJ_CONTEXT *ctx, + const PJ_OBJ *obj, + double* out_west_lon_degree, + double* out_south_lat_degree, + double* out_east_lon_degree, + double* out_north_lat_degree, + const char **out_area_name); /** \brief WKT version. */ typedef enum @@ -1217,7 +630,8 @@ typedef enum PJ_WKT1_ESRI } PJ_WKT_TYPE; -const char PROJ_DLL* proj_obj_as_wkt(PJ_OBJ *obj, PJ_WKT_TYPE type, +const char PROJ_DLL* proj_obj_as_wkt(PJ_CONTEXT *ctx, + const PJ_OBJ *obj, PJ_WKT_TYPE type, const char* const *options); /** \brief PROJ string version. */ @@ -1229,18 +643,22 @@ typedef enum PJ_PROJ_4 } PJ_PROJ_STRING_TYPE; -const char PROJ_DLL* proj_obj_as_proj_string(PJ_OBJ *obj, +const char PROJ_DLL* proj_obj_as_proj_string(PJ_CONTEXT *ctx, + const PJ_OBJ *obj, PJ_PROJ_STRING_TYPE type, const char* const *options); -PJ_OBJ PROJ_DLL *proj_obj_get_source_crs(PJ_OBJ *obj); +PJ_OBJ PROJ_DLL *proj_obj_get_source_crs(PJ_CONTEXT *ctx, + const PJ_OBJ *obj); -PJ_OBJ PROJ_DLL *proj_obj_get_target_crs(PJ_OBJ *obj); +PJ_OBJ PROJ_DLL *proj_obj_get_target_crs(PJ_CONTEXT *ctx, + const PJ_OBJ *obj); -PJ_OBJ_LIST PROJ_DLL *proj_obj_identify(PJ_OBJ* obj, +PJ_OBJ_LIST PROJ_DLL *proj_obj_identify(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, const char *auth_name, const char* const *options, - int **confidence); + int **out_confidence); void PROJ_DLL proj_free_int_list(int* list); @@ -1270,18 +688,20 @@ PJ_OPERATION_FACTORY_CONTEXT PROJ_DLL *proj_create_operation_factory_context( const char *authority); void PROJ_DLL proj_operation_factory_context_unref( - PJ_OPERATION_FACTORY_CONTEXT *ctxt); + PJ_OPERATION_FACTORY_CONTEXT *ctx); void PROJ_DLL proj_operation_factory_context_set_desired_accuracy( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, double accuracy); void PROJ_DLL proj_operation_factory_context_set_area_of_interest( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, - double west_lon, - double south_lat, - double east_lon, - double north_lat); + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + double west_lon_degree, + double south_lat_degree, + double east_lon_degree, + double north_lat_degree); /** Specify how source and target CRS extent should be used to restrict * candidate operations (only taken into account if no explicit area of @@ -1303,7 +723,8 @@ typedef enum } PROJ_CRS_EXTENT_USE; void PROJ_DLL proj_operation_factory_context_set_crs_extent_use( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, PROJ_CRS_EXTENT_USE use); /** Spatial criterion to restrict candiate operations. */ @@ -1318,7 +739,8 @@ typedef enum { } PROJ_SPATIAL_CRITERION; void PROJ_DLL proj_operation_factory_context_set_spatial_criterion( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, PROJ_SPATIAL_CRITERION criterion); @@ -1337,95 +759,148 @@ typedef enum { } PROJ_GRID_AVAILABILITY_USE; void PROJ_DLL proj_operation_factory_context_set_grid_availability_use( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, PROJ_GRID_AVAILABILITY_USE use); void PROJ_DLL proj_operation_factory_context_set_use_proj_alternative_grid_names( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, int usePROJNames); void PROJ_DLL proj_operation_factory_context_set_allow_use_intermediate_crs( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, int allow); + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, + int allow); void PROJ_DLL proj_operation_factory_context_set_allowed_intermediate_crs( - PJ_OPERATION_FACTORY_CONTEXT *ctxt, + PJ_CONTEXT *ctx, + PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, const char* const *list_of_auth_name_codes); /* ------------------------------------------------------------------------- */ PJ_OBJ_LIST PROJ_DLL *proj_obj_create_operations( - PJ_OBJ *source_crs, - PJ_OBJ *target_crs, - PJ_OPERATION_FACTORY_CONTEXT *operationContext); + PJ_CONTEXT *ctx, + const PJ_OBJ *source_crs, + const PJ_OBJ *target_crs, + const PJ_OPERATION_FACTORY_CONTEXT *operationContext); -int PROJ_DLL proj_obj_list_get_count(PJ_OBJ_LIST *result); +int PROJ_DLL proj_obj_list_get_count(const PJ_OBJ_LIST *result); -PJ_OBJ PROJ_DLL *proj_obj_list_get(PJ_OBJ_LIST *result, - int index); +PJ_OBJ PROJ_DLL *proj_obj_list_get(PJ_CONTEXT *ctx, + const PJ_OBJ_LIST *result, + int index); void PROJ_DLL proj_obj_list_unref(PJ_OBJ_LIST *result); /* ------------------------------------------------------------------------- */ -PJ_OBJ PROJ_DLL *proj_obj_crs_get_geodetic_crs(PJ_OBJ *crs); - -PJ_OBJ PROJ_DLL *proj_obj_crs_get_horizontal_datum(PJ_OBJ *crs); - -PJ_OBJ PROJ_DLL *proj_obj_crs_get_sub_crs(PJ_OBJ *crs, int index); - -PJ_OBJ PROJ_DLL *proj_obj_crs_create_bound_crs_to_WGS84(PJ_OBJ *crs); - -PJ_OBJ PROJ_DLL *proj_obj_get_ellipsoid(PJ_OBJ *obj); +PJ_OBJ PROJ_DLL *proj_obj_crs_get_geodetic_crs(PJ_CONTEXT *ctx, const PJ_OBJ *crs); -int PROJ_DLL proj_obj_ellipsoid_get_parameters(PJ_OBJ *ellipsoid, - double *pSemiMajorMetre, - double *pSemiMinorMetre, - int *pIsSemiMinorComputed, - double *pInverseFlattening); +PJ_OBJ PROJ_DLL *proj_obj_crs_get_horizontal_datum(PJ_CONTEXT *ctx, const PJ_OBJ *crs); -PJ_OBJ PROJ_DLL *proj_obj_get_prime_meridian(PJ_OBJ *obj); +PJ_OBJ PROJ_DLL *proj_obj_crs_get_sub_crs(PJ_CONTEXT *ctx, const PJ_OBJ *crs, int index); -int PROJ_DLL proj_obj_prime_meridian_get_parameters(PJ_OBJ *prime_meridian, - double *pLongitude, - double *pLongitudeUnitConvFactor, - const char **pLongitudeUnitName); +PJ_OBJ PROJ_DLL *proj_obj_crs_get_datum(PJ_CONTEXT *ctx, const PJ_OBJ *crs); -PJ_OBJ PROJ_DLL *proj_obj_crs_get_coordoperation(PJ_OBJ *crs, - const char **pMethodName, - const char **pMethodAuthorityName, - const char **pMethodCode); +PJ_OBJ PROJ_DLL *proj_obj_crs_get_coordinate_system(PJ_CONTEXT *ctx, const PJ_OBJ *crs); -int PROJ_DLL proj_coordoperation_is_instanciable(PJ_OBJ *coordoperation); - -int PROJ_DLL proj_coordoperation_get_param_count(PJ_OBJ *coordoperation); - -int PROJ_DLL proj_coordoperation_get_param_index(PJ_OBJ *coordoperation, +/** Type of coordinate system. */ +typedef enum +{ + PJ_CS_TYPE_UNKNOWN, + + PJ_CS_TYPE_CARTESIAN, + PJ_CS_TYPE_ELLIPSOIDAL, + PJ_CS_TYPE_VERTICAL, + PJ_CS_TYPE_SPHERICAL, + PJ_CS_TYPE_ORDINAL, + PJ_CS_TYPE_PARAMETRIC, + PJ_CS_TYPE_DATETIMETEMPORAL, + PJ_CS_TYPE_TEMPORALCOUNT, + PJ_CS_TYPE_TEMPORALMEASURE +} PJ_COORDINATE_SYSTEM_TYPE; + +PJ_COORDINATE_SYSTEM_TYPE PROJ_DLL proj_obj_cs_get_type(PJ_CONTEXT *ctx, + const PJ_OBJ* cs); + +int PROJ_DLL proj_obj_cs_get_axis_count(PJ_CONTEXT *ctx, + const PJ_OBJ *cs); + +int PROJ_DLL proj_obj_cs_get_axis_info(PJ_CONTEXT *ctx, + const PJ_OBJ *cs, int index, + const char **out_name, + const char **out_abbrev, + const char **out_direction, + double *out_unit_conv_factor, + const char **out_unit_name); + +PJ_OBJ PROJ_DLL *proj_obj_get_ellipsoid(PJ_CONTEXT *ctx, + const PJ_OBJ *obj); + +int PROJ_DLL proj_obj_ellipsoid_get_parameters(PJ_CONTEXT *ctx, + const PJ_OBJ *ellipsoid, + double *out_semi_major_metre, + double *out_semi_minor_metre, + int *out_is_semi_minor_computed, + double *out_inv_flattening); + +PJ_OBJ PROJ_DLL *proj_obj_get_prime_meridian(PJ_CONTEXT *ctx, + const PJ_OBJ *obj); + +int PROJ_DLL proj_obj_prime_meridian_get_parameters(PJ_CONTEXT *ctx, + const PJ_OBJ *prime_meridian, + double *out_longitude, + double *out_unit_conv_factor, + const char **out_unit_name); + +PJ_OBJ PROJ_DLL *proj_obj_crs_get_coordoperation(PJ_CONTEXT *ctx, + const PJ_OBJ *crs, + const char **out_method_name, + const char **out_method_auth_name, + const char **out_method_code); + +int PROJ_DLL proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation); + +int PROJ_DLL proj_coordoperation_get_param_count(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation); + +int PROJ_DLL proj_coordoperation_get_param_index(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation, const char *name); -int PROJ_DLL proj_coordoperation_get_param(PJ_OBJ *coordoperation, +int PROJ_DLL proj_coordoperation_get_param(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation, int index, - const char **pName, - const char **pNameAuthorityName, - const char **pNameCode, - double *pValue, - const char **pValueString, - double *pValueUnitConvFactor, - const char **pValueUnitName); - -int PROJ_DLL proj_coordoperation_get_grid_used_count(PJ_OBJ *coordoperation); - -int PROJ_DLL proj_coordoperation_get_grid_used(PJ_OBJ *coordoperation, + const char **out_name, + const char **out_auth_name, + const char **out_code, + double *out_value, + const char **out_value_string, + double *out_unit_conv_factor, + const char **out_unit_name); + +int PROJ_DLL proj_coordoperation_get_grid_used_count(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation); + +int PROJ_DLL proj_coordoperation_get_grid_used(PJ_CONTEXT *ctx, + const PJ_OBJ *coordoperation, int index, - const char **pShortName, - const char **pFullName, - const char **pPackageName, - const char **pURL, - int *pDirectDownload, - int *pOpenLicense, - int *pAvailable); - -double PROJ_DLL proj_coordoperation_get_accuracy(PJ_OBJ* obj); + const char **out_short_name, + const char **out_full_name, + const char **out_package_name, + const char **out_url, + int *out_direct_download, + int *out_open_license, + int *out_available); + +double PROJ_DLL proj_coordoperation_get_accuracy(PJ_CONTEXT *ctx, + const PJ_OBJ* obj); + +/**@}*/ #ifdef __cplusplus } diff --git a/src/proj_4D_api.c b/src/proj_4D_api.c index 56694aae..6ba56764 100644 --- a/src/proj_4D_api.c +++ b/src/proj_4D_api.c @@ -32,6 +32,9 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifndef _MSC_VER +#include <strings.h> +#endif #include "proj.h" #include "proj_internal.h" @@ -564,6 +567,7 @@ PJ *proj_create (PJ_CONTEXT *ctx, const char *definition) { char *args, **argv; size_t argc, n; int ret; + int allow_init_epsg; if (0==ctx) ctx = pj_get_default_ctx (); @@ -587,7 +591,9 @@ PJ *proj_create (PJ_CONTEXT *ctx, const char *definition) { argv = pj_trim_argv (argc, args); /* ...and let pj_init_ctx do the hard work */ - P = pj_init_ctx (ctx, (int) argc, argv); + /* New interface: forbid init=epsg:XXXX syntax by default */ + allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, FALSE); + P = pj_init_ctx_with_allow_init_epsg (ctx, (int) argc, argv, allow_init_epsg); pj_dealloc (argv); pj_dealloc (args); @@ -634,51 +640,183 @@ indicator, as in {"+proj=utm", "+zone=32"}, or leave it out, as in {"proj=utm", return P; } +/** Create an area of use */ +PJ_AREA * proj_area_create(void) { + return pj_calloc(1, sizeof(PJ_AREA)); +} + +/** Assign a bounding box to an area of use. */ +void proj_area_set_bbox(PJ_AREA *area, + double west_lon_degree, + double south_lat_degree, + double east_lon_degree, + double north_lat_degree) { + area->bbox_set = TRUE; + area->west_lon_degree = west_lon_degree; + area->south_lat_degree = south_lat_degree; + area->east_lon_degree = east_lon_degree; + area->north_lat_degree = north_lat_degree; +} + +/** Free an area of use */ +void proj_area_destroy(PJ_AREA* area) { + pj_dealloc(area); +} + +/************************************************************************/ +/* proj_context_use_proj4_init_rules() */ +/************************************************************************/ + +void proj_context_use_proj4_init_rules(PJ_CONTEXT *ctx, int enable) { + if( ctx == NULL ) { + ctx = pj_get_default_ctx(); + } + ctx->use_proj4_init_rules = enable; +} + +/************************************************************************/ +/* EQUAL() */ +/************************************************************************/ + +static int EQUAL(const char* a, const char* b) { +#ifdef _MSC_VER + return _stricmp(a, b) == 0; +#else + return strcasecmp(a, b) == 0; +#endif +} + +/************************************************************************/ +/* proj_context_get_use_proj4_init_rules() */ +/************************************************************************/ + +int proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_legacy_code_path) { + const char* val = getenv("PROJ_USE_PROJ4_INIT_RULES"); + + if( ctx == NULL ) { + ctx = pj_get_default_ctx(); + } + + if( val ) { + if( EQUAL(val, "yes") || EQUAL(val, "on") || EQUAL(val, "true") ) { + return TRUE; + } + if( EQUAL(val, "no") || EQUAL(val, "off") || EQUAL(val, "false") ) { + return FALSE; + } + pj_log(ctx, PJ_LOG_ERROR, "Invalid value for PROJ_USE_PROJ4_INIT_RULES"); + } + + if( ctx->use_proj4_init_rules >= 0 ) { + return ctx->use_proj4_init_rules; + } + return from_legacy_code_path; +} /*****************************************************************************/ -PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *srid_from, const char *srid_to, PJ_AREA *area) { +PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area) { /****************************************************************************** Create a transformation pipeline between two known coordinate reference systems. - srid_from and srid_to should be the value part of a +init=... parameter - set, i.e. "epsg:25833" or "IGNF:AMST63". Any projection definition that - can be found in a init-file in PROJ_LIB is a valid input to this function. - - For now the function mimics the cs2cs app: An input and an output CRS is - given and coordinates are transformed via a hub datum (WGS84). This - transformation strategy is referred to as "early-binding" by the EPSG. The - function can be extended to support "late-binding" transformations in the - future without affecting users of the function. - - An "area of use" can be specified in area. In the current version of this - function is has no function, but is added in anticipation of a - "late-binding" implementation in the future. The idea being, that if a user - supplies an area of use, the more accurate transformation between two given - systems can be chosen. + source_crs and target_crs can be : + - a "AUTHORITY:CODE", like EPSG:25832. When using that syntax for a source + CRS, the created pipeline will expect that the values passed to proj_trans() + respect the axis order and axis unit of the official definition ( + so for example, for EPSG:4326, with latitude first and longitude next, + in degrees). Similarly, when using that syntax for a target CRS, output + values will be emitted according to the official definition of this CRS. + - a PROJ string, like "+proj=longlat +datum=WGS84". + When using that syntax, the axis order and unit for geographic CRS will + be longitude, latitude, and the unit degrees. + - more generally any string accepted by proj_obj_create_from_user_input() + + An "area of use" can be specified in area. When it is supplied, the more + accurate transformation between two given systems can be chosen. Example call: - PJ *P = proj_create_crs_to_crs(0, "epsg:25832", "epsg:25833", NULL); + PJ *P = proj_create_crs_to_crs(0, "EPSG:25832", "EPSG:25833", NULL); ******************************************************************************/ PJ *P; - char buffer[512]; - size_t len; + PJ_OBJ* src; + PJ_OBJ* dst; + PJ_OPERATION_FACTORY_CONTEXT* operation_ctx; + PJ_OBJ_LIST* op_list; + PJ_OBJ* op; + const char* proj_string; + const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", NULL }; + const char* const* optionsImportCRS = + proj_context_get_use_proj4_init_rules(ctx, FALSE) ? optionsProj4Mode : NULL; + + src = proj_obj_create_from_user_input(ctx, source_crs, optionsImportCRS); + if( !src ) { + return NULL; + } + + dst = proj_obj_create_from_user_input(ctx, target_crs, optionsImportCRS); + if( !dst ) { + proj_obj_unref(src); + return NULL; + } + + operation_ctx = proj_create_operation_factory_context(ctx, NULL); + if( !operation_ctx ) { + proj_obj_unref(src); + proj_obj_unref(dst); + return NULL; + } + + if( area && area->bbox_set ) { + proj_operation_factory_context_set_area_of_interest( + ctx, + operation_ctx, + area->west_lon_degree, + area->south_lat_degree, + area->east_lon_degree, + area->north_lat_degree); + } + + proj_operation_factory_context_set_grid_availability_use( + ctx, operation_ctx, PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID); + + op_list = proj_obj_create_operations(ctx, src, dst, operation_ctx); + + proj_operation_factory_context_unref(operation_ctx); + proj_obj_unref(src); + proj_obj_unref(dst); + + if( !op_list ) { + return NULL; + } + + if( proj_obj_list_get_count(op_list) == 0 ) { + proj_obj_list_unref(op_list); + return NULL; + } + + op = proj_obj_list_get(ctx, op_list, 0); + proj_obj_list_unref(op_list); + if( !op ) { + return NULL; + } - /* area not in use yet, suppressing warning */ - (void)area; + proj_string = proj_obj_as_proj_string(ctx, op, PJ_PROJ_5, NULL); + if( !proj_string) { + proj_obj_unref(op); + return NULL; + } - strcpy(buffer, "+proj=pipeline +step +init="); - len = strlen(buffer); - strncat(buffer + len, srid_from, sizeof(buffer)-1-len); - len += strlen(buffer + len); - strncat(buffer + len, " +inv +step +init=", sizeof(buffer)-1-len); - len += strlen(buffer + len); - strncat(buffer + len, srid_to, sizeof(buffer)-1-len); + if( proj_string[0] == '\0' ) { + /* Null transform ? */ + P = proj_create(ctx, "proj=affine"); + } else { + P = proj_create(ctx, proj_string); + } - P = proj_create(ctx, buffer); + proj_obj_unref(op); return P; } @@ -1028,6 +1166,42 @@ PJ_INIT_INFO proj_init_info(const char *initname){ file_found = pj_find_file(ctx, initname, ininfo.filename, sizeof(ininfo.filename)); if (!file_found || strlen(initname) > 64) { + if( strcmp(initname, "epsg") == 0 || strcmp(initname, "EPSG") == 0 ) { + const char* val; + + pj_ctx_set_errno( ctx, 0 ); + + strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); + strcpy(ininfo.origin, "EPSG"); + val = proj_context_get_database_metadata(ctx, "EPSG.VERSION"); + if( val ) { + strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); + } + val = proj_context_get_database_metadata(ctx, "EPSG.DATE"); + if( val ) { + strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); + } + return ininfo; + } + + if( strcmp(initname, "IGNF") == 0 ) { + const char* val; + + pj_ctx_set_errno( ctx, 0 ); + + strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); + strcpy(ininfo.origin, "IGNF"); + val = proj_context_get_database_metadata(ctx, "IGNF.VERSION"); + if( val ) { + strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); + } + val = proj_context_get_database_metadata(ctx, "IGNF.DATE"); + if( val ) { + strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); + } + return ininfo; + } + return ininfo; } diff --git a/src/proj_experimental.h b/src/proj_experimental.h new file mode 100644 index 00000000..1dc16f99 --- /dev/null +++ b/src/proj_experimental.h @@ -0,0 +1,831 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: Experimental C API + * Author: Even Rouault <even dot rouault at spatialys dot com> + * + ****************************************************************************** + * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "proj.h" + +#ifndef PROJ_EXPERIMENTAL_H +#define PROJ_EXPERIMENTAL_H +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file proj_experimental.h + * + * Experimental C API. + * + * \warning + * This API has been considered now to be experimental, and may change or + * be removed in the future. It addresses for now the needs of the GDAL + * project to be able to construct CRS objects in a programmatic way, piece + * by piece, instead of whole conversion from PROJ string or WKT string. + */ + +/* ------------------------------------------------------------------------- */ +/* Binding in C of advanced methods from the C++ API */ +/* */ +/* Manual construction of CRS objects. */ +/* ------------------------------------------------------------------------- */ + +/** + * \defgroup advanced_cpp_binding Binding in C of advanced methods from the C++ API + * @{ + */ + +/** Type of unit of measure. */ +typedef enum +{ + /** Angular unit of measure */ + PJ_UT_ANGULAR, + /** Linear unit of measure */ + PJ_UT_LINEAR, + /** Scale unit of measure */ + PJ_UT_SCALE, + /** Time unit of measure */ + PJ_UT_TIME, + /** Parametric unit of measure */ + PJ_UT_PARAMETRIC +} PJ_UNIT_TYPE; + +/** Axis description. */ +typedef struct +{ + /** Axis name. */ + char* name; + /** Axis abbreviation. */ + char* abbreviation; + /** Axis direction. */ + char* direction; + /** Axis unit name. */ + char* unit_name; + /** Conversion factor to SI of the unit. */ + double unit_conv_factor; + /** Type of unit */ + PJ_UNIT_TYPE unit_type; +} PJ_AXIS_DESCRIPTION; + +PJ_OBJ PROJ_DLL *proj_obj_create_cs(PJ_CONTEXT *ctx, + PJ_COORDINATE_SYSTEM_TYPE type, + int axis_count, + const PJ_AXIS_DESCRIPTION* axis); + +/** Type of Cartesian 2D coordinate system. */ +typedef enum +{ + /* Easting-Norting */ + PJ_CART2D_EASTING_NORTHING, + /* Northing-Easting */ + PJ_CART2D_NORTHING_EASTING, +} PJ_CARTESIAN_CS_2D_TYPE; + +PJ_OBJ PROJ_DLL *proj_obj_create_cartesian_2D_cs(PJ_CONTEXT *ctx, + PJ_CARTESIAN_CS_2D_TYPE type, + const char* unit_name, + double unit_conv_factor); + + +/** Type of Cartesian 2D coordinate system. */ +typedef enum +{ + /* Longitude-Latitude */ + PJ_ELLPS2D_LONGITUDE_LATITUDE, + /* Latitude-Longitude */ + PJ_ELLPS2D_LATITUDE_LONGITUDE, +} PJ_ELLIPSOIDAL_CS_2D_TYPE; + +PJ_OBJ PROJ_DLL *proj_obj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx, + PJ_ELLIPSOIDAL_CS_2D_TYPE type, + const char* unit_name, + double unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_geographic_crs( + PJ_CONTEXT *ctx, + const char *crs_name, + const char *datum_name, + const char *ellps_name, + double semi_major_metre, double inv_flattening, + const char *prime_meridian_name, + double prime_meridian_offset, + const char *pm_angular_units, + double pm_units_conv, + PJ_OBJ* ellipsoidal_cs); + +PJ_OBJ PROJ_DLL *proj_obj_create_geographic_crs_from_datum( + PJ_CONTEXT *ctx, + const char *crs_name, + PJ_OBJ* datum, + PJ_OBJ* ellipsoidal_cs); + +PJ_OBJ PROJ_DLL *proj_obj_create_geocentric_crs( + PJ_CONTEXT *ctx, + const char *crs_name, + const char *datum_name, + const char *ellps_name, + double semi_major_metre, double inv_flattening, + const char *prime_meridian_name, + double prime_meridian_offset, + const char *angular_units, + double angular_units_conv, + const char *linear_units, + double linear_units_conv); + +PJ_OBJ PROJ_DLL *proj_obj_create_geocentric_crs_from_datum( + PJ_CONTEXT *ctx, + const char *crs_name, + const PJ_OBJ* datum, + const char *linear_units, + double linear_units_conv); + +PJ_OBJ PROJ_DLL *proj_obj_alter_name(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, const char* name); + +PJ_OBJ PROJ_DLL *proj_obj_crs_alter_geodetic_crs(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, + const PJ_OBJ* new_geod_crs); + +PJ_OBJ PROJ_DLL *proj_obj_crs_alter_cs_angular_unit(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, + const char *angular_units, + double angular_units_conv); + +PJ_OBJ PROJ_DLL *proj_obj_crs_alter_cs_linear_unit(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, + const char *linear_units, + double linear_units_conv); + +PJ_OBJ PROJ_DLL *proj_obj_crs_alter_parameters_linear_unit(PJ_CONTEXT *ctx, + const PJ_OBJ* obj, + const char *linear_units, + double linear_units_conv, + int convert_to_new_unit); + +PJ_OBJ PROJ_DLL *proj_obj_create_engineering_crs(PJ_CONTEXT *ctx, + const char *crsName); + +/** Description of a parameter value for a Conversion. */ +typedef struct +{ + /** Parameter name. */ + const char* name; + /** Parameter authority name. */ + const char* auth_name; + /** Parameter code. */ + const char* code; + /** Parameter value. */ + double value; + /** Name of unit in which parameter value is expressed. */ + const char* unit_name; + /** Conversion factor to SI of the unit. */ + double unit_conv_factor; + /** Type of unit */ + PJ_UNIT_TYPE unit_type; +} PJ_PARAM_DESCRIPTION; + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion(PJ_CONTEXT *ctx, + const char* name, + const char* auth_name, + const char* code, + const char* method_name, + const char* method_auth_name, + const char* method_code, + int param_count, + const PJ_PARAM_DESCRIPTION* params); + +PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs(PJ_CONTEXT *ctx, + const char* crs_name, + const PJ_OBJ* geodetic_crs, + const PJ_OBJ* conversion, + const PJ_OBJ* coordinate_system); + +PJ_OBJ PROJ_DLL *proj_obj_crs_create_bound_crs(PJ_CONTEXT *ctx, + const PJ_OBJ *base_crs, + const PJ_OBJ *hub_crs, + const PJ_OBJ *transformation); + +PJ_OBJ PROJ_DLL *proj_obj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx, + const PJ_OBJ *crs); + +/* BEGIN: Generated by scripts/create_c_api_projections.py*/ +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_utm( + PJ_CONTEXT *ctx, + int zone, + int north); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_transverse_mercator( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_gauss_schreiber_transverse_mercator( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_transverse_mercator_south_oriented( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_two_point_equidistant( + PJ_CONTEXT *ctx, + double latitude_first_point, + double longitude_first_point, + double latitude_second_point, + double longitude_secon_point, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_tunisia_mapping_grid( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_albers_equal_area( + PJ_CONTEXT *ctx, + double latitude_false_origin, + double longitude_false_origin, + double latitude_first_parallel, + double latitude_second_parallel, + double easting_false_origin, + double northing_false_origin, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_conic_conformal_1sp( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_conic_conformal_2sp( + PJ_CONTEXT *ctx, + double latitude_false_origin, + double longitude_false_origin, + double latitude_first_parallel, + double latitude_second_parallel, + double easting_false_origin, + double northing_false_origin, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_conic_conformal_2sp_michigan( + PJ_CONTEXT *ctx, + double latitude_false_origin, + double longitude_false_origin, + double latitude_first_parallel, + double latitude_second_parallel, + double easting_false_origin, + double northing_false_origin, + double ellipsoid_scaling_factor, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_conic_conformal_2sp_belgium( + PJ_CONTEXT *ctx, + double latitude_false_origin, + double longitude_false_origin, + double latitude_first_parallel, + double latitude_second_parallel, + double easting_false_origin, + double northing_false_origin, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_azimuthal_equidistant( + PJ_CONTEXT *ctx, + double latitude_nat_origin, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_guam_projection( + PJ_CONTEXT *ctx, + double latitude_nat_origin, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_bonne( + PJ_CONTEXT *ctx, + double latitude_nat_origin, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_cylindrical_equal_area_spherical( + PJ_CONTEXT *ctx, + double latitude_first_parallel, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_cylindrical_equal_area( + PJ_CONTEXT *ctx, + double latitude_first_parallel, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_cassini_soldner( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_equidistant_conic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double latitude_first_parallel, + double latitude_second_parallel, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_i( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_ii( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_iii( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_iv( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_v( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_eckert_vi( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_equidistant_cylindrical( + PJ_CONTEXT *ctx, + double latitude_first_parallel, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_equidistant_cylindrical_spherical( + PJ_CONTEXT *ctx, + double latitude_first_parallel, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_gall( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_goode_homolosine( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_interrupted_goode_homolosine( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_geostationary_satellite_sweep_x( + PJ_CONTEXT *ctx, + double center_long, + double height, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_geostationary_satellite_sweep_y( + PJ_CONTEXT *ctx, + double center_long, + double height, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_gnomonic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_hotine_oblique_mercator_variant_a( + PJ_CONTEXT *ctx, + double latitude_projection_centre, + double longitude_projection_centre, + double azimuth_initial_line, + double angle_from_rectified_to_skrew_grid, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_hotine_oblique_mercator_variant_b( + PJ_CONTEXT *ctx, + double latitude_projection_centre, + double longitude_projection_centre, + double azimuth_initial_line, + double angle_from_rectified_to_skrew_grid, + double scale, + double easting_projection_centre, + double northing_projection_centre, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_hotine_oblique_mercator_two_point_natural_origin( + PJ_CONTEXT *ctx, + double latitude_projection_centre, + double latitude_point1, + double longitude_point1, + double latitude_point2, + double longitude_point2, + double scale, + double easting_projection_centre, + double northing_projection_centre, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_international_map_world_polyconic( + PJ_CONTEXT *ctx, + double center_long, + double latitude_first_parallel, + double latitude_second_parallel, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_krovak_north_oriented( + PJ_CONTEXT *ctx, + double latitude_projection_centre, + double longitude_of_origin, + double colatitude_cone_axis, + double latitude_pseudo_standard_parallel, + double scale_factor_pseudo_standard_parallel, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_krovak( + PJ_CONTEXT *ctx, + double latitude_projection_centre, + double longitude_of_origin, + double colatitude_cone_axis, + double latitude_pseudo_standard_parallel, + double scale_factor_pseudo_standard_parallel, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_lambert_azimuthal_equal_area( + PJ_CONTEXT *ctx, + double latitude_nat_origin, + double longitude_nat_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_miller_cylindrical( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_mercator_variant_a( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_mercator_variant_b( + PJ_CONTEXT *ctx, + double latitude_first_parallel, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_popular_visualisation_pseudo_mercator( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_mollweide( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_new_zealand_mapping_grid( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_oblique_stereographic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_orthographic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_american_polyconic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_polar_stereographic_variant_a( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_polar_stereographic_variant_b( + PJ_CONTEXT *ctx, + double latitude_standard_parallel, + double longitude_of_origin, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_robinson( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_sinusoidal( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_stereographic( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double scale, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_van_der_grinten( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_i( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_ii( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_iii( + PJ_CONTEXT *ctx, + double latitude_true_scale, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_iv( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_v( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_vi( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_wagner_vii( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_quadrilateralized_spherical_cube( + PJ_CONTEXT *ctx, + double center_lat, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_spherical_cross_track_height( + PJ_CONTEXT *ctx, + double peg_point_lat, + double peg_point_long, + double peg_point_heading, + double peg_point_height, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +PJ_OBJ PROJ_DLL *proj_obj_create_conversion_equal_earth( + PJ_CONTEXT *ctx, + double center_long, + double false_easting, + double false_northing, + const char* ang_unit_name, double ang_unit_conv_factor, + const char* linear_unit_name, double linear_unit_conv_factor); + +/* END: Generated by scripts/create_c_api_projections.py*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* ndef PROJ_EXPERIMENTAL_H */ diff --git a/src/proj_symbol_rename.h b/src/proj_symbol_rename.h index d0dd09eb..a267b97e 100644 --- a/src/proj_symbol_rename.h +++ b/src/proj_symbol_rename.h @@ -101,14 +101,20 @@ #define pj_transform internal_pj_transform #define proj_angular_input internal_proj_angular_input #define proj_angular_output internal_proj_angular_output +#define proj_area_create internal_proj_area_create +#define proj_area_destroy internal_proj_area_destroy +#define proj_area_set_bbox internal_proj_area_set_bbox #define proj_context_create internal_proj_context_create #define proj_context_delete_cpp_context internal_proj_context_delete_cpp_context #define proj_context_destroy internal_proj_context_destroy #define proj_context_errno internal_proj_context_errno +#define proj_context_get_database_metadata internal_proj_context_get_database_metadata #define proj_context_get_database_path internal_proj_context_get_database_path +#define proj_context_get_use_proj4_init_rules internal_proj_context_get_use_proj4_init_rules #define proj_context_guess_wkt_dialect internal_proj_context_guess_wkt_dialect #define proj_context_set internal_proj_context_set #define proj_context_set_database_path internal_proj_context_set_database_path +#define proj_context_use_proj4_init_rules internal_proj_context_use_proj4_init_rules #define proj_coord internal_proj_coord #define proj_coord_error internal_proj_coord_error #define proj_coordoperation_get_accuracy internal_proj_coordoperation_get_accuracy @@ -132,7 +138,6 @@ #define proj_factors internal_proj_factors #define proj_free_int_list internal_proj_free_int_list #define proj_free_string_list internal_proj_free_string_list -#define proj_geocentric_latitude internal_proj_geocentric_latitude #define proj_geod internal_proj_geod #define proj_get_authorities_from_database internal_proj_get_authorities_from_database #define proj_get_codes_from_database internal_proj_get_codes_from_database @@ -151,6 +156,7 @@ #define proj_lpz_dist internal_proj_lpz_dist #define proj_obj_as_proj_string internal_proj_obj_as_proj_string #define proj_obj_as_wkt internal_proj_obj_as_wkt +#define proj_obj_clone internal_proj_obj_clone #define proj_obj_create_from_database internal_proj_obj_create_from_database #define proj_obj_create_from_name internal_proj_obj_create_from_name #define proj_obj_create_from_proj_string internal_proj_obj_create_from_proj_string @@ -223,10 +229,14 @@ #define proj_obj_create_projected_crs_WagnerVI internal_proj_obj_create_projected_crs_WagnerVI #define proj_obj_create_projected_crs_WagnerVII internal_proj_obj_create_projected_crs_WagnerVII #define proj_obj_crs_create_bound_crs_to_WGS84 internal_proj_obj_crs_create_bound_crs_to_WGS84 +#define proj_obj_crs_get_coordinate_system internal_proj_obj_crs_get_coordinate_system #define proj_obj_crs_get_coordoperation internal_proj_obj_crs_get_coordoperation #define proj_obj_crs_get_geodetic_crs internal_proj_obj_crs_get_geodetic_crs #define proj_obj_crs_get_horizontal_datum internal_proj_obj_crs_get_horizontal_datum #define proj_obj_crs_get_sub_crs internal_proj_obj_crs_get_sub_crs +#define proj_obj_cs_get_axis_count internal_proj_obj_cs_get_axis_count +#define proj_obj_cs_get_axis_info internal_proj_obj_cs_get_axis_info +#define proj_obj_cs_get_type internal_proj_obj_cs_get_type #define proj_obj_ellipsoid_get_parameters internal_proj_obj_ellipsoid_get_parameters #define proj_obj_get_area_of_use internal_proj_obj_get_area_of_use #define proj_obj_get_ellipsoid internal_proj_obj_get_ellipsoid diff --git a/src/projects.h b/src/projects.h index e34fc9e0..11467d56 100644 --- a/src/projects.h +++ b/src/projects.h @@ -224,10 +224,11 @@ struct PJ_REGION_S { }; struct PJ_AREA { - int id; /* Area ID in the EPSG database */ - LP ll; /* Lower left corner of bounding box */ - LP ur; /* Upper right corner of bounding box */ - char descr[64]; /* text representation of area */ + int bbox_set; + double west_lon_degree; + double south_lat_degree; + double east_lon_degree; + double north_lat_degree; }; struct projCtx_t; @@ -596,6 +597,8 @@ struct projCtx_t { void *app_data; struct projFileAPI_t *fileapi; struct projCppContext* cpp_context; /* internal context for C++ code */ + int use_proj4_init_rules; /* -1 = unknown, 0 = no, 1 = yes */ + int epsg_file_exists; /* -1 = unknown, 0 = no, 1 = yes */ }; /* classic public API */ @@ -831,6 +834,8 @@ double PROJ_DLL pj_atof( const char* nptr ); double pj_strtod( const char *nptr, char **endptr ); void pj_freeup_plain (PJ *P); +projPJ pj_init_ctx_with_allow_init_epsg( projCtx ctx, int argc, char **argv, int allow_init_epsg ); + #ifdef __cplusplus } #endif diff --git a/src/projinfo.cpp b/src/projinfo.cpp index dbbcdae2..7acb13af 100644 --- a/src/projinfo.cpp +++ b/src/projinfo.cpp @@ -65,6 +65,7 @@ struct OutputOptions { bool WKT1_GDAL = false; bool WKT1_ESRI = false; bool c_ify = false; + bool singleLine = false; }; // --------------------------------------------------------------------------- @@ -86,6 +87,7 @@ static void usage() { << " [--main-db-path path] [--aux-db-path path]*" << std::endl << " [--identify]" << std::endl + << " [--c-ify] [--single-line]" << std::endl << " {object_definition} | (-s {srs_def} -t {srs_def})" << std::endl; std::cerr << std::endl; @@ -204,7 +206,7 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, if (outputOpt.PROJ5) { try { if (!outputOpt.quiet) { - std::cout << "PROJ string: " << std::endl; + std::cout << "PROJ string:" << std::endl; } std::cout << projStringExportable->exportToPROJString( PROJStringFormatter::create( @@ -225,7 +227,7 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "PROJ.4 string: " << std::endl; + std::cout << "PROJ.4 string:" << std::endl; } auto crs = nn_dynamic_pointer_cast<CRS>(obj); @@ -261,11 +263,14 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT2_2015 string: " << std::endl; + std::cout << "WKT2_2015 string:" << std::endl; } - auto wkt = wktExportable->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT2_2015) - .get()); + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT2_2015); + if (outputOpt.singleLine) { + formatter->setMultiLine(false); + } + auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); } @@ -283,12 +288,14 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT2_2015_SIMPLIFIED string: " << std::endl; + std::cout << "WKT2_2015_SIMPLIFIED string:" << std::endl; } - auto wkt = wktExportable->exportToWKT( - WKTFormatter::create( - WKTFormatter::Convention::WKT2_2015_SIMPLIFIED) - .get()); + auto formatter = WKTFormatter::create( + WKTFormatter::Convention::WKT2_2015_SIMPLIFIED); + if (outputOpt.singleLine) { + formatter->setMultiLine(false); + } + auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); } @@ -306,11 +313,14 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT2_2018 string: " << std::endl; + std::cout << "WKT2_2018 string:" << std::endl; } - auto wkt = wktExportable->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT2_2018) - .get()); + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT2_2018); + if (outputOpt.singleLine) { + formatter->setMultiLine(false); + } + auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); } @@ -328,12 +338,14 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT2_2018_SIMPLIFIED string: " << std::endl; + std::cout << "WKT2_2018_SIMPLIFIED string:" << std::endl; } - auto wkt = wktExportable->exportToWKT( - WKTFormatter::create( - WKTFormatter::Convention::WKT2_2018_SIMPLIFIED) - .get()); + auto formatter = WKTFormatter::create( + WKTFormatter::Convention::WKT2_2018_SIMPLIFIED); + if (outputOpt.singleLine) { + formatter->setMultiLine(false); + } + auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); } @@ -351,7 +363,7 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT1_GDAL: " << std::endl; + std::cout << "WKT1_GDAL:" << std::endl; } auto crs = nn_dynamic_pointer_cast<CRS>(obj); @@ -364,9 +376,12 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, objToExport = wktExportable; } - auto wkt = objToExport->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL) - .get()); + auto formatter = + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL); + if (outputOpt.singleLine) { + formatter->setMultiLine(false); + } + auto wkt = objToExport->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); } @@ -385,7 +400,7 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "WKT1_ESRI: " << std::endl; + std::cout << "WKT1_ESRI:" << std::endl; } auto wkt = wktExportable->exportToWKT( @@ -571,6 +586,7 @@ int main(int argc, char **argv) { outputOpt.WKT2_2018 = true; outputOpt.WKT2_2015 = true; outputOpt.WKT1_GDAL = true; + outputOpt.WKT1_ESRI = true; } else if (ci_equal(format, "default")) { outputOpt.PROJ5 = true; outputOpt.PROJ4 = false; @@ -684,6 +700,8 @@ int main(int argc, char **argv) { outputOpt.quiet = true; } else if (arg == "--c-ify") { outputOpt.c_ify = true; + } else if (arg == "--single-line") { + outputOpt.singleLine = true; } else if (arg == "--summary") { summary = true; } else if (ci_equal(arg, "--boundcrs-to-wgs84")) { diff --git a/src/rtodms.c b/src/rtodms.c index f0e2f675..674cebdf 100644 --- a/src/rtodms.c +++ b/src/rtodms.c @@ -66,6 +66,13 @@ rtodms(char *s, double r, int pos, int neg) { size_t suffix_len = sign ? 3 : 2; (void)sprintf(ss,format,deg,min,sec,sign); + /* Replace potential decimal comma by decimal point for non C locale */ + for( p = ss; *p != '\0'; ++p ) { + if( *p == ',' ) { + *p = '.'; + break; + } + } for (q = p = ss + strlen(ss) - suffix_len; *p == '0'; --p) ; if (*p != '.') ++p; |
