aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/ctx.cpp8
-rw-r--r--src/datum_set.cpp12
-rw-r--r--src/ell_set.cpp8
-rw-r--r--src/iso19111/c_api.cpp44
-rw-r--r--src/iso19111/coordinateoperation.cpp88
-rw-r--r--src/iso19111/crs.cpp83
-rw-r--r--src/iso19111/io.cpp66
-rw-r--r--src/pipeline.cpp7
-rw-r--r--src/proj.h2
-rw-r--r--src/proj_api.h2
-rw-r--r--src/proj_internal.h2
-rw-r--r--src/projections/ob_tran.cpp4
-rw-r--r--src/release.cpp2
14 files changed, 259 insertions, 71 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index fe7f2572..0a868412 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,7 +42,7 @@ geodtest_LDADD = libproj.la
lib_LTLIBRARIES = libproj.la
-libproj_la_LDFLAGS = -no-undefined -version-info 17:0:2
+libproj_la_LDFLAGS = -no-undefined -version-info 17:1:2
libproj_la_LIBADD = @SQLITE3_LIBS@
libproj_la_SOURCES = \
diff --git a/src/ctx.cpp b/src/ctx.cpp
index 622a814d..bcb6e1cc 100644
--- a/src/ctx.cpp
+++ b/src/ctx.cpp
@@ -60,6 +60,14 @@ void pj_set_ctx( projPJ pj, projCtx ctx )
if (pj==nullptr)
return;
pj->ctx = ctx;
+ if( pj->is_pipeline )
+ {
+ pj_pipeline_assign_context_to_steps(pj, ctx);
+ }
+ for( const auto &alt: pj->alternativeCoordinateOperations )
+ {
+ pj_set_ctx(alt.pj, ctx);
+ }
}
/************************************************************************/
diff --git a/src/datum_set.cpp b/src/datum_set.cpp
index c1cb4cb9..873d7be5 100644
--- a/src/datum_set.cpp
+++ b/src/datum_set.cpp
@@ -85,10 +85,22 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef)
entry[ sizeof(entry) - 1 ] = '\0';
curr = curr->next = pj_mkparam(entry);
+ if (nullptr == curr)
+ {
+ pj_ctx_set_errno(ctx, ENOMEM);
+ return 1;
+ }
}
if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 )
+ {
curr = curr->next = pj_mkparam(pj_datums[i].defn);
+ if (nullptr == curr)
+ {
+ pj_ctx_set_errno(ctx, ENOMEM);
+ return 1;
+ }
+ }
(void)curr; /* make clang static analyzer happy */
}
diff --git a/src/ell_set.cpp b/src/ell_set.cpp
index d2930ca4..bb46b3a4 100644
--- a/src/ell_set.cpp
+++ b/src/ell_set.cpp
@@ -1,5 +1,6 @@
/* set ellipsoid parameters a and es */
+#include <errno.h>
#include <math.h>
#include <stddef.h>
#include <string.h>
@@ -156,7 +157,14 @@ static int ellps_ellps (PJ *P) {
err = proj_errno_reset (P);
paralist* new_params = pj_mkparam (ellps->major);
+ if (nullptr == new_params)
+ return proj_errno_set (P, ENOMEM);
new_params->next = pj_mkparam (ellps->ell);
+ if (nullptr == new_params->next)
+ {
+ pj_dealloc(new_params);
+ return proj_errno_set (P, ENOMEM);
+ }
paralist* old_params = P->params;
P->params = new_params;
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index 1e5c106a..fb3b7f40 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);
}
@@ -2089,14 +2101,26 @@ PJ *proj_get_target_crs(PJ_CONTEXT *ctx, const PJ *obj) {
* The method returns a list of matching reference CRS, and the percentage
* (0-100) of confidence in the match. The list is sorted by decreasing
* confidence.
- *
- * 100% means that the name of the reference entry
+ * <ul>
+ * <li>100% means that the name of the reference entry
* perfectly matches the CRS name, and both are equivalent. In which case a
* single result is returned.
- * 90% means that CRS are equivalent, but the names are not exactly the same.
- * 70% means that CRS are equivalent), but the names do not match at all.
- * 25% means that the CRS are not equivalent, but there is some similarity in
- * the names.
+ * Note: in the case of a GeographicCRS whose axis
+ * order is implicit in the input definition (for example ESRI WKT), then axis
+ * order is ignored for the purpose of identification. That is the CRS built
+ * from
+ * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],
+ * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
+ * will be identified to EPSG:4326, but will not pass a
+ * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test,
+ * but rather isEquivalentTo(EPSG_4326,
+ * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)
+ * </li>
+ * <li>90% means that CRS are equivalent, but the names are not exactly the same.</li>
+ * <li>70% means that CRS are equivalent), but the names do not match at all.</li>
+ * <li>25% means that the CRS are not equivalent, but there is some similarity in
+ * the names.</li>
+ * </ul>
* Other confidence values may be returned by some specialized implementations.
*
* This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 3ba5a5a2..0eaba883 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -5927,24 +5927,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);
}
}
@@ -6506,6 +6513,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
// ---------------------------------------------------------------------------
@@ -6534,12 +6559,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),
@@ -6592,11 +6618,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);
@@ -6641,11 +6668,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);
@@ -6784,12 +6812,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,
@@ -6861,12 +6890,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,
@@ -7448,6 +7478,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;
}
@@ -12619,9 +12657,7 @@ CoordinateOperationFactory::Private::createOperations(
auto vertCRSOfBaseOfBoundSrc =
dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get());
- if (vertCRSOfBaseOfBoundSrc && hubSrcGeog &&
- hubSrcGeog->coordinateSystem()->axisList().size() == 3 &&
- geogDst->coordinateSystem()->axisList().size() == 3) {
+ if (vertCRSOfBaseOfBoundSrc && hubSrcGeog) {
auto opsFirst = createOperations(sourceCRS, hubSrc, context);
if (context.skipHorizontalTransformation) {
if (!opsFirst.empty())
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index eea7cce8..e044c0c7 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -237,7 +237,7 @@ CRSNNPtr CRS::alterGeodeticCRS(const GeodeticCRSNNPtr &newGeodCRS) const {
auto projCRS = dynamic_cast<const ProjectedCRS *>(this);
if (projCRS) {
return ProjectedCRS::create(createPropertyMap(this), newGeodCRS,
- projCRS->derivingConversionRef(),
+ projCRS->derivingConversion(),
projCRS->coordinateSystem());
}
@@ -264,7 +264,7 @@ CRSNNPtr CRS::alterCSLinearUnit(const common::UnitOfMeasure &unit) const {
if (projCRS) {
return ProjectedCRS::create(
createPropertyMap(this), projCRS->baseCRS(),
- projCRS->derivingConversionRef(),
+ projCRS->derivingConversion(),
projCRS->coordinateSystem()->alterUnit(unit));
}
}
@@ -675,9 +675,8 @@ CRSNNPtr CRS::normalizeForVisualization() const {
axisList[0])
: cs::CartesianCS::create(util::PropertyMap(), axisList[1],
axisList[0], axisList[2]);
- return util::nn_static_pointer_cast<CRS>(
- ProjectedCRS::create(props, projCRS->baseCRS(),
- projCRS->derivingConversionRef(), cs));
+ return util::nn_static_pointer_cast<CRS>(ProjectedCRS::create(
+ props, projCRS->baseCRS(), projCRS->derivingConversion(), cs));
}
}
@@ -697,14 +696,26 @@ CRSNNPtr CRS::normalizeForVisualization() const {
* The method returns a list of matching reference CRS, and the percentage
* (0-100) of confidence in the match. The list is sorted by decreasing
* confidence.
- *
- * 100% means that the name of the reference entry
+ * <ul>
+ * <li>100% means that the name of the reference entry
* perfectly matches the CRS name, and both are equivalent. In which case a
* single result is returned.
- * 90% means that CRS are equivalent, but the names are not exactly the same.
- * 70% means that CRS are equivalent), but the names do not match at all.
- * 25% means that the CRS are not equivalent, but there is some similarity in
- * the names.
+ * Note: in the case of a GeographicCRS whose axis
+ * order is implicit in the input definition (for example ESRI WKT), then axis
+ * order is ignored for the purpose of identification. That is the CRS built
+ * from
+ * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],
+ * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
+ * will be identified to EPSG:4326, but will not pass a
+ * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test,
+ * but rather isEquivalentTo(EPSG_4326,
+ * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)
+ * </li>
+ * <li>90% means that CRS are equivalent, but the names are not exactly the same.</li>
+ * <li>70% means that CRS are equivalent), but the names do not match at all.</li>
+ * <li>25% means that the CRS are not equivalent, but there is some similarity in
+ * the names.</li>
+ * </ul>
* Other confidence values may be returned by some specialized implementations.
*
* This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and
@@ -829,7 +840,7 @@ CRSNNPtr CRS::promoteTo3D(const std::string &newName,
!newName.empty() ? newName : nameStr()),
NN_NO_CHECK(
util::nn_dynamic_pointer_cast<GeodeticCRS>(base3DCRS)),
- projCRS->derivingConversionRef(), cs));
+ projCRS->derivingConversion(), cs));
}
}
@@ -1554,17 +1565,30 @@ static bool hasCodeCompatibleOfAuthorityFactory(
* authorityFactory is not null.
*
* The method returns a list of matching reference CRS, and the percentage
- * (0-100) of confidence in the match.
- * 100% means that the name of the reference entry
+ * (0-100) of confidence in the match:
+ * <ul>
+ * <li>100% means that the name of the reference entry
* perfectly matches the CRS name, and both are equivalent. In which case a
* single result is returned.
- * 90% means that CRS are equivalent, but the names are not exactly the same.
- * 70% means that CRS are equivalent (equivalent datum and coordinate system),
- * but the names do not match at all.
- * 60% means that ellipsoid, prime meridian and coordinate systems are
- * equivalent, but the CRS and datum names do not match.
- * 25% means that the CRS are not equivalent, but there is some similarity in
- * the names.
+ * Note: in the case of a GeographicCRS whose axis
+ * order is implicit in the input definition (for example ESRI WKT), then axis
+ * order is ignored for the purpose of identification. That is the CRS built
+ * from
+ * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],
+ * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
+ * will be identified to EPSG:4326, but will not pass a
+ * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test,
+ * but rather isEquivalentTo(EPSG_4326,
+ * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)
+ * </li>
+ * <li>90% means that CRS are equivalent, but the names are not exactly the same.
+ * <li>70% means that CRS are equivalent (equivalent datum and coordinate system),
+ * but the names do not match at all.</li>
+ * <li>60% means that ellipsoid, prime meridian and coordinate systems are
+ * equivalent, but the CRS and datum names do not match.</li>
+ * <li>25% means that the CRS are not equivalent, but there is some similarity in
+ * the names.</li>
+ * </ul>
*
* @param authorityFactory Authority factory (or null, but degraded
* functionality)
@@ -3218,10 +3242,10 @@ bool ProjectedCRS::_isEquivalentTo(
ProjectedCRSNNPtr
ProjectedCRS::alterParametersLinearUnit(const common::UnitOfMeasure &unit,
bool convertToNewUnit) const {
- return create(createPropertyMap(this), baseCRS(),
- derivingConversionRef()->alterParametersLinearUnit(
- unit, convertToNewUnit),
- coordinateSystem());
+ return create(
+ createPropertyMap(this), baseCRS(),
+ derivingConversion()->alterParametersLinearUnit(unit, convertToNewUnit),
+ coordinateSystem());
}
//! @endcond
@@ -3239,13 +3263,16 @@ void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter,
if (!formatter->getCRSExport()) {
formatter->addStep("unitconvert");
formatter->addParam("xy_in", "m");
- formatter->addParam("z_in", "m");
+ if (!formatter->omitZUnitConversion())
+ formatter->addParam("z_in", "m");
if (projUnit.empty()) {
formatter->addParam("xy_out", toSI);
- formatter->addParam("z_out", toSI);
+ if (!formatter->omitZUnitConversion())
+ formatter->addParam("z_out", toSI);
} else {
formatter->addParam("xy_out", projUnit);
- formatter->addParam("z_out", projUnit);
+ if (!formatter->omitZUnitConversion())
+ formatter->addParam("z_out", projUnit);
}
} else {
if (projUnit.empty()) {
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index a9607247..c0628270 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -3185,7 +3185,16 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI(
}
}
- const auto *wkt2_mapping = getMapping(esriMapping->wkt2_name);
+ const char *projectionMethodWkt2Name = esriMapping->wkt2_name;
+ if (ci_equal(esriProjectionName, "Krovak")) {
+ const std::string projCRSName =
+ stripQuotes(projCRSNode->GP()->children()[0]);
+ if (projCRSName.find("_East_North") != std::string::npos) {
+ projectionMethodWkt2Name = EPSG_NAME_METHOD_KROVAK_NORTH_ORIENTED;
+ }
+ }
+
+ const auto *wkt2_mapping = getMapping(projectionMethodWkt2Name);
if (ci_equal(esriProjectionName, "Stereographic")) {
try {
if (std::fabs(io::asDouble(
@@ -3467,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();
@@ -3487,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,
@@ -3499,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,
@@ -3522,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)
diff --git a/src/pipeline.cpp b/src/pipeline.cpp
index afa3b19a..76ffc98e 100644
--- a/src/pipeline.cpp
+++ b/src/pipeline.cpp
@@ -105,6 +105,7 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-20
#include "geodesic.h"
#include "proj.h"
#include "proj_internal.h"
+#include "proj_experimental.h"
PROJ_HEAD(pipeline, "Transformation pipeline manager");
PROJ_HEAD(pop, "Retrieve coordinate value from pipeline stack");
@@ -136,7 +137,11 @@ static PJ_LPZ pipeline_reverse_3d (PJ_XYZ xyz, PJ *P);
static PJ_XY pipeline_forward (PJ_LP lp, PJ *P);
static PJ_LP pipeline_reverse (PJ_XY xy, PJ *P);
-
+void pj_pipeline_assign_context_to_steps( PJ* P, PJ_CONTEXT* ctx )
+{
+ for (int i = 1; i <= static_cast<struct pj_opaque*>(P->opaque)->steps; i++)
+ proj_assign_context(static_cast<struct pj_opaque*>(P->opaque)->pipeline[i], ctx);
+}
static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) {
diff --git a/src/proj.h b/src/proj.h
index 7a47f043..73c1165d 100644
--- a/src/proj.h
+++ b/src/proj.h
@@ -154,7 +154,7 @@ extern "C" {
/* The version numbers should be updated with every release! **/
#define PROJ_VERSION_MAJOR 6
#define PROJ_VERSION_MINOR 2
-#define PROJ_VERSION_PATCH 0
+#define PROJ_VERSION_PATCH 1
extern char const PROJ_DLL pj_release[]; /* global release id string */
diff --git a/src/proj_api.h b/src/proj_api.h
index b933fc6b..23eecfa7 100644
--- a/src/proj_api.h
+++ b/src/proj_api.h
@@ -38,7 +38,7 @@
#endif
#ifndef PJ_VERSION
-#define PJ_VERSION 620
+#define PJ_VERSION 621
#endif
#ifdef PROJ_RENAME_SYMBOLS
diff --git a/src/proj_internal.h b/src/proj_internal.h
index 4a126e98..77c4ba17 100644
--- a/src/proj_internal.h
+++ b/src/proj_internal.h
@@ -926,6 +926,8 @@ std::string pj_double_quote_string_param_if_needed(const std::string& str);
PJ *pj_create_internal (PJ_CONTEXT *ctx, const char *definition);
PJ *pj_create_argv_internal (PJ_CONTEXT *ctx, int argc, char **argv);
+void pj_pipeline_assign_context_to_steps( PJ* P, PJ_CONTEXT* ctx );
+
/* classic public API */
#include "proj_api.h"
diff --git a/src/projections/ob_tran.cpp b/src/projections/ob_tran.cpp
index 4ae8dbe7..badc6dd8 100644
--- a/src/projections/ob_tran.cpp
+++ b/src/projections/ob_tran.cpp
@@ -31,8 +31,10 @@ static PJ_XY o_forward(PJ_LP lp, PJ *P) { /* spheroid */
coslam = cos(lp.lam);
sinphi = sin(lp.phi);
cosphi = cos(lp.phi);
+ /* Formula (5-8b) of Snyder's "Map projections: a working manual" */
lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam +
Q->cphip * sinphi) + Q->lamp);
+ /* Formula (5-7) */
lp.phi = aasin(P->ctx,Q->sphip * sinphi - Q->cphip * cosphi * coslam);
return Q->link->fwd(lp, Q->link);
@@ -62,7 +64,9 @@ static PJ_LP o_inverse(PJ_XY xy, PJ *P) { /* spheroid */
coslam = cos(lp.lam -= Q->lamp);
sinphi = sin(lp.phi);
cosphi = cos(lp.phi);
+ /* Formula (5-9) */
lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam);
+ /* Formula (5-10b) */
lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam -
Q->cphip * sinphi);
}
diff --git a/src/release.cpp b/src/release.cpp
index 13ed45f0..7f62da3f 100644
--- a/src/release.cpp
+++ b/src/release.cpp
@@ -11,7 +11,7 @@ char const pj_release[] =
STR(PROJ_VERSION_MAJOR)"."
STR(PROJ_VERSION_MINOR)"."
STR(PROJ_VERSION_PATCH)", "
- "September 1st, 2019";
+ "November 1st, 2019";
const char *pj_get_release() {
return pj_release;