aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/4D_api.cpp7
-rw-r--r--src/iso19111/io.cpp319
-rw-r--r--test/unit/test_factory.cpp6
-rw-r--r--test/unit/test_io.cpp33
-rw-r--r--test/unit/test_operation.cpp6
5 files changed, 238 insertions, 133 deletions
diff --git a/src/4D_api.cpp b/src/4D_api.cpp
index 642fbb1f..9f88730b 100644
--- a/src/4D_api.cpp
+++ b/src/4D_api.cpp
@@ -456,6 +456,9 @@ Returns 1 on success, 0 on failure
/* Swap axes? */
p = pj_param_exists (P->params, "axis");
+ const bool disable_grid_presence_check = pj_param_exists (
+ P->params, "disable_grid_presence_check") != nullptr;
+
/* Don't axisswap if data are already in "enu" order */
if (p && (0!=strcmp ("enu", p->param))) {
char *def = static_cast<char*>(malloc (100+strlen(P->axis)));
@@ -471,7 +474,7 @@ Returns 1 on success, 0 on failure
/* Geoid grid(s) given? */
p = pj_param_exists (P->params, "geoidgrids");
- if (p && strlen (p->param) > strlen ("geoidgrids=")) {
+ if (!disable_grid_presence_check && p && strlen (p->param) > strlen ("geoidgrids=")) {
char *gridnames = p->param + strlen ("geoidgrids=");
char *def = static_cast<char*>(malloc (100+2*strlen(gridnames)));
if (nullptr==def)
@@ -487,7 +490,7 @@ Returns 1 on success, 0 on failure
/* Datum shift grid(s) given? */
p = pj_param_exists (P->params, "nadgrids");
- if (p && strlen (p->param) > strlen ("nadgrids=")) {
+ if (!disable_grid_presence_check && p && strlen (p->param) > strlen ("nadgrids=")) {
char *gridnames = p->param + strlen ("nadgrids=");
char *def = static_cast<char*>(malloc (100+2*strlen(gridnames)));
if (nullptr==def)
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 0722c22a..b3cd83d6 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -4692,6 +4692,7 @@ struct Step {
struct KeyValue {
std::string key{};
std::string value{};
+ bool usedByParser = false; // only for PROJStringParser used
explicit KeyValue(const std::string &keyIn) : key(keyIn) {}
@@ -5265,7 +5266,7 @@ void PROJStringFormatter::setCoordinateOperationOptimizations(bool enable) {
void PROJStringFormatter::Private::appendToResult(const char *str) {
if (!result_.empty()) {
- result_ += " ";
+ result_ += ' ';
}
result_ += str;
}
@@ -5735,16 +5736,20 @@ struct PROJStringParser::Private {
std::vector<Step::KeyValue> globalParamValues_{};
std::string title_{};
+ bool ignoreNadgrids_ = false;
+
template <class T>
// cppcheck-suppress functionStatic
- bool hasParamValue(const Step &step, const T key) {
- for (const auto &pair : globalParamValues_) {
+ bool hasParamValue(Step &step, const T key) {
+ for (auto &pair : globalParamValues_) {
if (ci_equal(pair.key, key)) {
+ pair.usedByParser = true;
return true;
}
}
- for (const auto &pair : step.paramValues) {
+ for (auto &pair : step.paramValues) {
if (ci_equal(pair.key, key)) {
+ pair.usedByParser = true;
return true;
}
}
@@ -5753,9 +5758,10 @@ struct PROJStringParser::Private {
template <class T>
// cppcheck-suppress functionStatic
- const std::string &getGlobalParamValue(const T key) {
- for (const auto &pair : globalParamValues_) {
+ const std::string &getGlobalParamValue(T key) {
+ for (auto &pair : globalParamValues_) {
if (ci_equal(pair.key, key)) {
+ pair.usedByParser = true;
return pair.value;
}
}
@@ -5764,24 +5770,26 @@ struct PROJStringParser::Private {
template <class T>
// cppcheck-suppress functionStatic
- const std::string &getParamValue(const Step &step, const T key) {
- for (const auto &pair : globalParamValues_) {
+ const std::string &getParamValue(Step &step, const T key) {
+ for (auto &pair : globalParamValues_) {
if (ci_equal(pair.key, key)) {
+ pair.usedByParser = true;
return pair.value;
}
}
- for (const auto &pair : step.paramValues) {
+ for (auto &pair : step.paramValues) {
if (ci_equal(pair.key, key)) {
+ pair.usedByParser = true;
return pair.value;
}
}
return emptyString;
}
- // cppcheck-suppress functionStatic
- const std::string &getParamValueK(const Step &step) {
- for (const auto &pair : step.paramValues) {
+ static const std::string &getParamValueK(Step &step) {
+ for (auto &pair : step.paramValues) {
if (ci_equal(pair.key, "k") || ci_equal(pair.key, "k_0")) {
+ pair.usedByParser = true;
return pair.value;
}
}
@@ -5789,10 +5797,22 @@ struct PROJStringParser::Private {
}
// cppcheck-suppress functionStatic
+ bool hasUnusedParameters(const Step &step) const {
+ if (steps_.size() == 1) {
+ for (const auto &pair : step.paramValues) {
+ if (pair.key != "no_defs" && !pair.usedByParser) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // cppcheck-suppress functionStatic
std::string guessBodyName(double a);
- PrimeMeridianNNPtr buildPrimeMeridian(const Step &step);
- GeodeticReferenceFrameNNPtr buildDatum(const Step &step,
+ PrimeMeridianNNPtr buildPrimeMeridian(Step &step);
+ GeodeticReferenceFrameNNPtr buildDatum(Step &step,
const std::string &title);
GeographicCRSNNPtr buildGeographicCRS(int iStep, int iUnitConvert,
int iAxisSwap, bool ignoreVUnits,
@@ -5801,7 +5821,7 @@ struct PROJStringParser::Private {
CRSNNPtr buildProjectedCRS(int iStep, GeographicCRSNNPtr geogCRS,
int iUnitConvert, int iAxisSwap);
CRSNNPtr buildBoundOrCompoundCRSIfNeeded(int iStep, CRSNNPtr crs);
- UnitOfMeasure buildUnit(const Step &step, const std::string &unitsParamName,
+ UnitOfMeasure buildUnit(Step &step, const std::string &unitsParamName,
const std::string &toMeterParamName);
CoordinateOperationNNPtr buildHelmertTransformation(
int iStep, int iFirstAxisSwap = -1, int iFirstUnitConvert = -1,
@@ -5815,7 +5835,7 @@ struct PROJStringParser::Private {
enum class AxisType { REGULAR, NORTH_POLE, SOUTH_POLE };
std::vector<CoordinateSystemAxisNNPtr>
- processAxisSwap(const Step &step, const UnitOfMeasure &unit, int iAxisSwap,
+ processAxisSwap(Step &step, const UnitOfMeasure &unit, int iAxisSwap,
AxisType axisType, bool ignorePROJAxis);
EllipsoidalCSNNPtr buildEllipsoidalCS(int iStep, int iUnitConvert,
@@ -5958,7 +5978,7 @@ static UnitOfMeasure _buildUnit(double to_meter_value) {
// ---------------------------------------------------------------------------
UnitOfMeasure
-PROJStringParser::Private::buildUnit(const Step &step,
+PROJStringParser::Private::buildUnit(Step &step,
const std::string &unitsParamName,
const std::string &toMeterParamName) {
UnitOfMeasure unit = UnitOfMeasure::METRE;
@@ -6067,8 +6087,7 @@ static PropertyMap createMapWithUnknownName() {
// ---------------------------------------------------------------------------
-PrimeMeridianNNPtr
-PROJStringParser::Private::buildPrimeMeridian(const Step &step) {
+PrimeMeridianNNPtr PROJStringParser::Private::buildPrimeMeridian(Step &step) {
PrimeMeridianNNPtr pm = PrimeMeridian::GREENWICH;
const auto &pmStr = getParamValue(step, "pm");
@@ -6116,8 +6135,7 @@ std::string PROJStringParser::Private::guessBodyName(double a) {
// ---------------------------------------------------------------------------
GeodeticReferenceFrameNNPtr
-PROJStringParser::Private::buildDatum(const Step &step,
- const std::string &title) {
+PROJStringParser::Private::buildDatum(Step &step, const std::string &title) {
const auto &ellpsStr = getParamValue(step, "ellps");
const auto &datumStr = getParamValue(step, "datum");
@@ -6434,7 +6452,7 @@ createAxis(const std::string &name, const std::string &abbreviation,
}
std::vector<CoordinateSystemAxisNNPtr>
-PROJStringParser::Private::processAxisSwap(const Step &step,
+PROJStringParser::Private::processAxisSwap(Step &step,
const UnitOfMeasure &unit,
int iAxisSwap, AxisType axisType,
bool ignorePROJAxis) {
@@ -6511,7 +6529,7 @@ PROJStringParser::Private::processAxisSwap(const Step &step,
throw ParsingException("Unhandled axis=" + axisStr);
}
} else if (iAxisSwap >= 0) {
- const auto &stepAxisSwap = steps_[iAxisSwap];
+ auto &stepAxisSwap = steps_[iAxisSwap];
const auto &orderStr = getParamValue(stepAxisSwap, "order");
auto orderTab = split(orderStr, ',');
if (orderTab.size() != 2) {
@@ -6544,13 +6562,13 @@ EllipsoidalCSNNPtr
PROJStringParser::Private::buildEllipsoidalCS(int iStep, int iUnitConvert,
int iAxisSwap, bool ignoreVUnits,
bool ignorePROJAxis) {
- const auto &step = steps_[iStep];
+ auto &step = steps_[iStep];
assert(iUnitConvert < 0 ||
ci_equal(steps_[iUnitConvert].name, "unitconvert"));
UnitOfMeasure angularUnit = UnitOfMeasure::DEGREE;
if (iUnitConvert >= 0) {
- const auto &stepUnitConvert = steps_[iUnitConvert];
+ auto &stepUnitConvert = steps_[iUnitConvert];
const std::string *xy_in = &getParamValue(stepUnitConvert, "xy_in");
const std::string *xy_out = &getParamValue(stepUnitConvert, "xy_out");
if (stepUnitConvert.inverted) {
@@ -6606,32 +6624,36 @@ GeographicCRSNNPtr
PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert,
int iAxisSwap, bool ignoreVUnits,
bool ignorePROJAxis) {
- const auto &step = steps_[iStep];
+ auto &step = steps_[iStep];
const bool l_isGeographicStep = isGeographicStep(step.name);
const auto &title = l_isGeographicStep ? title_ : emptyString;
+ // units=m is often found in the wild.
+ // No need to create a extension string for this
+ hasParamValue(step, "units");
+
auto datum = buildDatum(step, title);
auto props = PropertyMap().set(IdentifiedObject::NAME_KEY,
title.empty() ? "unknown" : title);
+ auto cs = buildEllipsoidalCS(iStep, iUnitConvert, iAxisSwap, ignoreVUnits,
+ ignorePROJAxis);
+
if (l_isGeographicStep &&
- (hasParamValue(step, "wktext") ||
- hasParamValue(step, "lon_wrap") | hasParamValue(step, "geoc") ||
+ (hasUnusedParameters(step) ||
getNumericValue(getParamValue(step, "lon_0")) != 0.0)) {
props.set("EXTENSION_PROJ4", projString_);
}
- return GeographicCRS::create(
- props, datum, buildEllipsoidalCS(iStep, iUnitConvert, iAxisSwap,
- ignoreVUnits, ignorePROJAxis));
+ return GeographicCRS::create(props, datum, cs);
}
// ---------------------------------------------------------------------------
GeodeticCRSNNPtr
PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) {
- const auto &step = steps_[iStep];
+ auto &step = steps_[iStep];
assert(isGeocentricStep(step.name));
assert(iUnitConvert < 0 ||
@@ -6643,7 +6665,7 @@ PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) {
UnitOfMeasure unit = UnitOfMeasure::METRE;
if (iUnitConvert >= 0) {
- const auto &stepUnitConvert = steps_[iUnitConvert];
+ auto &stepUnitConvert = steps_[iUnitConvert];
const std::string *xy_in = &getParamValue(stepUnitConvert, "xy_in");
const std::string *xy_out = &getParamValue(stepUnitConvert, "xy_out");
const std::string *z_in = &getParamValue(stepUnitConvert, "z_in");
@@ -6677,11 +6699,12 @@ PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) {
auto props = PropertyMap().set(IdentifiedObject::NAME_KEY,
title.empty() ? "unknown" : title);
- if (hasParamValue(step, "wktext")) {
+ auto cs = CartesianCS::createGeocentric(unit);
+
+ if (hasUnusedParameters(step)) {
props.set("EXTENSION_PROJ4", projString_);
}
- auto cs = CartesianCS::createGeocentric(unit);
return GeodeticCRS::create(props, datum, cs);
}
@@ -6690,11 +6713,11 @@ PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) {
CRSNNPtr
PROJStringParser::Private::buildBoundOrCompoundCRSIfNeeded(int iStep,
CRSNNPtr crs) {
- const auto &step = steps_[iStep];
+ auto &step = steps_[iStep];
const auto &nadgrids = getParamValue(step, "nadgrids");
const auto &towgs84 = getParamValue(step, "towgs84");
// nadgrids has the priority over towgs84
- if (!nadgrids.empty()) {
+ if (!ignoreNadgrids_ && !nadgrids.empty()) {
crs = BoundCRS::createFromNadgrids(crs, nadgrids);
} else if (!towgs84.empty()) {
std::vector<double> towgs84Values;
@@ -6847,7 +6870,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
EPSG_CODE_METHOD_POPULAR_VISUALISATION_PSEUDO_MERCATOR);
for (size_t i = 0; i < step.paramValues.size(); ++i) {
if (ci_equal(step.paramValues[i].key, "nadgrids")) {
- step.paramValues.erase(step.paramValues.begin() + i);
+ ignoreNadgrids_ = true;
break;
}
}
@@ -6909,7 +6932,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
UnitOfMeasure unit = buildUnit(step, "units", "to_meter");
if (iUnitConvert >= 0) {
- const auto &stepUnitConvert = steps_[iUnitConvert];
+ auto &stepUnitConvert = steps_[iUnitConvert];
const std::string *xy_in = &getParamValue(stepUnitConvert, "xy_in");
const std::string *xy_out = &getParamValue(stepUnitConvert, "xy_out");
if (stepUnitConvert.inverted) {
@@ -7102,8 +7125,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
auto props = PropertyMap().set(IdentifiedObject::NAME_KEY,
title.empty() ? "unknown" : title);
-
- if (hasParamValue(step, "wktext")) {
+ if (hasUnusedParameters(step)) {
props.set("EXTENSION_PROJ4", projString_);
}
@@ -7122,7 +7144,6 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
crs = CompoundCRS::create(mapWithUnknownName,
std::vector<CRSNNPtr>{crs, vcrs});
}
-
return crs;
}
@@ -7439,16 +7460,11 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
}
}
- if (((d->steps_.size() == 1 &&
+ const bool isGeocentricCRS =
+ ((d->steps_.size() == 1 &&
d->getParamValue(d->steps_[0], "type") == "crs") ||
(d->steps_.size() == 2 && d->steps_[1].name == "unitconvert")) &&
- !d->steps_[0].inverted && isGeocentricStep(d->steps_[0].name)) {
- return d->buildBoundOrCompoundCRSIfNeeded(
- 0, d->buildGeocentricCRS(0, (d->steps_.size() == 2 &&
- d->steps_[1].name == "unitconvert")
- ? 1
- : -1));
- }
+ !d->steps_[0].inverted && isGeocentricStep(d->steps_[0].name);
// +init=xxxx:yyyy syntax
if (d->steps_.size() == 1 && d->steps_[0].isInit &&
@@ -7691,60 +7707,133 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
unexpectedStructure = true;
}
- if (unexpectedStructure || iHelmert >= 0 || iMolodensky >= 0) {
- struct Logger {
- std::string msg{};
+ struct Logger {
+ std::string msg{};
- // cppcheck-suppress functionStatic
- void setMessage(const char *msgIn) noexcept {
- try {
- msg = msgIn;
- } catch (const std::exception &) {
- }
+ // cppcheck-suppress functionStatic
+ void setMessage(const char *msgIn) noexcept {
+ try {
+ msg = msgIn;
+ } catch (const std::exception &) {
}
+ }
- static void log(void *user_data, int level, const char *msg) {
- if (level == PJ_LOG_ERROR) {
- static_cast<Logger *>(user_data)->setMessage(msg);
- }
+ static void log(void *user_data, int level, const char *msg) {
+ if (level == PJ_LOG_ERROR) {
+ static_cast<Logger *>(user_data)->setMessage(msg);
}
- };
+ }
+ };
- // If the structure is not recognized, then try to instantiate the
- // pipeline, and if successful, wrap it in a PROJBasedOperation
- Logger logger;
- bool valid;
+ // If the structure is not recognized, then try to instantiate the
+ // pipeline, and if successful, wrap it in a PROJBasedOperation
+ Logger logger;
+ bool valid;
+
+ auto pj_context = d->ctx_ ? d->ctx_ : proj_context_create();
+ if (!pj_context) {
+ throw ParsingException("out of memory");
+ }
+ if (pj_context != d->ctx_) {
+ proj_log_func(pj_context, &logger, Logger::log);
+ proj_context_use_proj4_init_rules(pj_context, d->usePROJ4InitRules_);
+ }
+ auto pj = pj_create_internal(
+ pj_context, (projString.find("type=crs") != std::string::npos
+ ? projString + " +disable_grid_presence_check"
+ : projString)
+ .c_str());
+ valid = pj != nullptr;
+
+ // Remove parameters not understood by PROJ.
+ if (valid && d->steps_.size() == 1) {
+ std::vector<Step::KeyValue> newParamValues{};
+ std::set<std::string> foundKeys;
+ auto &step = d->steps_[0];
+
+ for (auto &kv : step.paramValues) {
+ bool recognizedByPROJ = false;
+ if (foundKeys.find(kv.key) != foundKeys.end()) {
+ continue;
+ }
+ foundKeys.insert(kv.key);
+ if (step.name == "krovak" && kv.key == "alpha") {
+ // We recognize it in our CRS parsing code
+ recognizedByPROJ = true;
+ } else {
+ for (auto cur = pj->params; cur; cur = cur->next) {
+ const char *equal = strchr(cur->param, '=');
+ if (equal &&
+ static_cast<size_t>(equal - cur->param) ==
+ kv.key.size()) {
+ if (memcmp(cur->param, kv.key.c_str(), kv.key.size()) ==
+ 0) {
+ recognizedByPROJ = (cur->used == 1);
+ break;
+ }
+ } else if (strcmp(cur->param, kv.key.c_str()) == 0) {
+ recognizedByPROJ = (cur->used == 1);
+ break;
+ }
+ }
+ }
+ if (recognizedByPROJ) {
+ newParamValues.emplace_back(kv);
+ }
+ }
+ step.paramValues = newParamValues;
- auto pj_context = d->ctx_ ? d->ctx_ : proj_context_create();
- if (!pj_context) {
- throw ParsingException("out of memory");
+ d->projString_.clear();
+ if (!step.name.empty()) {
+ d->projString_ += step.isInit ? "+init=" : "+proj=";
+ d->projString_ += step.name;
}
- if (pj_context != d->ctx_) {
- proj_log_func(pj_context, &logger, Logger::log);
- proj_context_use_proj4_init_rules(pj_context,
- d->usePROJ4InitRules_);
- }
- auto pj = pj_create_internal(pj_context, projString.c_str());
- valid = pj != nullptr;
- proj_destroy(pj);
-
- if (!valid) {
- std::string prefix("Error " +
- toString(proj_context_errno(pj_context)) + ": ");
- if (logger.msg.empty()) {
- logger.msg =
- prefix + proj_errno_string(proj_context_errno(pj_context));
- } else {
- logger.msg = prefix + logger.msg;
+ for (const auto &paramValue : step.paramValues) {
+ if (!d->projString_.empty()) {
+ d->projString_ += ' ';
+ }
+ d->projString_ += '+';
+ d->projString_ += paramValue.key;
+ if (!paramValue.value.empty()) {
+ d->projString_ += '=';
+ d->projString_ +=
+ pj_double_quote_string_param_if_needed(paramValue.value);
}
}
+ }
+
+ proj_destroy(pj);
- if (pj_context != d->ctx_) {
- proj_context_destroy(pj_context);
+ if (!valid) {
+ std::string prefix("Error " + toString(proj_context_errno(pj_context)) +
+ ": ");
+ if (logger.msg.empty()) {
+ logger.msg =
+ prefix + proj_errno_string(proj_context_errno(pj_context));
+ } else {
+ logger.msg = prefix + logger.msg;
}
+ }
+
+ if (pj_context != d->ctx_) {
+ proj_context_destroy(pj_context);
+ }
- if (!valid) {
- throw ParsingException(logger.msg);
+ if (!valid) {
+ throw ParsingException(logger.msg);
+ }
+
+ if (isGeocentricCRS) {
+ // First run is dry run to mark all recognized/unrecognized tokens
+ for (int iter = 0; iter < 2; iter++) {
+ auto obj = d->buildBoundOrCompoundCRSIfNeeded(
+ 0, d->buildGeocentricCRS(0, (d->steps_.size() == 2 &&
+ d->steps_[1].name == "unitconvert")
+ ? 1
+ : -1));
+ if (iter == 1) {
+ return nn_static_pointer_cast<BaseObject>(obj);
+ }
}
}
@@ -7755,9 +7844,16 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
(iFirstUnitConvert < 0 || iSecondUnitConvert < 0) &&
(iFirstAxisSwap < 0 || iSecondAxisSwap < 0)) {
const bool ignoreVUnits = false;
- return d->buildBoundOrCompoundCRSIfNeeded(
- 0, d->buildGeographicCRS(iFirstGeogStep, iFirstUnitConvert,
- iFirstAxisSwap, ignoreVUnits, false));
+ // First run is dry run to mark all recognized/unrecognized tokens
+ for (int iter = 0; iter < 2; iter++) {
+ auto obj = d->buildBoundOrCompoundCRSIfNeeded(
+ 0,
+ d->buildGeographicCRS(iFirstGeogStep, iFirstUnitConvert,
+ iFirstAxisSwap, ignoreVUnits, false));
+ if (iter == 1) {
+ return nn_static_pointer_cast<BaseObject>(obj);
+ }
+ }
}
if (iProjStep >= 0 && !d->steps_[iProjStep].inverted &&
(iFirstGeogStep < 0 || iFirstGeogStep + 1 == iProjStep) &&
@@ -7766,20 +7862,27 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
if (iFirstGeogStep < 0)
iFirstGeogStep = iProjStep;
const bool ignoreVUnits = true;
- return d->buildBoundOrCompoundCRSIfNeeded(
- iProjStep,
- d->buildProjectedCRS(
+ // First run is dry run to mark all recognized/unrecognized tokens
+ for (int iter = 0; iter < 2; iter++) {
+ auto obj = d->buildBoundOrCompoundCRSIfNeeded(
iProjStep,
- d->buildGeographicCRS(
- iFirstGeogStep,
- iFirstUnitConvert < iFirstGeogStep ? iFirstUnitConvert
- : -1,
- iFirstAxisSwap < iFirstGeogStep ? iFirstAxisSwap : -1,
- ignoreVUnits, true),
- iFirstUnitConvert < iFirstGeogStep ? iSecondUnitConvert
- : iFirstUnitConvert,
- iFirstAxisSwap < iFirstGeogStep ? iSecondAxisSwap
- : iFirstAxisSwap));
+ d->buildProjectedCRS(
+ iProjStep,
+ d->buildGeographicCRS(
+ iFirstGeogStep, iFirstUnitConvert < iFirstGeogStep
+ ? iFirstUnitConvert
+ : -1,
+ iFirstAxisSwap < iFirstGeogStep ? iFirstAxisSwap
+ : -1,
+ ignoreVUnits, true),
+ iFirstUnitConvert < iFirstGeogStep ? iSecondUnitConvert
+ : iFirstUnitConvert,
+ iFirstAxisSwap < iFirstGeogStep ? iSecondAxisSwap
+ : iFirstAxisSwap));
+ if (iter == 1) {
+ return nn_static_pointer_cast<BaseObject>(obj);
+ }
+ }
}
if (iProjStep < 0 && iHelmert > 0 && iMolodensky < 0 &&
diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp
index 027c0188..a6f4ecf8 100644
--- a/test/unit/test_factory.cpp
+++ b/test/unit/test_factory.cpp
@@ -2324,8 +2324,7 @@ TEST_F(FactoryWithTmpDatabase, custom_projected_crs) {
EXPECT_EQ(crs->identifiers().size(), 1);
EXPECT_EQ(crs->derivingConversion()->targetCRS().get(), crs.get());
EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=mbt_s +unused_flag +datum=WGS84 +units=m +no_defs "
- "+type=crs");
+ "+proj=mbt_s +datum=WGS84 +units=m +no_defs +type=crs");
EXPECT_TRUE(crs->canonicalBoundCRS() == nullptr);
}
{
@@ -2334,8 +2333,7 @@ TEST_F(FactoryWithTmpDatabase, custom_projected_crs) {
EXPECT_EQ(crs->identifiers().size(), 1);
EXPECT_EQ(crs->derivingConversion()->targetCRS().get(), crs.get());
EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=mbt_s +unused_flag +datum=WGS84 +units=m +no_defs "
- "+type=crs");
+ "+proj=mbt_s +datum=WGS84 +units=m +no_defs +type=crs");
EXPECT_TRUE(crs->canonicalBoundCRS() != nullptr);
}
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 9bd3d70f..e4886553 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -7472,7 +7472,7 @@ TEST(io, projparse_cea_ellipsoidal) {
TEST(io, projparse_geos_sweep_x) {
auto obj = PROJStringParser().createFromPROJString(
- "+proj=geos +sweep=x +type=crs");
+ "+proj=geos +sweep=x +h=1 +type=crs");
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);
WKTFormatterNNPtr f(WKTFormatter::create());
@@ -7488,7 +7488,8 @@ TEST(io, projparse_geos_sweep_x) {
// ---------------------------------------------------------------------------
TEST(io, projparse_geos_sweep_y) {
- auto obj = PROJStringParser().createFromPROJString("+proj=geos +type=crs");
+ auto obj =
+ PROJStringParser().createFromPROJString("+proj=geos +h=1 +type=crs");
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);
WKTFormatterNNPtr f(WKTFormatter::create());
@@ -8100,7 +8101,7 @@ TEST(io, projparse_projected_vunits) {
TEST(io, projparse_projected_unknown) {
auto obj = PROJStringParser().createFromPROJString(
"+proj=mbt_s +unused_flag +lat_0=45 +lon_0=0 +k=1 +x_0=10 +y_0=0 "
- "+type=crs");
+ "+datum=WGS84 +type=crs");
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);
@@ -8111,8 +8112,8 @@ TEST(io, projparse_projected_unknown) {
crs->exportToWKT(f.get());
auto wkt = f->toString();
EXPECT_TRUE(
- wkt.find("CONVERSION[\"unknown\",METHOD[\"PROJ mbt_s "
- "unused_flag\"],PARAMETER[\"lat_0\",45,ANGLEUNIT["
+ wkt.find("CONVERSION[\"unknown\",METHOD[\"PROJ mbt_s\"],"
+ "PARAMETER[\"lat_0\",45,ANGLEUNIT["
"\"degree\",0.0174532925199433]],PARAMETER[\"lon_0\","
"0,ANGLEUNIT[\"degree\",0.0174532925199433]],"
"PARAMETER[\"k\",1,SCALEUNIT[\"unity\",1]],PARAMETER["
@@ -8130,8 +8131,8 @@ TEST(io, projparse_projected_unknown) {
"\"9122\"]]],"
"PROJECTION[\"custom_proj4\"],UNIT[\"metre\",1,AUTHORITY[\"EPSG\","
"\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],EXTENSION["
- "\"PROJ4\",\"+proj=mbt_s +datum=WGS84 +unused_flag +lat_0=45 "
- "+lon_0=0 +k=1 +x_0=10 +y_0=0 +wktext +no_defs\"]]";
+ "\"PROJ4\",\"+proj=mbt_s +lat_0=45 "
+ "+lon_0=0 +k=1 +x_0=10 +y_0=0 +datum=WGS84\"]]";
{
WKTFormatterNNPtr f(
@@ -8144,8 +8145,8 @@ TEST(io, projparse_projected_unknown) {
}
EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=mbt_s +unused_flag +lat_0=45 +lon_0=0 +k=1 +x_0=10 "
- "+y_0=0 +datum=WGS84 +units=m +no_defs +type=crs");
+ "+proj=mbt_s +lat_0=45 +lon_0=0 +k=1 +x_0=10 "
+ "+y_0=0 +datum=WGS84 +type=crs");
{
auto obj2 = WKTParser().createFromWKT(expected_wkt1);
@@ -8158,8 +8159,8 @@ TEST(io, projparse_projected_unknown) {
crs2->exportToWKT(f.get());
auto wkt = f->toString();
EXPECT_TRUE(
- wkt.find("CONVERSION[\"unknown\",METHOD[\"PROJ mbt_s "
- "unused_flag\"],PARAMETER[\"lat_0\",45,ANGLEUNIT["
+ wkt.find("CONVERSION[\"unknown\",METHOD[\"PROJ mbt_s\"],"
+ "PARAMETER[\"lat_0\",45,ANGLEUNIT["
"\"degree\",0.0174532925199433]],PARAMETER[\"lon_0\","
"0,ANGLEUNIT[\"degree\",0.0174532925199433]],"
"PARAMETER[\"k\",1,SCALEUNIT[\"unity\",1]],PARAMETER["
@@ -8274,7 +8275,7 @@ TEST(io, projparse_longlat_wktext) {
crs->exportToPROJString(
PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
.get()),
- input);
+ "+proj=longlat +datum=WGS84 +no_defs +type=crs");
}
// ---------------------------------------------------------------------------
@@ -8288,7 +8289,7 @@ TEST(io, projparse_geocent_wktext) {
crs->exportToPROJString(
PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
.get()),
- input);
+ "+proj=geocent +datum=WGS84 +units=m +no_defs +type=crs");
}
// ---------------------------------------------------------------------------
@@ -8302,7 +8303,8 @@ TEST(io, projparse_projected_wktext) {
crs->exportToPROJString(
PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_4)
.get()),
- input);
+ "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs "
+ "+type=crs");
}
// ---------------------------------------------------------------------------
@@ -8312,8 +8314,7 @@ TEST(io, projparse_ob_tran_longlat) {
"+type=crs +proj=pipeline +step +proj=axisswap +order=2,1 +step "
"+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=ob_tran "
"+o_proj=longlat +o_lat_p=52 +o_lon_p=-30 +lon_0=-25 +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step "
- "+proj=axisswap +order=2,1");
+ "+step +proj=axisswap +order=2,1");
auto obj = PROJStringParser().createFromPROJString(input);
auto crs = nn_dynamic_pointer_cast<DerivedGeographicCRS>(obj);
ASSERT_TRUE(crs != nullptr);
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index ed31f155..01c6a38f 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -6323,8 +6323,8 @@ TEST(operation, createOperation_fallback_to_proj4_strings) {
TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) {
auto objSrc = PROJStringParser().createFromPROJString(
"+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
- "+units=m +no_defs +nadgrids=GDA94_GDA2020_conformal.gsb "
- "+type=crs");
+ "+units=m +no_defs +nadgrids=@GDA94_GDA2020_conformal.gsb +ignored1 "
+ "+ignored2=val +wktext +type=crs");
auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
ASSERT_TRUE(src != nullptr);
@@ -6340,7 +6340,7 @@ TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) {
EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline +step +inv +proj=utm +zone=55 +south "
"+ellps=GRS80 +step +proj=hgridshift "
- "+grids=GDA94_GDA2020_conformal.gsb +step +proj=utm +zone=55 "
+ "+grids=@GDA94_GDA2020_conformal.gsb +step +proj=utm +zone=55 "
"+south +ellps=GRS80");
}