diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-03-16 17:55:36 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-16 17:55:36 +0100 |
| commit | 175cbad0a7ca202cefff33f240100b01752f8f73 (patch) | |
| tree | 3969a91e8499312c698d928f262d219d91aaea3b /src | |
| parent | 78eaa34a4816fd9a36e902adae4663f13bc39fab (diff) | |
| parent | 2247841879faebe007ccade45d04027361d5d26c (diff) | |
| download | PROJ-175cbad0a7ca202cefff33f240100b01752f8f73.tar.gz PROJ-175cbad0a7ca202cefff33f240100b01752f8f73.zip | |
Merge pull request #2065 from rouault/add_proj_get_units_from_database
Add proj_get_units_from_database() (fixes #2004)
Diffstat (limited to 'src')
| -rw-r--r-- | src/apps/cs2cs.cpp | 17 | ||||
| -rw-r--r-- | src/apps/geod.cpp | 17 | ||||
| -rw-r--r-- | src/apps/geod_set.cpp | 24 | ||||
| -rw-r--r-- | src/apps/proj.cpp | 17 | ||||
| -rw-r--r-- | src/conversions/unitconvert.cpp | 4 | ||||
| -rw-r--r-- | src/init.cpp | 2 | ||||
| -rw-r--r-- | src/iso19111/c_api.cpp | 127 | ||||
| -rw-r--r-- | src/iso19111/common.cpp | 3 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 58 | ||||
| -rw-r--r-- | src/proj.h | 62 | ||||
| -rw-r--r-- | src/proj_internal.h | 2 | ||||
| -rw-r--r-- | src/units.cpp | 6 |
12 files changed, 298 insertions, 41 deletions
diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 6c85d4aa..affd2bec 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -425,11 +425,18 @@ int main(int argc, char **argv) { (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units(); lu->id; ++lu) - (void)printf("%12s %-20s %s\n", lu->id, - lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else if (arg[1] == 'm') { /* list prime meridians */ const struct PJ_PRIME_MERIDIANS *lpm; diff --git a/src/apps/geod.cpp b/src/apps/geod.cpp index b46188d3..919430ca 100644 --- a/src/apps/geod.cpp +++ b/src/apps/geod.cpp @@ -185,11 +185,18 @@ noargument: emess(1,"missing argument for -%c",*arg); (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list of units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units();lu->id ; ++lu) - (void)printf("%12s %-20s %s\n", - lu->id, lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else emess(1,"invalid list option: l%c",arg[1]); exit( 0 ); diff --git a/src/apps/geod_set.cpp b/src/apps/geod_set.cpp index ed7edeb9..603f0d95 100644 --- a/src/apps/geod_set.cpp +++ b/src/apps/geod_set.cpp @@ -14,7 +14,6 @@ geod_set(int argc, char **argv) { paralist *start = nullptr, *curr; double es; char *name; - int i; /* put arguments into internal linked list */ if (argc <= 0) @@ -22,7 +21,7 @@ geod_set(int argc, char **argv) { start = curr = pj_mkparam(argv[0]); if (!curr) emess(1, "memory allocation failed"); - for (i = 1; curr != nullptr && i < argc; ++i) { + for (int i = 1; curr != nullptr && i < argc; ++i) { curr->next = pj_mkparam(argv[i]); if (!curr->next) emess(1, "memory allocation failed"); @@ -32,13 +31,20 @@ geod_set(int argc, char **argv) { if (pj_ell_set(pj_get_default_ctx(),start, &geod_a, &es)) emess(1,"ellipse setup failure"); /* set units */ if ((name = pj_param(nullptr,start, "sunits").s) != nullptr) { - const char *s; - const struct PJ_UNITS *unit_list = proj_list_units(); - for (i = 0; (s = unit_list[i].id) && strcmp(name, s) ; ++i) ; - if (!s) - emess(1,"%s unknown unit conversion id", name); - to_meter = unit_list[i].factor; - fr_meter = 1 / to_meter; + bool unit_found = false; + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name && + strcmp(units[i]->proj_short_name, name) == 0 ) { + unit_found = true; + to_meter = units[i]->conv_factor; + fr_meter = 1 / to_meter; + } + } + proj_unit_list_destroy(units); + if( !unit_found ) + emess(1,"%s unknown unit conversion id", name); } else to_meter = fr_meter = 1; geod_f = es/(1 + sqrt(1 - es)); diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 852cea04..0bf98b3a 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -380,11 +380,18 @@ int main(int argc, char **argv) { (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units(); lu->id ; ++lu) - (void)printf("%12s %-20s %s\n", - lu->id, lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else emess(1,"invalid list option: l%c",arg[1]); exit(0); diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp index f8439aee..6ce55b02 100644 --- a/src/conversions/unitconvert.cpp +++ b/src/conversions/unitconvert.cpp @@ -393,9 +393,7 @@ static double get_unit_conversion_factor(const char* name, /***********************************************************************/ int i; const char* s; - const PJ_UNITS *units; - - units = proj_list_units(); + const PJ_UNITS *units = pj_list_linear_units(); /* Try first with linear units */ for (i = 0; (s = units[i].id) ; ++i) { diff --git a/src/init.cpp b/src/init.cpp index a25d1ccd..101fc8ad 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -738,7 +738,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); /* Set units */ - units = proj_list_units(); + units = pj_list_linear_units(); s = nullptr; if ((name = pj_param(ctx, start, "sunits").s) != nullptr) { for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index d5f299c2..13152662 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -662,7 +662,8 @@ PJ *proj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress -static const char *get_unit_category(UnitOfMeasure::Type type) { +static const char *get_unit_category(const std::string &unit_name, + UnitOfMeasure::Type type) { const char *ret = nullptr; switch (type) { case UnitOfMeasure::Type::UNKNOWN: @@ -672,19 +673,26 @@ static const char *get_unit_category(UnitOfMeasure::Type type) { ret = "none"; break; case UnitOfMeasure::Type::ANGULAR: - ret = "angular"; + ret = unit_name.find(" per ") != std::string::npos ? "angular_per_time" + : "angular"; break; case UnitOfMeasure::Type::LINEAR: - ret = "linear"; + ret = unit_name.find(" per ") != std::string::npos ? "linear_per_time" + : "linear"; break; case UnitOfMeasure::Type::SCALE: - ret = "scale"; + ret = unit_name.find(" per year") != std::string::npos || + unit_name.find(" per second") != std::string::npos + ? "scale_per_time" + : "scale"; break; case UnitOfMeasure::Type::TIME: ret = "time"; break; case UnitOfMeasure::Type::PARAMETRIC: - ret = "parametric"; + ret = unit_name.find(" per ") != std::string::npos + ? "parametric_per_time" + : "parametric"; break; } return ret; @@ -704,8 +712,9 @@ static const char *get_unit_category(UnitOfMeasure::Type type) { * @param out_conv_factor Pointer to a value to store the conversion * factor of the prime meridian longitude unit to radian. or NULL * @param out_category Pointer to a string value to store the parameter name. or - * NULL. This value might be "unknown", "none", "linear", "angular", "scale", - * "time" or "parametric"; + * NULL. This value might be "unknown", "none", "linear", "linear_per_time", + * "angular", "angular_per_time", "scale", "scale_per_time", "time", + * "parametric" or "parametric_per_time" * @return TRUE in case of success */ int proj_uom_get_info_from_database(PJ_CONTEXT *ctx, const char *auth_name, @@ -726,7 +735,7 @@ int proj_uom_get_info_from_database(PJ_CONTEXT *ctx, const char *auth_name, *out_conv_factor = obj->conversionToSI(); } if (out_category) { - *out_category = get_unit_category(obj->type()); + *out_category = get_unit_category(obj->name(), obj->type()); } ctx->cpp_context->autoCloseDbIfNeeded(); return true; @@ -2585,6 +2594,100 @@ void proj_crs_info_list_destroy(PROJ_CRS_INFO **list) { // --------------------------------------------------------------------------- +/** \brief Enumerate units from the database, taking into account various + * criteria. + * + * The returned object is an array of PROJ_UNIT_INFO* pointers, whose last + * entry is NULL. This array should be freed with proj_unit_list_destroy() + * + * @param ctx PROJ context, or NULL for default context + * @param auth_name Authority name, used to restrict the search. + * Or NULL for all authorities. + * @param category Filter by category, if this parameter is not NULL. Category + * is one of "linear", "linear_per_time", "angular", "angular_per_time", + * "scale", "scale_per_time" or "time" + * @param allow_deprecated whether we should return deprecated objects as well. + * @param out_result_count Output parameter pointing to an integer to receive + * the size of the result list. Might be NULL + * @return an array of PROJ_UNIT_INFO* pointers to be freed with + * proj_unit_list_destroy(), or NULL in case of error. + * + * @since 7.1 + */ +PROJ_UNIT_INFO **proj_get_units_from_database(PJ_CONTEXT *ctx, + const char *auth_name, + const char *category, + int allow_deprecated, + int *out_result_count) { + SANITIZE_CTX(ctx); + PROJ_UNIT_INFO **ret = nullptr; + int i = 0; + try { + auto factory = AuthorityFactory::create(getDBcontext(ctx), + auth_name ? auth_name : ""); + auto list = factory->getUnitList(); + ret = new PROJ_UNIT_INFO *[list.size() + 1]; + for (const auto &info : list) { + if (category && info.category != category) { + continue; + } + if (!allow_deprecated && info.deprecated) { + continue; + } + ret[i] = new PROJ_UNIT_INFO; + ret[i]->auth_name = pj_strdup(info.authName.c_str()); + ret[i]->code = pj_strdup(info.code.c_str()); + ret[i]->name = pj_strdup(info.name.c_str()); + ret[i]->category = pj_strdup(info.category.c_str()); + ret[i]->conv_factor = info.convFactor; + ret[i]->proj_short_name = + info.projShortName.empty() + ? nullptr + : pj_strdup(info.projShortName.c_str()); + ret[i]->deprecated = info.deprecated; + i++; + } + ret[i] = nullptr; + if (out_result_count) + *out_result_count = i; + ctx->cpp_context->autoCloseDbIfNeeded(); + return ret; + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + if (ret) { + ret[i + 1] = nullptr; + proj_unit_list_destroy(ret); + } + if (out_result_count) + *out_result_count = 0; + } + ctx->cpp_context->autoCloseDbIfNeeded(); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Destroy the result returned by + * proj_get_units_from_database(). + * + * @since 7.1 + */ +void proj_unit_list_destroy(PROJ_UNIT_INFO **list) { + if (list) { + for (int i = 0; list[i] != nullptr; i++) { + pj_dalloc(list[i]->auth_name); + pj_dalloc(list[i]->code); + pj_dalloc(list[i]->name); + pj_dalloc(list[i]->category); + pj_dalloc(list[i]->proj_short_name); + 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 * @@ -6749,8 +6852,9 @@ int proj_coordoperation_get_param_index(PJ_CONTEXT *ctx, * unit code. or NULL * @param out_unit_category Pointer to a string value to store the parameter * name. or - * NULL. This value might be "unknown", "none", "linear", "angular", "scale", - * "time" or "parametric"; + * NULL. This value might be "unknown", "none", "linear", "linear_per_time", + * "angular", "angular_per_time", "scale", "scale_per_time", "time", + * "parametric" or "parametric_per_time" * @return TRUE in case of success. */ @@ -6852,7 +6956,8 @@ int proj_coordoperation_get_param( *out_unit_code = unit.code().c_str(); } if (out_unit_category) { - *out_unit_category = get_unit_category(unit.type()); + *out_unit_category = + get_unit_category(unit.name(), unit.type()); } } } diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index f2e4de4c..4606905b 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -39,6 +39,7 @@ #include "proj/internal/io_internal.hpp" #include "proj.h" +#include "proj_internal.h" #include <cmath> // M_PI #include <cstdlib> @@ -312,7 +313,7 @@ bool UnitOfMeasure::operator!=(const UnitOfMeasure &other) PROJ_PURE_DEFN { //! @cond Doxygen_Suppress std::string UnitOfMeasure::exportToPROJString() const { if (type() == Type::LINEAR) { - auto proj_units = proj_list_units(); + auto proj_units = pj_list_linear_units(); for (int i = 0; proj_units[i].id != nullptr; i++) { if (::fabs(proj_units[i].factor - conversionToSI()) < 1e-10 * conversionToSI()) { diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 1c836367..6a707e0d 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5214,6 +5214,64 @@ std::list<AuthorityFactory::CRSInfo> AuthorityFactory::getCRSInfoList() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +AuthorityFactory::UnitInfo::UnitInfo() + : authName{}, code{}, name{}, category{}, convFactor{}, projShortName{}, + deprecated{} {} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Return the list of units. + * @throw FactoryException + * + * @since 7.1 + */ +std::list<AuthorityFactory::UnitInfo> AuthorityFactory::getUnitList() const { + std::string sql = "SELECT auth_name, code, name, type, conv_factor, " + "proj_short_name, deprecated FROM unit_of_measure"; + ListOfParams params; + if (d->hasAuthorityRestriction()) { + sql += " WHERE auth_name = ?"; + params.emplace_back(d->authority()); + } + sql += " ORDER BY auth_name, code"; + + auto sqlRes = d->run(sql, params); + std::list<AuthorityFactory::UnitInfo> res; + for (const auto &row : sqlRes) { + AuthorityFactory::UnitInfo info; + info.authName = row[0]; + info.code = row[1]; + info.name = row[2]; + const std::string &raw_category(row[3]); + if (raw_category == "length") { + info.category = info.name.find(" per ") != std::string::npos + ? "linear_per_time" + : "linear"; + } else if (raw_category == "angle") { + info.category = info.name.find(" per ") != std::string::npos + ? "angular_per_time" + : "angular"; + } else if (raw_category == "scale") { + info.category = + info.name.find(" per year") != std::string::npos || + info.name.find(" per second") != std::string::npos + ? "scale_per_time" + : "scale"; + } else { + info.category = raw_category; + } + info.convFactor = row[4].empty() ? 0 : c_locale_stod(row[4]); + info.projShortName = row[5]; + info.deprecated = row[6] == "1"; + res.emplace_back(info); + } + return res; +} + +// --------------------------------------------------------------------------- + /** \brief Gets the official name from a possibly alias name. * * @param aliasedName Alias name. @@ -151,6 +151,24 @@ extern "C" { #endif #endif +#ifdef PROJ_SUPPRESS_DEPRECATION_MESSAGE + #define PROJ_DEPRECATED(decl, msg) decl +#elif defined(__has_extension) + #if __has_extension(attribute_deprecated_with_message) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated(msg))) + #elif defined(__GNUC__) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated)) + #else + #define PROJ_DEPRECATED(decl, msg) decl + #endif +#elif defined(__GNUC__) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated)) +#elif defined(_MSVC_VER) + #define PROJ_DEPRECATED(decl, msg) __declspec(deprecated(msg)) decl +#else + #define PROJ_DEPRECATED(decl, msg) decl +#endif + /* The version numbers should be updated with every release! **/ #define PROJ_VERSION_MAJOR 7 #define PROJ_VERSION_MINOR 1 @@ -608,7 +626,7 @@ PJ_INIT_INFO PROJ_DLL proj_init_info(const char *initname); /* Get lists of operations, ellipsoids, units and prime meridians. */ const PJ_OPERATIONS PROJ_DLL *proj_list_operations(void); const PJ_ELLPS PROJ_DLL *proj_list_ellps(void); -const PJ_UNITS PROJ_DLL *proj_list_units(void); +PROJ_DEPRECATED(const PJ_UNITS PROJ_DLL *proj_list_units(void), "Deprecated by proj_get_units_from_database"); const PJ_UNITS PROJ_DLL *proj_list_angular_units(void); const PJ_PRIME_MERIDIANS PROJ_DLL *proj_list_prime_meridians(void); @@ -912,6 +930,39 @@ typedef struct int allow_deprecated; } PROJ_CRS_LIST_PARAMETERS; +/** \brief Structure given description of a unit. + * + * This structure may grow over time, and should not be directly allocated by + * client code. + * @since 7.1 + */ +typedef struct +{ + /** Authority name. */ + char* auth_name; + + /** Object code. */ + char* code; + + /** Object name. For example "metre", "US survey foot", etc. */ + char* name; + + /** Category of the unit: one of "linear", "linear_per_time", "angular", + * "angular_per_time", "scale", "scale_per_time" or "time" */ + char* category; + + /** Conversion factor to apply to transform from that unit to the + * corresponding SI unit (metre for "linear", radian for "angular", etc.). + * It might be 0 in some cases to indicate no known conversion factor. */ + double conv_factor; + + /** PROJ short name, like "m", "ft", "us-ft", etc... Might be NULL */ + char* proj_short_name; + + /** Whether the object is deprecated */ + int deprecated; +} PROJ_UNIT_INFO; + /**@}*/ @@ -1077,6 +1128,15 @@ PROJ_CRS_INFO PROJ_DLL **proj_get_crs_info_list_from_database( void PROJ_DLL proj_crs_info_list_destroy(PROJ_CRS_INFO** list); +PROJ_UNIT_INFO PROJ_DLL **proj_get_units_from_database( + PJ_CONTEXT *ctx, + const char *auth_name, + const char *category, + int allow_deprecated, + int *out_result_count); + +void PROJ_DLL proj_unit_list_destroy(PROJ_UNIT_INFO** list); + /* ------------------------------------------------------------------------- */ diff --git a/src/proj_internal.h b/src/proj_internal.h index 8f73200d..78aff49f 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -873,6 +873,8 @@ std::string PROJ_DLL pj_context_get_user_writable_directory(PJ_CONTEXT *ctx, boo void PROJ_DLL pj_context_set_user_writable_directory(PJ_CONTEXT* ctx, const std::string& path); std::string PROJ_DLL pj_get_relative_share_proj(PJ_CONTEXT *ctx); +const PJ_UNITS *pj_list_linear_units(); + /* classic public API */ #include "proj_api.h" diff --git a/src/units.cpp b/src/units.cpp index 34a71db1..36f2d4c7 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -36,6 +36,12 @@ pj_units[] = { {nullptr, nullptr, nullptr, 0.0} }; +// For internal use +const PJ_UNITS *pj_list_linear_units() +{ + return pj_units; +} + const PJ_UNITS *proj_list_units() { return pj_units; |
