aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-10-30 16:56:41 +0100
committerEven Rouault <even.rouault@spatialys.com>2019-10-30 17:49:39 +0100
commit9095cf6fa351b5e6208cec811b86eb3d958c6f06 (patch)
tree771aed528565271f68509090396e6ed4555802dc /src
parentfc769bbd9a4fb61e96e500788d24d1d12019a4d0 (diff)
downloadPROJ-9095cf6fa351b5e6208cec811b86eb3d958c6f06.tar.gz
PROJ-9095cf6fa351b5e6208cec811b86eb3d958c6f06.zip
createFromWkt(): be tolerant to missing scale_factor parameter (fixes #1700)
This is invalid WKT, but GDAL 2.4 used to accept it and make a reasonable use of it... Currently we default it to 0 which is non sensical. Better use 1 as GDAL 2.4 did, and emit a warning. Other fix: proj_create_from_wkt() was documented to operate by default in non-strict validation mode, but it was actually in strict mode. So do as documented.
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/c_api.cpp20
-rw-r--r--src/iso19111/coordinateoperation.cpp33
-rw-r--r--src/iso19111/io.cpp55
3 files changed, 90 insertions, 18 deletions
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index f5f7ba55..337de313 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -498,7 +498,7 @@ template <class T> static PROJ_STRING_LIST to_string_list(T &&set) {
* proj_string_list_destroy().
* @param out_grammar_errors Pointer to a PROJ_STRING_LIST object, or NULL.
* If provided, *out_grammar_errors will contain a list of errors regarding the
- * WKT grammaer. It must be freed with proj_string_list_destroy().
+ * WKT grammar. It must be freed with proj_string_list_destroy().
* @return Object that must be unreferenced with proj_destroy(), or NULL in
* case of error.
*/
@@ -522,6 +522,7 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
if (dbContext) {
parser.attachDatabaseContext(NN_NO_CHECK(dbContext));
}
+ parser.setStrict(false);
for (auto iter = options; iter && iter[0]; ++iter) {
const char *value;
if ((value = getOptionValue(*iter, "STRICT="))) {
@@ -536,10 +537,19 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
auto obj = nn_dynamic_pointer_cast<IdentifiedObject>(
parser.createFromWKT(wkt));
+ std::vector<std::string> warningsFromParsing;
if (out_grammar_errors) {
- auto warnings = parser.warningList();
- if (!warnings.empty()) {
- *out_grammar_errors = to_string_list(warnings);
+ auto rawWarnings = parser.warningList();
+ std::vector<std::string> grammarWarnings;
+ for (const auto &msg : rawWarnings) {
+ if (msg.find("Default it to") != std::string::npos) {
+ warningsFromParsing.push_back(msg);
+ } else {
+ grammarWarnings.push_back(msg);
+ }
+ }
+ if (!grammarWarnings.empty()) {
+ *out_grammar_errors = to_string_list(grammarWarnings);
}
}
@@ -548,6 +558,8 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
if (derivedCRS) {
auto warnings =
derivedCRS->derivingConversionRef()->validateParameters();
+ warnings.insert(warnings.end(), warningsFromParsing.begin(),
+ warningsFromParsing.end());
if (!warnings.empty()) {
*out_warnings = to_string_list(warnings);
}
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index c7581642..5ac81aa1 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -6056,24 +6056,31 @@ void Conversion::_exportToPROJString(
if (!param->proj_name) {
continue;
}
- auto value =
+ const auto value =
parameterValueMeasure(param->wkt2_name, param->epsg_code);
+ double valueConverted = 0;
+ if (value == nullMeasure) {
+ // Deal with missing values. In an ideal world, this would
+ // not happen
+ if (param->epsg_code ==
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN) {
+ valueConverted = 1.0;
+ }
+ } else if (param->unit_type ==
+ common::UnitOfMeasure::Type::ANGULAR) {
+ valueConverted =
+ value.convertToUnit(common::UnitOfMeasure::DEGREE);
+ } else {
+ valueConverted = value.getSIValue();
+ }
+
if (mapping->epsg_code ==
EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP &&
strcmp(param->proj_name, "lat_1") == 0) {
- formatter->addParam(
- param->proj_name,
- value.convertToUnit(common::UnitOfMeasure::DEGREE));
- formatter->addParam(
- "lat_0",
- value.convertToUnit(common::UnitOfMeasure::DEGREE));
- } else if (param->unit_type ==
- common::UnitOfMeasure::Type::ANGULAR) {
- formatter->addParam(
- param->proj_name,
- value.convertToUnit(common::UnitOfMeasure::DEGREE));
+ formatter->addParam(param->proj_name, valueConverted);
+ formatter->addParam("lat_0", valueConverted);
} else {
- formatter->addParam(param->proj_name, value.getSIValue());
+ formatter->addParam(param->proj_name, valueConverted);
}
}
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index fc66b6c9..50ad5a87 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -3476,6 +3476,14 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
}
propertiesMethod.set(IdentifiedObject::NAME_KEY, projectionName);
+ std::vector<bool> foundParameters;
+ if (mapping) {
+ size_t countParams = 0;
+ while (mapping->params[countParams] != nullptr) {
+ ++countParams;
+ }
+ foundParameters.resize(countParams);
+ }
for (const auto &childNode : projCRSNode->GP()->children()) {
if (ci_equal(childNode->GP()->value(), WKTConstants::PARAMETER)) {
const auto &childNodeChildren = childNode->GP()->children();
@@ -3496,11 +3504,18 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
continue;
}
}
- const auto *paramMapping =
+ auto *paramMapping =
mapping ? getMappingFromWKT1(mapping, parameterName) : nullptr;
if (mapping &&
mapping->epsg_code == EPSG_CODE_METHOD_MERCATOR_VARIANT_B &&
ci_equal(parameterName, "latitude_of_origin")) {
+ for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) {
+ if (mapping->params[idx]->epsg_code ==
+ EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN) {
+ foundParameters[idx] = true;
+ break;
+ }
+ }
parameterName = EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN;
propertiesParameter.set(
Identifier::CODE_KEY,
@@ -3508,6 +3523,12 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
propertiesParameter.set(Identifier::CODESPACE_KEY,
Identifier::EPSG);
} else if (paramMapping) {
+ for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) {
+ if (mapping->params[idx] == paramMapping) {
+ foundParameters[idx] = true;
+ break;
+ }
+ }
parameterName = paramMapping->wkt2_name;
if (paramMapping->epsg_code != 0) {
propertiesParameter.set(Identifier::CODE_KEY,
@@ -3531,6 +3552,38 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
}
}
+ // Add back important parameters that should normally be present, but
+ // are sometimes missing. Currently we only deal with Scale factor at
+ // natural origin. This is to avoid a default value of 0 to slip in later.
+ // But such WKT should be considered invalid.
+ if (mapping) {
+ for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) {
+ if (!foundParameters[idx] &&
+ mapping->params[idx]->epsg_code ==
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN) {
+
+ emitRecoverableWarning(
+ "The WKT string lacks a value "
+ "for " EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
+ ". Default it to 1.");
+
+ PropertyMap propertiesParameter;
+ propertiesParameter.set(
+ Identifier::CODE_KEY,
+ EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN);
+ propertiesParameter.set(Identifier::CODESPACE_KEY,
+ Identifier::EPSG);
+ propertiesParameter.set(
+ IdentifiedObject::NAME_KEY,
+ EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN);
+ parameters.push_back(
+ OperationParameter::create(propertiesParameter));
+ values.push_back(ParameterValue::create(
+ Measure(1.0, UnitOfMeasure::SCALE_UNITY)));
+ }
+ }
+ }
+
return Conversion::create(
PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"),
propertiesMethod, parameters, values)