aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2020-03-03 19:42:44 +0100
committerGitHub <noreply@github.com>2020-03-03 19:42:44 +0100
commitb2ca8e5f6b1879d88312188fc9de24e0f32daf73 (patch)
tree38d12ed11eaa630c51c0f1d980ace727a90fece4 /src
parent57c12c27d2318d8c74d85e1d35c01cbed28986d0 (diff)
downloadPROJ-b2ca8e5f6b1879d88312188fc9de24e0f32daf73.tar.gz
PROJ-b2ca8e5f6b1879d88312188fc9de24e0f32daf73.zip
createUnitOfMeasure(): use full double resolution for the conversion factor (#2011)
Fixes https://github.com/OSGeo/gdal/issues/2290 where it was found that PROJ returned value for conversion factor of US Survey Foot unit wasn't at the maximum resolution, but only accurate to 15 significant digits.
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/factory.cpp29
1 files changed, 21 insertions, 8 deletions
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index e7017ca3..a4529c9f 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -52,6 +52,7 @@
#include <cstring>
#include <iomanip>
#include <limits>
+#include <locale>
#include <map>
#include <memory>
#include <sstream> // std::ostringstream
@@ -138,7 +139,8 @@ struct DatabaseContext::Private {
void setPjCtxt(PJ_CONTEXT *ctxt) { pjCtxt_ = ctxt; }
SQLResultSet run(const std::string &sql,
- const ListOfParams &parameters = ListOfParams());
+ const ListOfParams &parameters = ListOfParams(),
+ bool useMaxFloatPrecision = false);
std::vector<std::string> getDatabaseStructure();
@@ -733,7 +735,8 @@ void DatabaseContext::Private::registerFunctions() {
// ---------------------------------------------------------------------------
SQLResultSet DatabaseContext::Private::run(const std::string &sql,
- const ListOfParams &parameters) {
+ const ListOfParams &parameters,
+ bool useMaxFloatPrecision) {
sqlite3_stmt *stmt = nullptr;
auto iter = mapSqlToStatement_.find(sql);
@@ -791,10 +794,20 @@ SQLResultSet DatabaseContext::Private::run(const std::string &sql,
if (ret == SQLITE_ROW) {
SQLRow row(column_count);
for (int i = 0; i < column_count; i++) {
- const char *txt = reinterpret_cast<const char *>(
- sqlite3_column_text(stmt, i));
- if (txt) {
- row[i] = txt;
+ if (useMaxFloatPrecision &&
+ sqlite3_column_type(stmt, i) == SQLITE_FLOAT) {
+ // sqlite3_column_text() does not use maximum precision
+ std::ostringstream buffer;
+ buffer.imbue(std::locale::classic());
+ buffer << std::setprecision(18);
+ buffer << sqlite3_column_double(stmt, i);
+ row[i] = buffer.str();
+ } else {
+ const char *txt = reinterpret_cast<const char *>(
+ sqlite3_column_text(stmt, i));
+ if (txt) {
+ row[i] = txt;
+ }
}
}
result.emplace_back(std::move(row));
@@ -1646,10 +1659,10 @@ AuthorityFactory::createUnitOfMeasure(const std::string &code) const {
return NN_NO_CHECK(uom);
}
}
- auto res = d->runWithCodeParam(
+ auto res = d->context()->d->run(
"SELECT name, conv_factor, type, deprecated FROM unit_of_measure WHERE "
"auth_name = ? AND code = ?",
- code);
+ {d->authority(), code}, true);
if (res.empty()) {
throw NoSuchAuthorityCodeException("unit of measure not found",
d->authority(), code);