From a9b6f39494e6dab0ea02af9d82e7b3d570f5422f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 24 Sep 2020 22:41:59 +0200 Subject: Database: "minimal" update to EPSG v10.003 Content mostly unchanged since v9.9 This update is "minimal" in that it mostly reflects the removal of the 'area' table, replaced now by 'extent', 'scope' and 'usage' Other new aspects of EPSG v10 are left aside. --- src/iso19111/factory.cpp | 442 ++++++++++++++++++++++++++++------------------- 1 file changed, 262 insertions(+), 180 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index a011f397..f98e5cc8 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1064,6 +1064,28 @@ std::string DatabaseContext::getOldProjGridName(const std::string &gridName) { // --------------------------------------------------------------------------- +// FIXME: as we don't support datum ensemble yet, remove it from name +static std::string addEnsembleSuffix(const std::string &name) { + if (name == "World Geodetic System 1984") { + return "World Geodetic System 1984 ensemble"; + } else if (name == "European Terrestrial Reference System 1989") { + return "European Terrestrial Reference System 1989 ensemble"; + } + return name; +} + +// FIXME: as we don't support datum ensemble yet, add it from name +static std::string removeEnsembleSuffix(const std::string &name) { + if (name == "World Geodetic System 1984 ensemble") { + return "World Geodetic System 1984"; + } else if (name == "European Terrestrial Reference System 1989 ensemble") { + return "European Terrestrial Reference System 1989"; + } + return name; +} + +// --------------------------------------------------------------------------- + /** \brief Gets the alias name from an official name. * * @param officialName Official name. Mandatory @@ -1082,7 +1104,7 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName, if (tableName == "geodetic_crs") { sql += " AND type = " GEOG_2D_SINGLE_QUOTED; } - auto res = d->run(sql, {officialName}); + auto res = d->run(sql, {addEnsembleSuffix(officialName)}); if (res.empty()) { return std::string(); } @@ -1129,7 +1151,7 @@ std::list DatabaseContext::getAliases( if (tableName == "geodetic_crs") { sql += " AND type = " GEOG_2D_SINGLE_QUOTED; } - auto resSql = d->run(sql, {officialName}); + auto resSql = d->run(sql, {addEnsembleSuffix(officialName)}); if (resSql.empty()) { d->cacheAliasNames_.insert(key, res); return res; @@ -1312,21 +1334,19 @@ struct AuthorityFactory::Private { UnitOfMeasure createUnitOfMeasure(const std::string &auth_name, const std::string &code); - util::PropertyMap createProperties(const std::string &code, - const std::string &name, bool deprecated, - const metadata::ExtentPtr &extent); + util::PropertyMap + createProperties(const std::string &code, const std::string &name, + bool deprecated, + const std::vector &usages); - util::PropertyMap createProperties(const std::string &code, - const std::string &name, bool deprecated, - const std::string &area_of_use_auth_name, - const std::string &area_of_use_code); + util::PropertyMap + createPropertiesSearchUsages(const std::string &table_name, + const std::string &code, + const std::string &name, bool deprecated); - util::PropertyMap createProperties(const std::string &code, - const std::string &name, bool deprecated, - const std::string &remarks, - const std::string &scope, - const std::string &area_of_use_auth_name, - const std::string &area_of_use_code); + util::PropertyMap createPropertiesSearchUsages( + const std::string &table_name, const std::string &code, + const std::string &name, bool deprecated, const std::string &remarks); SQLResultSet run(const std::string &sql, const ListOfParams ¶meters = ListOfParams()); @@ -1385,7 +1405,7 @@ AuthorityFactory::Private::createUnitOfMeasure(const std::string &auth_name, util::PropertyMap AuthorityFactory::Private::createProperties( const std::string &code, const std::string &name, bool deprecated, - const metadata::ExtentPtr &extent) { + const std::vector &usages) { auto props = util::PropertyMap() .set(metadata::Identifier::CODESPACE_KEY, authority()) .set(metadata::Identifier::CODE_KEY, code) @@ -1393,45 +1413,93 @@ util::PropertyMap AuthorityFactory::Private::createProperties( if (deprecated) { props.set(common::IdentifiedObject::DEPRECATED_KEY, true); } - if (extent) { - props.set( - common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, - NN_NO_CHECK(std::static_pointer_cast(extent))); + if (!usages.empty()) { + + auto array(util::ArrayOfBaseObject::create()); + for (const auto &usage : usages) { + array->add(usage); + } + props.set(common::ObjectUsage::OBJECT_DOMAIN_KEY, + util::nn_static_pointer_cast(array)); } return props; } // --------------------------------------------------------------------------- -util::PropertyMap AuthorityFactory::Private::createProperties( - const std::string &code, const std::string &name, bool deprecated, - const std::string &area_of_use_auth_name, - const std::string &area_of_use_code) { - return createProperties(code, name, deprecated, - area_of_use_auth_name.empty() - ? nullptr - : createFactory(area_of_use_auth_name) - ->createExtent(area_of_use_code) - .as_nullable()); +util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( + const std::string &table_name, const std::string &code, + const std::string &name, bool deprecated) { + + const std::string sql( + "SELECT extent.name, extent.description, extent.south_lat, " + "extent.north_lat, extent.west_lon, extent.east_lon, " + "scope.scope, " + "(CASE WHEN scope.scope LIKE '%large scale%' THEN 0 ELSE 1 END) " + "AS score " + "FROM usage " + "JOIN extent ON usage.extent_auth_name = extent.auth_name AND " + "usage.extent_code = extent.code " + "JOIN scope ON usage.scope_auth_name = scope.auth_name AND " + "usage.scope_code = scope.code " + "WHERE object_table_name = ? AND object_auth_name = ? AND " + "object_code = ? " + "ORDER BY score, usage.auth_name, usage.code"); + auto res = run(sql, {table_name, authority(), code}); + std::vector usages; + for (const auto &row : res) { + try { + size_t idx = 0; + const auto &extent_name = row[idx++]; + idx++; /*const auto &extent_description = row[idx++];*/ + const auto &south_lat_str = row[idx++]; + const auto &north_lat_str = row[idx++]; + const auto &west_lon_str = row[idx++]; + const auto &east_lon_str = row[idx++]; + const auto &scope = row[idx]; + + util::optional scopeOpt; + if (!scope.empty()) { + scopeOpt = scope; + } + + metadata::ExtentPtr extent; + if (south_lat_str.empty()) { + extent = + metadata::Extent::create( + util::optional(extent_name), {}, {}, {}) + .as_nullable(); + } else { + double south_lat = c_locale_stod(south_lat_str); + double north_lat = c_locale_stod(north_lat_str); + double west_lon = c_locale_stod(west_lon_str); + double east_lon = c_locale_stod(east_lon_str); + auto bbox = metadata::GeographicBoundingBox::create( + west_lon, south_lat, east_lon, north_lat); + extent = metadata::Extent::create( + util::optional(extent_name), + std::vector{bbox}, + std::vector(), + std::vector()) + .as_nullable(); + } + + usages.emplace_back(ObjectDomain::create(scopeOpt, extent)); + } catch (const std::exception &) { + } + } + return createProperties(code, name, deprecated, std::move(usages)); } // --------------------------------------------------------------------------- -util::PropertyMap AuthorityFactory::Private::createProperties( - const std::string &code, const std::string &name, bool deprecated, - const std::string &remarks, const std::string &scope, - const std::string &area_of_use_auth_name, - const std::string &area_of_use_code) { - auto props = createProperties(code, name, deprecated, - area_of_use_auth_name.empty() - ? nullptr - : createFactory(area_of_use_auth_name) - ->createExtent(area_of_use_code) - .as_nullable()); +util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( + const std::string &table_name, const std::string &code, + const std::string &name, bool deprecated, const std::string &remarks) { + auto props = + createPropertiesSearchUsages(table_name, code, name, deprecated); if (!remarks.empty()) props.set(common::IdentifiedObject::REMARKS_KEY, remarks); - if (!scope.empty()) - props.set(common::ObjectUsage::SCOPE_KEY, scope); return props; } @@ -1554,7 +1622,7 @@ AuthorityFactory::createObject(const std::string &code) const { throw FactoryException(msg); } const auto &table_name = res.front()[0]; - if (table_name == "area") { + if (table_name == "extent") { return util::nn_static_pointer_cast( createExtent(code)); } @@ -1639,10 +1707,10 @@ AuthorityFactory::createExtent(const std::string &code) const { } } auto sql = "SELECT name, south_lat, north_lat, west_lon, east_lon, " - "deprecated FROM area WHERE auth_name = ? AND code = ?"; + "deprecated FROM extent WHERE auth_name = ? AND code = ?"; auto res = d->runWithCodeParam(sql, code); if (res.empty()) { - throw NoSuchAuthorityCodeException("area not found", d->authority(), + throw NoSuchAuthorityCodeException("extent not found", d->authority(), code); } try { @@ -1670,7 +1738,7 @@ AuthorityFactory::createExtent(const std::string &code) const { return extent; } catch (const std::exception &ex) { - throw buildFactoryException("area", code, ex); + throw buildFactoryException("extent", code, ex); } } @@ -1816,7 +1884,7 @@ AuthorityFactory::createPrimeMeridian(const std::string &code) const { normalizeMeasure(uom_code, longitude, normalized_uom_code); auto uom = d->createUnitOfMeasure(uom_auth_name, normalized_uom_code); - auto props = d->createProperties(code, name, deprecated, nullptr); + auto props = d->createProperties(code, name, deprecated, {}); auto pm = datum::PrimeMeridian::create( props, common::Angle(normalized_value, uom)); d->context()->d->cache(cacheKey, pm); @@ -1897,7 +1965,7 @@ AuthorityFactory::createEllipsoid(const std::string &code) const { const auto &body = row[6]; const bool deprecated = row[7] == "1"; auto uom = d->createUnitOfMeasure(uom_auth_name, uom_code); - auto props = d->createProperties(code, name, deprecated, nullptr); + auto props = d->createProperties(code, name, deprecated, {}); if (!inv_flattening_str.empty()) { auto ellps = datum::Ellipsoid::createFlattenedSphere( props, common::Length(semi_major_axis, uom), @@ -1940,13 +2008,13 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { return NN_NO_CHECK(datum); } } - auto res = d->runWithCodeParam( - "SELECT name, ellipsoid_auth_name, ellipsoid_code, " - "prime_meridian_auth_name, prime_meridian_code, area_of_use_auth_name, " - "area_of_use_code, publication_date, deprecated FROM geodetic_datum " - "WHERE " - "auth_name = ? AND code = ?", - code); + auto res = + d->runWithCodeParam("SELECT name, ellipsoid_auth_name, ellipsoid_code, " + "prime_meridian_auth_name, prime_meridian_code, " + "publication_date, deprecated FROM geodetic_datum " + "WHERE " + "auth_name = ? AND code = ?", + code); if (res.empty()) { throw NoSuchAuthorityCodeException("geodetic datum not found", d->authority(), code); @@ -1958,16 +2026,14 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { const auto &ellipsoid_code = row[2]; const auto &prime_meridian_auth_name = row[3]; const auto &prime_meridian_code = row[4]; - const auto &area_of_use_auth_name = row[5]; - const auto &area_of_use_code = row[6]; - const auto &publication_date = row[7]; - const bool deprecated = row[8] == "1"; + const auto &publication_date = row[5]; + const bool deprecated = row[6] == "1"; auto ellipsoid = d->createFactory(ellipsoid_auth_name) ->createEllipsoid(ellipsoid_code); auto pm = d->createFactory(prime_meridian_auth_name) ->createPrimeMeridian(prime_meridian_code); - auto props = d->createProperties( - code, name, deprecated, area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages( + "geodetic_datum", code, removeEnsembleSuffix(name), deprecated); auto anchor = util::optional(); if (!publication_date.empty()) { props.set("PUBLICATION_DATE", publication_date); @@ -1993,10 +2059,10 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { datum::VerticalReferenceFrameNNPtr AuthorityFactory::createVerticalDatum(const std::string &code) const { - auto res = d->runWithCodeParam( - "SELECT name, area_of_use_auth_name, area_of_use_code, deprecated FROM " - "vertical_datum WHERE auth_name = ? AND code = ?", - code); + auto res = + d->runWithCodeParam("SELECT name, deprecated FROM " + "vertical_datum WHERE auth_name = ? AND code = ?", + code); if (res.empty()) { throw NoSuchAuthorityCodeException("vertical datum not found", d->authority(), code); @@ -2004,11 +2070,9 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { try { const auto &row = res.front(); const auto &name = row[0]; - const auto &area_of_use_auth_name = row[1]; - const auto &area_of_use_code = row[2]; - const bool deprecated = row[3] == "1"; - auto props = d->createProperties( - code, name, deprecated, area_of_use_auth_name, area_of_use_code); + const bool deprecated = row[1] == "1"; + auto props = d->createPropertiesSearchUsages("vertical_datum", code, + name, deprecated); auto anchor = util::optional(); return datum::VerticalReferenceFrame::create(props, anchor); } catch (const std::exception &ex) { @@ -2105,7 +2169,13 @@ AuthorityFactory::createCoordinateSystem(const std::string &code) const { const auto &orientation = row[2]; const auto &uom_auth_name = row[3]; const auto &uom_code = row[4]; - auto uom = d->createUnitOfMeasure(uom_auth_name, uom_code); + if (uom_auth_name.empty() && csType != "ordinal") { + throw FactoryException("no unit of measure for an axis is only " + "supported for ordinatal CS"); + } + auto uom = uom_auth_name.empty() + ? common::UnitOfMeasure::NONE + : d->createUnitOfMeasure(uom_auth_name, uom_code); auto props = util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, name); const cs::AxisDirection *direction = @@ -2176,6 +2246,9 @@ AuthorityFactory::createCoordinateSystem(const std::string &code) const { } throw FactoryException("invalid number of axis for VerticalCS"); } + if (csType == "ordinal") { + return cacheAndRet(cs::OrdinalCS::create(props, axisList)); + } throw FactoryException("unhandled coordinate system type: " + csType); } @@ -2250,7 +2323,7 @@ AuthorityFactory::createGeodeticCRS(const std::string &code, } std::string sql("SELECT name, type, coordinate_system_auth_name, " "coordinate_system_code, datum_auth_name, datum_code, " - "area_of_use_auth_name, area_of_use_code, text_definition, " + "text_definition, " "deprecated FROM " "geodetic_crs WHERE auth_name = ? AND code = ?"); if (geographicOnly) { @@ -2270,13 +2343,11 @@ AuthorityFactory::createGeodeticCRS(const std::string &code, const auto &cs_code = row[3]; const auto &datum_auth_name = row[4]; const auto &datum_code = row[5]; - const auto &area_of_use_auth_name = row[6]; - const auto &area_of_use_code = row[7]; - const auto &text_definition = row[8]; - const bool deprecated = row[9] == "1"; + const auto &text_definition = row[6]; + const bool deprecated = row[7] == "1"; - auto props = d->createProperties( - code, name, deprecated, area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages("geodetic_crs", code, name, + deprecated); if (!text_definition.empty()) { DatabaseContext::Private::RecursionDetector detector(d->context()); @@ -2359,7 +2430,7 @@ AuthorityFactory::createVerticalCRS(const std::string &code) const { auto res = d->runWithCodeParam( "SELECT name, coordinate_system_auth_name, " "coordinate_system_code, datum_auth_name, datum_code, " - "area_of_use_auth_name, area_of_use_code, deprecated FROM " + "deprecated FROM " "vertical_crs WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -2373,16 +2444,14 @@ AuthorityFactory::createVerticalCRS(const std::string &code) const { const auto &cs_code = row[2]; const auto &datum_auth_name = row[3]; const auto &datum_code = row[4]; - const auto &area_of_use_auth_name = row[5]; - const auto &area_of_use_code = row[6]; - const bool deprecated = row[7] == "1"; + const bool deprecated = row[5] == "1"; auto cs = d->createFactory(cs_auth_name)->createCoordinateSystem(cs_code); auto datum = d->createFactory(datum_auth_name)->createVerticalDatum(datum_code); - auto props = d->createProperties( - code, name, deprecated, area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages("vertical_crs", code, name, + deprecated); auto verticalCS = util::nn_dynamic_pointer_cast(cs); if (verticalCS) { @@ -2412,8 +2481,7 @@ operation::ConversionNNPtr AuthorityFactory::createConversion(const std::string &code) const { static const char *sql = - "SELECT name, description, scope, " - "area_of_use_auth_name, area_of_use_code, " + "SELECT name, description, " "method_auth_name, method_code, method_name, " "param1_auth_name, param1_code, param1_name, param1_value, " @@ -2463,9 +2531,6 @@ AuthorityFactory::createConversion(const std::string &code) const { size_t idx = 0; const auto &name = row[idx++]; const auto &description = row[idx++]; - const auto &scope = row[idx++]; - const auto &area_of_use_auth_name = row[idx++]; - const auto &area_of_use_code = row[idx++]; const auto &method_auth_name = row[idx++]; const auto &method_code = row[idx++]; const auto &method_name = row[idx++]; @@ -2498,9 +2563,11 @@ AuthorityFactory::createConversion(const std::string &code) const { } const bool deprecated = row[base_param_idx + N_MAX_PARAMS * 6] == "1"; - auto propConversion = - d->createProperties(code, name, deprecated, description, scope, - area_of_use_auth_name, area_of_use_code); + auto propConversion = d->createPropertiesSearchUsages( + "conversion", code, name, deprecated); + if (!description.empty()) + propConversion.set(common::IdentifiedObject::REMARKS_KEY, + description); auto propMethod = util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, method_name); @@ -2556,7 +2623,7 @@ AuthorityFactory::Private::createProjectedCRSBegin(const std::string &code) { "SELECT name, coordinate_system_auth_name, " "coordinate_system_code, geodetic_crs_auth_name, geodetic_crs_code, " "conversion_auth_name, conversion_code, " - "area_of_use_auth_name, area_of_use_code, text_definition, " + "text_definition, " "deprecated FROM projected_crs WHERE auth_name = ? AND code = ?", code); } @@ -2581,13 +2648,11 @@ AuthorityFactory::Private::createProjectedCRSEnd(const std::string &code, const auto &geodetic_crs_code = row[4]; const auto &conversion_auth_name = row[5]; const auto &conversion_code = row[6]; - const auto &area_of_use_auth_name = row[7]; - const auto &area_of_use_code = row[8]; - const auto &text_definition = row[9]; - const bool deprecated = row[10] == "1"; + const auto &text_definition = row[7]; + const bool deprecated = row[8] == "1"; - auto props = createProperties(code, name, deprecated, - area_of_use_auth_name, area_of_use_code); + auto props = createPropertiesSearchUsages("projected_crs", code, name, + deprecated); if (!text_definition.empty()) { DatabaseContext::Private::RecursionDetector detector(context()); @@ -2670,12 +2735,12 @@ AuthorityFactory::Private::createProjectedCRSEnd(const std::string &code, crs::CompoundCRSNNPtr AuthorityFactory::createCompoundCRS(const std::string &code) const { - auto res = d->runWithCodeParam( - "SELECT name, horiz_crs_auth_name, horiz_crs_code, " - "vertical_crs_auth_name, vertical_crs_code, " - "area_of_use_auth_name, area_of_use_code, deprecated FROM " - "compound_crs WHERE auth_name = ? AND code = ?", - code); + auto res = + d->runWithCodeParam("SELECT name, horiz_crs_auth_name, horiz_crs_code, " + "vertical_crs_auth_name, vertical_crs_code, " + "deprecated FROM " + "compound_crs WHERE auth_name = ? AND code = ?", + code); if (res.empty()) { throw NoSuchAuthorityCodeException("compoundCRS not found", d->authority(), code); @@ -2687,9 +2752,7 @@ AuthorityFactory::createCompoundCRS(const std::string &code) const { const auto &horiz_crs_code = row[2]; const auto &vertical_crs_auth_name = row[3]; const auto &vertical_crs_code = row[4]; - const auto &area_of_use_auth_name = row[5]; - const auto &area_of_use_code = row[6]; - const bool deprecated = row[7] == "1"; + const bool deprecated = row[5] == "1"; auto horizCRS = d->createFactory(horiz_crs_auth_name) @@ -2697,8 +2760,8 @@ AuthorityFactory::createCompoundCRS(const std::string &code) const { auto vertCRS = d->createFactory(vertical_crs_auth_name) ->createVerticalCRS(vertical_crs_code); - auto props = d->createProperties( - code, name, deprecated, area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages("compound_crs", code, name, + deprecated); return crs::CompoundCRS::create( props, std::vector{horizCRS, vertCRS}); } catch (const std::exception &ex) { @@ -2831,10 +2894,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( if (type == "helmert_transformation") { auto res = d->runWithCodeParam( - "SELECT name, description, scope, " + "SELECT name, description, " "method_auth_name, method_code, method_name, " "source_crs_auth_name, source_crs_code, target_crs_auth_name, " - "target_crs_code, area_of_use_auth_name, area_of_use_code, " + "target_crs_code, " "accuracy, tx, ty, tz, translation_uom_auth_name, " "translation_uom_code, rx, ry, rz, rotation_uom_auth_name, " "rotation_uom_code, scale_difference, " @@ -2858,7 +2921,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( size_t idx = 0; const auto &name = row[idx++]; const auto &description = row[idx++]; - const auto &scope = row[idx++]; const auto &method_auth_name = row[idx++]; const auto &method_code = row[idx++]; const auto &method_name = row[idx++]; @@ -2866,8 +2928,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &source_crs_code = row[idx++]; const auto &target_crs_auth_name = row[idx++]; const auto &target_crs_code = row[idx++]; - const auto &area_of_use_auth_name = row[idx++]; - const auto &area_of_use_code = row[idx++]; const auto &accuracy = row[idx++]; const auto &tx = row[idx++]; @@ -3046,9 +3106,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( values.emplace_back(createLength(pz, uom_pivot)); } - auto props = - d->createProperties(code, name, deprecated, description, scope, - area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages( + type, code, name, deprecated, description); if (!operation_version.empty()) { props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, operation_version); @@ -3076,10 +3135,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( if (type == "grid_transformation") { auto res = d->runWithCodeParam( - "SELECT name, description, scope, " + "SELECT name, description, " "method_auth_name, method_code, method_name, " "source_crs_auth_name, source_crs_code, target_crs_auth_name, " - "target_crs_code, area_of_use_auth_name, area_of_use_code, " + "target_crs_code, " "accuracy, grid_param_auth_name, grid_param_code, grid_param_name, " "grid_name, " "grid2_param_auth_name, grid2_param_code, grid2_param_name, " @@ -3098,7 +3157,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( size_t idx = 0; const auto &name = row[idx++]; const auto &description = row[idx++]; - const auto &scope = row[idx++]; const auto &method_auth_name = row[idx++]; const auto &method_code = row[idx++]; const auto &method_name = row[idx++]; @@ -3106,8 +3164,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &source_crs_code = row[idx++]; const auto &target_crs_auth_name = row[idx++]; const auto &target_crs_code = row[idx++]; - const auto &area_of_use_auth_name = row[idx++]; - const auto &area_of_use_code = row[idx++]; const auto &accuracy = row[idx++]; const auto &grid_param_auth_name = row[idx++]; const auto &grid_param_code = row[idx++]; @@ -3162,9 +3218,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( operation::ParameterValue::createFilename(grid2_name)); } - auto props = - d->createProperties(code, name, deprecated, description, scope, - area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages( + type, code, name, deprecated, description); if (!operation_version.empty()) { props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, operation_version); @@ -3197,10 +3252,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( std::ostringstream buffer; buffer.imbue(std::locale::classic()); buffer - << "SELECT name, description, scope, " + << "SELECT name, description, " "method_auth_name, method_code, method_name, " "source_crs_auth_name, source_crs_code, target_crs_auth_name, " - "target_crs_code, area_of_use_auth_name, area_of_use_code, " + "target_crs_code, " "accuracy"; constexpr int N_MAX_PARAMS = 7; for (int i = 1; i <= N_MAX_PARAMS; ++i) { @@ -3225,7 +3280,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( size_t idx = 0; const auto &name = row[idx++]; const auto &description = row[idx++]; - const auto &scope = row[idx++]; const auto &method_auth_name = row[idx++]; const auto &method_code = row[idx++]; const auto &method_name = row[idx++]; @@ -3233,8 +3287,6 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &source_crs_code = row[idx++]; const auto &target_crs_auth_name = row[idx++]; const auto &target_crs_code = row[idx++]; - const auto &area_of_use_auth_name = row[idx++]; - const auto &area_of_use_code = row[idx++]; const auto &accuracy = row[idx++]; const size_t base_param_idx = idx; @@ -3279,9 +3331,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( d->createFactory(target_crs_auth_name) ->createCoordinateReferenceSystem(target_crs_code); - auto props = - d->createProperties(code, name, deprecated, description, scope, - area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages( + type, code, name, deprecated, description); if (!operation_version.empty()) { props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, operation_version); @@ -3338,10 +3389,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( if (allowConcatenated && type == "concatenated_operation") { auto res = d->runWithCodeParam( - "SELECT name, description, scope, " + "SELECT name, description, " "source_crs_auth_name, source_crs_code, " "target_crs_auth_name, target_crs_code, " - "area_of_use_auth_name, area_of_use_code, accuracy, " + "accuracy, " "operation_version, deprecated FROM " "concatenated_operation WHERE auth_name = ? AND code = ?", code); @@ -3362,13 +3413,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( size_t idx = 0; const auto &name = row[idx++]; const auto &description = row[idx++]; - const auto &scope = row[idx++]; const auto &source_crs_auth_name = row[idx++]; const auto &source_crs_code = row[idx++]; const auto &target_crs_auth_name = row[idx++]; const auto &target_crs_code = row[idx++]; - const auto &area_of_use_auth_name = row[idx++]; - const auto &area_of_use_code = row[idx++]; const auto &accuracy = row[idx++]; const auto &operation_version = row[idx++]; const auto &deprecated_str = row[idx++]; @@ -3392,9 +3440,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( ->createCoordinateReferenceSystem(target_crs_code), operations); - auto props = - d->createProperties(code, name, deprecated, description, scope, - area_of_use_auth_name, area_of_use_code); + auto props = d->createPropertiesSearchUsages( + type, code, name, deprecated, description); if (!operation_version.empty()) { props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, operation_version); @@ -3602,11 +3649,17 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes( sql = "SELECT source_crs_auth_name, source_crs_code, " "target_crs_auth_name, target_crs_code, " "cov.auth_name, cov.code, cov.table_name, " - "area.south_lat, area.west_lon, area.north_lat, area.east_lon, " + "extent.south_lat, extent.west_lon, extent.north_lat, " + "extent.east_lon, " "ss.replacement_auth_name, ss.replacement_code FROM " - "coordinate_operation_view cov JOIN area " - "ON cov.area_of_use_auth_name = area.auth_name AND " - "cov.area_of_use_code = area.code " + "coordinate_operation_view cov " + "JOIN usage ON " + "usage.object_table_name = cov.table_name AND " + "usage.object_auth_name = cov.auth_name AND " + "usage.object_code = cov.code " + "JOIN extent " + "ON extent.auth_name = usage.extent_auth_name AND " + "extent.code = usage.extent_code " "LEFT JOIN supersession ss ON " "ss.superseded_table_name = cov.table_name AND " "ss.superseded_auth_name = cov.auth_name AND " @@ -3618,11 +3671,17 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes( sql = "SELECT source_crs_auth_name, source_crs_code, " "target_crs_auth_name, target_crs_code, " "cov.auth_name, cov.code, cov.table_name, " - "area.south_lat, area.west_lon, area.north_lat, area.east_lon " + "extent.south_lat, extent.west_lon, extent.north_lat, " + "extent.east_lon " "FROM " - "coordinate_operation_view cov JOIN area " - "ON cov.area_of_use_auth_name = area.auth_name AND " - "cov.area_of_use_code = area.code " + "coordinate_operation_view cov " + "JOIN usage ON " + "usage.object_table_name = cov.table_name AND " + "usage.object_auth_name = cov.auth_name AND " + "usage.object_code = cov.code " + "JOIN extent " + "ON extent.auth_name = usage.extent_auth_name AND " + "extent.code = usage.extent_code " "WHERE "; } ListOfParams params; @@ -3955,10 +4014,20 @@ AuthorityFactory::createFromCRSCodesWithIntermediates( "ss2.same_source_target_crs = 1 "); 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 " - "AND v2.area_of_use_code = a2.code "); + "JOIN usage u1 ON " + "u1.object_table_name = v1.table_name AND " + "u1.object_auth_name = v1.auth_name AND " + "u1.object_code = v1.code " + "JOIN extent a1 " + "ON a1.auth_name = u1.extent_auth_name AND " + "a1.code = u1.extent_code " + "JOIN usage u2 ON " + "u2.object_table_name = v2.table_name AND " + "u2.object_auth_name = v2.auth_name AND " + "u2.object_code = v2.code " + "JOIN extent a2 " + "ON a2.auth_name = u2.extent_auth_name AND " + "a2.code = u2.extent_code "); const std::string orderBy( "ORDER BY (CASE WHEN accuracy1 is NULL THEN 1 ELSE 0 END) + " "(CASE WHEN accuracy2 is NULL THEN 1 ELSE 0 END), " @@ -4399,11 +4468,20 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates( "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( - "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 " - "AND v2.area_of_use_code = a2.code "); + const std::string joinArea("JOIN usage u1 ON " + "u1.object_table_name = v1.table_name AND " + "u1.object_auth_name = v1.auth_name AND " + "u1.object_code = v1.code " + "JOIN extent a1 " + "ON a1.auth_name = u1.extent_auth_name AND " + "a1.code = u1.extent_code " + "JOIN usage u2 ON " + "u2.object_table_name = v2.table_name AND " + "u2.object_auth_name = v2.auth_name AND " + "u2.object_code = v2.code " + "JOIN extent a2 " + "ON a2.auth_name = u2.extent_auth_name AND " + "a2.code = u2.extent_code "); auto params = ListOfParams{sourceCRSAuthName, sourceCRSCode, targetCRSAuthName, targetCRSCode}; @@ -5206,13 +5284,23 @@ AuthorityFactory::getDescriptionText(const std::string &code) const { * @throw FactoryException */ std::list AuthorityFactory::getCRSInfoList() const { + + const auto getSqlArea = [](const std::string &table_name) { + return "JOIN usage u ON " + "u.object_table_name = '" + + table_name + "' AND " + "u.object_auth_name = c.auth_name AND " + "u.object_code = c.code " + "JOIN extent a " + "ON a.auth_name = u.extent_auth_name AND " + "a.code = u.extent_code "; + }; + std::string sql = "SELECT c.auth_name, c.code, c.name, c.type, " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM geodetic_crs c " - "JOIN area a ON " - "c.area_of_use_auth_name = a.auth_name AND " - "c.area_of_use_code = a.code"; + "a.name, NULL FROM geodetic_crs c " + + getSqlArea("geodetic_crs"); ListOfParams params; if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; @@ -5222,10 +5310,8 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'projected', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, cm.name AS conversion_method_name FROM projected_crs c " - "JOIN area a ON " - "c.area_of_use_auth_name = a.auth_name AND " - "c.area_of_use_code = a.code " + "a.name, cm.name AS conversion_method_name FROM projected_crs c " + + getSqlArea("projected_crs") + "LEFT JOIN conversion_table conv ON " "c.conversion_auth_name = conv.auth_name AND " "c.conversion_code = conv.code " @@ -5240,10 +5326,8 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'vertical', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM vertical_crs c " - "JOIN area a ON " - "c.area_of_use_auth_name = a.auth_name AND " - "c.area_of_use_code = a.code"; + "a.name, NULL FROM vertical_crs c " + + getSqlArea("vertical_crs"); if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; params.emplace_back(d->authority()); @@ -5252,10 +5336,8 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'compound', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM compound_crs c " - "JOIN area a ON " - "c.area_of_use_auth_name = a.auth_name AND " - "c.area_of_use_code = a.code"; + "a.name, NULL FROM compound_crs c " + + getSqlArea("compound_crs"); if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; params.emplace_back(d->authority()); @@ -5416,7 +5498,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias( if (res.empty()) { // shouldn't happen normally return std::string(); } - return res.front()[0]; + return removeEnsembleSuffix(res.front()[0]); } } return std::string(); @@ -5466,7 +5548,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias( outTableName = row[1]; outAuthName = row[2]; outCode = row[3]; - return row[0]; + return removeEnsembleSuffix(row[0]); } } @@ -5521,7 +5603,7 @@ AuthorityFactory::createObjectsFromNameEx( const std::string &searchedName, const std::vector &allowedObjectTypes, bool approximateMatch, size_t limitResultCount) const { - std::string searchedNameWithoutDeprecated(searchedName); + std::string searchedNameWithoutDeprecated(addEnsembleSuffix(searchedName)); bool deprecated = false; if (ends_with(searchedNameWithoutDeprecated, " (deprecated)")) { deprecated = true; @@ -5925,7 +6007,7 @@ std::list> AuthorityFactory::listAreaOfUseFromName(const std::string &name, bool approximateMatch) const { std::string sql( - "SELECT auth_name, code FROM area WHERE deprecated = 0 AND "); + "SELECT auth_name, code FROM extent WHERE deprecated = 0 AND "); ListOfParams params; if (d->hasAuthorityRestriction()) { sql += " auth_name = ? AND "; -- cgit v1.2.3 From 2cfdd6f7fc683517a62147feace1b98b3f587abc Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 5 Oct 2020 14:56:41 +0200 Subject: Database: instanciate DynamicGeodeticReferenceFrame (things like ITRFxxx, WGS 84 (Gxxxx), etc.) when possible --- src/iso19111/factory.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index f98e5cc8..79419d73 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -2011,7 +2011,8 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { auto res = d->runWithCodeParam("SELECT name, ellipsoid_auth_name, ellipsoid_code, " "prime_meridian_auth_name, prime_meridian_code, " - "publication_date, deprecated FROM geodetic_datum " + "publication_date, frame_reference_epoch, " + "deprecated FROM geodetic_datum " "WHERE " "auth_name = ? AND code = ?", code); @@ -2027,7 +2028,8 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { const auto &prime_meridian_auth_name = row[3]; const auto &prime_meridian_code = row[4]; const auto &publication_date = row[5]; - const bool deprecated = row[6] == "1"; + const auto &frame_reference_epoch = row[6]; + const bool deprecated = row[7] == "1"; auto ellipsoid = d->createFactory(ellipsoid_auth_name) ->createEllipsoid(ellipsoid_code); auto pm = d->createFactory(prime_meridian_auth_name) @@ -2039,7 +2041,15 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { props.set("PUBLICATION_DATE", publication_date); } auto datum = - datum::GeodeticReferenceFrame::create(props, ellipsoid, anchor, pm); + frame_reference_epoch.empty() + ? datum::GeodeticReferenceFrame::create(props, ellipsoid, + anchor, pm) + : util::nn_static_pointer_cast( + datum::DynamicGeodeticReferenceFrame::create( + props, ellipsoid, anchor, pm, + common::Measure(c_locale_stod(frame_reference_epoch), + common::UnitOfMeasure::YEAR), + util::optional())); d->context()->d->cache(cacheKey, datum); return datum; } catch (const std::exception &ex) { -- cgit v1.2.3 From 3ed9a613d8da9874f45d2a069686f1fa38c72ad9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 5 Oct 2020 15:40:20 +0200 Subject: Database: use extended description for extent/area of use, as done by epsg.org WKT export --- src/iso19111/factory.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 79419d73..6eb03ad4 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1432,7 +1432,7 @@ util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( const std::string &name, bool deprecated) { const std::string sql( - "SELECT extent.name, extent.description, extent.south_lat, " + "SELECT extent.description, extent.south_lat, " "extent.north_lat, extent.west_lon, extent.east_lon, " "scope.scope, " "(CASE WHEN scope.scope LIKE '%large scale%' THEN 0 ELSE 1 END) " @@ -1450,8 +1450,7 @@ util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( for (const auto &row : res) { try { size_t idx = 0; - const auto &extent_name = row[idx++]; - idx++; /*const auto &extent_description = row[idx++];*/ + const auto &extent_description = row[idx++]; const auto &south_lat_str = row[idx++]; const auto &north_lat_str = row[idx++]; const auto &west_lon_str = row[idx++]; @@ -1465,10 +1464,10 @@ util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( metadata::ExtentPtr extent; if (south_lat_str.empty()) { - extent = - metadata::Extent::create( - util::optional(extent_name), {}, {}, {}) - .as_nullable(); + extent = metadata::Extent::create( + util::optional(extent_description), + {}, {}, {}) + .as_nullable(); } else { double south_lat = c_locale_stod(south_lat_str); double north_lat = c_locale_stod(north_lat_str); @@ -1477,7 +1476,7 @@ util::PropertyMap AuthorityFactory::Private::createPropertiesSearchUsages( auto bbox = metadata::GeographicBoundingBox::create( west_lon, south_lat, east_lon, north_lat); extent = metadata::Extent::create( - util::optional(extent_name), + util::optional(extent_description), std::vector{bbox}, std::vector(), std::vector()) @@ -1706,7 +1705,7 @@ AuthorityFactory::createExtent(const std::string &code) const { return NN_NO_CHECK(extent); } } - auto sql = "SELECT name, south_lat, north_lat, west_lon, east_lon, " + auto sql = "SELECT description, south_lat, north_lat, west_lon, east_lon, " "deprecated FROM extent WHERE auth_name = ? AND code = ?"; auto res = d->runWithCodeParam(sql, code); if (res.empty()) { @@ -1715,10 +1714,10 @@ AuthorityFactory::createExtent(const std::string &code) const { } try { const auto &row = res.front(); - const auto &name = row[0]; + const auto &description = row[0]; if (row[1].empty()) { auto extent = metadata::Extent::create( - util::optional(name), {}, {}, {}); + util::optional(description), {}, {}, {}); d->context()->d->cache(cacheKey, extent); return extent; } @@ -1730,7 +1729,7 @@ AuthorityFactory::createExtent(const std::string &code) const { west_lon, south_lat, east_lon, north_lat); auto extent = metadata::Extent::create( - util::optional(name), + util::optional(description), std::vector{bbox}, std::vector(), std::vector()); -- cgit v1.2.3 From ecf9cf0d975b3eb7630a314e8b32dd59658c3e2a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 8 Oct 2020 17:31:13 +0200 Subject: getCRSInfoList(): make it use area description --- src/iso19111/factory.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 6eb03ad4..5d0ed69a 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5308,7 +5308,7 @@ std::list AuthorityFactory::getCRSInfoList() const { std::string sql = "SELECT c.auth_name, c.code, c.name, c.type, " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM geodetic_crs c " + + "a.description, NULL FROM geodetic_crs c " + getSqlArea("geodetic_crs"); ListOfParams params; if (d->hasAuthorityRestriction()) { @@ -5319,7 +5319,8 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'projected', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, cm.name AS conversion_method_name FROM projected_crs c " + + "a.description, cm.name AS conversion_method_name FROM " + "projected_crs c " + getSqlArea("projected_crs") + "LEFT JOIN conversion_table conv ON " "c.conversion_auth_name = conv.auth_name AND " @@ -5335,7 +5336,7 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'vertical', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM vertical_crs c " + + "a.description, NULL FROM vertical_crs c " + getSqlArea("vertical_crs"); if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; @@ -5345,7 +5346,7 @@ std::list AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'compound', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, NULL FROM compound_crs c " + + "a.description, NULL FROM compound_crs c " + getSqlArea("compound_crs"); if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; -- cgit v1.2.3 From fece8a6c6e2e5eebeac6f9b4fc47ca830f2e3a3a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 6 Oct 2020 17:49:14 +0200 Subject: Database: add aliases for 'old' names of WGS84 and ETRS89 datums, and remove one hack --- src/iso19111/factory.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 5d0ed69a..46657431 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1064,16 +1064,6 @@ std::string DatabaseContext::getOldProjGridName(const std::string &gridName) { // --------------------------------------------------------------------------- -// FIXME: as we don't support datum ensemble yet, remove it from name -static std::string addEnsembleSuffix(const std::string &name) { - if (name == "World Geodetic System 1984") { - return "World Geodetic System 1984 ensemble"; - } else if (name == "European Terrestrial Reference System 1989") { - return "European Terrestrial Reference System 1989 ensemble"; - } - return name; -} - // FIXME: as we don't support datum ensemble yet, add it from name static std::string removeEnsembleSuffix(const std::string &name) { if (name == "World Geodetic System 1984 ensemble") { @@ -1104,9 +1094,15 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName, if (tableName == "geodetic_crs") { sql += " AND type = " GEOG_2D_SINGLE_QUOTED; } - auto res = d->run(sql, {addEnsembleSuffix(officialName)}); + auto res = d->run(sql, {officialName}); if (res.empty()) { - return std::string(); + res = d->run( + "SELECT auth_name, code FROM alias_name WHERE table_name = ? AND " + "alt_name = ? AND source IN ('EPSG', 'PROJ')", + {tableName, officialName}); + if (res.size() != 1) { + return std::string(); + } } const auto &row = res.front(); res = d->run("SELECT alt_name FROM alias_name WHERE table_name = ? AND " @@ -1151,10 +1147,16 @@ std::list DatabaseContext::getAliases( if (tableName == "geodetic_crs") { sql += " AND type = " GEOG_2D_SINGLE_QUOTED; } - auto resSql = d->run(sql, {addEnsembleSuffix(officialName)}); + auto resSql = d->run(sql, {officialName}); if (resSql.empty()) { - d->cacheAliasNames_.insert(key, res); - return res; + resSql = d->run("SELECT auth_name, code FROM alias_name WHERE " + "table_name = ? AND " + "alt_name = ? AND source IN ('EPSG', 'PROJ')", + {tableName, officialName}); + if (resSql.size() != 1) { + d->cacheAliasNames_.insert(key, res); + return res; + } } const auto &row = resSql.front(); resolvedAuthName = row[0]; @@ -5613,7 +5615,7 @@ AuthorityFactory::createObjectsFromNameEx( const std::string &searchedName, const std::vector &allowedObjectTypes, bool approximateMatch, size_t limitResultCount) const { - std::string searchedNameWithoutDeprecated(addEnsembleSuffix(searchedName)); + std::string searchedNameWithoutDeprecated(searchedName); bool deprecated = false; if (ends_with(searchedNameWithoutDeprecated, " (deprecated)")) { deprecated = true; -- cgit v1.2.3 From b5369cc79eccc625419d37bb97a5361731fd8f0f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 6 Oct 2020 22:15:31 +0200 Subject: Add a AuthorityFactory::createDatumEnsemble() method, and make it inherit from ObjectUsage as mandated by ISO 19111:2019 --- src/iso19111/factory.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 46657431..3895edb2 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1604,9 +1604,9 @@ AuthorityFactory::CRSInfo::CRSInfo() util::BaseObjectNNPtr AuthorityFactory::createObject(const std::string &code) const { - auto res = d->runWithCodeParam( - "SELECT table_name FROM object_view WHERE auth_name = ? AND code = ?", - code); + auto res = d->runWithCodeParam("SELECT table_name, type FROM object_view " + "WHERE auth_name = ? AND code = ?", + code); if (res.empty()) { throw NoSuchAuthorityCodeException("not found", d->authority(), code); } @@ -1622,7 +1622,9 @@ AuthorityFactory::createObject(const std::string &code) const { } throw FactoryException(msg); } - const auto &table_name = res.front()[0]; + const auto &first_row = res.front(); + const auto &table_name = first_row[0]; + const auto &type = first_row[1]; if (table_name == "extent") { return util::nn_static_pointer_cast( createExtent(code)); @@ -1640,10 +1642,18 @@ AuthorityFactory::createObject(const std::string &code) const { createEllipsoid(code)); } if (table_name == "geodetic_datum") { + if (type == "ensemble") { + return util::nn_static_pointer_cast( + createDatumEnsemble(code, table_name)); + } return util::nn_static_pointer_cast( createGeodeticDatum(code)); } if (table_name == "vertical_datum") { + if (type == "ensemble") { + return util::nn_static_pointer_cast( + createDatumEnsemble(code, table_name)); + } return util::nn_static_pointer_cast( createVerticalDatum(code)); } @@ -2093,6 +2103,62 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { // --------------------------------------------------------------------------- +/** \brief Returns a datum::DatumEnsemble from the specified code. + * + * @param code Object code allocated by authority. + * @param type "geodetic_datum", "vertical_datum" or empty string if unknown + * @return object. + * @throw NoSuchAuthorityCodeException + * @throw FactoryException + */ + +datum::DatumEnsembleNNPtr +AuthorityFactory::createDatumEnsemble(const std::string &code, + const std::string &type) const { + auto res = d->run( + "SELECT 'geodetic_datum', name, ensemble_accuracy, deprecated FROM " + "geodetic_datum WHERE " + "auth_name = ? AND code = ? AND ensemble_accuracy IS NOT NULL " + "UNION ALL " + "SELECT 'vertical_datum', name, ensemble_accuracy, deprecated FROM " + "vertical_datum WHERE " + "auth_name = ? AND code = ? AND ensemble_accuracy IS NOT NULL", + {d->authority(), code, d->authority(), code}); + if (res.empty()) { + throw NoSuchAuthorityCodeException("datum ensemble not found", + d->authority(), code); + } + for (const auto &row : res) { + const std::string &gotType = row[0]; + const std::string &name = row[1]; + const std::string &ensembleAccuracy = row[2]; + const bool deprecated = row[3] == "1"; + if (type.empty() || type == gotType) { + auto resMembers = + d->run("SELECT member_auth_name, member_code FROM " + gotType + + "_ensemble_member WHERE " + "ensemble_auth_name = ? AND ensemble_code = ? " + "ORDER BY sequence", + {d->authority(), code}); + + std::vector members; + for (const auto &memberRow : resMembers) { + members.push_back( + d->createFactory(memberRow[0])->createDatum(memberRow[1])); + } + auto props = d->createPropertiesSearchUsages(gotType, code, name, + deprecated); + return datum::DatumEnsemble::create( + props, std::move(members), + metadata::PositionalAccuracy::create(ensembleAccuracy)); + } + } + throw NoSuchAuthorityCodeException("datum ensemble not found", + d->authority(), code); +} + +// --------------------------------------------------------------------------- + /** \brief Returns a datum::Datum from the specified code. * * @param code Object code allocated by authority. -- cgit v1.2.3 From 4049f4cc961f78d9313525e3eb82fbc5bb3fd879 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 8 Oct 2020 01:09:54 +0200 Subject: createGeodeticCRS(): more DatumEnsemble compatibility in the case when creating from text_definition --- src/iso19111/factory.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 3895edb2..5f12273d 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -2366,18 +2366,16 @@ static crs::GeodeticCRSNNPtr cloneWithProps(const crs::GeodeticCRSNNPtr &geodCRS, const util::PropertyMap &props) { auto cs = geodCRS->coordinateSystem(); - auto datum = geodCRS->datum(); - if (!datum) { - return geodCRS; - } auto ellipsoidalCS = util::nn_dynamic_pointer_cast(cs); if (ellipsoidalCS) { - return crs::GeographicCRS::create(props, NN_NO_CHECK(datum), + return crs::GeographicCRS::create(props, geodCRS->datum(), + geodCRS->datumEnsemble(), NN_NO_CHECK(ellipsoidalCS)); } auto geocentricCS = util::nn_dynamic_pointer_cast(cs); if (geocentricCS) { - return crs::GeodeticCRS::create(props, NN_NO_CHECK(datum), + return crs::GeodeticCRS::create(props, geodCRS->datum(), + geodCRS->datumEnsemble(), NN_NO_CHECK(geocentricCS)); } return geodCRS; -- cgit v1.2.3 From ad80dc88a70032e1d96812b574b2d4d22e223394 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 11 Oct 2020 19:50:09 +0200 Subject: Database: add a frame_reference_epoch column in vertical_datum to be able to handle dynamic vertical datums, and instanciate them properly from database --- src/iso19111/factory.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 5f12273d..473aa254 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -2081,7 +2081,8 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { datum::VerticalReferenceFrameNNPtr AuthorityFactory::createVerticalDatum(const std::string &code) const { auto res = - d->runWithCodeParam("SELECT name, deprecated FROM " + d->runWithCodeParam("SELECT name, publication_date, " + "frame_reference_epoch, deprecated FROM " "vertical_datum WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -2091,11 +2092,23 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { try { const auto &row = res.front(); const auto &name = row[0]; - const bool deprecated = row[1] == "1"; + const auto &publication_date = row[1]; + const auto &frame_reference_epoch = row[2]; + const bool deprecated = row[3] == "1"; auto props = d->createPropertiesSearchUsages("vertical_datum", code, name, deprecated); + if (!publication_date.empty()) { + props.set("PUBLICATION_DATE", publication_date); + } auto anchor = util::optional(); - return datum::VerticalReferenceFrame::create(props, anchor); + return frame_reference_epoch.empty() + ? datum::VerticalReferenceFrame::create(props, anchor) + : datum::DynamicVerticalReferenceFrame::create( + props, anchor, + util::optional(), + common::Measure(c_locale_stod(frame_reference_epoch), + common::UnitOfMeasure::YEAR), + util::optional()); } catch (const std::exception &ex) { throw buildFactoryException("vertical reference frame", code, ex); } -- cgit v1.2.3 From d1a0d95da549f7d32bcd8be408afe1fca62a6fb2 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 11 Oct 2020 20:01:29 +0200 Subject: Database query: add AuthorityFactory::ObjectType::DYNAMIC_GEODETIC_REFERENCE_FRAME and DYNAMIC_VERTICAL_REFERENCE_FRAME, and make corresponding C API work --- src/iso19111/factory.cpp | 53 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 473aa254..ef5c6e02 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -2101,14 +2101,15 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { props.set("PUBLICATION_DATE", publication_date); } auto anchor = util::optional(); - return frame_reference_epoch.empty() - ? datum::VerticalReferenceFrame::create(props, anchor) - : datum::DynamicVerticalReferenceFrame::create( - props, anchor, - util::optional(), - common::Measure(c_locale_stod(frame_reference_epoch), - common::UnitOfMeasure::YEAR), - util::optional()); + if (frame_reference_epoch.empty()) { + return datum::VerticalReferenceFrame::create(props, anchor); + } else { + return datum::DynamicVerticalReferenceFrame::create( + props, anchor, util::optional(), + common::Measure(c_locale_stod(frame_reference_epoch), + common::UnitOfMeasure::YEAR), + util::optional()); + } } catch (const std::exception &ex) { throw buildFactoryException("vertical reference frame", code, ex); } @@ -5260,9 +5261,17 @@ AuthorityFactory::getAuthorityCodes(const ObjectType &type, case ObjectType::GEODETIC_REFERENCE_FRAME: sql = "SELECT code FROM geodetic_datum WHERE "; break; + case ObjectType::DYNAMIC_GEODETIC_REFERENCE_FRAME: + sql = "SELECT code FROM geodetic_datum WHERE " + "frame_reference_epoch IS NOT NULL AND "; + break; case ObjectType::VERTICAL_REFERENCE_FRAME: sql = "SELECT code FROM vertical_datum WHERE "; break; + case ObjectType::DYNAMIC_VERTICAL_REFERENCE_FRAME: + sql = "SELECT code FROM vertical_datum WHERE " + "frame_reference_epoch IS NOT NULL AND "; + break; case ObjectType::CRS: sql = "SELECT code FROM crs_view WHERE "; break; @@ -5742,10 +5751,18 @@ AuthorityFactory::createObjectsFromNameEx( res.emplace_back( TableType("geodetic_datum", std::string())); break; + case ObjectType::DYNAMIC_GEODETIC_REFERENCE_FRAME: + res.emplace_back( + TableType("geodetic_datum", "frame_reference_epoch")); + break; case ObjectType::VERTICAL_REFERENCE_FRAME: res.emplace_back( TableType("vertical_datum", std::string())); break; + case ObjectType::DYNAMIC_VERTICAL_REFERENCE_FRAME: + res.emplace_back( + TableType("vertical_datum", "frame_reference_epoch")); + break; case ObjectType::CRS: res.emplace_back(TableType("geodetic_crs", std::string())); res.emplace_back(TableType("projected_crs", std::string())); @@ -5824,9 +5841,13 @@ AuthorityFactory::createObjectsFromNameEx( sql += tableNameTypePair.first; sql += " WHERE 1 = 1 "; if (!tableNameTypePair.second.empty()) { - sql += "AND type = '"; - sql += tableNameTypePair.second; - sql += "' "; + if (tableNameTypePair.second == "frame_reference_epoch") { + sql += "AND frame_reference_epoch IS NOT NULL "; + } else { + sql += "AND type = '"; + sql += tableNameTypePair.second; + sql += "' "; + } } if (deprecated) { sql += "AND deprecated = 1 "; @@ -5854,9 +5875,13 @@ AuthorityFactory::createObjectsFromNameEx( sql += tableNameTypePair.first; sql += "' "; if (!tableNameTypePair.second.empty()) { - sql += "AND ov.type = '"; - sql += tableNameTypePair.second; - sql += "' "; + if (tableNameTypePair.second == "frame_reference_epoch") { + sql += "AND ov.frame_reference_epoch IS NOT NULL "; + } else { + sql += "AND ov.type = '"; + sql += tableNameTypePair.second; + sql += "' "; + } } if (deprecated) { sql += "AND ov.deprecated = 1 "; -- cgit v1.2.3