diff options
| author | Kristian Evers <kristianevers@gmail.com> | 2020-01-08 19:42:22 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-08 19:42:22 +0100 |
| commit | 2d76bcffdc4d154860512c904c877ad086ca6b6d (patch) | |
| tree | fb7a89bad15edbd55aab154532911933af591dc8 /src | |
| parent | 6cd3a80bf5d015ec9c6dc601720a418c17ffa340 (diff) | |
| parent | 6426bcbd3605bf8cd6ae5c7869931fa89a26d641 (diff) | |
| download | PROJ-2d76bcffdc4d154860512c904c877ad086ca6b6d.tar.gz PROJ-2d76bcffdc4d154860512c904c877ad086ca6b6d.zip | |
Merge pull request #1827 from rouault/improve_createObjectsFromName
Improvements regarding name aliases (refs #1823)
Diffstat (limited to 'src')
| -rw-r--r-- | src/apps/projinfo.cpp | 60 | ||||
| -rw-r--r-- | src/iso19111/c_api.cpp | 23 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 252 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 30 |
4 files changed, 240 insertions, 125 deletions
diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 8ce9eefe..bef47746 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -78,7 +78,7 @@ struct OutputOptions { static void usage() { std::cerr - << "usage: projinfo [-o formats] [-k crs|operation|ellipsoid] " + << "usage: projinfo [-o formats] [-k crs|operation|datum|ellipsoid] " "[--summary] [-q]" << std::endl << " ([--area name_or_code] | " @@ -184,6 +184,9 @@ static BaseObjectNNPtr buildObject( } else if (kind == "ellipsoid" && tokens.size() == 2) { auto urn = "urn:ogc:def:ellipsoid:" + tokens[0] + "::" + tokens[1]; obj = createFromUserInput(urn, dbContext).as_nullable(); + } else if (kind == "datum" && tokens.size() == 2) { + auto urn = "urn:ogc:def:datum:" + tokens[0] + "::" + tokens[1]; + obj = createFromUserInput(urn, dbContext).as_nullable(); } else { // Convenience to be able to use C escaped strings... if (l_user_string.size() > 2 && l_user_string[0] == '"' && @@ -205,6 +208,59 @@ static BaseObjectNNPtr buildObject( } } } + } else if (dbContext && !kind.empty() && kind != "crs" && + l_user_string.find(':') == std::string::npos) { + std::vector<AuthorityFactory::ObjectType> allowedTypes; + if (kind == "operation") + allowedTypes.push_back( + AuthorityFactory::ObjectType::COORDINATE_OPERATION); + else if (kind == "ellipsoid") + allowedTypes.push_back( + AuthorityFactory::ObjectType::ELLIPSOID); + else if (kind == "datum") + allowedTypes.push_back(AuthorityFactory::ObjectType::DATUM); + constexpr size_t limitResultCount = 10; + auto factory = AuthorityFactory::create(NN_NO_CHECK(dbContext), + std::string()); + for (int pass = 0; pass <= 1; ++pass) { + const bool approximateMatch = (pass == 1); + auto res = factory->createObjectsFromName( + l_user_string, allowedTypes, approximateMatch, + limitResultCount); + if (res.size() == 1) { + obj = res.front().as_nullable(); + } else { + for (const auto &l_obj : res) { + if (Identifier::isEquivalentName( + l_obj->nameStr().c_str(), + l_user_string.c_str())) { + obj = l_obj.as_nullable(); + break; + } + } + if (obj) { + break; + } + } + if (res.size() > 1) { + std::string msg("several objects matching this name: "); + bool first = true; + for (const auto &l_obj : res) { + if (msg.size() > 200) { + msg += ", ..."; + break; + } + if (!first) { + msg += ", "; + } + first = false; + msg += l_obj->nameStr(); + } + std::cerr << context << ": " << msg << std::endl; + std::exit(1); + } + } + } else { obj = createFromUserInput(l_user_string, dbContext).as_nullable(); @@ -861,6 +917,8 @@ int main(int argc, char **argv) { objectKind = "operation"; } else if (ci_equal(kind, "ellipsoid")) { objectKind = "ellipsoid"; + } else if (ci_equal(kind, "datum")) { + objectKind = "datum"; } else { std::cerr << "Unrecognized value for option -k: " << kind << std::endl; diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 5a5e97f6..7d4f5eba 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -2760,16 +2760,19 @@ static GeodeticReferenceFrameNNPtr createGeodeticReferenceFrame( if (metadata::Identifier::isEquivalentName( datumName.c_str(), refDatum->nameStr().c_str())) { datumName = refDatum->nameStr(); - } - } else { - std::string outTableName; - std::string authNameFromAlias; - std::string codeFromAlias; - auto officialName = authFactory->getOfficialNameFromAlias( - datumName, "geodetic_datum", std::string(), true, - outTableName, authNameFromAlias, codeFromAlias); - if (!officialName.empty()) { - datumName = officialName; + } else if (refDatum->identifiers().size() == 1) { + const auto &id = refDatum->identifiers()[0]; + const auto aliases = + authFactory->databaseContext()->getAliases( + *id->codeSpace(), id->code(), refDatum->nameStr(), + "geodetic_datum", std::string()); + for (const auto &alias : aliases) { + if (metadata::Identifier::isEquivalentName( + datumName.c_str(), alias.c_str())) { + datumName = refDatum->nameStr(); + break; + } + } } } } diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 0bd44308..33fce593 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5248,13 +5248,12 @@ static void addToListString(std::string &out, const char *in) { out += in; } -static void addToListStringWithOR(std::string &out, const char *in) { +static void addToListStringWithOR(std::string &out, const std::string &in) { if (!out.empty()) { out += " OR "; } out += in; } - //! @endcond // --------------------------------------------------------------------------- @@ -5291,6 +5290,7 @@ AuthorityFactory::createObjectsFromName( } std::string sql( + "SELECT table_name, auth_name, code, name, deprecated FROM (" "SELECT table_name, auth_name, code, name, deprecated FROM object_view " "WHERE "); if (deprecated) { @@ -5306,108 +5306,141 @@ AuthorityFactory::createObjectsFromName( params.emplace_back(d->authority()); } - if (allowedObjectTypes.empty()) { - sql += "table_name IN (" - "'prime_meridian','ellipsoid','geodetic_datum'," - "'vertical_datum','geodetic_crs','projected_crs'," - "'vertical_crs','compound_crs','conversion'," - "'helmert_transformation','grid_transformation'," - "'other_transformation','concatenated_operation'" - ")"; - } else { - std::string tableNameList; - std::string otherConditions; - for (const auto type : allowedObjectTypes) { - switch (type) { - case ObjectType::PRIME_MERIDIAN: - addToListString(tableNameList, "'prime_meridian'"); - break; - case ObjectType::ELLIPSOID: - addToListString(tableNameList, "'ellipsoid'"); - break; - case ObjectType::DATUM: - addToListString(tableNameList, - "'geodetic_datum','vertical_datum'"); - break; - case ObjectType::GEODETIC_REFERENCE_FRAME: - addToListString(tableNameList, "'geodetic_datum'"); - break; - case ObjectType::VERTICAL_REFERENCE_FRAME: - addToListString(tableNameList, "'vertical_datum'"); - break; - case ObjectType::CRS: - addToListString(tableNameList, "'geodetic_crs','projected_crs'," - "'vertical_crs','compound_crs'"); - break; - case ObjectType::GEODETIC_CRS: - addToListString(tableNameList, "'geodetic_crs'"); - break; - case ObjectType::GEOCENTRIC_CRS: - addToListStringWithOR(otherConditions, - "(table_name = " GEOCENTRIC_SINGLE_QUOTED - " AND " - "type = " GEOCENTRIC_SINGLE_QUOTED ")"); - break; - case ObjectType::GEOGRAPHIC_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type IN (" GEOG_2D_SINGLE_QUOTED - "," GEOG_3D_SINGLE_QUOTED "))"); - break; - case ObjectType::GEOGRAPHIC_2D_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type = " GEOG_2D_SINGLE_QUOTED ")"); - break; - case ObjectType::GEOGRAPHIC_3D_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type = " GEOG_3D_SINGLE_QUOTED ")"); - break; - case ObjectType::PROJECTED_CRS: - addToListString(tableNameList, "'projected_crs'"); - break; - case ObjectType::VERTICAL_CRS: - addToListString(tableNameList, "'vertical_crs'"); - break; - case ObjectType::COMPOUND_CRS: - addToListString(tableNameList, "'compound_crs'"); - break; - case ObjectType::COORDINATE_OPERATION: - addToListString(tableNameList, - "'conversion','helmert_transformation'," - "'grid_transformation','other_transformation'," - "'concatenated_operation'"); - break; - case ObjectType::CONVERSION: - addToListString(tableNameList, "'conversion'"); - break; - case ObjectType::TRANSFORMATION: - addToListString(tableNameList, - "'helmert_transformation'," - "'grid_transformation','other_transformation'"); - break; - case ObjectType::CONCATENATED_OPERATION: - addToListString(tableNameList, "'concatenated_operation'"); - break; + const auto getTableNameConstraint = [&allowedObjectTypes]( + const std::string &colName) { + if (allowedObjectTypes.empty()) { + return colName + " IN (" + "'prime_meridian','ellipsoid','geodetic_datum'," + "'vertical_datum','geodetic_crs','projected_crs'," + "'vertical_crs','compound_crs','conversion'," + "'helmert_transformation','grid_transformation'," + "'other_transformation','concatenated_operation'" + ")"; + } else { + std::string tableNameList; + std::string otherConditions; + for (const auto type : allowedObjectTypes) { + switch (type) { + case ObjectType::PRIME_MERIDIAN: + addToListString(tableNameList, "'prime_meridian'"); + break; + case ObjectType::ELLIPSOID: + addToListString(tableNameList, "'ellipsoid'"); + break; + case ObjectType::DATUM: + addToListString(tableNameList, + "'geodetic_datum','vertical_datum'"); + break; + case ObjectType::GEODETIC_REFERENCE_FRAME: + addToListString(tableNameList, "'geodetic_datum'"); + break; + case ObjectType::VERTICAL_REFERENCE_FRAME: + addToListString(tableNameList, "'vertical_datum'"); + break; + case ObjectType::CRS: + addToListString(tableNameList, + "'geodetic_crs','projected_crs'," + "'vertical_crs','compound_crs'"); + break; + case ObjectType::GEODETIC_CRS: + addToListString(tableNameList, "'geodetic_crs'"); + break; + case ObjectType::GEOCENTRIC_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = " GEOCENTRIC_SINGLE_QUOTED " AND " + "type = " GEOCENTRIC_SINGLE_QUOTED ")"); + break; + case ObjectType::GEOGRAPHIC_CRS: + addToListStringWithOR(otherConditions, + "(" + colName + + " = 'geodetic_crs' AND " + "type IN (" GEOG_2D_SINGLE_QUOTED + "," GEOG_3D_SINGLE_QUOTED "))"); + break; + case ObjectType::GEOGRAPHIC_2D_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = 'geodetic_crs' AND " + "type = " GEOG_2D_SINGLE_QUOTED ")"); + break; + case ObjectType::GEOGRAPHIC_3D_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = 'geodetic_crs' AND " + "type = " GEOG_3D_SINGLE_QUOTED ")"); + break; + case ObjectType::PROJECTED_CRS: + addToListString(tableNameList, "'projected_crs'"); + break; + case ObjectType::VERTICAL_CRS: + addToListString(tableNameList, "'vertical_crs'"); + break; + case ObjectType::COMPOUND_CRS: + addToListString(tableNameList, "'compound_crs'"); + break; + case ObjectType::COORDINATE_OPERATION: + addToListString( + tableNameList, + "'conversion','helmert_transformation'," + "'grid_transformation','other_transformation'," + "'concatenated_operation'"); + break; + case ObjectType::CONVERSION: + addToListString(tableNameList, "'conversion'"); + break; + case ObjectType::TRANSFORMATION: + addToListString( + tableNameList, + "'helmert_transformation'," + "'grid_transformation','other_transformation'"); + break; + case ObjectType::CONCATENATED_OPERATION: + addToListString(tableNameList, "'concatenated_operation'"); + break; + } } - } - if (!tableNameList.empty()) { - sql += "((table_name IN ("; - sql += tableNameList; - sql += "))"; - if (!otherConditions.empty()) { - sql += " OR "; - sql += otherConditions; + std::string l_sql; + if (!tableNameList.empty()) { + l_sql = "((" + colName + " IN ("; + l_sql += tableNameList; + l_sql += "))"; + if (!otherConditions.empty()) { + l_sql += " OR "; + l_sql += otherConditions; + } + l_sql += ')'; + } else if (!otherConditions.empty()) { + l_sql = "("; + l_sql += otherConditions; + l_sql += ')'; } - sql += ')'; - } else if (!otherConditions.empty()) { - sql += "("; - sql += otherConditions; - sql += ')'; + return l_sql; } + }; + + sql += getTableNameConstraint("table_name"); + + sql += " UNION SELECT ov.table_name AS table_name, " + "ov.auth_name AS auth_name, " + "ov.code AS code, a.alt_name AS name, " + "ov.deprecated AS deprecated FROM object_view ov " + "JOIN alias_name a ON ov.table_name = a.table_name AND " + "ov.auth_name = a.auth_name AND ov.code = a.code WHERE "; + if (deprecated) { + sql += "ov.deprecated = 1 AND "; + } + if (!approximateMatch) { + sql += "a.alt_name LIKE ? AND "; + params.push_back(searchedNameWithoutDeprecated); + } + if (d->hasAuthorityRestriction()) { + sql += "ov.auth_name = ? AND "; + params.emplace_back(d->authority()); } - sql += " ORDER BY deprecated, length(name), name"; + sql += getTableNameConstraint("ov.table_name"); + + sql += ") ORDER BY deprecated, length(name), name"; if (limitResultCount > 0 && limitResultCount < static_cast<size_t>(std::numeric_limits<int>::max()) && @@ -5417,6 +5450,7 @@ AuthorityFactory::createObjectsFromName( } std::list<common::IdentifiedObjectNNPtr> res; + std::set<std::pair<std::string, std::string>> setIdentified; // Querying geodetic datum is a super hot path when importing from WKT1 // so cache results. @@ -5444,6 +5478,12 @@ AuthorityFactory::createObjectsFromName( for (const auto &row : listOfRow) { const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair<std::string, std::string>(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); auto factory = d->createFactory(auth_name); res.emplace_back(factory->createGeodeticDatum(code)); if (limitResultCount > 0 && res.size() == limitResultCount) { @@ -5469,6 +5509,12 @@ AuthorityFactory::createObjectsFromName( const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair<std::string, std::string>(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); auto factory = d->createFactory(auth_name); res.emplace_back(factory->createGeodeticDatum(code)); if (limitResultCount > 0 && @@ -5504,6 +5550,12 @@ AuthorityFactory::createObjectsFromName( const auto &table_name = row[0]; const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair<std::string, std::string>(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); const auto &deprecatedStr = row[4]; if (isFirst) { firstIsDeprecated = deprecatedStr == "1"; diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index a67238d9..c013ce24 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -2051,12 +2051,27 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( auto res = authFactory->createObjectsFromName( name, {AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, true, 1); - bool foundDatumName = false; if (!res.empty()) { + bool foundDatumName = false; const auto &refDatum = res.front(); if (metadata::Identifier::isEquivalentName( name.c_str(), refDatum->nameStr().c_str())) { foundDatumName = true; + } else if (refDatum->identifiers().size() == 1) { + const auto &id = refDatum->identifiers()[0]; + const auto aliases = + authFactory->databaseContext()->getAliases( + *id->codeSpace(), id->code(), refDatum->nameStr(), + "geodetic_datum", std::string()); + for (const auto &alias : aliases) { + if (metadata::Identifier::isEquivalentName( + name.c_str(), alias.c_str())) { + foundDatumName = true; + break; + } + } + } + if (foundDatumName) { properties.set(IdentifiedObject::NAME_KEY, refDatum->nameStr()); if (!properties.get(Identifier::CODESPACE_KEY) && @@ -2083,25 +2098,12 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( NN_NO_CHECK(dbContext_), *id->codeSpace()); auto dbDatum = authFactory2->createGeodeticDatum(id->code()); - foundDatumName = true; properties.set(IdentifiedObject::NAME_KEY, dbDatum->nameStr()); } catch (const std::exception &) { } } } - - if (!foundDatumName) { - std::string outTableName; - std::string authNameFromAlias; - std::string codeFromAlias; - auto officialName = authFactory->getOfficialNameFromAlias( - name, "geodetic_datum", std::string(), true, outTableName, - authNameFromAlias, codeFromAlias); - if (!officialName.empty()) { - properties.set(IdentifiedObject::NAME_KEY, officialName); - } - } } } |
