diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-02-06 19:42:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-06 19:42:04 +0100 |
| commit | 20e9bdea538efea120e4aa48ba4847c28679dc99 (patch) | |
| tree | 9168a76717b3012b8a17c2d808eea0df6bd2fa97 /src | |
| parent | 4d0b2e91c52e4ddae04741931dead86cc52492f5 (diff) | |
| parent | 7fb3ebbf3724050787653afd3f6010760c280a32 (diff) | |
| download | PROJ-20e9bdea538efea120e4aa48ba4847c28679dc99.tar.gz PROJ-20e9bdea538efea120e4aa48ba4847c28679dc99.zip | |
Merge pull request #1916 from rouault/backport_1884_1914_1915
[Backport 6.3] PR #1884 #1914 #1915
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/factory.cpp | 319 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 173 |
2 files changed, 320 insertions, 172 deletions
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<std::pair<std::string, std::string>> setTransf1; - std::set<std::pair<std::string, std::string>> 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<std::pair<std::string, std::string>> 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<std::string> 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<std::string, std::string>(auth_name1, code1)); - setTransf2.insert( + setTransf.insert( std::pair<std::string, std::string>(auth_name2, code2)); } + + std::map<std::string, std::vector<std::pair<std::string, std::string>>> + 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<std::string, std::string>( + 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<std::string, std::string>( - 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<std::string, std::string>( + 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<std::string, std::string>( - 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<std::string, std::string>( + 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); diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 7a3cba6b..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); @@ -8734,22 +8752,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]"); } } } |
