From d7cd77244e1565fdc232b3d85a3b99720ecb42b4 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 25 Jan 2020 16:31:00 +0100 Subject: Fix ingestion of +proj=cea with +k_0 Fixes #1881 Digging into the implementation of proj=cea, it appears that k_0 and lat_ts are intended to be exclusive ways of specifying the same concept. EPSG only models the variant using lat_s. So if k_0 is found and lat_ts is absent, compute the equivalent value of lat_ts from k_0. Note: k_0 should normally be in the [0,1] range. In case creative users would use something outside, we raise an exception, even if the cea implementation could potentially deal with any k_0 value. Hopefully this is a (reasonable) limitation that will address nominal use cases. --- src/iso19111/io.cpp | 51 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 7a3cba6b..2eded943 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -8734,22 +8734,43 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( } else if (param->unit_type == UnitOfMeasure::Type::SCALE) { value = 1; - } else { - // For omerc, if gamma is missing, the default value is - // alpha - if (step.name == "omerc" && proj_name == "gamma") { - paramValue = &getParamValue(step, "alpha"); - if (!paramValue->empty()) { - value = getAngularValue(*paramValue); + } + // For omerc, if gamma is missing, the default value is + // alpha + else if (step.name == "omerc" && proj_name == "gamma") { + paramValue = &getParamValue(step, "alpha"); + if (!paramValue->empty()) { + value = getAngularValue(*paramValue); + } + } else if (step.name == "krovak") { + if (param->epsg_code == + EPSG_CODE_PARAMETER_COLATITUDE_CONE_AXIS) { + value = 30.28813975277777776; + } else if ( + param->epsg_code == + EPSG_CODE_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL) { + value = 78.5; + } + } else if (step.name == "cea" && proj_name == "lat_ts") { + paramValue = &getParamValueK(step); + if (!paramValue->empty()) { + bool hasError = false; + const double k = getNumericValue(*paramValue, &hasError); + if (hasError) { + throw ParsingException("invalid value for k/k_0"); } - } else if (step.name == "krovak") { - if (param->epsg_code == - EPSG_CODE_PARAMETER_COLATITUDE_CONE_AXIS) { - value = 30.28813975277777776; - } else if ( - param->epsg_code == - EPSG_CODE_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL) { - value = 78.5; + if (k >= 0 && k <= 1) { + const double es = + geogCRS->ellipsoid()->squaredEccentricity(); + if (es < 0) { + throw ParsingException("Invalid flattening"); + } + value = + Angle(acos(k * sqrt((1 - es) / (1 - k * k * es))), + UnitOfMeasure::RADIAN) + .convertToUnit(UnitOfMeasure::DEGREE); + } else { + throw ParsingException("k/k_0 should be in [0,1]"); } } } -- cgit v1.2.3 From 589c44aa12f7a93e73297e76a898bae3783879c9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 5 Feb 2020 17:59:55 +0100 Subject: Fix performance issue, affecting projinfo EPSG:7842 Fixes #1913 AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates() issued a complex SQL query that pushes the SQLite3 query plan optimizer to its limits. Was working reasonably with sqlite 3.11, but not with later versions. So put less constraints in the main query and do post-processing checks and auxiliary requests to avoid such issues. For some unknown reason, this slightly slows down a bit execution time of the whole test_cpp_api binary (~ 10%), but couldn't come with something better, despite trying many variations of the main SQL query. It seems that in the general case the non-filter LEFT JOIN on the supersession table helped, except on this EPSG:7842 case. --- src/iso19111/factory.cpp | 319 +++++++++++++++++++++++++++++++---------------- 1 file changed, 214 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 9ed9dc25..2fe12fb3 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -4331,56 +4331,29 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( // For some reason, filtering on v1.deprecated and v2.deprecated kills // performance - std::string sqlProlog("SELECT v1.table_name as table1, " - "v1.auth_name AS auth_name1, v1.code AS code1, " - "v1.deprecated AS deprecated1, " - "v2.table_name as table2, " - "v2.auth_name AS auth_name2, v2.code AS code2, " - "v2.deprecated AS deprecated2, " - "a1.south_lat AS south_lat1, " - "a1.west_lon AS west_lon1, " - "a1.north_lat AS north_lat1, " - "a1.east_lon AS east_lon1, " - "a2.south_lat AS south_lat2, " - "a2.west_lon AS west_lon2, " - "a2.north_lat AS north_lat2, " - "a2.east_lon AS east_lon2 "); - if (discardSuperseded) { - sqlProlog += ", ss1.replacement_auth_name AS replacement_auth_name1, " - "ss1.replacement_code AS replacement_code1, " - "ss2.replacement_auth_name AS replacement_auth_name2, " - "ss2.replacement_code AS replacement_code2 "; - } - sqlProlog += "FROM coordinate_operation_view v1 " - "JOIN coordinate_operation_view v2 " - "JOIN geodetic_crs g_source " - "JOIN geodetic_crs g_v1s " - "JOIN geodetic_crs g_v1t " - "JOIN geodetic_crs g_v2s " - "JOIN geodetic_crs g_v2t " - "JOIN geodetic_crs g_target " - "ON g_v1s.auth_name = v1.source_crs_auth_name " - "AND g_v1s.code = v1.source_crs_code " - "AND g_v1t.auth_name = v1.target_crs_auth_name " - "AND g_v1t.code = v1.target_crs_code " - "AND g_v2s.auth_name = v2.source_crs_auth_name " - "AND g_v2s.code = v2.source_crs_code " - "AND g_v2t.auth_name = v2.target_crs_auth_name " - "AND g_v2t.code = v2.target_crs_code "; - - const std::string joinSupersession( - "LEFT JOIN supersession ss1 ON " - "ss1.superseded_table_name = v1.table_name AND " - "ss1.superseded_auth_name = v1.auth_name AND " - "ss1.superseded_code = v1.code AND " - "ss1.superseded_table_name = ss1.replacement_table_name " - "LEFT JOIN supersession ss2 ON " - "ss2.superseded_table_name = v2.table_name AND " - "ss2.superseded_auth_name = v2.auth_name AND " - "ss2.superseded_code = v2.code AND " - "ss2.superseded_table_name = ss2.replacement_table_name "); + const std::string sqlProlog("SELECT v1.table_name as table1, " + "v1.auth_name AS auth_name1, v1.code AS code1, " + "v1.deprecated AS deprecated1, " + "v2.table_name as table2, " + "v2.auth_name AS auth_name2, v2.code AS code2, " + "v2.deprecated AS deprecated2 " + "FROM coordinate_operation_view v1 " + "JOIN coordinate_operation_view v2 " + "JOIN geodetic_crs g_source " + "JOIN geodetic_crs g_v1s " + "JOIN geodetic_crs g_v1t " + "JOIN geodetic_crs g_v2s " + "JOIN geodetic_crs g_v2t " + "JOIN geodetic_crs g_target " + "ON g_v1s.auth_name = v1.source_crs_auth_name " + "AND g_v1s.code = v1.source_crs_code " + "AND g_v1t.auth_name = v1.target_crs_auth_name " + "AND g_v1t.code = v1.target_crs_code " + "AND g_v2s.auth_name = v2.source_crs_auth_name " + "AND g_v2s.code = v2.source_crs_code " + "AND g_v2t.auth_name = v2.target_crs_auth_name " + "AND g_v2t.code = v2.target_crs_code "); const std::string joinArea( - (discardSuperseded ? joinSupersession : std::string()) + "JOIN area a1 ON v1.area_of_use_auth_name = a1.auth_name " "AND v1.area_of_use_code = a1.code " "JOIN area a2 ON v2.area_of_use_auth_name = a2.auth_name " @@ -4393,8 +4366,13 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( additionalWhere += "WHERE g_source.auth_name = ? AND g_source.code = ? " "AND g_target.auth_name = ? AND g_target.code = ? " - "AND intersects_bbox(south_lat1, west_lon1, north_lat1, east_lon1, " - "south_lat2, west_lon2, north_lat2, east_lon2) = 1 "; + "AND intersects_bbox(" + "a1.south_lat, a1.west_lon, a1.north_lat, a1.east_lon, " + "a2.south_lat, a2.west_lon, a2.north_lat, a2.east_lon) = 1 "; + +#if 0 + // While those additonal constraints are correct, they are found to + // kill performance. So enforce them as post-processing if (!allowedAuthorities.empty()) { additionalWhere += "AND v1.auth_name IN ("; @@ -4409,7 +4387,7 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( additionalWhere += ','; additionalWhere += '?'; } - additionalWhere += ')'; + additionalWhere += ") "; for (const auto &allowedAuthority : allowedAuthorities) { params.emplace_back(allowedAuthority); } @@ -4422,6 +4400,8 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( params.emplace_back(d->authority()); params.emplace_back(d->authority()); } +#endif + for (const auto &extent : {intersectingExtent1, intersectingExtent2}) { if (extent) { const auto &geogExtent = extent->geographicElements(); @@ -4437,10 +4417,10 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( if (south_lat != -90.0 || west_lon != -180.0 || north_lat != 90.0 || east_lon != 180.0) { additionalWhere += - "AND intersects_bbox(south_lat1, " - "west_lon1, north_lat1, east_lon1, ?, ?, ?, ?) AND " - "intersects_bbox(south_lat2, west_lon2, " - "north_lat2, east_lon2, ?, ?, ?, ?) "; + "AND intersects_bbox(a1.south_lat, a1.west_lon, " + "a1.north_lat, a1.east_lon, ?, ?, ?, ?) AND " + "intersects_bbox(a2.south_lat, a2.west_lon, " + "a2.north_lat, a2.east_lon, ?, ?, ?, ?) "; params.emplace_back(south_lat); params.emplace_back(west_lon); params.emplace_back(north_lat); @@ -4478,53 +4458,192 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( auto res = d->run(sql + additionalWhere, params); // fprintf(stderr, "after\n"); - const auto filterOutSuperseded = [](SQLResultSet &&resultSet) { - std::set> setTransf1; - std::set> setTransf2; + const auto filterDeprecatedAndNotMatchingAuth = + [&](SQLResultSet &&resultSet) { + + SQLResultSet filteredResultSet; + for (const auto &row : resultSet) { + const auto &deprecated1 = row[3]; + const auto &deprecated2 = row[7]; + if (deprecated1 == "1" || deprecated2 == "1") { + continue; + } + const auto &auth_name1 = row[1]; + const auto &auth_name2 = row[5]; + if (d->hasAuthorityRestriction()) { + if (auth_name1 != d->authority() || + auth_name2 != d->authority()) { + continue; + } + } + if (!allowedAuthorities.empty()) { + { + bool found = false; + for (const auto &auth : allowedAuthorities) { + if (auth_name1 == auth) { + found = true; + break; + } + } + if (!found) { + continue; + } + } + { + bool found = false; + for (const auto &auth : allowedAuthorities) { + if (auth_name2 == auth) { + found = true; + break; + } + } + if (!found) { + continue; + } + } + } + + filteredResultSet.emplace_back(row); + } + return filteredResultSet; + }; + + const auto filterOutSuperseded = [&](SQLResultSet &&resultSet) { + std::set> setTransf; + std::string findSupersededSql("SELECT superseded_table_name, " + "superseded_auth_name, superseded_code, " + "replacement_auth_name, replacement_code " + "FROM supersession WHERE "); + bool findSupersededFirstWhere = true; + ListOfParams findSupersededParams; + + std::set setAlreadyAsked; + const auto keyMapSupersession = []( + const std::string &table_name, const std::string &auth_name, + const std::string &code) { return table_name + auth_name + code; }; + for (const auto &row : resultSet) { - // table1 + const auto &table1 = row[0]; const auto &auth_name1 = row[1]; const auto &code1 = row[2]; - const auto &deprecated1 = row[3]; - // table2 + const auto key1 = keyMapSupersession(table1, auth_name1, code1); + if (setAlreadyAsked.find(key1) == setAlreadyAsked.end()) { + setAlreadyAsked.insert(key1); + if (!findSupersededFirstWhere) + findSupersededSql += " OR "; + findSupersededFirstWhere = false; + findSupersededSql += + "(superseded_table_name = ? AND replacement_table_name = " + "superseded_table_name AND superseded_auth_name = ? AND " + "superseded_code = ?)"; + findSupersededParams.push_back(table1); + findSupersededParams.push_back(auth_name1); + findSupersededParams.push_back(code1); + } + + const auto &table2 = row[4]; const auto &auth_name2 = row[5]; const auto &code2 = row[6]; - const auto &deprecated2 = row[7]; - if (deprecated1 == "1" || deprecated2 == "1") { - continue; + const auto key2 = keyMapSupersession(table2, auth_name2, code2); + if (setAlreadyAsked.find(key2) == setAlreadyAsked.end()) { + setAlreadyAsked.insert(key2); + if (!findSupersededFirstWhere) + findSupersededSql += " OR "; + findSupersededFirstWhere = false; + findSupersededSql += + "(superseded_table_name = ? AND replacement_table_name = " + "superseded_table_name AND superseded_auth_name = ? AND " + "superseded_code = ?)"; + findSupersededParams.push_back(table2); + findSupersededParams.push_back(auth_name2); + findSupersededParams.push_back(code2); } - setTransf1.insert( + + setTransf.insert( std::pair(auth_name1, code1)); - setTransf2.insert( + setTransf.insert( std::pair(auth_name2, code2)); } + + std::map>> + mapSupersession; + + if (!findSupersededParams.empty()) { + const auto resSuperseded = + d->run(findSupersededSql, findSupersededParams); + for (const auto &row : resSuperseded) { + const auto &superseded_table_name = row[0]; + const auto &superseded_auth_name = row[1]; + const auto &superseded_code = row[2]; + const auto &replacement_auth_name = row[3]; + const auto &replacement_code = row[4]; + mapSupersession[keyMapSupersession(superseded_table_name, + superseded_auth_name, + superseded_code)] + .push_back(std::pair( + replacement_auth_name, replacement_code)); + } + } + SQLResultSet filteredResultSet; for (const auto &row : resultSet) { - const auto &replacement_auth_name1 = row[16]; - const auto &replacement_code1 = row[17]; - const auto &replacement_auth_name2 = row[18]; - const auto &replacement_code2 = row[19]; - if (!replacement_auth_name1.empty() && - setTransf1.find(std::pair( - replacement_auth_name1, replacement_code1)) != - setTransf1.end()) { - // Skip transformations that are superseded by others that got - // returned in the result set. - continue; + const auto &table1 = row[0]; + const auto &auth_name1 = row[1]; + const auto &code1 = row[2]; + const auto &table2 = row[4]; + const auto &auth_name2 = row[5]; + const auto &code2 = row[6]; + + auto iter1 = mapSupersession.find( + keyMapSupersession(table1, auth_name1, code1)); + if (iter1 != mapSupersession.end()) { + bool foundReplacement = false; + for (const auto &replacement : iter1->second) { + const auto &replacement_auth_name = replacement.first; + const auto &replacement_code = replacement.second; + if (setTransf.find(std::pair( + replacement_auth_name, replacement_code)) != + setTransf.end()) { + // Skip transformations that are superseded by others + // that got + // returned in the result set. + foundReplacement = true; + break; + } + } + if (foundReplacement) { + continue; + } } - if (!replacement_auth_name2.empty() && - setTransf2.find(std::pair( - replacement_auth_name2, replacement_code2)) != - setTransf2.end()) { - // Skip transformations that are superseded by others that got - // returned in the result set. - continue; + + auto iter2 = mapSupersession.find( + keyMapSupersession(table2, auth_name2, code2)); + if (iter2 != mapSupersession.end()) { + bool foundReplacement = false; + for (const auto &replacement : iter2->second) { + const auto &replacement_auth_name = replacement.first; + const auto &replacement_code = replacement.second; + if (setTransf.find(std::pair( + replacement_auth_name, replacement_code)) != + setTransf.end()) { + // Skip transformations that are superseded by others + // that got + // returned in the result set. + foundReplacement = true; + break; + } + } + if (foundReplacement) { + continue; + } } + filteredResultSet.emplace_back(row); } return filteredResultSet; }; + res = filterDeprecatedAndNotMatchingAuth(std::move(res)); if (discardSuperseded) { res = filterOutSuperseded(std::move(res)); } @@ -4535,14 +4654,10 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( const auto &table1 = row[0]; const auto &auth_name1 = row[1]; const auto &code1 = row[2]; - const auto &deprecated1 = row[3]; const auto &table2 = row[4]; const auto &auth_name2 = row[5]; const auto &code2 = row[6]; - const auto &deprecated2 = row[7]; - if (deprecated1 == "1" || deprecated2 == "1") { - continue; - } + auto op1 = d->createFactory(auth_name1) ->createCoordinateOperation( code1, true, usePROJAlternativeGridNames, table1); @@ -4623,6 +4738,8 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( // fprintf(stderr, "before %s\n", (sql + additionalWhere).c_str()); res = d->run(sql + additionalWhere, params); // fprintf(stderr, "after\n"); + + res = filterDeprecatedAndNotMatchingAuth(std::move(res)); if (discardSuperseded) { res = filterOutSuperseded(std::move(res)); } @@ -4630,14 +4747,10 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( const auto &table1 = row[0]; const auto &auth_name1 = row[1]; const auto &code1 = row[2]; - const auto &deprecated1 = row[3]; const auto &table2 = row[4]; const auto &auth_name2 = row[5]; const auto &code2 = row[6]; - const auto &deprecated2 = row[7]; - if (deprecated1 == "1" || deprecated2 == "1") { - continue; - } + auto op1 = d->createFactory(auth_name1) ->createCoordinateOperation( code1, true, usePROJAlternativeGridNames, table1); @@ -4718,6 +4831,8 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( // fprintf(stderr, "before %s\n", (sql + additionalWhere).c_str()); res = d->run(sql + additionalWhere, params); // fprintf(stderr, "after\n"); + + res = filterDeprecatedAndNotMatchingAuth(std::move(res)); if (discardSuperseded) { res = filterOutSuperseded(std::move(res)); } @@ -4725,14 +4840,10 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( const auto &table1 = row[0]; const auto &auth_name1 = row[1]; const auto &code1 = row[2]; - const auto &deprecated1 = row[3]; const auto &table2 = row[4]; const auto &auth_name2 = row[5]; const auto &code2 = row[6]; - const auto &deprecated2 = row[7]; - if (deprecated1 == "1" || deprecated2 == "1") { - continue; - } + auto op1 = d->createFactory(auth_name1) ->createCoordinateOperation( code1, true, usePROJAlternativeGridNames, table1); @@ -4813,6 +4924,8 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( // fprintf(stderr, "before %s\n", (sql + additionalWhere).c_str()); res = d->run(sql + additionalWhere, params); // fprintf(stderr, "after\n"); + + res = filterDeprecatedAndNotMatchingAuth(std::move(res)); if (discardSuperseded) { res = filterOutSuperseded(std::move(res)); } @@ -4820,14 +4933,10 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( const auto &table1 = row[0]; const auto &auth_name1 = row[1]; const auto &code1 = row[2]; - const auto &deprecated1 = row[3]; const auto &table2 = row[4]; const auto &auth_name2 = row[5]; const auto &code2 = row[6]; - const auto &deprecated2 = row[7]; - if (deprecated1 == "1" || deprecated2 == "1") { - continue; - } + auto op1 = d->createFactory(auth_name1) ->createCoordinateOperation( code1, true, usePROJAlternativeGridNames, table1); -- cgit v1.2.3 From 7fb3ebbf3724050787653afd3f6010760c280a32 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 5 Feb 2020 19:58:57 +0100 Subject: Fix identification of ESRI-style datum names starting with D_ but without alias Fixes #1911 --- src/iso19111/io.cpp | 122 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 2eded943..9d463091 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -1997,65 +1997,20 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( // do that before buildEllipsoid() so that esriStyle_ can be set auto name = stripQuotes(nodeP->children()[0]); - if (name == "WGS_1984") { - properties.set(IdentifiedObject::NAME_KEY, - GeodeticReferenceFrame::EPSG_6326->nameStr()); - } else if (starts_with(name, "D_")) { - esriStyle_ = true; - const char *tableNameForAlias = nullptr; - std::string authNameFromAlias; - std::string codeFromAlias; - if (name == "D_WGS_1984") { - name = "World Geodetic System 1984"; - authNameFromAlias = Identifier::EPSG; - codeFromAlias = "6326"; - } else { - tableNameForAlias = "geodetic_datum"; - } - if (dbContext_ && tableNameForAlias) { - std::string outTableName; - auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), - std::string()); - auto officialName = authFactory->getOfficialNameFromAlias( - name, tableNameForAlias, "ESRI", false, outTableName, - authNameFromAlias, codeFromAlias); - if (!officialName.empty()) { - if (primeMeridian->nameStr() != - PrimeMeridian::GREENWICH->nameStr()) { - auto nameWithPM = - officialName + " (" + primeMeridian->nameStr() + ")"; - if (dbContext_->isKnownName(nameWithPM, "geodetic_datum")) { - officialName = nameWithPM; - } - } - name = officialName; - } - } - - properties.set(IdentifiedObject::NAME_KEY, name); - if (!authNameFromAlias.empty()) { - auto identifiers = ArrayOfBaseObject::create(); - identifiers->add(Identifier::create( - codeFromAlias, - PropertyMap() - .set(Identifier::CODESPACE_KEY, authNameFromAlias) - .set(Identifier::AUTHORITY_KEY, authNameFromAlias))); - properties.set(IdentifiedObject::IDENTIFIERS_KEY, identifiers); - } - } else if (name.find('_') != std::string::npos) { - // Likely coming from WKT1 + const auto identifyFromName = [&](const std::string &l_name) { + bool foundDatumName = false; if (dbContext_) { auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), std::string()); auto res = authFactory->createObjectsFromName( - name, {AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, - true, 1); - bool foundDatumName = false; + l_name, + {AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, true, + 1); if (!res.empty()) { const auto &refDatum = res.front(); if (metadata::Identifier::isEquivalentName( - name.c_str(), refDatum->nameStr().c_str())) { + l_name.c_str(), refDatum->nameStr().c_str())) { foundDatumName = true; properties.set(IdentifiedObject::NAME_KEY, refDatum->nameStr()); @@ -2096,13 +2051,76 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( std::string authNameFromAlias; std::string codeFromAlias; auto officialName = authFactory->getOfficialNameFromAlias( - name, "geodetic_datum", std::string(), true, outTableName, + l_name, "geodetic_datum", std::string(), true, outTableName, authNameFromAlias, codeFromAlias); if (!officialName.empty()) { + foundDatumName = true; properties.set(IdentifiedObject::NAME_KEY, officialName); } } } + return foundDatumName; + }; + + if (name == "WGS_1984") { + properties.set(IdentifiedObject::NAME_KEY, + GeodeticReferenceFrame::EPSG_6326->nameStr()); + } else if (starts_with(name, "D_")) { + esriStyle_ = true; + const char *tableNameForAlias = nullptr; + std::string authNameFromAlias; + std::string codeFromAlias; + if (name == "D_WGS_1984") { + name = "World Geodetic System 1984"; + authNameFromAlias = Identifier::EPSG; + codeFromAlias = "6326"; + } else { + tableNameForAlias = "geodetic_datum"; + } + + bool setNameAndId = true; + if (dbContext_ && tableNameForAlias) { + std::string outTableName; + auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), + std::string()); + auto officialName = authFactory->getOfficialNameFromAlias( + name, tableNameForAlias, "ESRI", false, outTableName, + authNameFromAlias, codeFromAlias); + if (officialName.empty()) { + // For the case of "D_GDA2020" where there is no D_GDA2020 ESRI + // alias, so just try without the D_ prefix. + const auto nameWithoutDPrefix = name.substr(2); + if (identifyFromName(nameWithoutDPrefix)) { + setNameAndId = false; // already done in identifyFromName() + } + } else { + if (primeMeridian->nameStr() != + PrimeMeridian::GREENWICH->nameStr()) { + auto nameWithPM = + officialName + " (" + primeMeridian->nameStr() + ")"; + if (dbContext_->isKnownName(nameWithPM, "geodetic_datum")) { + officialName = nameWithPM; + } + } + name = officialName; + } + } + + if (setNameAndId) { + properties.set(IdentifiedObject::NAME_KEY, name); + if (!authNameFromAlias.empty()) { + auto identifiers = ArrayOfBaseObject::create(); + identifiers->add(Identifier::create( + codeFromAlias, + PropertyMap() + .set(Identifier::CODESPACE_KEY, authNameFromAlias) + .set(Identifier::AUTHORITY_KEY, authNameFromAlias))); + properties.set(IdentifiedObject::IDENTIFIERS_KEY, identifiers); + } + } + } else if (name.find('_') != std::string::npos) { + // Likely coming from WKT1 + identifyFromName(name); } auto ellipsoid = buildEllipsoid(ellipsoidNode); -- cgit v1.2.3