diff options
Diffstat (limited to 'src/c_api.cpp')
| -rw-r--r-- | src/c_api.cpp | 4038 |
1 files changed, 4038 insertions, 0 deletions
diff --git a/src/c_api.cpp b/src/c_api.cpp new file mode 100644 index 00000000..1720a7a1 --- /dev/null +++ b/src/c_api.cpp @@ -0,0 +1,4038 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: C API wraper of 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. + ****************************************************************************/ + +#ifndef FROM_PROJ_CPP +#define FROM_PROJ_CPP +#endif + +#include <cassert> +#include <cstdarg> +#include <cstring> +#include <map> +#include <utility> +#include <vector> + +#include "proj/common.hpp" +#include "proj/coordinateoperation.hpp" +#include "proj/crs.hpp" +#include "proj/datum.hpp" +#include "proj/io.hpp" +#include "proj/metadata.hpp" +#include "proj/util.hpp" + +#include "proj/internal/internal.hpp" + +// PROJ include order is sensitive +// clang-format off +#include "proj_internal.h" +#include "proj.h" +#include "projects.h" +// clang-format on + +using namespace NS_PROJ::common; +using namespace NS_PROJ::crs; +using namespace NS_PROJ::datum; +using namespace NS_PROJ::io; +using namespace NS_PROJ::internal; +using namespace NS_PROJ::metadata; +using namespace NS_PROJ::operation; +using namespace NS_PROJ::util; +using namespace NS_PROJ; + +// --------------------------------------------------------------------------- + +static void PROJ_NO_INLINE proj_log_error(PJ_CONTEXT *ctx, const char *function, + const char *text) { + std::string msg(function); + msg += ": "; + msg += text; + ctx->logger(ctx->app_data, PJ_LOG_ERROR, msg.c_str()); +} + +// --------------------------------------------------------------------------- + +static void PROJ_NO_INLINE proj_log_debug(PJ_CONTEXT *ctx, const char *function, + const char *text) { + std::string msg(function); + msg += ": "; + msg += text; + ctx->logger(ctx->app_data, PJ_LOG_DEBUG, msg.c_str()); +} + +// --------------------------------------------------------------------------- + +/** \brief Opaque object representing a Ellipsoid, Datum, CRS or Coordinate + * 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{}; + + explicit PJ_OBJ(PJ_CONTEXT *ctxIn, const IdentifiedObjectNNPtr &objIn) + : ctx(ctxIn), obj(objIn) {} + static PJ_OBJ *create(PJ_CONTEXT *ctxIn, + const IdentifiedObjectNNPtr &objIn); + + PJ_OBJ(const PJ_OBJ &) = delete; + PJ_OBJ &operator=(const PJ_OBJ &) = delete; + //! @endcond +}; + +//! @cond Doxygen_Suppress +PJ_OBJ *PJ_OBJ::create(PJ_CONTEXT *ctxIn, const IdentifiedObjectNNPtr &objIn) { + return new PJ_OBJ(ctxIn, objIn); +} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \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)) {} + + PJ_OBJ_LIST(const PJ_OBJ_LIST &) = delete; + PJ_OBJ_LIST &operator=(const PJ_OBJ_LIST &) = delete; + //! @endcond +}; + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +/** Auxiliary structure to PJ_CONTEXT storing C++ context stuff. */ +struct projCppContext { + DatabaseContextNNPtr databaseContext; + + explicit projCppContext(PJ_CONTEXT *ctxt, const char *dbPath = nullptr, + const char *const *auxDbPaths = nullptr) + : databaseContext(DatabaseContext::create( + dbPath ? dbPath : std::string(), toVector(auxDbPaths))) { + databaseContext->attachPJContext(ctxt); + } + + static std::vector<std::string> toVector(const char *const *auxDbPaths) { + std::vector<std::string> res; + for (auto iter = auxDbPaths; iter && *iter; ++iter) { + res.emplace_back(std::string(*iter)); + } + return res; + } +}; + +// --------------------------------------------------------------------------- + +void proj_context_delete_cpp_context(struct projCppContext *cppContext) { + delete cppContext; +} + +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +#define SANITIZE_CTX(ctx) \ + do { \ + if (ctx == nullptr) { \ + ctx = pj_get_default_ctx(); \ + } \ + } while (0) + +// --------------------------------------------------------------------------- + +static PROJ_NO_INLINE const DatabaseContextNNPtr & +getDBcontext(PJ_CONTEXT *ctx) { + if (ctx->cpp_context == nullptr) { + ctx->cpp_context = new projCppContext(ctx); + } + return ctx->cpp_context->databaseContext; +} + +// --------------------------------------------------------------------------- + +static PROJ_NO_INLINE DatabaseContextPtr +getDBcontextNoException(PJ_CONTEXT *ctx, const char *function) { + try { + return getDBcontext(ctx).as_nullable(); + } catch (const std::exception &e) { + proj_log_debug(ctx, function, e.what()); + return nullptr; + } +} + +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Explicitly point to the main PROJ CRS and coordinate operation + * definition database ("proj.db"), and potentially auxiliary databases with + * same structure. + * + * @param ctx PROJ context, or NULL for default context + * @param dbPath Path to main database, or NULL for default. + * @param auxDbPaths NULL-terminated list of auxiliary database filenames, or + * NULL. + * @param options should be set to NULL for now + * @return TRUE in case of success + */ +int proj_context_set_database_path(PJ_CONTEXT *ctx, const char *dbPath, + const char *const *auxDbPaths, + const char *const *options) { + SANITIZE_CTX(ctx); + (void)options; + delete ctx->cpp_context; + ctx->cpp_context = nullptr; + try { + ctx->cpp_context = new projCppContext(ctx, dbPath, auxDbPaths); + return true; + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return false; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the path to the database. + * + * The returned pointer remains valid while ctx is valid, and until + * proj_context_set_database_path() is called. + * + * @param ctx PROJ context, or NULL for default context + * @return path, or nullptr + */ +const char *proj_context_get_database_path(PJ_CONTEXT *ctx) { + SANITIZE_CTX(ctx); + try { + return getDBcontext(ctx)->getPath().c_str(); + } 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 + * @param wkt String (must not be NULL) + */ +PJ_GUESSED_WKT_DIALECT proj_context_guess_wkt_dialect(PJ_CONTEXT *ctx, + const char *wkt) { + (void)ctx; + assert(wkt); + switch (WKTParser().guessDialect(wkt)) { + case WKTParser::WKTGuessedDialect::WKT2_2018: + return PJ_GUESSED_WKT2_2018; + case WKTParser::WKTGuessedDialect::WKT2_2015: + return PJ_GUESSED_WKT2_2015; + case WKTParser::WKTGuessedDialect::WKT1_GDAL: + return PJ_GUESSED_WKT1_GDAL; + case WKTParser::WKTGuessedDialect::WKT1_ESRI: + return PJ_GUESSED_WKT1_ESRI; + case WKTParser::WKTGuessedDialect::NOT_WKT: + break; + } + return PJ_GUESSED_NOT_WKT; +} + +// --------------------------------------------------------------------------- + +/** \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"). + * + * This function calls osgeo::proj::io::createFromUserInput() + * + * 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 text String (must not be NULL) + * @param options should be set to NULL for now + * @return Object that must be unreferenced with proj_obj_unref(), or NULL in + * case of error. + */ +PJ_OBJ *proj_obj_create_from_user_input(PJ_CONTEXT *ctx, const char *text, + const char *const *options) { + SANITIZE_CTX(ctx); + assert(text); + (void)options; + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + try { + auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( + createFromUserInput(text, dbContext)); + if (identifiedObject) { + return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate an object from a WKT string. + * + * This function calls osgeo::proj::io::WKTParser::createFromWKT() + * + * 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 wkt WKT string (must not be NULL) + * @param options should be set to NULL for now + * @return Object that must be unreferenced with proj_obj_unref(), or NULL in + * case of error. + */ +PJ_OBJ *proj_obj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt, + const char *const *options) { + SANITIZE_CTX(ctx); + assert(wkt); + (void)options; + try { + auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( + WKTParser().createFromWKT(wkt)); + if (identifiedObject) { + return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate an object from a PROJ string. + * + * This function calls osgeo::proj::io::PROJStringParser::createFromPROJString() + * + * 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 proj_string PROJ string (must not be NULL) + * @param options should be set to NULL for now + * @return Object that must be unreferenced with proj_obj_unref(), or NULL in + * case of error. + */ +PJ_OBJ *proj_obj_create_from_proj_string(PJ_CONTEXT *ctx, + const char *proj_string, + const char *const *options) { + SANITIZE_CTX(ctx); + (void)options; + assert(proj_string); + try { + auto identifiedObject = nn_dynamic_pointer_cast<IdentifiedObject>( + PROJStringParser().createFromPROJString(proj_string)); + if (identifiedObject) { + return PJ_OBJ::create(ctx, NN_NO_CHECK(identifiedObject)); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate an object from a database lookup. + * + * 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 Context, or NULL for default context. + * @param auth_name Authority name (must not be NULL) + * @param code Object code (must not be NULL) + * @param category Object category + * @param usePROJAlternativeGridNames Whether PROJ alternative grid names + * should be substituted to the official grid names. Only used on + * transformations + * @param options should be set to NULL for now + * @return Object that must be unreferenced with proj_obj_unref(), or NULL in + * case of error. + */ +PJ_OBJ *proj_obj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, + const char *code, + PJ_OBJ_CATEGORY category, + int usePROJAlternativeGridNames, + const char *const *options) { + assert(auth_name); + assert(code); + (void)options; + SANITIZE_CTX(ctx); + const std::string codeStr(code); + try { + auto factory = AuthorityFactory::create(getDBcontext(ctx), auth_name); + IdentifiedObjectPtr obj; + switch (category) { + case PJ_OBJ_CATEGORY_ELLIPSOID: + obj = factory->createEllipsoid(codeStr).as_nullable(); + break; + case PJ_OBJ_CATEGORY_DATUM: + obj = factory->createDatum(codeStr).as_nullable(); + break; + case PJ_OBJ_CATEGORY_CRS: + obj = + factory->createCoordinateReferenceSystem(codeStr).as_nullable(); + break; + case PJ_OBJ_CATEGORY_COORDINATE_OPERATION: + obj = factory + ->createCoordinateOperation( + codeStr, usePROJAlternativeGridNames != 0) + .as_nullable(); + break; + } + return PJ_OBJ::create(ctx, NN_NO_CHECK(obj)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Drops a reference on an object. + * + * This method should be called one and exactly one for each function + * returning a PJ_OBJ* + * + * @param obj Object, or NULL. + */ +void proj_obj_unref(PJ_OBJ *obj) { delete obj; } + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +static AuthorityFactory::ObjectType +convertPJObjectTypeToObjectType(PJ_OBJ_TYPE type, bool &valid) { + valid = true; + AuthorityFactory::ObjectType cppType = AuthorityFactory::ObjectType::CRS; + switch (type) { + case PJ_OBJ_TYPE_ELLIPSOID: + cppType = AuthorityFactory::ObjectType::ELLIPSOID; + break; + + case PJ_OBJ_TYPE_GEODETIC_REFERENCE_FRAME: + case PJ_OBJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME: + cppType = AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME; + break; + + case PJ_OBJ_TYPE_VERTICAL_REFERENCE_FRAME: + case PJ_OBJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME: + cppType = AuthorityFactory::ObjectType::VERTICAL_REFERENCE_FRAME; + break; + + case PJ_OBJ_TYPE_DATUM_ENSEMBLE: + cppType = AuthorityFactory::ObjectType::DATUM; + break; + + case PJ_OBJ_TYPE_CRS: + cppType = AuthorityFactory::ObjectType::CRS; + break; + + case PJ_OBJ_TYPE_GEODETIC_CRS: + cppType = AuthorityFactory::ObjectType::GEODETIC_CRS; + break; + + case PJ_OBJ_TYPE_GEOCENTRIC_CRS: + cppType = AuthorityFactory::ObjectType::GEOCENTRIC_CRS; + break; + + case PJ_OBJ_TYPE_GEOGRAPHIC_CRS: + cppType = AuthorityFactory::ObjectType::GEOGRAPHIC_CRS; + break; + + case PJ_OBJ_TYPE_GEOGRAPHIC_2D_CRS: + cppType = AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS; + break; + + case PJ_OBJ_TYPE_GEOGRAPHIC_3D_CRS: + cppType = AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS; + break; + + case PJ_OBJ_TYPE_VERTICAL_CRS: + cppType = AuthorityFactory::ObjectType::VERTICAL_CRS; + break; + + case PJ_OBJ_TYPE_PROJECTED_CRS: + cppType = AuthorityFactory::ObjectType::PROJECTED_CRS; + break; + + case PJ_OBJ_TYPE_COMPOUND_CRS: + cppType = AuthorityFactory::ObjectType::COMPOUND_CRS; + break; + + case PJ_OBJ_TYPE_TEMPORAL_CRS: + valid = false; + break; + + case PJ_OBJ_TYPE_BOUND_CRS: + valid = false; + break; + + case PJ_OBJ_TYPE_OTHER_CRS: + cppType = AuthorityFactory::ObjectType::CRS; + break; + + case PJ_OBJ_TYPE_CONVERSION: + cppType = AuthorityFactory::ObjectType::CONVERSION; + break; + + case PJ_OBJ_TYPE_TRANSFORMATION: + cppType = AuthorityFactory::ObjectType::TRANSFORMATION; + break; + + case PJ_OBJ_TYPE_CONCATENATED_OPERATION: + cppType = AuthorityFactory::ObjectType::CONCATENATED_OPERATION; + break; + + case PJ_OBJ_TYPE_OTHER_COORDINATE_OPERATION: + cppType = AuthorityFactory::ObjectType::COORDINATE_OPERATION; + break; + + case PJ_OBJ_TYPE_UNKNOWN: + valid = false; + break; + } + return cppType; +} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Return a list of objects by their name. + * + * @param ctx Context, or NULL for default context. + * @param auth_name Authority name, used to restrict the search. + * Or NULL for all authorities. + * @param searchedName Searched name. Must be at least 2 character long. + * @param types List of object types into which to search. If + * NULL, all object types will be searched. + * @param typesCount Number of elements in types, or 0 if types is NULL + * @param approximateMatch Whether approximate name identification is allowed. + * @param limitResultCount Maximum number of results to return. + * Or 0 for unlimited. + * @param options should be set to NULL for now + * @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_from_name(PJ_CONTEXT *ctx, const char *auth_name, + const char *searchedName, + const PJ_OBJ_TYPE *types, + size_t typesCount, int approximateMatch, + size_t limitResultCount, + const char *const *options) { + assert(searchedName); + assert((types != nullptr && typesCount > 0) || + (types == nullptr && typesCount == 0)); + (void)options; + SANITIZE_CTX(ctx); + try { + auto factory = AuthorityFactory::create(getDBcontext(ctx), + auth_name ? auth_name : ""); + std::vector<AuthorityFactory::ObjectType> allowedTypes; + for (size_t i = 0; i < typesCount; ++i) { + bool valid = false; + auto type = convertPJObjectTypeToObjectType(types[i], valid); + if (valid) { + allowedTypes.push_back(type); + } + } + auto res = factory->createObjectsFromName(searchedName, allowedTypes, + approximateMatch != 0, + limitResultCount); + std::vector<IdentifiedObjectNNPtr> objects; + for (const auto &obj : res) { + objects.push_back(obj); + } + return new PJ_OBJ_LIST(ctx, std::move(objects)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return the type of an object. + * + * @param obj Object (must not be NULL) + * @return its type. + */ +PJ_OBJ_TYPE proj_obj_get_type(PJ_OBJ *obj) { + assert(obj); + auto ptr = obj->obj.get(); + if (dynamic_cast<Ellipsoid *>(ptr)) { + return PJ_OBJ_TYPE_ELLIPSOID; + } + + if (dynamic_cast<DynamicGeodeticReferenceFrame *>(ptr)) { + return PJ_OBJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME; + } + if (dynamic_cast<GeodeticReferenceFrame *>(ptr)) { + return PJ_OBJ_TYPE_GEODETIC_REFERENCE_FRAME; + } + if (dynamic_cast<DynamicVerticalReferenceFrame *>(ptr)) { + return PJ_OBJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME; + } + if (dynamic_cast<VerticalReferenceFrame *>(ptr)) { + return PJ_OBJ_TYPE_VERTICAL_REFERENCE_FRAME; + } + if (dynamic_cast<DatumEnsemble *>(ptr)) { + return PJ_OBJ_TYPE_DATUM_ENSEMBLE; + } + + { + auto crs = dynamic_cast<GeographicCRS *>(ptr); + if (crs) { + if (crs->coordinateSystem()->axisList().size() == 2) { + return PJ_OBJ_TYPE_GEOGRAPHIC_2D_CRS; + } else { + return PJ_OBJ_TYPE_GEOGRAPHIC_3D_CRS; + } + } + } + + { + auto crs = dynamic_cast<GeodeticCRS *>(ptr); + if (crs) { + if (crs->isGeocentric()) { + return PJ_OBJ_TYPE_GEOCENTRIC_CRS; + } else { + return PJ_OBJ_TYPE_GEODETIC_CRS; + } + } + } + + if (dynamic_cast<VerticalCRS *>(ptr)) { + return PJ_OBJ_TYPE_VERTICAL_CRS; + } + if (dynamic_cast<ProjectedCRS *>(ptr)) { + return PJ_OBJ_TYPE_PROJECTED_CRS; + } + if (dynamic_cast<CompoundCRS *>(ptr)) { + return PJ_OBJ_TYPE_COMPOUND_CRS; + } + if (dynamic_cast<TemporalCRS *>(ptr)) { + return PJ_OBJ_TYPE_TEMPORAL_CRS; + } + if (dynamic_cast<BoundCRS *>(ptr)) { + return PJ_OBJ_TYPE_BOUND_CRS; + } + if (dynamic_cast<CRS *>(ptr)) { + return PJ_OBJ_TYPE_OTHER_CRS; + } + + if (dynamic_cast<Conversion *>(ptr)) { + return PJ_OBJ_TYPE_CONVERSION; + } + if (dynamic_cast<Transformation *>(ptr)) { + return PJ_OBJ_TYPE_TRANSFORMATION; + } + if (dynamic_cast<ConcatenatedOperation *>(ptr)) { + return PJ_OBJ_TYPE_CONCATENATED_OPERATION; + } + if (dynamic_cast<CoordinateOperation *>(ptr)) { + return PJ_OBJ_TYPE_OTHER_COORDINATE_OPERATION; + } + + return PJ_OBJ_TYPE_UNKNOWN; +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether an object is deprecated. + * + * @param obj Object (must not be NULL) + * @return TRUE if it is deprecated, FALSE otherwise + */ +int proj_obj_is_deprecated(PJ_OBJ *obj) { + assert(obj); + return obj->obj->isDeprecated(); +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether two objects are equivalent. + * + * @param obj Object (must not be NULL) + * @param other Other object (must not be NULL) + * @param criterion Comparison criterion + * @return TRUE if they are equivalent + */ +int proj_obj_is_equivalent_to(PJ_OBJ *obj, PJ_OBJ *other, + PJ_COMPARISON_CRITERION criterion) { + assert(obj); + assert(other); + + // Make sure that the C and C++ enumerations match + static_assert(static_cast<int>(PJ_COMP_STRICT) == + static_cast<int>(IComparable::Criterion::STRICT), + ""); + static_assert(static_cast<int>(PJ_COMP_EQUIVALENT) == + static_cast<int>(IComparable::Criterion::EQUIVALENT), + ""); + static_assert( + static_cast<int>(PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) == + static_cast<int>( + IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS), + ""); + + // Make sure we enumerate all values. If adding a new value, as we + // don't have a default clause, the compiler will warn. + switch (criterion) { + case PJ_COMP_STRICT: + case PJ_COMP_EQUIVALENT: + case PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS: + break; + } + const IComparable::Criterion cppCriterion = + static_cast<IComparable::Criterion>(criterion); + return obj->obj->isEquivalentTo(other->obj.get(), cppCriterion); +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether an object is a CRS + * + * @param obj Object (must not be NULL) + */ +int proj_obj_is_crs(PJ_OBJ *obj) { + assert(obj); + return dynamic_cast<CRS *>(obj->obj.get()) != nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Get the name of an object. + * + * The lifetime of the returned string is the same as the input obj parameter. + * + * @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) { + assert(obj); + const auto &desc = obj->obj->name()->description(); + if (!desc.has_value()) { + return nullptr; + } + // The object will still be alived after the function call. + // cppcheck-suppress stlcstr + return desc->c_str(); +} + +// --------------------------------------------------------------------------- + +/** \brief Get the authority name / codespace of an identifier of an object. + * + * The lifetime of the returned string is the same as the input obj parameter. + * + * @param obj Object (must not be NULL) + * @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) { + assert(obj); + const auto &ids = obj->obj->identifiers(); + if (static_cast<size_t>(index) >= ids.size()) { + return nullptr; + } + const auto &codeSpace = ids[index]->codeSpace(); + if (!codeSpace.has_value()) { + return nullptr; + } + // The object will still be alived after the function call. + // cppcheck-suppress stlcstr + return codeSpace->c_str(); +} + +// --------------------------------------------------------------------------- + +/** \brief Get the code of an identifier of an object. + * + * The lifetime of the returned string is the same as the input obj parameter. + * + * @param obj Object (must not be NULL) + * @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) { + assert(obj); + const auto &ids = obj->obj->identifiers(); + if (static_cast<size_t>(index) >= ids.size()) { + return nullptr; + } + return ids[index]->code().c_str(); +} + +// --------------------------------------------------------------------------- + +//! @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, + * and until a next call to proj_obj_as_wkt() with the same input object. + * + * This function calls osgeo::proj::io::IWKTExportable::exportToWKT(). + * + * This function may return NULL if the object is not compatible with an + * export to the requested type. + * + * @param obj Object (must not be NULL) + * @param type WKT version. + * @param options null-terminated list of options, or NULL. Currently + * supported options are: + * <ul> + * <li>MULTILINE=YES/NO. Defaults to YES, except for WKT1_ESRI</li> + * <li>INDENTATION_WIDTH=number. Defauls to 4 (when multiline output is + * on).</li> + * <li>OUTPUT_AXIS=YES/NO. Defaults to YES, except for WKT1_ESRI.</li> + * </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) { + assert(obj); + + // Make sure that the C and C++ enumerations match + static_assert(static_cast<int>(PJ_WKT2_2015) == + static_cast<int>(WKTFormatter::Convention::WKT2_2015), + ""); + static_assert( + static_cast<int>(PJ_WKT2_2015_SIMPLIFIED) == + static_cast<int>(WKTFormatter::Convention::WKT2_2015_SIMPLIFIED), + ""); + static_assert(static_cast<int>(PJ_WKT2_2018) == + static_cast<int>(WKTFormatter::Convention::WKT2_2018), + ""); + static_assert( + static_cast<int>(PJ_WKT2_2018_SIMPLIFIED) == + static_cast<int>(WKTFormatter::Convention::WKT2_2018_SIMPLIFIED), + ""); + static_assert(static_cast<int>(PJ_WKT1_GDAL) == + static_cast<int>(WKTFormatter::Convention::WKT1_GDAL), + ""); + static_assert(static_cast<int>(PJ_WKT1_ESRI) == + static_cast<int>(WKTFormatter::Convention::WKT1_ESRI), + ""); + // Make sure we enumerate all values. If adding a new value, as we + // don't have a default clause, the compiler will warn. + switch (type) { + case PJ_WKT2_2015: + case PJ_WKT2_2015_SIMPLIFIED: + case PJ_WKT2_2018: + case PJ_WKT2_2018_SIMPLIFIED: + case PJ_WKT1_GDAL: + case PJ_WKT1_ESRI: + break; + } + const WKTFormatter::Convention convention = + static_cast<WKTFormatter::Convention>(type); + try { + auto formatter = WKTFormatter::create(convention); + for (auto iter = options; iter && iter[0]; ++iter) { + const char *value; + if ((value = getOptionValue(*iter, "MULTILINE="))) { + formatter->setMultiLine(ci_equal(value, "YES")); + } else if ((value = getOptionValue(*iter, "INDENTATION_WIDTH="))) { + formatter->setIndentationWidth(std::atoi(value)); + } else if ((value = getOptionValue(*iter, "OUTPUT_AXIS="))) { + formatter->setOutputAxis(ci_equal(value, "YES")); + } else { + std::string msg("Unknown option :"); + msg += *iter; + proj_log_error(obj->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()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Get a PROJ string representation of an object. + * + * The returned string is valid while the input obj parameter is valid, + * and until a next call to proj_obj_as_proj_string() with the same input + * object. + * + * This function calls + * osgeo::proj::io::IPROJStringExportable::exportToPROJString(). + * + * This function may return NULL if the object is not compatible with an + * export to the requested type. + * + * @param obj Object (must not be NULL) + * @param type PROJ String version. + * @param options NULL-terminated list of strings with "KEY=VALUE" format. or + * NULL. + * The currently recognized option is USE_ETMERC=YES to use + * +proj=etmerc instead of +proj=tmerc + * @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 *const *options) { + 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"); + return nullptr; + } + // Make sure that the C and C++ enumeration match + static_assert(static_cast<int>(PJ_PROJ_5) == + static_cast<int>(PROJStringFormatter::Convention::PROJ_5), + ""); + static_assert(static_cast<int>(PJ_PROJ_4) == + static_cast<int>(PROJStringFormatter::Convention::PROJ_4), + ""); + // Make sure we enumerate all values. If adding a new value, as we + // don't have a default clause, the compiler will warn. + switch (type) { + case PJ_PROJ_5: + case PJ_PROJ_4: + break; + } + const PROJStringFormatter::Convention convention = + static_cast<PROJStringFormatter::Convention>(type); + auto dbContext = getDBcontextNoException(obj->ctx, __FUNCTION__); + try { + auto formatter = PROJStringFormatter::create(convention, dbContext); + if (options != nullptr && options[0] != nullptr) { + if (ci_equal(options[0], "USE_ETMERC=YES")) { + formatter->setUseETMercForTMerc(true); + } + } + obj->lastPROJString = exportable->exportToPROJString(formatter.get()); + return obj->lastPROJString.c_str(); + } catch (const std::exception &e) { + proj_log_error(obj->ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return the area of use of an object. + * + * @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 + * 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 + * 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 + * 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 + * unknown. + * @param p_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; + } + auto objectUsage = dynamic_cast<const ObjectUsage *>(obj->obj.get()); + if (!objectUsage) { + return false; + } + const auto &domains = objectUsage->domains(); + if (domains.empty()) { + return false; + } + const auto &extent = domains[0]->domainOfValidity(); + if (!extent) { + return false; + } + const auto &desc = extent->description(); + if (desc.has_value() && p_area_name) { + *p_area_name = desc->c_str(); + } + + const auto &geogElements = extent->geographicElements(); + if (!geogElements.empty()) { + auto bbox = + dynamic_cast<const GeographicBoundingBox *>(geogElements[0].get()); + if (bbox) { + if (p_west_lon) { + *p_west_lon = bbox->westBoundLongitude(); + } + if (p_south_lat) { + *p_south_lat = bbox->southBoundLatitude(); + } + if (p_east_lon) { + *p_east_lon = bbox->eastBoundLongitude(); + } + if (p_north_lat) { + *p_north_lat = bbox->northBoundLatitude(); + } + return true; + } + } + if (p_west_lon) { + *p_west_lon = -1000; + } + if (p_south_lat) { + *p_south_lat = -1000; + } + if (p_east_lon) { + *p_east_lon = -1000; + } + if (p_north_lat) { + *p_north_lat = -1000; + } + return true; +} + +// --------------------------------------------------------------------------- + +static const GeodeticCRS *extractGeodeticCRS(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"); + return nullptr; + } + auto geodCRS = l_crs->extractGeodeticCRSRaw(); + if (!geodCRS) { + proj_log_error(crs->ctx, fname, "CRS has no geodetic CRS"); + } + return geodCRS; +} + +// --------------------------------------------------------------------------- + +/** \brief Get the geodeticCRS / geographicCRS from a CRS + * + * 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 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__); + if (!geodCRS) { + return nullptr; + } + return PJ_OBJ::create(crs->ctx, + NN_NO_CHECK(nn_dynamic_pointer_cast<IdentifiedObject>( + geodCRS->shared_from_this()))); +} + +// --------------------------------------------------------------------------- + +/** \brief Get a CRS component from a CompoundCRS + * + * 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 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) { + 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"); + 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]); +} + +// --------------------------------------------------------------------------- + +/** \brief Returns potentially + * a BoundCRS, with a transformation to EPSG:4326, wrapping this CRS + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * This is the same as method + * osgeo::proj::crs::CRS::createBoundCRSToWGS84IfPossible() + * + * @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) { + 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"); + return nullptr; + } + auto dbContext = getDBcontextNoException(crs->ctx, __FUNCTION__); + return PJ_OBJ::create(crs->ctx, + l_crs->createBoundCRSToWGS84IfPossible(dbContext)); +} + +// --------------------------------------------------------------------------- + +/** \brief Get the ellipsoid from a CRS or a GeodeticReferenceFrame. + * + * 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 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) { + auto ptr = obj->obj.get(); + if (dynamic_cast<const CRS *>(ptr)) { + auto geodCRS = extractGeodeticCRS(obj, __FUNCTION__); + if (geodCRS) { + return PJ_OBJ::create(obj->ctx, geodCRS->ellipsoid()); + } + } else { + auto datum = dynamic_cast<const GeodeticReferenceFrame *>(ptr); + if (datum) { + return PJ_OBJ::create(obj->ctx, datum->ellipsoid()); + } + } + proj_log_error(obj->ctx, __FUNCTION__, + "Object is not a CRS or GeodeticReferenceFrame"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Get the horizontal datum from a CRS + * + * 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 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__); + if (!geodCRS) { + return nullptr; + } + const auto &datum = geodCRS->datum(); + if (datum) { + return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(datum)); + } + + const auto &datumEnsemble = geodCRS->datumEnsemble(); + if (datumEnsemble) { + return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(datumEnsemble)); + } + proj_log_error(crs->ctx, __FUNCTION__, "CRS has no datum"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return ellipsoid parameters. + * + * @param ellipsoid Object of type Ellipsoid (must not be NULL) + * @param pSemiMajorMetre 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 + * metre. or NULL + * @param pIsSemiMinorComputed 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 + * 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) { + 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"); + return FALSE; + } + + if (pSemiMajorMetre) { + *pSemiMajorMetre = l_ellipsoid->semiMajorAxis().getSIValue(); + } + if (pSemiMinorMetre) { + *pSemiMinorMetre = l_ellipsoid->computeSemiMinorAxis().getSIValue(); + } + if (pIsSemiMinorComputed) { + *pIsSemiMinorComputed = !(l_ellipsoid->semiMinorAxis().has_value()); + } + if (pInverseFlattening) { + *pInverseFlattening = l_ellipsoid->computedInverseFlattening(); + } + return TRUE; +} + +// --------------------------------------------------------------------------- + +/** \brief Get the prime meridian of a CRS or a GeodeticReferenceFrame. + * + * 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 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) { + auto ptr = obj->obj.get(); + if (dynamic_cast<CRS *>(ptr)) { + auto geodCRS = extractGeodeticCRS(obj, __FUNCTION__); + if (geodCRS) { + return PJ_OBJ::create(obj->ctx, geodCRS->primeMeridian()); + } + } else { + auto datum = dynamic_cast<const GeodeticReferenceFrame *>(ptr); + if (datum) { + return PJ_OBJ::create(obj->ctx, datum->primeMeridian()); + } + } + proj_log_error(obj->ctx, __FUNCTION__, + "Object is not a CRS or GeodeticReferenceFrame"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return prime meridian parameters. + * + * @param prime_meridian Object of type PrimeMeridian (must not be NULL) + * @param pLongitude 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 + * factor of the prime meridian longitude unit to radian. or NULL + * @param pLongitudeUnitName 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) { + 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"); + return false; + } + const auto &longitude = l_pm->longitude(); + if (pLongitude) { + *pLongitude = longitude.value(); + } + const auto &unit = longitude.unit(); + if (pLongitudeUnitConvFactor) { + *pLongitudeUnitConvFactor = unit.conversionToSI(); + } + if (pLongitudeUnitName) { + *pLongitudeUnitName = unit.name().c_str(); + } + return true; +} + +// --------------------------------------------------------------------------- + +/** \brief Return the base CRS of a BoundCRS 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 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) { + assert(obj); + auto ptr = obj->obj.get(); + auto boundCRS = dynamic_cast<const BoundCRS *>(ptr); + if (boundCRS) { + return PJ_OBJ::create(obj->ctx, boundCRS->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 nullptr; + } + proj_log_error(obj->ctx, __FUNCTION__, + "Object is not a BoundCRS or a CoordinateOperation"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return the hub CRS of a BoundCRS or the target 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 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) { + assert(obj); + auto ptr = obj->obj.get(); + auto boundCRS = dynamic_cast<const BoundCRS *>(ptr); + if (boundCRS) { + return PJ_OBJ::create(obj->ctx, 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 nullptr; + } + proj_log_error(obj->ctx, __FUNCTION__, + "Object is not a BoundCRS or a CoordinateOperation"); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Identify the CRS with reference CRSs. + * + * The candidate CRSs are either hard-coded, or looked in the database when + * authorityFactory is not null. + * + * The method returns a list of matching reference CRS, and the percentage + * (0-100) of confidence in the match. + * 100% means that the name of the reference entry + * perfectly matches the CRS name, and both are equivalent. In which case a + * single result is returned. + * 90% means that CRS are equivalent, but the names are not exactly the same. + * 70% means that CRS are equivalent), but the names do not match at all. + * 25% means that the CRS are not equivalent, but there is some similarity in + * the names. + * Other confidence values may be returned by some specialized implementations. + * + * This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and + * CompoundCRS. + * + * @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 + * (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) { + assert(obj); + (void)options; + if (confidence) { + *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"); + } else { + int *confidenceTemp = nullptr; + try { + auto factory = AuthorityFactory::create(getDBcontext(obj->ctx), + auth_name ? auth_name : ""); + auto res = crs->identify(factory); + std::vector<IdentifiedObjectNNPtr> objects; + confidenceTemp = confidence ? new int[res.size()] : nullptr; + size_t i = 0; + for (const auto &pair : res) { + objects.push_back(pair.first); + if (confidenceTemp) { + confidenceTemp[i] = pair.second; + ++i; + } + } + auto ret = internal::make_unique<PJ_OBJ_LIST>(obj->ctx, + std::move(objects)); + if (confidence) { + *confidence = confidenceTemp; + confidenceTemp = nullptr; + } + return ret.release(); + } catch (const std::exception &e) { + delete[] confidenceTemp; + proj_log_error(obj->ctx, __FUNCTION__, e.what()); + } + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Free an array of integer. */ +void proj_free_int_list(int *list) { delete[] list; } + +// --------------------------------------------------------------------------- + +static PROJ_STRING_LIST set_to_string_list(std::set<std::string> &&set) { + auto ret = new char *[set.size() + 1]; + size_t i = 0; + for (const auto &str : set) { + ret[i] = new char[str.size() + 1]; + std::memcpy(ret[i], str.c_str(), str.size() + 1); + i++; + } + ret[i] = nullptr; + return ret; +} + +// --------------------------------------------------------------------------- + +/** \brief Return the list of authorities used in the database. + * + * The returned list is NULL terminated and must be freed with + * proj_free_string_list(). + * + * @param ctx PROJ context, or NULL for default context + * + * @return a NULL terminated list of NUL-terminated strings that must be + * freed with proj_free_string_list(), or NULL in case of error. + */ +PROJ_STRING_LIST proj_get_authorities_from_database(PJ_CONTEXT *ctx) { + SANITIZE_CTX(ctx); + try { + return set_to_string_list(getDBcontext(ctx)->getAuthorities()); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Returns the set of authority codes of the given object type. + * + * The returned list is NULL terminated and must be freed with + * proj_free_string_list(). + * + * @param ctx PROJ context, or NULL for default context. + * @param auth_name Authority name (must not be NULL) + * @param type Object type. + * @param allow_deprecated whether we should return deprecated objects as well. + * + * @return a NULL terminated list of NUL-terminated strings that must be + * freed with proj_free_string_list(), or NULL in case of error. + */ +PROJ_STRING_LIST proj_get_codes_from_database(PJ_CONTEXT *ctx, + const char *auth_name, + PJ_OBJ_TYPE type, + int allow_deprecated) { + assert(auth_name); + SANITIZE_CTX(ctx); + try { + auto factory = AuthorityFactory::create(getDBcontext(ctx), auth_name); + bool valid = false; + auto typeInternal = convertPJObjectTypeToObjectType(type, valid); + if (!valid) { + return nullptr; + } + return set_to_string_list( + factory->getAuthorityCodes(typeInternal, allow_deprecated != 0)); + + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** Free a list of NULL terminated strings. */ +void proj_free_string_list(PROJ_STRING_LIST list) { + if (list) { + for (size_t i = 0; list[i] != nullptr; i++) { + delete[] list[i]; + } + delete[] list; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return the Conversion of a DerivedCRS (such as a ProjectedCRS), + * or the Transformation from the baseCRS to the hubCRS of 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 crs Objet of type DerivedCRS or BoundCRSs (must not be NULL) + * @param pMethodName Pointer to a string value to store the method + * (projection) name. or NULL + * @param pMethodAuthorityName Pointer to a string value to store the method + * authority name. or NULL + * @param pMethodCode 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) { + assert(crs); + SingleOperationPtr co; + + auto derivedCRS = dynamic_cast<const DerivedCRS *>(crs->obj.get()); + if (derivedCRS) { + co = derivedCRS->derivingConversion().as_nullable(); + } else { + auto boundCRS = dynamic_cast<const BoundCRS *>(crs->obj.get()); + if (boundCRS) { + co = boundCRS->transformation().as_nullable(); + } else { + proj_log_error(crs->ctx, __FUNCTION__, + "Object is not a DerivedCRS or BoundCRS"); + return nullptr; + } + } + + const auto &method = co->method(); + const auto &method_ids = method->identifiers(); + if (pMethodName) { + *pMethodName = method->name()->description()->c_str(); + } + if (pMethodAuthorityName) { + if (!method_ids.empty()) { + *pMethodAuthorityName = method_ids[0]->codeSpace()->c_str(); + } else { + *pMethodAuthorityName = nullptr; + } + } + if (pMethodCode) { + if (!method_ids.empty()) { + *pMethodCode = method_ids[0]->code().c_str(); + } else { + *pMethodCode = nullptr; + } + } + return PJ_OBJ::create(crs->ctx, NN_NO_CHECK(co)); +} + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +static PropertyMap createPropertyMapName(const char *name) { + return PropertyMap().set(common::IdentifiedObject::NAME_KEY, + name ? name : "unnamed"); +} + +// --------------------------------------------------------------------------- + +static UnitOfMeasure createLinearUnit(const char *name, double convFactor) { + return name == nullptr ? UnitOfMeasure::METRE + : UnitOfMeasure(name, convFactor); +} + +// --------------------------------------------------------------------------- + +static UnitOfMeasure createAngularUnit(const char *name, double convFactor) { + return name ? (ci_equal(name, "degree") + ? UnitOfMeasure::DEGREE + : ci_equal(name, "grad") + ? UnitOfMeasure::GRAD + : UnitOfMeasure(name, convFactor)) + : UnitOfMeasure::DEGREE; +} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Create a GeographicCRS 2D from its definition. + * + * 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 + * 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. + * + * @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) { + + SANITIZE_CTX(ctx); + 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); + } 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 = + util::nn_dynamic_pointer_cast<GeodeticCRS>(geodetic_crs->obj); + if (!geogCRS) { + 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); +} + +//! @endcond + +/* BEGIN: Generated by scripts/create_c_api_projections.py*/ + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a Universal Transverse Mercator + * conversion. + * + * See osgeo::proj::operation::Conversion::createUTM(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Transverse + * Mercator projection method. + * + * See osgeo::proj::operation::Conversion::createTransverseMercator(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Gauss + * Schreiber Transverse Mercator projection method. + * + * See + * osgeo::proj::operation::Conversion::createGaussSchreiberTransverseMercator(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Transverse + * Mercator South Orientated projection method. + * + * See + * osgeo::proj::operation::Conversion::createTransverseMercatorSouthOriented(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Two Point + * Equidistant projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Tunisia + * Mapping Grid projection method. + * + * See osgeo::proj::operation::Conversion::createTunisiaMappingGrid(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Albers + * Conic Equal Area projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Conic Conformal 1SP projection method. + * + * See osgeo::proj::operation::Conversion::createLambertConicConformal_1SP(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Conic Conformal (2SP) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Conic Conformal (2SP Michigan) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Conic Conformal (2SP Belgium) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Modified + * Azimuthal Equidistant projection method. + * + * See osgeo::proj::operation::Conversion::createAzimuthalEquidistant(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Guam + * Projection projection method. + * + * See osgeo::proj::operation::Conversion::createGuamProjection(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Bonne + * projection method. + * + * See osgeo::proj::operation::Conversion::createBonne(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Cylindrical Equal Area (Spherical) projection method. + * + * See + * osgeo::proj::operation::Conversion::createLambertCylindricalEqualAreaSpherical(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Cylindrical Equal Area (ellipsoidal form) projection method. + * + * See osgeo::proj::operation::Conversion::createLambertCylindricalEqualArea(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Cassini-Soldner projection method. + * + * See osgeo::proj::operation::Conversion::createCassiniSoldner(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Equidistant + * Conic projection method. + * + * See osgeo::proj::operation::Conversion::createEquidistantConic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert I + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertI(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert II + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertII(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert III + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertIII(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert IV + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertIV(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert V + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertV(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Eckert VI + * projection method. + * + * See osgeo::proj::operation::Conversion::createEckertVI(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Equidistant + * Cylindrical projection method. + * + * See osgeo::proj::operation::Conversion::createEquidistantCylindrical(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Equidistant + * Cylindrical (Spherical) projection method. + * + * See + * osgeo::proj::operation::Conversion::createEquidistantCylindricalSpherical(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Gall + * (Stereographic) projection method. + * + * See osgeo::proj::operation::Conversion::createGall(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Goode + * Homolosine projection method. + * + * See osgeo::proj::operation::Conversion::createGoodeHomolosine(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Interrupted + * Goode Homolosine projection method. + * + * See osgeo::proj::operation::Conversion::createInterruptedGoodeHomolosine(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Geostationary Satellite View projection method, with the sweep angle axis of + * the viewing instrument being x. + * + * See osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepX(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Geostationary Satellite View projection method, with the sweep angle axis of + * the viewing instrument being y. + * + * See osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepY(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Gnomonic + * projection method. + * + * See osgeo::proj::operation::Conversion::createGnomonic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Hotine + * Oblique Mercator (Variant A) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Hotine + * Oblique Mercator (Variant B) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Hotine + * Oblique Mercator Two Point Natural Origin projection method. + * + * See + * osgeo::proj::operation::Conversion::createHotineObliqueMercatorTwoPointNaturalOrigin(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * International Map of the World Polyconic projection method. + * + * See + * osgeo::proj::operation::Conversion::createInternationalMapWorldPolyconic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Krovak + * (north oriented) projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Krovak + * projection method. + * + * 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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Lambert + * Azimuthal Equal Area projection method. + * + * See osgeo::proj::operation::Conversion::createLambertAzimuthalEqualArea(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Miller + * Cylindrical projection method. + * + * See osgeo::proj::operation::Conversion::createMillerCylindrical(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Mercator + * projection method. + * + * See osgeo::proj::operation::Conversion::createMercatorVariantA(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Mercator + * projection method. + * + * See osgeo::proj::operation::Conversion::createMercatorVariantB(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Popular + * Visualisation Pseudo Mercator projection method. + * + * See + * osgeo::proj::operation::Conversion::createPopularVisualisationPseudoMercator(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Mollweide + * projection method. + * + * See osgeo::proj::operation::Conversion::createMollweide(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the New Zealand + * Map Grid projection method. + * + * See osgeo::proj::operation::Conversion::createNewZealandMappingGrid(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Oblique + * Stereographic (Alternative) projection method. + * + * See osgeo::proj::operation::Conversion::createObliqueStereographic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Orthographic projection method. + * + * See osgeo::proj::operation::Conversion::createOrthographic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the American + * Polyconic projection method. + * + * See osgeo::proj::operation::Conversion::createAmericanPolyconic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Polar + * Stereographic (Variant A) projection method. + * + * See osgeo::proj::operation::Conversion::createPolarStereographicVariantA(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Polar + * Stereographic (Variant B) projection method. + * + * See osgeo::proj::operation::Conversion::createPolarStereographicVariantB(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Robinson + * projection method. + * + * See osgeo::proj::operation::Conversion::createRobinson(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Sinusoidal + * projection method. + * + * See osgeo::proj::operation::Conversion::createSinusoidal(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Stereographic projection method. + * + * See osgeo::proj::operation::Conversion::createStereographic(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Van der + * Grinten projection method. + * + * See osgeo::proj::operation::Conversion::createVanDerGrinten(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner I + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerI(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner II + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerII(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner III + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerIII(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner IV + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerIV(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner V + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerV(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner VI + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerVI(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Wagner VII + * projection method. + * + * See osgeo::proj::operation::Conversion::createWagnerVII(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the + * Quadrilateralized Spherical Cube projection method. + * + * See + * osgeo::proj::operation::Conversion::createQuadrilateralizedSphericalCube(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Spherical + * Cross-Track Height projection method. + * + * See osgeo::proj::operation::Conversion::createSphericalCrossTrackHeight(). + * + * Linear parameters are expressed in (linearUnitName, linearUnitConvFactor). + * Angular parameters are expressed in (angUnitName, angUnitConvFactor). + */ +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); +} +// --------------------------------------------------------------------------- + +/** \brief Instanciate a ProjectedCRS with a conversion based on the Equal Earth + * projection method. + * + * 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); +} +/* END: Generated by scripts/create_c_api_projections.py*/ + +// --------------------------------------------------------------------------- + +/** \brief Return whether a coordinate operation can be instanciated as + * a PROJ pipeline, checking in particular that referenced grids are + * available. + * + * @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) { + assert(coordoperation); + auto op = + dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); + if (!op) { + proj_log_error(coordoperation->ctx, __FUNCTION__, + "Object is not a CoordinateOperation"); + return 0; + } + auto dbContext = getDBcontextNoException(coordoperation->ctx, __FUNCTION__); + try { + return op->isPROJInstanciable(dbContext) ? 1 : 0; + } catch (const std::exception &) { + return 0; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return the number of parameters of a SingleOperation + * + * @param coordoperation Objet of type SingleOperation or derived classes + * (must not be NULL) + */ + +int proj_coordoperation_get_param_count(PJ_OBJ *coordoperation) { + assert(coordoperation); + auto op = dynamic_cast<const SingleOperation *>(coordoperation->obj.get()); + if (!op) { + proj_log_error(coordoperation->ctx, __FUNCTION__, + "Object is not a SingleOperation"); + return 0; + } + return static_cast<int>(op->parameterValues().size()); +} + +// --------------------------------------------------------------------------- + +/** \brief Return the index of a parameter of a SingleOperation + * + * @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, + const char *name) { + 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"); + return -1; + } + int index = 0; + for (const auto &genParam : op->method()->parameters()) { + if (Identifier::isEquivalentName(genParam->nameStr().c_str(), name)) { + return index; + } + index++; + } + return -1; +} + +// --------------------------------------------------------------------------- + +/** \brief Return a parameter of a SingleOperation + * + * @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 + * authority name. or NULL + * @param pNameCode Pointer to a string value to store the parameter + * code. or NULL + * @param pValue 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 + * value (if of type string). or NULL + * @param pValueUnitConvFactor 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 + * 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) { + assert(coordoperation); + auto op = dynamic_cast<const SingleOperation *>(coordoperation->obj.get()); + if (!op) { + proj_log_error(coordoperation->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"); + return false; + } + + const auto ¶m = parameters[index]; + const auto ¶m_ids = param->identifiers(); + if (pName) { + *pName = param->name()->description()->c_str(); + } + if (pNameAuthorityName) { + if (!param_ids.empty()) { + *pNameAuthorityName = param_ids[0]->codeSpace()->c_str(); + } else { + *pNameAuthorityName = nullptr; + } + } + if (pNameCode) { + if (!param_ids.empty()) { + *pNameCode = param_ids[0]->code().c_str(); + } else { + *pNameCode = nullptr; + } + } + + const auto &value = values[index]; + ParameterValuePtr paramValue = nullptr; + auto opParamValue = + dynamic_cast<const OperationParameterValue *>(value.get()); + if (opParamValue) { + paramValue = opParamValue->parameterValue().as_nullable(); + } + if (pValue) { + *pValue = 0; + if (paramValue) { + if (paramValue->type() == ParameterValue::Type::MEASURE) { + *pValue = paramValue->value().value(); + } + } + } + if (pValueString) { + *pValueString = nullptr; + if (paramValue) { + if (paramValue->type() == ParameterValue::Type::FILENAME) { + *pValueString = paramValue->valueFile().c_str(); + } else if (paramValue->type() == ParameterValue::Type::STRING) { + *pValueString = paramValue->stringValue().c_str(); + } + } + } + if (pValueUnitConvFactor) { + *pValueUnitConvFactor = 0; + if (paramValue) { + if (paramValue->type() == ParameterValue::Type::MEASURE) { + *pValueUnitConvFactor = + paramValue->value().unit().conversionToSI(); + } + } + } + if (pValueUnitName) { + *pValueUnitName = nullptr; + if (paramValue) { + if (paramValue->type() == ParameterValue::Type::MEASURE) { + *pValueUnitName = paramValue->value().unit().name().c_str(); + } + } + } + + return true; +} + +// --------------------------------------------------------------------------- + +/** \brief Return the number of grids used by a CoordinateOperation + * + * @param coordoperation Objet of type CoordinateOperation or derived classes + * (must not be NULL) + */ + +int proj_coordoperation_get_grid_used_count(PJ_OBJ *coordoperation) { + assert(coordoperation); + auto co = + dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); + if (!co) { + proj_log_error(coordoperation->ctx, __FUNCTION__, + "Object is not a CoordinateOperation"); + return 0; + } + auto dbContext = getDBcontextNoException(coordoperation->ctx, __FUNCTION__); + try { + if (!coordoperation->gridsNeededAsked) { + coordoperation->gridsNeededAsked = true; + const auto gridsNeeded = co->gridsNeeded(dbContext); + for (const auto &gridDesc : gridsNeeded) { + coordoperation->gridsNeeded.emplace_back(gridDesc); + } + } + return static_cast<int>(coordoperation->gridsNeeded.size()); + } catch (const std::exception &e) { + proj_log_error(coordoperation->ctx, __FUNCTION__, e.what()); + return 0; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return a parameter of a SingleOperation + * + * @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. + * or NULL + * @param pPackageName 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 + * 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 + * 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 + * @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); + if (index < 0 || index >= count) { + proj_log_error(coordoperation->ctx, __FUNCTION__, "Invalid index"); + return false; + } + + const auto &gridDesc = coordoperation->gridsNeeded[index]; + if (pShortName) { + *pShortName = gridDesc.shortName.c_str(); + } + + if (pFullName) { + *pFullName = gridDesc.fullName.c_str(); + } + + if (pPackageName) { + *pPackageName = gridDesc.packageName.c_str(); + } + + if (pURL) { + *pURL = gridDesc.url.c_str(); + } + + if (pDirectDownload) { + *pDirectDownload = gridDesc.directDownload; + } + + if (pOpenLicense) { + *pOpenLicense = gridDesc.openLicense; + } + + if (pAvailable) { + *pAvailable = gridDesc.available; + } + + return true; +} + +// --------------------------------------------------------------------------- + +/** \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)) {} + + PJ_OPERATION_FACTORY_CONTEXT(const PJ_OPERATION_FACTORY_CONTEXT &) = delete; + PJ_OPERATION_FACTORY_CONTEXT & + operator=(const PJ_OPERATION_FACTORY_CONTEXT &) = delete; + //! @endcond +}; + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a context for building coordinate operations between + * two CRS. + * + * The returned object must be unreferenced with + * proj_operation_factory_context_unref() after use. + * + * @param ctx Context, or NULL for default context. + * @param authority Name of authority to which to restrict the search of + * canidate operations. Or NULL to allow any authority. + * @return Object that must be unreferenced with + * proj_operation_factory_context_unref(), or NULL in + * case of error. + */ +PJ_OPERATION_FACTORY_CONTEXT * +proj_create_operation_factory_context(PJ_CONTEXT *ctx, const char *authority) { + SANITIZE_CTX(ctx); + auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); + try { + if (dbContext) { + auto factory = CoordinateOperationFactory::create(); + auto authFactory = AuthorityFactory::create( + NN_NO_CHECK(dbContext), + std::string(authority ? authority : "")); + auto operationContext = + CoordinateOperationContext::create(authFactory, nullptr, 0.0); + return new PJ_OPERATION_FACTORY_CONTEXT( + ctx, std::move(operationContext)); + } else { + auto operationContext = + CoordinateOperationContext::create(nullptr, nullptr, 0.0); + return new PJ_OPERATION_FACTORY_CONTEXT( + ctx, std::move(operationContext)); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Drops a reference on an object. + * + * This method should be called one and exactly one for each function + * returning a PJ_OPERATION_FACTORY_CONTEXT* + * + * @param ctxt Object, or NULL. + */ +void proj_operation_factory_context_unref(PJ_OPERATION_FACTORY_CONTEXT *ctxt) { + delete ctxt; +} + +// --------------------------------------------------------------------------- + +/** \brief Set the desired accuracy of the resulting coordinate transformations. + * @param ctxt 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); +} + +// --------------------------------------------------------------------------- + +/** \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. + * + * @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). + */ +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)); +} + +// --------------------------------------------------------------------------- + +/** \brief Set how source and target CRS extent should be used + * when considering if a transformation can be used (only takes effect if + * no area of interest is explicitly defined). + * + * The default is PJ_CRS_EXTENT_SMALLEST. + * + * @param ctxt 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; + + case PJ_CRS_EXTENT_BOTH: + ctxt->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::BOTH); + break; + + case PJ_CRS_EXTENT_INTERSECTION: + ctxt->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION); + break; + + case PJ_CRS_EXTENT_SMALLEST: + ctxt->operationContext->setSourceAndTargetCRSExtentUse( + CoordinateOperationContext::SourceTargetCRSExtentUse::SMALLEST); + break; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Set the spatial criterion to use when comparing the area of + * validity of coordinate operations with the area of interest / area of + * validity of + * source and target CRS. + * + * The default is PROJ_SPATIAL_CRITERION_STRICT_CONTAINMENT. + * + * @param ctxt 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; + + case PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION: + ctxt->operationContext->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + break; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Set how grid availability is used. + * + * The default is USE_FOR_SORTING. + * + * @param ctxt 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; + + case PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID: + ctxt->operationContext->setGridAvailabilityUse( + CoordinateOperationContext::GridAvailabilityUse:: + DISCARD_OPERATION_IF_MISSING_GRID); + break; + + case PROJ_GRID_AVAILABILITY_IGNORED: + ctxt->operationContext->setGridAvailabilityUse( + CoordinateOperationContext::GridAvailabilityUse:: + IGNORE_GRID_AVAILABILITY); + break; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Set whether PROJ alternative grid names should be substituted to + * the official authority names. + * + * The default is true. + * + * @param ctxt 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); +} + +// --------------------------------------------------------------------------- + +/** \brief Set whether an intermediate pivot CRS can be used for researching + * coordinate operations between a source and target CRS. + * + * Concretely if in the database there is an operation from A to C + * (or C to A), and another one from C to B (or B to C), but no direct + * operation between A and B, setting this parameter to true, allow + * chaining both operations. + * + * The current implementation is limited to researching one intermediate + * step. + * + * By default, all potential C candidates will be used. + * proj_operation_factory_context_set_allowed_intermediate_crs() + * can be used to restrict them. + * + * The default is true. + * + * @param ctxt 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); +} + +// --------------------------------------------------------------------------- + +/** \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 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, + 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]))); + } + ctxt->operationContext->setIntermediateCRS(pivots); +} + +// --------------------------------------------------------------------------- + +/** \brief Find a list of CoordinateOperation from source_crs to target_crs. + * + * The operations are sorted with the most relevant ones first: by + * descending + * area (intersection of the transformation area with the area of interest, + * or intersection of the transformation with the area of use of the CRS), + * and + * by increasing accuracy. Operations with unknown accuracy are sorted last, + * whatever their area. + * + * @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) { + 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"); + 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"); + return nullptr; + } + + try { + auto factory = CoordinateOperationFactory::create(); + std::vector<IdentifiedObjectNNPtr> objects; + auto ops = factory->createOperations( + NN_NO_CHECK(sourceCRS), NN_NO_CHECK(targetCRS), + operationContext->operationContext); + for (const auto &op : ops) { + objects.emplace_back(op); + } + return new PJ_OBJ_LIST(operationContext->ctx, std::move(objects)); + } catch (const std::exception &e) { + proj_log_error(operationContext->ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Return the number of objects in the result set + * + * @param result Objet of type PJ_OBJ_LIST (must not be NULL) + */ +int proj_obj_list_get_count(PJ_OBJ_LIST *result) { + assert(result); + return static_cast<int>(result->objects.size()); +} + +// --------------------------------------------------------------------------- + +/** \brief Return an object from the result set + * + * 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 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) { + assert(result); + if (index < 0 || index >= proj_obj_list_get_count(result)) { + proj_log_error(result->ctx, __FUNCTION__, "Invalid index"); + return nullptr; + } + return PJ_OBJ::create(result->ctx, result->objects[index]); +} + +// --------------------------------------------------------------------------- + +/** \brief Drops a reference on the result set. + * + * This method should be called one and exactly one for each function + * returning a PJ_OBJ_LIST* + * + * @param result Object, or NULL. + */ +void proj_obj_list_unref(PJ_OBJ_LIST *result) { delete result; } + +// --------------------------------------------------------------------------- + +/** \brief Return the accuracy (in metre) of a coordinate operation. + * + * @return the accuracy, or a negative value if unknown or in case of error. + */ +double proj_coordoperation_get_accuracy(PJ_OBJ *coordoperation) { + assert(coordoperation); + auto co = + dynamic_cast<const CoordinateOperation *>(coordoperation->obj.get()); + if (!co) { + proj_log_error(coordoperation->ctx, __FUNCTION__, + "Object is not a CoordinateOperation"); + return -1; + } + const auto &accuracies = co->coordinateOperationAccuracies(); + if (accuracies.empty()) { + return -1; + } + try { + return c_locale_stod(accuracies[0]->value()); + } catch (const std::exception &) { + } + return -1; +} |
