diff options
| author | Even Rouault <even.rouault@mines-paris.org> | 2018-12-03 22:51:40 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-03 22:51:40 +0100 |
| commit | addf30e4446fd39891fd5bdcb22413ed41e0913b (patch) | |
| tree | f1494607cebc2316b8ab17b43a9b37c887ccdec8 | |
| parent | d0506e19a71888f7f0c3aa8618d919624e754c4d (diff) | |
| parent | 0ba9d249136ec7adf6e3a44c8148701818d0e63e (diff) | |
| download | PROJ-addf30e4446fd39891fd5bdcb22413ed41e0913b.tar.gz PROJ-addf30e4446fd39891fd5bdcb22413ed41e0913b.zip | |
Merge pull request #1189 from rouault/projinfo_improvements
Projinfo improvements: output operation summary and add --area option
| -rw-r--r-- | include/proj/io.hpp | 5 | ||||
| -rw-r--r-- | src/factory.cpp | 35 | ||||
| -rw-r--r-- | src/projinfo.cpp | 164 | ||||
| -rwxr-xr-x | test/cli/testprojinfo | 25 | ||||
| -rw-r--r-- | test/cli/testprojinfo_out.dist | 47 | ||||
| -rw-r--r-- | test/unit/test_factory.cpp | 22 |
6 files changed, 254 insertions, 44 deletions
diff --git a/include/proj/io.hpp b/include/proj/io.hpp index ba7e9f53..41038e2d 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -907,7 +907,10 @@ class PROJ_GCC_DLL AuthorityFactory { const std::vector<ObjectType> &allowedObjectTypes = std::vector<ObjectType>(), bool approximateMatch = true, - size_t limitResultCount = 0); + size_t limitResultCount = 0) const; + + PROJ_DLL std::list<std::pair<std::string, std::string>> + listAreaOfUseFromName(const std::string &name, bool approximateMatch) const; PROJ_PRIVATE : //! @cond Doxygen_Suppress diff --git a/src/factory.cpp b/src/factory.cpp index 91d0c478..7bc9c4d2 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -3642,7 +3642,7 @@ std::list<common::IdentifiedObjectNNPtr> AuthorityFactory::createObjectsFromName( const std::string &searchedName, const std::vector<ObjectType> &allowedObjectTypes, bool approximateMatch, - size_t limitResultCount) { + size_t limitResultCount) const { std::string searchedNameWithoutDeprecated(searchedName); bool deprecated = false; @@ -3885,6 +3885,39 @@ AuthorityFactory::createObjectsFromName( // --------------------------------------------------------------------------- +/** \brief Return a list of area of use from their name + * + * @param name Searched name. + * @param approximateMatch Whether approximate name identification is allowed. + * @return list of (auth_name, code) of matched objects. + * @throw FactoryException + */ +std::list<std::pair<std::string, std::string>> +AuthorityFactory::listAreaOfUseFromName(const std::string &name, + bool approximateMatch) const { + std::string sql( + "SELECT auth_name, code FROM area WHERE deprecated = 0 AND "); + std::vector<SQLValues> params; + if (!getAuthority().empty()) { + sql += " auth_name = ? AND "; + params.emplace_back(getAuthority()); + } + sql += "name LIKE ?"; + if (!approximateMatch) { + params.push_back(name); + } else { + params.push_back('%' + name + '%'); + } + auto sqlRes = d->run(sql, params); + std::list<std::pair<std::string, std::string>> res; + for (const auto &row : sqlRes) { + res.emplace_back(row[0], row[1]); + } + return res; +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress std::list<datum::EllipsoidNNPtr> AuthorityFactory::createEllipsoidFromExisting( const datum::EllipsoidNNPtr &ellipsoid) const { diff --git a/src/projinfo.cpp b/src/projinfo.cpp index 7acb13af..d13b5ee5 100644 --- a/src/projinfo.cpp +++ b/src/projinfo.cpp @@ -74,7 +74,8 @@ static void usage() { std::cerr << "usage: projinfo [-o formats] [-k crs|operation] [--summary] [-q]" << std::endl - << " [--bbox min_long,min_lat,max_long,max_lat] " + << " ([--area name_or_code] | " + "[--bbox min_long,min_lat,max_long,max_lat]) " << std::endl << " [--spatial-test contains|intersects]" << std::endl << " [--crs-extent-use none|both|intersection|smallest]" @@ -422,6 +423,51 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, // --------------------------------------------------------------------------- +static void outputOperationSummary(const CoordinateOperationNNPtr &op) { + auto ids = op->identifiers(); + if (!ids.empty()) { + std::cout << *(ids[0]->codeSpace()) << ":" << ids[0]->code(); + } else { + std::cout << "unknown id"; + } + + std::cout << ", "; + + auto name = op->nameStr(); + if (!name.empty()) { + std::cout << name; + } else { + std::cout << "unknown name"; + } + + std::cout << ", "; + + auto accuracies = op->coordinateOperationAccuracies(); + if (!accuracies.empty()) { + std::cout << accuracies[0]->value() << " m"; + } else { + if (std::dynamic_pointer_cast<Conversion>(op.as_nullable())) { + std::cout << "0 m"; + } else { + std::cout << "unknown accuracy"; + } + } + + std::cout << ", "; + + auto domains = op->domains(); + if (!domains.empty() && domains[0]->domainOfValidity() && + domains[0]->domainOfValidity()->description().has_value()) { + std::cout << *(domains[0]->domainOfValidity()->description()); + } else { + std::cout << "unknown domain of validity"; + } + + std::cout << std::endl; +} + +// --------------------------------------------------------------------------- + static void outputOperations( DatabaseContextPtr dbContext, const std::string &sourceCRSStr, const std::string &targetCRSStr, const ExtentPtr &bboxFilter, @@ -477,46 +523,7 @@ static void outputOperations( if (summary) { std::cout << "Candidate operations found: " << list.size() << std::endl; for (const auto &op : list) { - auto ids = op->identifiers(); - if (!ids.empty()) { - std::cout << *(ids[0]->codeSpace()) << ":" << ids[0]->code(); - } else { - std::cout << "unknown id"; - } - - std::cout << ", "; - - auto name = op->nameStr(); - if (!name.empty()) { - std::cout << name; - } else { - std::cout << "unknown name"; - } - - std::cout << ", "; - - auto accuracies = op->coordinateOperationAccuracies(); - if (!accuracies.empty()) { - std::cout << accuracies[0]->value() << " m"; - } else { - if (std::dynamic_pointer_cast<Conversion>(op.as_nullable())) { - std::cout << "0 m"; - } else { - std::cout << "unknown accuracy"; - } - } - - std::cout << ", "; - - auto domains = op->domains(); - if (!domains.empty() && domains[0]->domainOfValidity() && - domains[0]->domainOfValidity()->description().has_value()) { - std::cout << *(domains[0]->domainOfValidity()->description()); - } else { - std::cout << "unknown domain of validity"; - } - - std::cout << std::endl; + outputOperationSummary(op); } } else { bool first = true; @@ -534,6 +541,8 @@ static void outputOperations( << (i + 1) << ":" << std::endl << std::endl; } + outputOperationSummary(op); + std::cout << std::endl; outputObject(dbContext, op, outputOpt); } } @@ -557,6 +566,7 @@ int main(int argc, char **argv) { bool kindIsCRS = true; bool summary = false; ExtentPtr bboxFilter = nullptr; + std::string area; CoordinateOperationContext::SpatialCriterion spatialCriterion = CoordinateOperationContext::SpatialCriterion::STRICT_CONTAINMENT; CoordinateOperationContext::SourceTargetCRSExtentUse crsExtentUse = @@ -678,6 +688,9 @@ int main(int argc, char **argv) { << ", " << e.what() << std::endl; usage(); } + } else if (arg == "--area" && i + 1 < argc) { + i++; + area = argv[i]; } else if (arg == "-k" && i + 1 < argc) { i++; std::string kind(argv[i]); @@ -810,12 +823,17 @@ int main(int argc, char **argv) { } } + if (bboxFilter && !area.empty()) { + std::cerr << "ERROR: --bbox and --area are exclusive" << std::endl; + std::exit(1); + } + DatabaseContextPtr dbContext; try { dbContext = DatabaseContext::create(mainDBPath, auxDBPath).as_nullable(); } catch (const std::exception &e) { - if (!mainDBPath.empty() || !auxDBPath.empty()) { + if (!mainDBPath.empty() || !auxDBPath.empty() || !area.empty()) { std::cerr << "ERROR: Cannot create database connection: " << e.what() << std::endl; std::exit(1); @@ -920,6 +938,68 @@ int main(int argc, char **argv) { } } } else { + + if (!area.empty()) { + assert(dbContext); + try { + if (area.find(' ') == std::string::npos && + area.find(':') != std::string::npos) { + auto tokens = split(area, ':'); + if (tokens.size() == 2) { + const std::string &areaAuth = tokens[0]; + const std::string &areaCode = tokens[1]; + bboxFilter = AuthorityFactory::create( + NN_NO_CHECK(dbContext), areaAuth) + ->createExtent(areaCode) + .as_nullable(); + } + } + if (!bboxFilter) { + auto authFactory = AuthorityFactory::create( + NN_NO_CHECK(dbContext), std::string()); + auto res = authFactory->listAreaOfUseFromName(area, false); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else { + res = authFactory->listAreaOfUseFromName(area, true); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else if (res.empty()) { + std::cerr << "No area of use matching provided name" + << std::endl; + std::exit(1); + } else { + std::cerr << "Several candidates area of use " + "matching provided name :" + << std::endl; + for (const auto &candidate : res) { + auto obj = + AuthorityFactory::create( + NN_NO_CHECK(dbContext), candidate.first) + ->createExtent(candidate.second); + std::cerr << " " << candidate.first << ":" + << candidate.second << " : " + << *obj->description() << std::endl; + } + std::exit(1); + } + } + } + } catch (const std::exception &e) { + std::cerr << "Area of use retrieval failed: " << e.what() + << std::endl; + std::exit(1); + } + } + outputOperations(dbContext, sourceCRSStr, targetCRSStr, bboxFilter, spatialCriterion, crsExtentUse, gridAvailabilityUse, allowPivots, pivots, authority, diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo index ad62d1da..90829fdd 100755 --- a/test/cli/testprojinfo +++ b/test/cli/testprojinfo @@ -49,6 +49,31 @@ echo "Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test inters $EXE -s NAD27 -t NAD83 --grid-check none --spatial-test intersects >>${OUT} echo "" >>${OUT} +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --bbox 8,54.51,15.24,57.8 --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --bbox 8,54.51,15.24,57.8 --summary >>${OUT} +echo "" >>${OUT} + +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area EPSG:3237 --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --area EPSG:3237 --summary >>${OUT} +echo "" >>${OUT} + +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area 'Denmark - onshore' --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --area 'Denmark - onshore' --summary >>${OUT} +echo "" >>${OUT} + +# several match +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area 'Denmark -' --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --area 'Denmark -' --summary >>${OUT} 2>&1 +echo "" >>${OUT} + +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area no_match --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --area no_match --summary >>${OUT} 2>&1 +echo "" >>${OUT} + +echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary" >> ${OUT} +$EXE -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary >>${OUT} 2>&1 +echo "" >>${OUT} + # do 'diff' with distribution results echo "diff ${OUT} with testprojinfo_out.dist" diff -u ${OUT} ${TEST_CLI_DIR}/testprojinfo_out.dist diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index fea5a299..f3d4854a 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -83,6 +83,8 @@ GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.25722 Testing projinfo -s EPSG:4326 -t EPSG:32631 +EPSG:16031, UTM zone 31N, 0 m, World - N hemisphere - 0°E to 6°E + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=utm +zone=31 +ellps=WGS84 @@ -122,6 +124,8 @@ Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects ------------------------------------- Operation n°1: +DERIVED_FROM(EPSG):1312, NAD27 to NAD83 (3), 1.0 m, Canada + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=ntv1_can.dat +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -166,6 +170,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (3)", ------------------------------------- Operation n°2: +DERIVED_FROM(EPSG):1313, NAD27 to NAD83 (4), 1.5 m, Canada - NAD27 + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=ntv2_0.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -210,6 +216,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (4)", ------------------------------------- Operation n°3: +DERIVED_FROM(EPSG):1241, NAD27 to NAD83 (1), 0.15 m, USA - CONUS including EEZ + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=conus +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -253,6 +261,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (1)", ------------------------------------- Operation n°4: +DERIVED_FROM(EPSG):1243, NAD27 to NAD83 (2), 0.5 m, USA - Alaska including EEZ + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=alaska +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -296,6 +306,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)", ------------------------------------- Operation n°5: +ESRI:108003, NAD_1927_To_NAD_1983_PR_VI, 0.05 m, Caribbean - Puerto Rico and Virgin Islands - onshore + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=prvi +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -340,6 +352,8 @@ COORDINATEOPERATION["NAD_1927_To_NAD_1983_PR_VI", ------------------------------------- Operation n°6: +unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World + PROJ string: @@ -393,6 +407,8 @@ COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83", ------------------------------------- Operation n°7: +EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GS2783v1.QUE +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -437,6 +453,8 @@ COORDINATEOPERATION["NAD27 to NAD83 (5)", ------------------------------------- Operation n°8: +EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec + PROJ string: +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=QUE27-83.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 @@ -478,3 +496,32 @@ COORDINATEOPERATION["NAD27 to NAD83 (6)", BBOX[44.99,-79.85,62.62,-57.1], ID["EPSG",1573]] +Testing projinfo -s EPSG:4230 -t EPSG:4258 --bbox 8,54.51,15.24,57.8 --summary +Candidate operations found: 1 +EPSG:1626, ED50 to ETRS89 (4), 1.0 m, Denmark - onshore + +Testing projinfo -s EPSG:4230 -t EPSG:4258 --area EPSG:3237 --summary +Candidate operations found: 1 +EPSG:1626, ED50 to ETRS89 (4), 1.0 m, Denmark - onshore + +Testing projinfo -s EPSG:4230 -t EPSG:4258 --area 'Denmark - onshore' --summary +Candidate operations found: 1 +EPSG:1626, ED50 to ETRS89 (4), 1.0 m, Denmark - onshore + +Testing projinfo -s EPSG:4230 -t EPSG:4258 --area 'Denmark -' --summary +Several candidates area of use matching provided name : + EPSG:2531 : Denmark - onshore Jutland and Funen + EPSG:2532 : Denmark - onshore Zealand and Lolland + EPSG:2533 : Denmark - onshore Bornholm + EPSG:3237 : Denmark - onshore + EPSG:3471 : Denmark - onshore west of 12°E + EPSG:3472 : Denmark - onshore east of 12°E + EPSG:3631 : Denmark - onshore Jutland west of 10°E + EPSG:3632 : Denmark - onshore Jutland east of 9°E and Funen + +Testing projinfo -s EPSG:4230 -t EPSG:4258 --area no_match --summary +No area of use matching provided name + +Testing projinfo -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary +Area of use retrieval failed: area not found + diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index 7cdb0b40..c30111ce 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -2746,4 +2746,26 @@ TEST(factory, getMetadata) { EXPECT_EQ(std::string(IGNF_VERSION), "3.0.2"); } +// --------------------------------------------------------------------------- + +TEST(factory, listAreaOfUseFromName) { + auto ctxt = DatabaseContext::create(); + auto factory = AuthorityFactory::create(ctxt, std::string()); + auto factoryEPSG = AuthorityFactory::create(ctxt, "EPSG"); + { + auto res = factory->listAreaOfUseFromName("Denmark - onshore", false); + ASSERT_EQ(res.size(), 1); + EXPECT_EQ(res.front().first, "EPSG"); + EXPECT_EQ(res.front().second, "3237"); + } + { + auto res = factory->listAreaOfUseFromName("Denmark", true); + EXPECT_GT(res.size(), 1U); + } + { + auto res = factory->listAreaOfUseFromName("no where land", false); + ASSERT_EQ(res.size(), 0); + } +} + } // namespace |
