Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WKT1 import: better deal when the angular unit of the GEOGCS[] of the… #3274

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/proj/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,8 @@ class PROJ_GCC_DLL WKTParser {
PROJ_DLL WKTParser &setStrict(bool strict);
PROJ_DLL std::list<std::string> warningList() const;

PROJ_DLL WKTParser &setUnsetIdentifiersIfIncompatibleDef(bool unset);

PROJ_DLL util::BaseObjectNNPtr
createFromWKT(const std::string &wkt); // throw(ParsingException)

Expand Down
1 change: 1 addition & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ osgeo::proj::io::WKTParser::attachDatabaseContext(std::shared_ptr<osgeo::proj::i
osgeo::proj::io::WKTParser::createFromWKT(std::string const&)
osgeo::proj::io::WKTParser::guessDialect(std::string const&)
osgeo::proj::io::WKTParser::setStrict(bool)
osgeo::proj::io::WKTParser::setUnsetIdentifiersIfIncompatibleDef(bool)
osgeo::proj::io::WKTParser::warningList() const
osgeo::proj::io::WKTParser::~WKTParser()
osgeo::proj::io::WKTParser::WKTParser()
Expand Down
8 changes: 8 additions & 0 deletions src/iso19111/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,10 @@ PJ *proj_create(PJ_CONTEXT *ctx, const char *text) {
* <ul>
* <li>STRICT=YES/NO. Defaults to NO. When set to YES, strict validation will
* be enabled.</li>
* <li>UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF=YES/NO. Defaults to YES.
* When set to YES, object identifiers are unset when there is
* a contradiction between the definition from WKT and the one from
* the database./<li>
* </ul>
* @param out_warnings Pointer to a PROJ_STRING_LIST object, or NULL.
* If provided, *out_warnings will contain a list of warnings, typically for
Expand Down Expand Up @@ -639,6 +643,10 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
const char *value;
if ((value = getOptionValue(*iter, "STRICT="))) {
parser.setStrict(ci_equal(value, "YES"));
} else if ((value = getOptionValue(
*iter, "UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF="))) {
parser.setUnsetIdentifiersIfIncompatibleDef(
ci_equal(value, "YES"));
} else {
std::string msg("Unknown option :");
msg += *iter;
Expand Down
54 changes: 45 additions & 9 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,7 @@ struct WKTParser::Private {
};

bool strict_ = true;
bool unsetIdentifiersIfIncompatibleDef_ = true;
std::list<std::string> warningList_{};
std::vector<double> toWGS84Parameters_{};
std::string datumPROJ4Grids_{};
Expand Down Expand Up @@ -1503,6 +1504,20 @@ WKTParser &WKTParser::setStrict(bool strict) {

// ---------------------------------------------------------------------------

/** \brief Set whether object identifiers should be unset when there is
* a contradiction between the definition from WKT and the one from
* the database.
*
* At time of writing, this only applies to the base geographic CRS of a
* projected CRS, when comparing its coordinate system.
*/
WKTParser &WKTParser::setUnsetIdentifiersIfIncompatibleDef(bool unset) {
d->unsetIdentifiersIfIncompatibleDef_ = unset;
return *this;
}

// ---------------------------------------------------------------------------

/** \brief Return the list of warnings found during parsing.
*
* \note The list might be non-empty only is setStrict(false) has been called.
Expand Down Expand Up @@ -3084,19 +3099,40 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) {
!ellipsoidalCS->_isEquivalentTo(
dbCRS->coordinateSystem().get(),
util::IComparable::Criterion::EQUIVALENT)) {
emitRecoverableWarning(
"Coordinate system of GeographicCRS in the WKT "
"definition is different from the one of the "
"authority. Unsetting the identifier to avoid "
"confusion");
props.unset(Identifier::CODESPACE_KEY);
props.unset(Identifier::AUTHORITY_KEY);
props.unset(IdentifiedObject::IDENTIFIERS_KEY);
if (unsetIdentifiersIfIncompatibleDef_) {
emitRecoverableWarning(
"Coordinate system of GeographicCRS in the WKT "
"definition is different from the one of the "
"authority. Unsetting the identifier to avoid "
"confusion");
props.unset(Identifier::CODESPACE_KEY);
props.unset(Identifier::AUTHORITY_KEY);
props.unset(IdentifiedObject::IDENTIFIERS_KEY);
}
crs = GeographicCRS::create(props, datum, datumEnsemble,
NN_NO_CHECK(ellipsoidalCS));
} else if (dbCRS) {
auto csFromDB = dbCRS->coordinateSystem();
auto csFromDBAltered = csFromDB;
if (!isNull(nodeP->lookForChild(WKTConstants::UNIT))) {
csFromDBAltered =
csFromDB->alterAngularUnit(angularUnit);
if (unsetIdentifiersIfIncompatibleDef_ &&
!csFromDBAltered->_isEquivalentTo(
csFromDB.get(),
util::IComparable::Criterion::EQUIVALENT)) {
emitRecoverableWarning(
"Coordinate system of GeographicCRS in the WKT "
"definition is different from the one of the "
"authority. Unsetting the identifier to avoid "
"confusion");
props.unset(Identifier::CODESPACE_KEY);
props.unset(Identifier::AUTHORITY_KEY);
props.unset(IdentifiedObject::IDENTIFIERS_KEY);
}
}
crs = GeographicCRS::create(props, datum, datumEnsemble,
dbCRS->coordinateSystem());
csFromDBAltered);
}
}
return crs;
Expand Down
33 changes: 33 additions & 0 deletions test/unit/test_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,39 @@ TEST_F(CApi, proj_create_from_wkt) {
EXPECT_NE(errorList, nullptr);
proj_string_list_destroy(errorList);
}
{
PROJ_STRING_LIST warningList = nullptr;
PROJ_STRING_LIST errorList = nullptr;
const char *const options[] = {
"UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF=NO", nullptr};
auto wkt = "PROJCS[\"Merchich / Nord Maroc\","
" GEOGCS[\"Merchich\","
" DATUM[\"Merchich\","
" SPHEROID[\"Clarke 1880 (IGN)\","
"6378249.2,293.466021293627]],"
" PRIMEM[\"Greenwich\",0],"
" UNIT[\"grad\",0.015707963267949,"
" AUTHORITY[\"EPSG\",\"9105\"]],"
" AUTHORITY[\"EPSG\",\"4261\"]],"
" PROJECTION[\"Lambert_Conformal_Conic_1SP\"],"
" PARAMETER[\"latitude_of_origin\",37],"
" PARAMETER[\"central_meridian\",-6],"
" PARAMETER[\"scale_factor\",0.999625769],"
" PARAMETER[\"false_easting\",500000],"
" PARAMETER[\"false_northing\",300000],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
" AXIS[\"Easting\",EAST],"
" AXIS[\"Northing\",NORTH]]";
auto obj = proj_create_from_wkt(m_ctxt, wkt, options, &warningList,
&errorList);
ObjectKeeper keeper(obj);
EXPECT_NE(obj, nullptr);
EXPECT_EQ(warningList, nullptr);
proj_string_list_destroy(warningList);
EXPECT_EQ(errorList, nullptr);
proj_string_list_destroy(errorList);
}
{
PROJ_STRING_LIST warningList = nullptr;
PROJ_STRING_LIST errorList = nullptr;
Expand Down
95 changes: 84 additions & 11 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1260,19 +1260,92 @@ TEST(wkt_parse, wkt1_projected_wrong_axis_geogcs) {
" UNIT[\"metre\",1,\n"
" AUTHORITY[\"EPSG\",\"9001\"]],\n"
" AUTHORITY[\"EPSG\",\"32631\"]]";
WKTParser parser;
parser.setStrict(false).attachDatabaseContext(DatabaseContext::create());
auto obj = parser.createFromWKT(wkt);
EXPECT_TRUE(!parser.warningList().empty());
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);
{
WKTParser parser;
parser.setStrict(false).attachDatabaseContext(
DatabaseContext::create());
auto obj = parser.createFromWKT(wkt);
EXPECT_TRUE(!parser.warningList().empty());
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

EXPECT_TRUE(crs->baseCRS()->identifiers().empty());
EXPECT_TRUE(crs->baseCRS()->identifiers().empty());

auto cs = crs->baseCRS()->coordinateSystem();
ASSERT_EQ(cs->axisList().size(), 2U);
EXPECT_EQ(cs->axisList()[0]->direction(), AxisDirection::EAST);
EXPECT_EQ(cs->axisList()[1]->direction(), AxisDirection::NORTH);
auto cs = crs->baseCRS()->coordinateSystem();
ASSERT_EQ(cs->axisList().size(), 2U);
EXPECT_EQ(cs->axisList()[0]->direction(), AxisDirection::EAST);
EXPECT_EQ(cs->axisList()[1]->direction(), AxisDirection::NORTH);
}
{
WKTParser parser;
parser.setStrict(false)
.setUnsetIdentifiersIfIncompatibleDef(false)
.attachDatabaseContext(DatabaseContext::create());
auto obj = parser.createFromWKT(wkt);
EXPECT_TRUE(parser.warningList().empty());
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

EXPECT_TRUE(!crs->baseCRS()->identifiers().empty());
}
}

// ---------------------------------------------------------------------------

TEST(wkt_parse, wkt1_projected_wrong_angular_unit) {
auto wkt = "PROJCS[\"Merchich / Nord Maroc\","
" GEOGCS[\"Merchich\","
" DATUM[\"Merchich\","
" SPHEROID[\"Clarke 1880 (IGN)\","
"6378249.2,293.466021293627]],"
" PRIMEM[\"Greenwich\",0],"
" UNIT[\"grad\",0.015707963267949,"
" AUTHORITY[\"EPSG\",\"9105\"]],"
" AUTHORITY[\"EPSG\",\"4261\"]],"
" PROJECTION[\"Lambert_Conformal_Conic_1SP\"],"
" PARAMETER[\"latitude_of_origin\",37],"
" PARAMETER[\"central_meridian\",-6],"
" PARAMETER[\"scale_factor\",0.999625769],"
" PARAMETER[\"false_easting\",500000],"
" PARAMETER[\"false_northing\",300000],"
" UNIT[\"metre\",1,"
" AUTHORITY[\"EPSG\",\"9001\"]],"
" AXIS[\"Easting\",EAST],"
" AXIS[\"Northing\",NORTH]]";
{
WKTParser parser;
parser.setStrict(false).attachDatabaseContext(
DatabaseContext::create());
auto obj = parser.createFromWKT(wkt);
EXPECT_TRUE(!parser.warningList().empty());
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

// No base CRS identifiers
EXPECT_TRUE(crs->baseCRS()->identifiers().empty());

auto cs = crs->baseCRS()->coordinateSystem();
ASSERT_EQ(cs->axisList().size(), 2U);
EXPECT_NEAR(cs->axisList()[0]->unit().conversionToSI(),
UnitOfMeasure::GRAD.conversionToSI(), 1e-10);
}
{
WKTParser parser;
parser.setUnsetIdentifiersIfIncompatibleDef(false)
.attachDatabaseContext(DatabaseContext::create());
auto obj = parser.createFromWKT(wkt);
EXPECT_TRUE(parser.warningList().empty());
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

// Base CRS identifier preserved
EXPECT_TRUE(!crs->baseCRS()->identifiers().empty());

auto cs = crs->baseCRS()->coordinateSystem();
ASSERT_EQ(cs->axisList().size(), 2U);
EXPECT_NEAR(cs->axisList()[0]->unit().conversionToSI(),
UnitOfMeasure::GRAD.conversionToSI(), 1e-10);
}
}

// ---------------------------------------------------------------------------
Expand Down