diff options
| -rw-r--r-- | src/4D_api.cpp | 7 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 319 | ||||
| -rw-r--r-- | test/unit/test_factory.cpp | 6 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 33 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 6 |
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 ¶mValue : 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"); } |
