Skip to content

Commit

Permalink
WKT importer: tune for Oracle WKT and 'Lambert Conformal Conic' (#2322)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
PROJ-BOT and github-actions[bot] committed Aug 13, 2020
1 parent 2989fcf commit 5a38563
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 11 deletions.
5 changes: 5 additions & 0 deletions include/proj/internal/coordinateoperation_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,11 @@ static const MethodMapping projectionMethodMappings[] = {
EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP,
"Lambert_Conformal_Conic_2SP", "lcc", nullptr, paramsLCC2SP},

// Oracle WKT
{EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP,
EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP, "Lambert Conformal Conic",
"lcc", nullptr, paramsLCC2SP},

{EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_MICHIGAN,
EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP_MICHIGAN,
nullptr, // no mapping to WKT1_GDAL
Expand Down
57 changes: 46 additions & 11 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,19 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node,
std::string codeFromAlias;
const auto *nodeP = node->GP();
const auto &nodeChildren = nodeP->children();

auto identifiers = ArrayOfBaseObject::create();
for (const auto &subNode : nodeChildren) {
const auto &subNodeName(subNode->GP()->value());
if (ci_equal(subNodeName, WKTConstants::ID) ||
ci_equal(subNodeName, WKTConstants::AUTHORITY)) {
auto id = buildId(subNode, true, removeInverseOf);
if (id) {
identifiers->add(NN_NO_CHECK(id));
}
}
}

if (!nodeChildren.empty()) {
const auto &nodeName(nodeP->value());
auto name(stripQuotes(nodeChildren[0]));
Expand All @@ -1547,6 +1560,26 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node,
properties->set(common::IdentifiedObject::DEPRECATED_KEY, true);
}

// Oracle WKT can contain names like
// "Reseau Geodesique Francais 1993 (EPSG ID 6171)"
// for WKT attributes to the auth_name = "IGN - Paris"
// Strip that suffix from the name and assign a true EPSG code to the
// object
if (identifiers->empty()) {
const auto pos = name.find(" (EPSG ID ");
if (pos != std::string::npos && name.back() == ')') {
const auto code =
name.substr(pos + strlen(" (EPSG ID "),
name.size() - 1 - pos - strlen(" (EPSG ID "));
name.resize(pos);

PropertyMap propertiesId;
propertiesId.set(Identifier::CODESPACE_KEY, Identifier::EPSG);
propertiesId.set(Identifier::AUTHORITY_KEY, Identifier::EPSG);
identifiers->add(Identifier::create(code, propertiesId));
}
}

const char *tableNameForAlias = nullptr;
if (ci_equal(nodeName, WKTConstants::GEOGCS)) {
if (starts_with(name, "GCS_")) {
Expand Down Expand Up @@ -1589,17 +1622,6 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node,
properties->set(IdentifiedObject::NAME_KEY, name);
}

auto identifiers = ArrayOfBaseObject::create();
for (const auto &subNode : nodeChildren) {
const auto &subNodeName(subNode->GP()->value());
if (ci_equal(subNodeName, WKTConstants::ID) ||
ci_equal(subNodeName, WKTConstants::AUTHORITY)) {
auto id = buildId(subNode, true, removeInverseOf);
if (id) {
identifiers->add(NN_NO_CHECK(id));
}
}
}
if (identifiers->empty() && !authNameFromAlias.empty()) {
identifiers->add(Identifier::create(
codeFromAlias,
Expand Down Expand Up @@ -3606,6 +3628,7 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
}
foundParameters.resize(countParams);
}
bool found2ndStdParallel = false;
for (const auto &childNode : projCRSNode->GP()->children()) {
if (ci_equal(childNode->GP()->value(), WKTConstants::PARAMETER)) {
const auto &childNodeChildren = childNode->GP()->children();
Expand Down Expand Up @@ -3658,6 +3681,10 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
propertiesParameter.set(Identifier::CODESPACE_KEY,
Identifier::EPSG);
}
if (paramMapping->epsg_code ==
EPSG_CODE_PARAMETER_LATITUDE_2ND_STD_PARALLEL) {
found2ndStdParallel = true;
}
}
propertiesParameter.set(IdentifiedObject::NAME_KEY, parameterName);
parameters.push_back(
Expand All @@ -3674,6 +3701,14 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard(
}
}

// Oracle WKT: make sure that the 2nd std parallel parameter is found to
// select the LCC_2SP mapping
if (metadata::Identifier::isEquivalentName(wkt1ProjectionName.c_str(),
"Lambert Conformal Conic") &&
!found2ndStdParallel) {
propertiesMethod.set(IdentifiedObject::NAME_KEY, wkt1ProjectionName);
}

// 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.
Expand Down
36 changes: 36 additions & 0 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5910,6 +5910,42 @@ TEST(wkt_parse, wkt1_esri_gauss_kruger) {

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

TEST(wkt_parse, wkt1_oracle) {
// WKT from mdsys.cs_srs Oracle table
auto wkt = "PROJCS[\"RGF93 / Lambert-93\", GEOGCS [ \"RGF93\", "
"DATUM [\"Reseau Geodesique Francais 1993 (EPSG ID 6171)\", "
"SPHEROID [\"GRS 1980 (EPSG ID 7019)\", 6378137.0, "
"298.257222101]], PRIMEM [ \"Greenwich\", 0.000000000 ], "
"UNIT [\"Decimal Degree\", 0.0174532925199433]], "
"PROJECTION [\"Lambert Conformal Conic\"], "
"PARAMETER [\"Latitude_Of_Origin\", 46.5], "
"PARAMETER [\"Central_Meridian\", 3.0], "
"PARAMETER [\"Standard_Parallel_1\", 49.0], "
"PARAMETER [\"Standard_Parallel_2\", 44.0], "
"PARAMETER [\"False_Easting\", 700000.0], "
"PARAMETER [\"False_Northing\", 6600000.0], "
"UNIT [\"Meter\", 1.0]]";

auto dbContext = DatabaseContext::create();
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

EXPECT_EQ(crs->baseCRS()->datum()->nameStr(),
"Reseau Geodesique Francais 1993");
EXPECT_EQ(crs->baseCRS()->datum()->getEPSGCode(), 6171);
EXPECT_EQ(crs->derivingConversion()->method()->nameStr(),
"Lambert Conic Conformal (2SP)");

auto factoryAll = AuthorityFactory::create(dbContext, std::string());
auto res = crs->identify(factoryAll);
ASSERT_GE(res.size(), 1U);
EXPECT_EQ(res.front().first->getEPSGCode(), 2154);
EXPECT_EQ(res.front().second, 100);
}

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

TEST(wkt_parse, invalid) {
EXPECT_THROW(WKTParser().createFromWKT(""), ParsingException);
EXPECT_THROW(WKTParser().createFromWKT("A"), ParsingException);
Expand Down

0 comments on commit 5a38563

Please sign in to comment.