diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2018-12-09 19:49:25 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2018-12-09 19:49:25 +0100 |
| commit | 3945d99793709ba68b614fbdd24c1b9069be475b (patch) | |
| tree | 3d8a7bcefd22ef99da1fc97951ffa75ec75b36bc | |
| parent | 23127c01ad535902665a975da81e27c389bb7aeb (diff) | |
| parent | 9d60a52fdaf17a28235a3d7103b1757d7b59de03 (diff) | |
| download | PROJ-3945d99793709ba68b614fbdd24c1b9069be475b.tar.gz PROJ-3945d99793709ba68b614fbdd24c1b9069be475b.zip | |
Merge remote-tracking branch 'rouault/gdalbarn'
| -rw-r--r-- | include/proj/internal/coordinateoperation_internal.hpp | 2 | ||||
| -rw-r--r-- | src/coordinateoperation.cpp | 49 | ||||
| -rw-r--r-- | src/factory.cpp | 68 | ||||
| -rw-r--r-- | src/internal.cpp | 33 |
4 files changed, 127 insertions, 25 deletions
diff --git a/include/proj/internal/coordinateoperation_internal.hpp b/include/proj/internal/coordinateoperation_internal.hpp index bafc3a3b..d8c091d0 100644 --- a/include/proj/internal/coordinateoperation_internal.hpp +++ b/include/proj/internal/coordinateoperation_internal.hpp @@ -66,8 +66,6 @@ const MethodMapping *getMapping(const char *wkt2_name) noexcept; const MethodMapping *getMapping(const OperationMethod *method) noexcept; std::vector<const MethodMapping *> getMappingsFromPROJName(const std::string &projName); -const ParamMapping *getMapping(const MethodMapping *mapping, - const OperationParameterValue *param); const ParamMapping *getMappingFromWKT1(const MethodMapping *mapping, const std::string &wkt1_name); bool areEquivalentParameters(const std::string &a, const std::string &b); diff --git a/src/coordinateoperation.cpp b/src/coordinateoperation.cpp index 8f75864e..3fa5ea9c 100644 --- a/src/coordinateoperation.cpp +++ b/src/coordinateoperation.cpp @@ -264,21 +264,37 @@ getMappingsFromPROJName(const std::string &projName) { // --------------------------------------------------------------------------- -const ParamMapping *getMapping(const MethodMapping *mapping, - const OperationParameterValue *param) { - const auto ¶m_name = param->parameter()->name(); - const std::string &name = *(param_name->description()); - const std::string &code = param_name->code(); - const int epsg_code = !code.empty() ? ::atoi(code.c_str()) : 0; +static const ParamMapping *getMapping(const MethodMapping *mapping, + const OperationParameterNNPtr ¶m) { + // First try with id + const int epsg_code = param->getEPSGCode(); + if (epsg_code) { + for (int i = 0; mapping->params[i] != nullptr; ++i) { + const auto *paramMapping = mapping->params[i]; + if (paramMapping->epsg_code == epsg_code) { + return paramMapping; + } + } + } + + // then equivalent name + const std::string &name = param->nameStr(); for (int i = 0; mapping->params[i] != nullptr; ++i) { const auto *paramMapping = mapping->params[i]; if (metadata::Identifier::isEquivalentName(paramMapping->wkt2_name, - name.c_str()) || - (epsg_code != 0 && paramMapping->epsg_code == epsg_code) || - areEquivalentParameters(paramMapping->wkt2_name, name)) { + name.c_str())) { + return paramMapping; + } + } + + // and finally different name, but equivalent parameter + for (int i = 0; mapping->params[i] != nullptr; ++i) { + const auto *paramMapping = mapping->params[i]; + if (areEquivalentParameters(paramMapping->wkt2_name, name)) { return paramMapping; } } + return nullptr; } @@ -1002,7 +1018,7 @@ void OperationParameterValue::_exportToWKT( void OperationParameterValue::_exportToWKT(io::WKTFormatter *formatter, const MethodMapping *mapping) const { const ParamMapping *paramMapping = - mapping ? getMapping(mapping, this) : nullptr; + mapping ? getMapping(mapping, d->parameter) : nullptr; if (paramMapping && paramMapping->wkt1_name == nullptr) { return; } @@ -9206,9 +9222,9 @@ static size_t getStepCount(const CoordinateOperationNNPtr &op) { // --------------------------------------------------------------------------- -struct FilterAndSort { +struct FilterResults { - FilterAndSort(const std::vector<CoordinateOperationNNPtr> &sourceListIn, + FilterResults(const std::vector<CoordinateOperationNNPtr> &sourceListIn, const CoordinateOperationContextNNPtr &contextIn, const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn, @@ -9223,6 +9239,9 @@ struct FilterAndSort { computeAreaOfIntest(); filterOut(forceStrictContainmentTest); + } + + FilterResults &andSort() { sort(); // And now that we have a sorted list, we can remove uninteresting @@ -9232,6 +9251,7 @@ struct FilterAndSort { removeUninterestingOps(); removeDuplicateOps(); removeSyntheticNullTransforms(); + return *this; } // ---------------------------------------------------------------------- @@ -9646,7 +9666,8 @@ static std::vector<CoordinateOperationNNPtr> filterAndSort(const std::vector<CoordinateOperationNNPtr> &sourceList, const CoordinateOperationContextNNPtr &context, const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS) { - return FilterAndSort(sourceList, context, sourceCRS, targetCRS, false) + return FilterResults(sourceList, context, sourceCRS, targetCRS, false) + .andSort() .getRes(); } //! @endcond @@ -10449,7 +10470,7 @@ createNullGeocentricTranslation(const crs::CRSNNPtr &sourceCRS, bool CoordinateOperationFactory::Private::hasPerfectAccuracyResult( const std::vector<CoordinateOperationNNPtr> &res, const Context &context) { - auto resTmp = FilterAndSort(res, context.context, context.sourceCRS, + auto resTmp = FilterResults(res, context.context, context.sourceCRS, context.targetCRS, true) .getRes(); for (const auto &op : resTmp) { diff --git a/src/factory.cpp b/src/factory.cpp index 39679082..47d31db9 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -202,6 +202,21 @@ struct DatabaseContext::Private { void cache(const std::string &code, const std::vector<operation::CoordinateOperationNNPtr> &list); + struct GridInfoCache { + std::string fullFilename{}; + std::string packageName{}; + std::string url{}; + bool found = false; + bool directDownload = false; + bool openLicense = false; + bool gridAvailable = false; + }; + + // cppcheck-suppress functionStatic + bool getGridInfoFromCache(const std::string &code, GridInfoCache &info); + // cppcheck-suppress functionStatic + void cache(const std::string &code, const GridInfoCache &info); + private: friend class DatabaseContext; @@ -226,6 +241,7 @@ struct DatabaseContext::Private { LRUCacheOfObjects cacheExtent_{CACHE_SIZE}; lru11::Cache<std::string, std::vector<operation::CoordinateOperationNNPtr>> cacheCRSToCrsCoordOp_{CACHE_SIZE}; + lru11::Cache<std::string, GridInfoCache> cacheGridInfo_{CACHE_SIZE}; static void insertIntoCache(LRUCacheOfObjects &cache, const std::string &code, @@ -428,6 +444,20 @@ void DatabaseContext::Private::cache(const std::string &code, // --------------------------------------------------------------------------- +bool DatabaseContext::Private::getGridInfoFromCache(const std::string &code, + GridInfoCache &info) { + return cacheGridInfo_.tryGet(code, info); +} + +// --------------------------------------------------------------------------- + +void DatabaseContext::Private::cache(const std::string &code, + const GridInfoCache &info) { + cacheGridInfo_.insert(code, info); +} + +// --------------------------------------------------------------------------- + #ifdef ENABLE_CUSTOM_LOCKLESS_VFS typedef int (*ClosePtr)(sqlite3_file *); @@ -965,6 +995,17 @@ bool DatabaseContext::lookForGridInfo(const std::string &projFilename, std::string &url, bool &directDownload, bool &openLicense, bool &gridAvailable) const { + Private::GridInfoCache info; + if (d->getGridInfoFromCache(projFilename, info)) { + fullFilename = info.fullFilename; + packageName = info.packageName; + url = info.url; + directDownload = info.directDownload; + openLicense = info.openLicense; + gridAvailable = info.gridAvailable; + return info.found; + } + fullFilename.clear(); packageName.clear(); url.clear(); @@ -994,15 +1035,24 @@ bool DatabaseContext::lookForGridInfo(const std::string &projFilename, "grid_alternatives.package_name = grid_packages.package_name " "WHERE proj_grid_name = ?", {projFilename}); - if (res.empty()) { - return false; - } - const auto &row = res.front(); - packageName = std::move(row[0]); - url = row[1].empty() ? std::move(row[2]) : std::move(row[1]); - openLicense = (row[3].empty() ? row[4] : row[3]) == "1"; - directDownload = (row[5].empty() ? row[6] : row[5]) == "1"; - return true; + bool ret = !res.empty(); + if (ret) { + const auto &row = res.front(); + packageName = std::move(row[0]); + url = row[1].empty() ? std::move(row[2]) : std::move(row[1]); + openLicense = (row[3].empty() ? row[4] : row[3]) == "1"; + directDownload = (row[5].empty() ? row[6] : row[5]) == "1"; + + info.fullFilename = fullFilename; + info.packageName = packageName; + info.url = url; + info.directDownload = directDownload; + info.openLicense = openLicense; + info.gridAvailable = gridAvailable; + } + info.found = ret; + d->cache(projFilename, info); + return ret; } // --------------------------------------------------------------------------- diff --git a/src/internal.cpp b/src/internal.cpp index ecb724c2..c43605d1 100644 --- a/src/internal.cpp +++ b/src/internal.cpp @@ -45,6 +45,8 @@ #include <sstream> // std::istringstream and std::ostringstream #include <string> +#include "sqlite3.h" + NS_PROJ_START namespace internal { @@ -296,6 +298,12 @@ std::vector<std::string> split(const std::string &str, char separator) { // --------------------------------------------------------------------------- +#ifdef _WIN32 + +// For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor +// doesn't round identically to the Unix builds, and thus breaks a number of +// unit test. So to avoid this, use the stdlib formatting + std::string toString(int val) { std::ostringstream buffer; buffer.imbue(std::locale::classic()); @@ -319,6 +327,31 @@ std::string toString(double val, int precision) { return str; } +#else + +std::string toString(int val) { + // use sqlite3 API that is slighly faster than std::ostringstream + // with forcing the C locale. sqlite3_snprintf() emulates a C locale. + constexpr int BUF_SIZE = 16; + char szBuffer[BUF_SIZE]; + sqlite3_snprintf(BUF_SIZE, szBuffer, "%d", val); + return szBuffer; +} + +std::string toString(double val, int precision) { + // use sqlite3 API that is slighly faster than std::ostringstream + // with forcing the C locale. sqlite3_snprintf() emulates a C locale. + constexpr int BUF_SIZE = 32; + char szBuffer[BUF_SIZE]; + sqlite3_snprintf(BUF_SIZE, szBuffer, "%.*g", precision, val); + if (precision == 15 && strstr(szBuffer, "9999999999")) { + sqlite3_snprintf(BUF_SIZE, szBuffer, "%.14g", val); + } + return szBuffer; +} + +#endif + // --------------------------------------------------------------------------- std::string concat(const char *a, const std::string &b) { |
