aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@mines-paris.org>2018-12-03 22:51:40 +0100
committerGitHub <noreply@github.com>2018-12-03 22:51:40 +0100
commitaddf30e4446fd39891fd5bdcb22413ed41e0913b (patch)
treef1494607cebc2316b8ab17b43a9b37c887ccdec8
parentd0506e19a71888f7f0c3aa8618d919624e754c4d (diff)
parent0ba9d249136ec7adf6e3a44c8148701818d0e63e (diff)
downloadPROJ-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.hpp5
-rw-r--r--src/factory.cpp35
-rw-r--r--src/projinfo.cpp164
-rwxr-xr-xtest/cli/testprojinfo25
-rw-r--r--test/cli/testprojinfo_out.dist47
-rw-r--r--test/unit/test_factory.cpp22
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