Skip to content

Commit

Permalink
Merge pull request #3588 from rouault/proj_get_domain_count
Browse files Browse the repository at this point in the history
C API: add proj_get_domain_count(), proj_get_area_of_use_ex() and proj_get_scope_ex()
  • Loading branch information
rouault authored Jan 23, 2023
2 parents 0622cf1 + 36226d5 commit b83a006
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 5 deletions.
3 changes: 3 additions & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1005,13 +1005,15 @@ proj_errno_string
proj_factors
proj_geod
proj_get_area_of_use
proj_get_area_of_use_ex
proj_get_authorities_from_database
proj_get_celestial_body_list_from_database
proj_get_celestial_body_name
proj_get_codes_from_database
proj_get_crs_info_list_from_database
proj_get_crs_list_parameters_create
proj_get_crs_list_parameters_destroy
proj_get_domain_count
proj_get_ellipsoid
proj_get_geoid_models_from_database
proj_get_id_auth_name
Expand All @@ -1022,6 +1024,7 @@ proj_get_non_deprecated
proj_get_prime_meridian
proj_get_remarks
proj_get_scope
proj_get_scope_ex
proj_get_source_crs
proj_get_suggested_operation
proj_get_target_crs
Expand Down
83 changes: 78 additions & 5 deletions src/iso19111/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,29 @@ const char *proj_as_projjson(PJ_CONTEXT *ctx, const PJ *obj,

// ---------------------------------------------------------------------------

/** \brief Get the number of domains/usages for a given object.
*
* Most objects have a single domain/usage, but for some of them, there might
* be multiple.
*
* @param obj Object (must not be NULL)
* @return the number of domains, or 0 in case of error.
* @since 9.2
*/
int proj_get_domain_count(const PJ *obj) {
if (!obj || !obj->iso_obj) {
return 0;
}
auto objectUsage = dynamic_cast<const ObjectUsage *>(obj->iso_obj.get());
if (!objectUsage) {
return 0;
}
const auto &domains = objectUsage->domains();
return static_cast<int>(domains.size());
}

// ---------------------------------------------------------------------------

/** \brief Get the scope of an object.
*
* In case of multiple usages, this will be the one of first usage.
Expand All @@ -1839,7 +1862,20 @@ const char *proj_as_projjson(PJ_CONTEXT *ctx, const PJ *obj,
* @param obj Object (must not be NULL)
* @return a string, or NULL in case of error or missing scope.
*/
const char *proj_get_scope(const PJ *obj) {
const char *proj_get_scope(const PJ *obj) { return proj_get_scope_ex(obj, 0); }

// ---------------------------------------------------------------------------

/** \brief Get the scope 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 domainIdx Index of the domain/usage. In [0,proj_get_domain_count(obj)[
* @return a string, or NULL in case of error or missing scope.
* @since 9.2
*/
const char *proj_get_scope_ex(const PJ *obj, int domainIdx) {
if (!obj || !obj->iso_obj) {
return nullptr;
}
Expand All @@ -1848,10 +1884,10 @@ const char *proj_get_scope(const PJ *obj) {
return nullptr;
}
const auto &domains = objectUsage->domains();
if (domains.empty()) {
if (domainIdx < 0 || static_cast<size_t>(domainIdx) >= domains.size()) {
return nullptr;
}
const auto &scope = domains[0]->scope();
const auto &scope = domains[domainIdx]->scope();
if (!scope.has_value()) {
return nullptr;
}
Expand Down Expand Up @@ -1891,6 +1927,43 @@ int proj_get_area_of_use(PJ_CONTEXT *ctx, const PJ *obj,
double *out_east_lon_degree,
double *out_north_lat_degree,
const char **out_area_name) {
return proj_get_area_of_use_ex(ctx, obj, 0, out_west_lon_degree,
out_south_lat_degree, out_east_lon_degree,
out_north_lat_degree, out_area_name);
}

// ---------------------------------------------------------------------------

/** \brief Return the area of use of an object.
*
* In case of multiple usages, this will be the one of first usage.
*
* @param ctx PROJ context, or NULL for default context
* @param obj Object (must not be NULL)
* @param domainIdx Index of the domain/usage. In [0,proj_get_domain_count(obj)[
* @param out_west_lon_degree Pointer to a double to receive the west longitude
* (in degrees). Or NULL. If the returned value is -1000, the bounding box is
* unknown.
* @param out_south_lat_degree Pointer to a double to receive the south latitude
* (in degrees). Or NULL. If the returned value is -1000, the bounding box is
* unknown.
* @param out_east_lon_degree Pointer to a double to receive the east longitude
* (in degrees). Or NULL. If the returned value is -1000, the bounding box is
* unknown.
* @param out_north_lat_degree Pointer to a double to receive the north latitude
* (in degrees). Or NULL. If the returned value is -1000, the bounding box is
* unknown.
* @param out_area_name Pointer to a string to receive the name of the area of
* use. Or NULL. *p_area_name is valid while obj is valid itself.
* @return TRUE in case of success, FALSE in case of error or if the area
* of use is unknown.
*/
int proj_get_area_of_use_ex(PJ_CONTEXT *ctx, const PJ *obj, int domainIdx,
double *out_west_lon_degree,
double *out_south_lat_degree,
double *out_east_lon_degree,
double *out_north_lat_degree,
const char **out_area_name) {
(void)ctx;
if (out_area_name) {
*out_area_name = nullptr;
Expand All @@ -1900,10 +1973,10 @@ int proj_get_area_of_use(PJ_CONTEXT *ctx, const PJ *obj,
return false;
}
const auto &domains = objectUsage->domains();
if (domains.empty()) {
if (domainIdx < 0 || static_cast<size_t>(domainIdx) >= domains.size()) {
return false;
}
const auto &extent = domains[0]->domainOfValidity();
const auto &extent = domains[domainIdx]->domainOfValidity();
if (!extent) {
return false;
}
Expand Down
13 changes: 13 additions & 0 deletions src/proj.h
Original file line number Diff line number Diff line change
Expand Up @@ -1179,8 +1179,12 @@ const char PROJ_DLL* proj_get_id_code(const PJ *obj, int index);

const char PROJ_DLL* proj_get_remarks(const PJ *obj);

int PROJ_DLL proj_get_domain_count(const PJ *obj);

const char PROJ_DLL* proj_get_scope(const PJ *obj);

const char PROJ_DLL* proj_get_scope_ex(const PJ *obj, int domainIdx);

int PROJ_DLL proj_get_area_of_use(PJ_CONTEXT *ctx,
const PJ *obj,
double* out_west_lon_degree,
Expand All @@ -1189,6 +1193,15 @@ int PROJ_DLL proj_get_area_of_use(PJ_CONTEXT *ctx,
double* out_north_lat_degree,
const char **out_area_name);

int PROJ_DLL proj_get_area_of_use_ex(PJ_CONTEXT *ctx,
const PJ *obj,
int domainIdx,
double* out_west_lon_degree,
double* out_south_lat_degree,
double* out_east_lon_degree,
double* out_north_lat_degree,
const char **out_area_name);

const char PROJ_DLL* proj_as_wkt(PJ_CONTEXT *ctx,
const PJ *obj, PJ_WKT_TYPE type,
const char* const *options);
Expand Down
40 changes: 40 additions & 0 deletions test/unit/test_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2359,6 +2359,46 @@ TEST_F(CApi, proj_identify) {

// ---------------------------------------------------------------------------

TEST_F(CApi, proj_get_domain_count) {

auto crs = proj_create_from_database(m_ctxt, "EPSG", "6316",
PJ_CATEGORY_CRS, false, nullptr);
ASSERT_NE(crs, nullptr);
ObjectKeeper keeper(crs);
EXPECT_EQ(proj_get_domain_count(crs), 2);

const char *name = nullptr;
EXPECT_TRUE(proj_get_area_of_use_ex(m_ctxt, crs, 0, nullptr, nullptr,
nullptr, nullptr, &name));
ASSERT_TRUE(name != nullptr);
EXPECT_EQ(std::string(name),
"Bosnia and Herzegovina - east of 19°30'E; Kosovo; Montenegro - "
"east of 19°30'E; Serbia - between 19°30'E and 22°30'E.");

const char *scope = proj_get_scope_ex(crs, 0);
ASSERT_TRUE(scope != nullptr);
EXPECT_STREQ(scope, "Cadastre, engineering survey, topographic mapping "
"(large and medium scale).");

EXPECT_TRUE(proj_get_area_of_use_ex(m_ctxt, crs, 1, nullptr, nullptr,
nullptr, nullptr, &name));
ASSERT_TRUE(name != nullptr);
EXPECT_EQ(std::string(name), "North Macedonia.");

scope = proj_get_scope_ex(crs, 1);
ASSERT_TRUE(scope != nullptr);
EXPECT_STREQ(scope, "Cadastre.");

EXPECT_FALSE(proj_get_area_of_use_ex(m_ctxt, crs, -1, nullptr, nullptr,
nullptr, nullptr, &name));
EXPECT_FALSE(proj_get_area_of_use_ex(m_ctxt, crs, 2, nullptr, nullptr,
nullptr, nullptr, &name));
EXPECT_EQ(proj_get_scope_ex(crs, -1), nullptr);
EXPECT_EQ(proj_get_scope_ex(crs, 2), nullptr);
}

// ---------------------------------------------------------------------------

TEST_F(CApi, proj_get_area_of_use) {
{
auto crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
Expand Down

0 comments on commit b83a006

Please sign in to comment.