diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-11-04 14:58:24 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-11-04 14:58:24 +0100 |
| commit | c975c6d13f5c0c13c57834c15ecd265a9d91a705 (patch) | |
| tree | 556baa55635a44b21e83366d9e92254f3cce0b23 /src | |
| parent | cff22050faa67017eb4c5b44cb383b265c07d156 (diff) | |
| parent | 90c1166e316cc95296cd6db3ab1fc81243310de6 (diff) | |
| download | PROJ-c975c6d13f5c0c13c57834c15ecd265a9d91a705.tar.gz PROJ-c975c6d13f5c0c13c57834c15ecd265a9d91a705.zip | |
Merge remote-tracking branch 'origin/master' into geoid_model
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/c_api.cpp | 20 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 84 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 55 |
3 files changed, 131 insertions, 28 deletions
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 32c8df45..7341131f 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 e8f195e3..c51b4d3d 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -6132,24 +6132,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); } } @@ -6711,6 +6718,24 @@ static void getTransformationType(const crs::CRSNNPtr &sourceCRSIn, isGeog2D = nSrcAxisCount == 2 && nTargetAxisCount == 2; isGeog3D = !isGeog2D && nSrcAxisCount >= 2 && nTargetAxisCount >= 2; } + +// --------------------------------------------------------------------------- + +static int +useOperationMethodEPSGCodeIfPresent(const util::PropertyMap &properties, + int nDefaultOperationMethodEPSGCode) { + const auto *operationMethodEPSGCode = + properties.get("OPERATION_METHOD_EPSG_CODE"); + if (operationMethodEPSGCode) { + const auto boxedValue = dynamic_cast<const util::BoxedValue *>( + (*operationMethodEPSGCode).get()); + if (boxedValue && + boxedValue->type() == util::BoxedValue::Type::INTEGER) { + return boxedValue->integerValue(); + } + } + return nDefaultOperationMethodEPSGCode; +} //! @endcond // --------------------------------------------------------------------------- @@ -6739,12 +6764,13 @@ TransformationNNPtr Transformation::createGeocentricTranslations( isGeog3D); return create( properties, sourceCRSIn, targetCRSIn, nullptr, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D)), VectorOfParameters{ createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_X_AXIS_TRANSLATION), createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_Y_AXIS_TRANSLATION), @@ -6797,11 +6823,12 @@ TransformationNNPtr Transformation::createPositionVector( isGeog3D); return createSevenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_POSITION_VECTOR_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, accuracies); @@ -6846,11 +6873,12 @@ TransformationNNPtr Transformation::createCoordinateFrameRotation( isGeog3D); return createSevenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_COORDINATE_FRAME_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, accuracies); @@ -6989,12 +7017,13 @@ TransformationNNPtr Transformation::createTimeDependentPositionVector( isGeog3D); return createFifteenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, rateTranslationX, @@ -7066,12 +7095,13 @@ TransformationNNPtr Transformation::createTimeDependentCoordinateFrameRotation( isGeog3D); return createFifteenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, rateTranslationX, @@ -7609,6 +7639,14 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, addModifiedIdentifier(map, op, true, derivedFrom); + const auto so = dynamic_cast<const SingleOperation *>(op); + if (so) { + const int soMethodEPSGCode = so->method()->getEPSGCode(); + if (soMethodEPSGCode > 0) { + map.set("OPERATION_METHOD_EPSG_CODE", soMethodEPSGCode); + } + } + return map; } diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index aab1db4f..645bec0b 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) |
