diff options
| -rw-r--r-- | cmake/ProjUtilities.cmake | 3 | ||||
| -rw-r--r-- | docs/source/development/bindings.rst | 6 | ||||
| -rw-r--r-- | include/proj/coordinatesystem.hpp | 8 | ||||
| -rw-r--r-- | scripts/reference_exported_symbols.txt | 2 | ||||
| -rw-r--r-- | src/4D_api.cpp | 4 | ||||
| -rw-r--r-- | src/bin_proj.cmake | 2 | ||||
| -rw-r--r-- | src/iso19111/c_api.cpp | 54 | ||||
| -rw-r--r-- | src/iso19111/coordinatesystem.cpp | 22 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 72 | ||||
| -rw-r--r-- | src/lib_proj.cmake | 1 | ||||
| -rw-r--r-- | src/proj.h | 4 | ||||
| -rw-r--r-- | src/proj_experimental.h | 16 | ||||
| -rw-r--r-- | src/proj_internal.h | 2 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 155 |
14 files changed, 320 insertions, 31 deletions
diff --git a/cmake/ProjUtilities.cmake b/cmake/ProjUtilities.cmake index 1a2b6052..d63cedac 100644 --- a/cmake/ProjUtilities.cmake +++ b/cmake/ProjUtilities.cmake @@ -89,7 +89,8 @@ endfunction() # # Generates output name for given target depending on platform and version. -# For instance, on Windows, libraries get ABI version suffix proj_X_Y.{dll|lib}. +# For instance, on Windows, dynamic link libraries get ABI version suffix +# proj_X_Y.dll. # function(proj_target_output_name TARGET_NAME OUTPUT_NAME) diff --git a/docs/source/development/bindings.rst b/docs/source/development/bindings.rst index 27d3fddc..c339bfdc 100644 --- a/docs/source/development/bindings.rst +++ b/docs/source/development/bindings.rst @@ -18,6 +18,12 @@ Ruby `proj4rb <https://github.com/cfis/proj4rb>`_: Bindings for PROJ in ruby +Rust +======= + +`proj <https://github.com/georust/proj>`_: +Rust bindings for the latest stable version of PROJ + TCL ======== `proj4tcl <http://wiki.tcl.tk/41270>`_: diff --git a/include/proj/coordinatesystem.hpp b/include/proj/coordinatesystem.hpp index 573f18e2..20c3383c 100644 --- a/include/proj/coordinatesystem.hpp +++ b/include/proj/coordinatesystem.hpp @@ -352,19 +352,27 @@ class PROJ_GCC_DLL EllipsoidalCS final : public CoordinateSystem { create(const util::PropertyMap &properties, const CoordinateSystemAxisNNPtr &axis1, const CoordinateSystemAxisNNPtr &axis2); + PROJ_DLL static EllipsoidalCSNNPtr create(const util::PropertyMap &properties, const CoordinateSystemAxisNNPtr &axis1, const CoordinateSystemAxisNNPtr &axis2, const CoordinateSystemAxisNNPtr &axis3); + PROJ_DLL static EllipsoidalCSNNPtr createLatitudeLongitude(const common::UnitOfMeasure &unit); + PROJ_DLL static EllipsoidalCSNNPtr createLatitudeLongitudeEllipsoidalHeight( const common::UnitOfMeasure &angularUnit, const common::UnitOfMeasure &linearUnit); + PROJ_DLL static EllipsoidalCSNNPtr createLongitudeLatitude(const common::UnitOfMeasure &unit); + PROJ_DLL static EllipsoidalCSNNPtr createLongitudeLatitudeEllipsoidalHeight( + const common::UnitOfMeasure &angularUnit, + const common::UnitOfMeasure &linearUnit); + //! @cond Doxygen_Suppress /** \brief Typical axis order. */ diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index 71de2d0e..c6937d18 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -202,6 +202,7 @@ osgeo::proj::cs::DateTimeTemporalCS::create(osgeo::proj::util::PropertyMap const osgeo::proj::cs::DateTimeTemporalCS::~DateTimeTemporalCS() osgeo::proj::cs::EllipsoidalCS::createLatitudeLongitudeEllipsoidalHeight(osgeo::proj::common::UnitOfMeasure const&, osgeo::proj::common::UnitOfMeasure const&) osgeo::proj::cs::EllipsoidalCS::createLatitudeLongitude(osgeo::proj::common::UnitOfMeasure const&) +osgeo::proj::cs::EllipsoidalCS::createLongitudeLatitudeEllipsoidalHeight(osgeo::proj::common::UnitOfMeasure const&, osgeo::proj::common::UnitOfMeasure const&) osgeo::proj::cs::EllipsoidalCS::createLongitudeLatitude(osgeo::proj::common::UnitOfMeasure const&) osgeo::proj::cs::EllipsoidalCS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&) osgeo::proj::cs::EllipsoidalCS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&) @@ -878,6 +879,7 @@ proj_create_crs_to_crs proj_create_crs_to_crs_from_pj proj_create_cs proj_create_ellipsoidal_2D_cs +proj_create_ellipsoidal_3D_cs proj_create_engineering_crs proj_create_from_database proj_create_from_name diff --git a/src/4D_api.cpp b/src/4D_api.cpp index 3a9582e6..ffef8d81 100644 --- a/src/4D_api.cpp +++ b/src/4D_api.cpp @@ -946,7 +946,7 @@ static PJ* add_coord_op_to_list(PJ* op, } /*****************************************************************************/ -static PJ* create_operation_to_base_geog_crs(PJ_CONTEXT* ctx, PJ* crs) { +static PJ* create_operation_to_base_geog_crs(PJ_CONTEXT* ctx, const PJ* crs) { /*****************************************************************************/ // Create a geographic 2D long-lat degrees CRS that is related to the // CRS @@ -1052,7 +1052,7 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char } /*****************************************************************************/ -PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, PJ *source_crs, PJ *target_crs, PJ_AREA *area, const char* const *) { +PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, const PJ *target_crs, PJ_AREA *area, const char* const *) { /****************************************************************************** Create a transformation pipeline between two known coordinate reference systems. diff --git a/src/bin_proj.cmake b/src/bin_proj.cmake index ce282fc6..3826ac8d 100644 --- a/src/bin_proj.cmake +++ b/src/bin_proj.cmake @@ -9,7 +9,7 @@ source_group("Source Files\\Bin" FILES ${PROJ_SRC}) add_executable(binproj ${PROJ_SRC}) set_target_properties(binproj PROPERTIES - OUTPUT_NAME proj) + RUNTIME_OUTPUT_NAME proj) target_link_libraries(binproj ${PROJ_LIBRARIES}) target_compile_options(binproj PRIVATE ${PROJ_CXX_WARN_FLAGS}) diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 53cfa31e..45eb16d1 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -3763,6 +3763,58 @@ PJ *proj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx, // --------------------------------------------------------------------------- +/** \brief Instantiate a Ellipsoidal 3D + * + * The returned object must be unreferenced with proj_destroy() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param type Coordinate system type. + * @param horizontal_angular_unit_name Horizontal angular unit name. + * @param horizontal_angular_unit_conv_factor Horizontal angular unit conversion + * factor to SI. + * @param vertical_linear_unit_name Vertical linear unit name. + * @param vertical_linear_unit_conv_factor Vertical linear unit conversion + * factor to SI. + * + * @return Object that must be unreferenced with + * proj_destroy(), or NULL in case of error. + * @since 7.0 + */ + +PJ *proj_create_ellipsoidal_3D_cs(PJ_CONTEXT *ctx, + PJ_ELLIPSOIDAL_CS_3D_TYPE type, + const char *horizontal_angular_unit_name, + double horizontal_angular_unit_conv_factor, + const char *vertical_linear_unit_name, + double vertical_linear_unit_conv_factor) { + try { + switch (type) { + case PJ_ELLPS3D_LONGITUDE_LATITUDE_HEIGHT: + return pj_obj_create( + ctx, EllipsoidalCS::createLongitudeLatitudeEllipsoidalHeight( + createAngularUnit(horizontal_angular_unit_name, + horizontal_angular_unit_conv_factor), + createLinearUnit(vertical_linear_unit_name, + vertical_linear_unit_conv_factor))); + + case PJ_ELLPS3D_LATITUDE_LONGITUDE_HEIGHT: + return pj_obj_create( + ctx, EllipsoidalCS::createLatitudeLongitudeEllipsoidalHeight( + createAngularUnit(horizontal_angular_unit_name, + horizontal_angular_unit_conv_factor), + createLinearUnit(vertical_linear_unit_name, + vertical_linear_unit_conv_factor))); + } + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + /** \brief Instantiate a ProjectedCRS * * The returned object must be unreferenced with proj_destroy() after @@ -6039,6 +6091,7 @@ PJ *proj_create_conversion_equal_earth(PJ_CONTEXT *ctx, double center_long, int proj_coordoperation_is_instantiable(PJ_CONTEXT *ctx, const PJ *coordoperation) { + SANITIZE_CTX(ctx); assert(coordoperation); auto op = dynamic_cast<const CoordinateOperation *>( coordoperation->iso_obj.get()); @@ -6081,6 +6134,7 @@ int proj_coordoperation_is_instantiable(PJ_CONTEXT *ctx, int proj_coordoperation_has_ballpark_transformation(PJ_CONTEXT *ctx, const PJ *coordoperation) { + SANITIZE_CTX(ctx); assert(coordoperation); auto op = dynamic_cast<const CoordinateOperation *>( coordoperation->iso_obj.get()); diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp index c58fcaaa..6769b486 100644 --- a/src/iso19111/coordinatesystem.cpp +++ b/src/iso19111/coordinatesystem.cpp @@ -789,6 +789,28 @@ EllipsoidalCS::createLongitudeLatitude(const common::UnitOfMeasure &unit) { // --------------------------------------------------------------------------- +/** \brief Instantiate a EllipsoidalCS with a Longitude (first), Latitude + * (second) axis and ellipsoidal height (third) axis. + * + * @param angularUnit Angular unit of the latitude and longitude axes. + * @param linearUnit Linear unit of the ellipsoidal height axis. + * @return a new EllipsoidalCS. + * @since 7.0 + */ +EllipsoidalCSNNPtr EllipsoidalCS::createLongitudeLatitudeEllipsoidalHeight( + const common::UnitOfMeasure &angularUnit, + const common::UnitOfMeasure &linearUnit) { + return EllipsoidalCS::create( + util::PropertyMap(), CoordinateSystemAxis::createLONG_EAST(angularUnit), + CoordinateSystemAxis::createLAT_NORTH(angularUnit), + CoordinateSystemAxis::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, + AxisName::Ellipsoidal_height), + AxisAbbreviation::h, AxisDirection::UP, linearUnit)); +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress /** \brief Return the axis order in an enumerated way. */ EllipsoidalCS::AxisOrder EllipsoidalCS::axisOrder() const { diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 097bc5b8..a86982d4 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -8638,6 +8638,21 @@ static const metadata::ExtentPtr &getExtent(const crs::CRS *crs) { //! @endcond +namespace { +struct PJContextHolder { + PJ_CONTEXT *ctx_; + bool bFree_; + + PJContextHolder(PJ_CONTEXT *ctx, bool bFree) : ctx_(ctx), bFree_(bFree) {} + ~PJContextHolder() { + if (bFree_) + proj_context_destroy(ctx_); + } + PJContextHolder(const PJContextHolder &) = delete; + PJContextHolder &operator=(const PJContextHolder &) = delete; +}; +} // namespace + // --------------------------------------------------------------------------- /** \brief Instantiate a sub-class of BaseObject from a PROJ string. @@ -8652,8 +8667,10 @@ PROJStringParser::createFromPROJString(const std::string &projString) { // In some abnormal situations involving init=epsg:XXXX syntax, we could // have infinite loop - if (d->ctx_ && d->ctx_->curStringInCreateFromPROJString == projString) { - throw ParsingException("invalid PROJ string"); + if (d->ctx_ && + d->ctx_->projStringParserCreateFromPROJStringRecursionCounter == 2) { + throw ParsingException( + "Infinite recursion in PROJStringParser::createFromPROJString()"); } d->steps_.clear(); @@ -8701,27 +8718,38 @@ PROJStringParser::createFromPROJString(const std::string &projString) { const std::string &stepName = d->steps_[0].name; if (ci_starts_with(stepName, "epsg:") || ci_starts_with(stepName, "IGNF:")) { + + /* We create a new context so as to avoid messing up with the */ + /* errorno of the main context, when trying to find the likely */ + /* missing epsg file */ + auto ctx = proj_context_create(); + if (!ctx) { + throw ParsingException("out of memory"); + } + PJContextHolder contextHolder(ctx, true); + if (d->ctx_) { + ctx->set_search_paths(d->ctx_->search_paths); + ctx->file_finder = d->ctx_->file_finder; + ctx->file_finder_legacy = d->ctx_->file_finder_legacy; + ctx->file_finder_user_data = d->ctx_->file_finder_user_data; + } + bool usePROJ4InitRules = d->usePROJ4InitRules_; if (!usePROJ4InitRules) { - PJ_CONTEXT *ctx = proj_context_create(); - if (ctx) { - usePROJ4InitRules = proj_context_get_use_proj4_init_rules( - ctx, FALSE) == TRUE; - proj_context_destroy(ctx); - } + usePROJ4InitRules = + proj_context_get_use_proj4_init_rules(ctx, FALSE) == TRUE; } if (!usePROJ4InitRules) { throw ParsingException("init=epsg:/init=IGNF: syntax not " "supported in non-PROJ4 emulation mode"); } - PJ_CONTEXT *ctx = proj_context_create(); char unused[256]; std::string initname(stepName); initname.resize(initname.find(':')); int file_found = pj_find_file(ctx, initname.c_str(), unused, sizeof(unused)); - proj_context_destroy(ctx); + if (!file_found) { auto obj = createFromUserInput(stepName, d->dbContext_, true); auto crs = dynamic_cast<CRS *>(obj.get()); @@ -8790,19 +8818,19 @@ PROJStringParser::createFromPROJString(const std::string &projString) { } } - paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); - if (!init) { + auto ctx = d->ctx_ ? d->ctx_ : proj_context_create(); + if (!ctx) { throw ParsingException("out of memory"); } - PJ_CONTEXT *ctx = d->ctx_ ? d->ctx_ : proj_context_create(); - if (!ctx) { - pj_dealloc(init); + PJContextHolder contextHolder(ctx, ctx != d->ctx_); + + paralist *init = pj_mkparam(("init=" + d->steps_[0].name).c_str()); + if (!init) { throw ParsingException("out of memory"); } + ctx->projStringParserCreateFromPROJStringRecursionCounter++; paralist *list = pj_expand_init(ctx, init); - if (ctx != d->ctx_) { - proj_context_destroy(ctx); - } + ctx->projStringParserCreateFromPROJStringRecursionCounter--; if (!list) { pj_dealloc(init); throw ParsingException("cannot expand " + projString); @@ -8933,18 +8961,14 @@ PROJStringParser::createFromPROJString(const std::string &projString) { proj_log_func(pj_context, &logger, Logger::log); proj_context_use_proj4_init_rules(pj_context, d->usePROJ4InitRules_); } - if (d->ctx_) { - d->ctx_->curStringInCreateFromPROJString = projString; - } + pj_context->projStringParserCreateFromPROJStringRecursionCounter++; auto log_level = proj_log_level(pj_context, PJ_LOG_NONE); auto pj = pj_create_internal( pj_context, (projString.find("type=crs") != std::string::npos ? projString + " +disable_grid_presence_check" : projString) .c_str()); - if (d->ctx_) { - d->ctx_->curStringInCreateFromPROJString.clear(); - } + pj_context->projStringParserCreateFromPROJStringRecursionCounter--; valid = pj != nullptr; proj_log_level(pj_context, log_level); diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index bad60324..d1d6f766 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -405,6 +405,7 @@ if(WIN32) PROPERTIES VERSION "${${PROJECT_INTERN_NAME}_BUILD_VERSION}" OUTPUT_NAME "${PROJ_CORE_TARGET_OUTPUT_NAME}" + ARCHIVE_OUTPUT_NAME "${PROJ_CORE_TARGET}" CLEAN_DIRECT_OUTPUT 1) elseif(BUILD_FRAMEWORKS_AND_BUNDLE) set_target_properties(${PROJ_CORE_TARGET} @@ -358,8 +358,8 @@ PJ PROJ_DLL *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ PROJ_DLL *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); PJ PROJ_DLL *proj_create_crs_to_crs(PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area); PJ PROJ_DLL *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, - PJ *source_crs, - PJ *target_crs, + const PJ *source_crs, + const PJ *target_crs, PJ_AREA *area, const char* const *options); PJ PROJ_DLL *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ* obj); diff --git a/src/proj_experimental.h b/src/proj_experimental.h index 0e97ac9f..5a96203c 100644 --- a/src/proj_experimental.h +++ b/src/proj_experimental.h @@ -130,6 +130,22 @@ PJ PROJ_DLL *proj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx, const char* unit_name, double unit_conv_factor); +/** Type of Ellipsoidal 3D coordinate system. */ +typedef enum +{ + /* Longitude-Latitude-Height(up) */ + PJ_ELLPS3D_LONGITUDE_LATITUDE_HEIGHT, + /* Latitude-Longitude-Height(up) */ + PJ_ELLPS3D_LATITUDE_LONGITUDE_HEIGHT, +} PJ_ELLIPSOIDAL_CS_3D_TYPE; + +PJ PROJ_DLL *proj_create_ellipsoidal_3D_cs(PJ_CONTEXT *ctx, + PJ_ELLIPSOIDAL_CS_3D_TYPE type, + const char* horizontal_angular_unit_name, + double horizontal_angular_unit_conv_factor, + const char* vertical_linear_unit_name, + double vertical_linear_unit_conv_factor); + PJ_OBJ_LIST PROJ_DLL *proj_query_geodetic_crs_from_datum( PJ_CONTEXT *ctx, const char *crs_auth_name, diff --git a/src/proj_internal.h b/src/proj_internal.h index 761746c1..4a126e98 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -706,7 +706,7 @@ struct projCtx_t { const char* (*file_finder) (PJ_CONTEXT *, const char*, void* user_data) = nullptr; void* file_finder_user_data = nullptr; - std::string curStringInCreateFromPROJString{}; + int projStringParserCreateFromPROJStringRecursionCounter = 0; // to avoid potential infinite recursion in PROJStringParser::createFromPROJString() projCtx_t() = default; projCtx_t(const projCtx_t&); diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index ace66a0c..fd129c80 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -3737,4 +3737,159 @@ TEST_F(CApi, proj_create_crs_to_crs_from_pj) { "+step +proj=utm +zone=31 +ellps=WGS84"); } +// --------------------------------------------------------------------------- + +static void +check_axis_is_latitude(PJ_CONTEXT *ctx, PJ *cs, int axis_number, + const char *unit_name = "degree", + double unit_conv_factor = 0.017453292519943295, + const char *auth = "EPSG", const char *code = "9122") { + + const char *name = nullptr; + const char *abbrev = nullptr; + const char *direction = nullptr; + double unitConvFactor = 0.0; + const char *unitName = nullptr; + const char *unitAuthority = nullptr; + const char *unitCode = nullptr; + + EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev, + &direction, &unitConvFactor, &unitName, + &unitAuthority, &unitCode)); + ASSERT_NE(name, nullptr); + ASSERT_NE(abbrev, nullptr); + ASSERT_NE(direction, nullptr); + ASSERT_NE(unitName, nullptr); + if (auth) { + ASSERT_NE(unitAuthority, nullptr); + ASSERT_NE(unitCode, nullptr); + } + EXPECT_EQ(std::string(name), "Latitude"); + EXPECT_EQ(std::string(abbrev), "lat"); + EXPECT_EQ(std::string(direction), "north"); + EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor; + EXPECT_EQ(std::string(unitName), unit_name); + if (auth) { + EXPECT_EQ(std::string(unitAuthority), auth); + EXPECT_EQ(std::string(unitCode), code); + } +} + +// --------------------------------------------------------------------------- + +static void +check_axis_is_longitude(PJ_CONTEXT *ctx, PJ *cs, int axis_number, + const char *unit_name = "degree", + double unit_conv_factor = 0.017453292519943295, + const char *auth = "EPSG", const char *code = "9122") { + + const char *name = nullptr; + const char *abbrev = nullptr; + const char *direction = nullptr; + double unitConvFactor = 0.0; + const char *unitName = nullptr; + const char *unitAuthority = nullptr; + const char *unitCode = nullptr; + + EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev, + &direction, &unitConvFactor, &unitName, + &unitAuthority, &unitCode)); + ASSERT_NE(name, nullptr); + ASSERT_NE(abbrev, nullptr); + ASSERT_NE(direction, nullptr); + ASSERT_NE(unitName, nullptr); + if (auth) { + ASSERT_NE(unitAuthority, nullptr); + ASSERT_NE(unitCode, nullptr); + } + EXPECT_EQ(std::string(name), "Longitude"); + EXPECT_EQ(std::string(abbrev), "lon"); + EXPECT_EQ(std::string(direction), "east"); + EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor; + EXPECT_EQ(std::string(unitName), unit_name); + if (auth) { + EXPECT_EQ(std::string(unitAuthority), auth); + EXPECT_EQ(std::string(unitCode), code); + } +} + +// --------------------------------------------------------------------------- + +static void check_axis_is_height(PJ_CONTEXT *ctx, PJ *cs, int axis_number, + const char *unit_name = "metre", + double unit_conv_factor = 1, + const char *auth = "EPSG", + const char *code = "9001") { + + const char *name = nullptr; + const char *abbrev = nullptr; + const char *direction = nullptr; + double unitConvFactor = 0.0; + const char *unitName = nullptr; + const char *unitAuthority = nullptr; + const char *unitCode = nullptr; + + EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev, + &direction, &unitConvFactor, &unitName, + &unitAuthority, &unitCode)); + ASSERT_NE(name, nullptr); + ASSERT_NE(abbrev, nullptr); + ASSERT_NE(direction, nullptr); + ASSERT_NE(unitName, nullptr); + if (auth) { + ASSERT_NE(unitAuthority, nullptr); + ASSERT_NE(unitCode, nullptr); + } + EXPECT_EQ(std::string(name), "Ellipsoidal height"); + EXPECT_EQ(std::string(abbrev), "h"); + EXPECT_EQ(std::string(direction), "up"); + EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor; + EXPECT_EQ(std::string(unitName), unit_name); + if (auth) { + EXPECT_EQ(std::string(unitAuthority), auth); + EXPECT_EQ(std::string(unitCode), code); + } +} + +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_create_ellipsoidal_3D_cs) { + + { + auto cs = proj_create_ellipsoidal_3D_cs( + m_ctxt, PJ_ELLPS3D_LATITUDE_LONGITUDE_HEIGHT, nullptr, 0, nullptr, + 0); + ObjectKeeper keeper_cs(cs); + ASSERT_NE(cs, nullptr); + + EXPECT_EQ(proj_cs_get_type(m_ctxt, cs), PJ_CS_TYPE_ELLIPSOIDAL); + + EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3); + + check_axis_is_latitude(m_ctxt, cs, 0); + + check_axis_is_longitude(m_ctxt, cs, 1); + + check_axis_is_height(m_ctxt, cs, 2); + } + + { + auto cs = proj_create_ellipsoidal_3D_cs( + m_ctxt, PJ_ELLPS3D_LONGITUDE_LATITUDE_HEIGHT, "foo", 0.5, "bar", + 0.6); + ObjectKeeper keeper_cs(cs); + ASSERT_NE(cs, nullptr); + + EXPECT_EQ(proj_cs_get_type(m_ctxt, cs), PJ_CS_TYPE_ELLIPSOIDAL); + + EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3); + + check_axis_is_longitude(m_ctxt, cs, 0, "foo", 0.5, nullptr, nullptr); + + check_axis_is_latitude(m_ctxt, cs, 1, "foo", 0.5, nullptr, nullptr); + + check_axis_is_height(m_ctxt, cs, 2, "bar", 0.6, nullptr, nullptr); + } +} + } // namespace |
