aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@mines-paris.org>2019-04-23 21:54:29 +0200
committerGitHub <noreply@github.com>2019-04-23 21:54:29 +0200
commit4c7364ba84b97fc87270386906af66522feea94f (patch)
tree7b721bd91cc8a45d4e7b245c9db36a4fd0ef8688
parent8cfd9ca89c89b52a3c22d5ee7ecbe06791924a15 (diff)
parent292807eee9e1194175b64cb5c0a9f0b432352abc (diff)
downloadPROJ-4c7364ba84b97fc87270386906af66522feea94f.tar.gz
PROJ-4c7364ba84b97fc87270386906af66522feea94f.zip
Merge pull request #1441 from rouault/support_compound_crs_urn
proj_create(): add support for compoundCRS and concatenatedOperation named from their components
-rw-r--r--docs/source/apps/projinfo.rst17
-rw-r--r--docs/source/development/reference/functions.rst17
-rw-r--r--include/proj/io.hpp8
-rw-r--r--src/iso19111/factory.cpp5
-rw-r--r--src/iso19111/io.cpp102
-rw-r--r--test/unit/test_io.cpp58
6 files changed, 190 insertions, 17 deletions
diff --git a/docs/source/apps/projinfo.rst b/docs/source/apps/projinfo.rst
index c8219838..955b9a18 100644
--- a/docs/source/apps/projinfo.rst
+++ b/docs/source/apps/projinfo.rst
@@ -29,12 +29,17 @@ Synopsis
| {object_definition} | (-s {srs_def} -t {srs_def})
|
- where {object_definition} or {object_definition} is a PROJ string, a
- WKT string, an object name, AUTHORITY:CODE
- (where AUTHORITY is the name of a CRS authority and CODE the code of a CRS
- found in the proj.db database) or a OGC URN (such as "urn:ogc:def:crs:EPSG::4326",
- "urn:ogc:def:coordinateOperation:EPSG::1671", "urn:ogc:def:ellipsoid:EPSG::7001"
- or "urn:ogc:def:datum:EPSG::6326")
+ where {object_definition} or {srs_def} is
+
+ - a proj-string,
+ - a WKT string,
+ - an object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326",
+ "urn:ogc:def:coordinateOperation:EPSG::1671"),
+ - a OGC URN combining references for compound coordinate reference systems
+ (e.g "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" or custom abbreviated
+ syntax "EPSG:2393+5717"),
+ - a OGC URN combining references for concatenated operations
+ (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618")
Description
***********
diff --git a/docs/source/development/reference/functions.rst b/docs/source/development/reference/functions.rst
index 00653ad9..aa177b31 100644
--- a/docs/source/development/reference/functions.rst
+++ b/docs/source/development/reference/functions.rst
@@ -29,9 +29,17 @@ paragraph for more details.
.. c:function:: PJ* proj_create(PJ_CONTEXT *ctx, const char *definition)
- Create a transformation object, or a CRS object, from a proj-string,
- a WKT string, or object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326",
- "urn:ogc:def:coordinateOperation:EPSG::1671").
+ Create a transformation object, or a CRS object, from:
+
+ - a proj-string,
+ - a WKT string,
+ - an object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326",
+ "urn:ogc:def:coordinateOperation:EPSG::1671"),
+ - a OGC URN combining references for compound coordinate reference systems
+ (e.g "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" or custom abbreviated
+ syntax "EPSG:2393+5717"),
+ - a OGC URN combining references for concatenated operations
+ (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618")
Example call:
@@ -110,7 +118,8 @@ paragraph for more details.
- the name of a CRS as found in the PROJ database, e.g "WGS84", "NAD27", etc.
- - more generally any string accepted by :c:func:`proj_create`
+ - more generally any string accepted by :c:func:`proj_create` representing
+ a CRS
An "area of use" can be specified in area. When it is supplied, the more
accurate transformation between two given systems can be chosen.
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index 5386ca6c..a603533e 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -993,16 +993,16 @@ class PROJ_GCC_DLL AuthorityFactory {
PROJ_INTERNAL std::list<crs::CompoundCRSNNPtr>
createCompoundCRSFromExisting(const crs::CompoundCRSNNPtr &crs) const;
+
+ PROJ_INTERNAL crs::CRSNNPtr
+ createCoordinateReferenceSystem(const std::string &code,
+ bool allowCompound) const;
//! @endcond
protected:
PROJ_INTERNAL AuthorityFactory(const DatabaseContextNNPtr &context,
const std::string &authorityName);
- PROJ_INTERNAL crs::CRSNNPtr
- createCoordinateReferenceSystem(const std::string &code,
- bool allowCompound) const;
-
PROJ_INTERNAL crs::GeodeticCRSNNPtr
createGeodeticCRS(const std::string &code, bool geographicOnly) const;
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index f24b3457..9f7467a2 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -2484,6 +2484,8 @@ crs::CRSNNPtr AuthorityFactory::createCoordinateReferenceSystem(
return createCoordinateReferenceSystem(code, true);
}
+//! @cond Doxygen_Suppress
+
crs::CRSNNPtr
AuthorityFactory::createCoordinateReferenceSystem(const std::string &code,
bool allowCompound) const {
@@ -2513,6 +2515,9 @@ AuthorityFactory::createCoordinateReferenceSystem(const std::string &code,
}
throw FactoryException("unhandled CRS type: " + type);
}
+
+//! @endcond
+
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 360d55a2..d8282bb0 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -4397,15 +4397,97 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
const auto authorities = dbContextNNPtr->getAuthorities();
for (const auto &authCandidate : authorities) {
if (ci_equal(authCandidate, authName)) {
- return AuthorityFactory::create(dbContextNNPtr,
- authCandidate)
- ->createCoordinateReferenceSystem(code);
+ factory =
+ AuthorityFactory::create(dbContextNNPtr, authCandidate);
+ try {
+ return factory->createCoordinateReferenceSystem(code);
+ } catch (...) {
+ // EPSG:4326+3855
+ auto tokensCode = split(code, '+');
+ if (tokensCode.size() == 2) {
+ auto crs1(factory->createCoordinateReferenceSystem(
+ tokensCode[0], false));
+ auto crs2(factory->createCoordinateReferenceSystem(
+ tokensCode[1], false));
+ return CompoundCRS::create(
+ util::PropertyMap().set(
+ IdentifiedObject::NAME_KEY,
+ crs1->nameStr() + " + " + crs2->nameStr()),
+ {crs1, crs2});
+ }
+ throw;
+ }
}
}
throw;
}
}
+ // OGC 07-092r2: para 7.5.2
+ // URN combined references for compound coordinate reference systems
+ if (starts_with(text, "urn:ogc:def:crs,")) {
+ if (!dbContext) {
+ throw ParsingException("no database context specified");
+ }
+ auto tokensComma = split(text, ',');
+ std::vector<CRSNNPtr> components;
+ std::string name;
+ for (size_t i = 1; i < tokensComma.size(); i++) {
+ tokens = split(tokensComma[i], ':');
+ if (tokens.size() != 4) {
+ throw ParsingException(
+ concat("invalid crs component: ", tokensComma[i]));
+ }
+ const auto &type = tokens[0];
+ auto factory =
+ AuthorityFactory::create(NN_NO_CHECK(dbContext), tokens[1]);
+ const auto &code = tokens[3];
+ if (type == "crs") {
+ auto crs(factory->createCoordinateReferenceSystem(code, false));
+ components.emplace_back(crs);
+ if (!name.empty()) {
+ name += " + ";
+ }
+ name += crs->nameStr();
+ } else {
+ throw ParsingException(
+ concat("unexpected object type: ", type));
+ }
+ }
+ return CompoundCRS::create(
+ util::PropertyMap().set(IdentifiedObject::NAME_KEY, name),
+ components);
+ }
+
+ // OGC 07-092r2: para 7.5.3
+ // 7.5.3 URN combined references for concatenated operations
+ if (starts_with(text, "urn:ogc:def:coordinateOperation,")) {
+ if (!dbContext) {
+ throw ParsingException("no database context specified");
+ }
+ auto tokensComma = split(text, ',');
+ std::vector<CoordinateOperationNNPtr> components;
+ for (size_t i = 1; i < tokensComma.size(); i++) {
+ tokens = split(tokensComma[i], ':');
+ if (tokens.size() != 4) {
+ throw ParsingException(concat(
+ "invalid coordinateOperation component: ", tokensComma[i]));
+ }
+ const auto &type = tokens[0];
+ auto factory =
+ AuthorityFactory::create(NN_NO_CHECK(dbContext), tokens[1]);
+ const auto &code = tokens[3];
+ if (type == "coordinateOperation") {
+ auto op(factory->createCoordinateOperation(code, false));
+ components.emplace_back(op);
+ } else {
+ throw ParsingException(
+ concat("unexpected object type: ", type));
+ }
+ }
+ return ConcatenatedOperation::createComputeMetadata(components, true);
+ }
+
// urn:ogc:def:crs:EPSG::4326
if (tokens.size() == 7) {
if (!dbContext) {
@@ -4510,6 +4592,13 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
* "urn:ogc:def:coordinateOperation:EPSG::1671",
* "urn:ogc:def:ellipsoid:EPSG::7001"
* or "urn:ogc:def:datum:EPSG::6326"</li>
+ * <li> OGC URN combining references for compound coordinate reference systems
+ * e.g. "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717"
+ * We also accept a custom abbreviated syntax EPSG:2393+5717
+ * </li>
+ * <li> OGC URN combining references for concatenated operations
+ * e.g.
+ * "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618"</li>
* <li>an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as
* uniqueness is not guaranteed, the function may apply heuristics to
* determine the appropriate best match.</li>
@@ -4546,6 +4635,13 @@ BaseObjectNNPtr createFromUserInput(const std::string &text,
* "urn:ogc:def:coordinateOperation:EPSG::1671",
* "urn:ogc:def:ellipsoid:EPSG::7001"
* or "urn:ogc:def:datum:EPSG::6326"</li>
+ * <li> OGC URN combining references for compound coordinate reference systems
+ * e.g. "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717"
+ * We also accept a custom abbreviated syntax EPSG:2393+5717
+ * </li>
+ * <li> OGC URN combining references for concatenated operations
+ * e.g.
+ * "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618"</li>
* <li>an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as
* uniqueness is not guaranteed, the function may apply heuristics to
* determine the appropriate best match.</li>
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 30e0b427..df2481e6 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -8775,6 +8775,39 @@ TEST(io, createFromUserInput) {
EXPECT_THROW(
createFromUserInput("urn:ogc:def:unhandled:EPSG::4326", dbContext),
ParsingException);
+ EXPECT_THROW(createFromUserInput("urn:ogc:def:crs:non_existing_auth::4326",
+ dbContext),
+ NoSuchAuthorityCodeException);
+ EXPECT_THROW(createFromUserInput(
+ "urn:ogc:def:crs,crs:EPSG::2393,unhandled_type:EPSG::5717",
+ dbContext),
+ ParsingException);
+ EXPECT_THROW(createFromUserInput(
+ "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::unexisting_code",
+ dbContext),
+ NoSuchAuthorityCodeException);
+ EXPECT_THROW(
+ createFromUserInput(
+ "urn:ogc:def:crs,crs:EPSG::2393::extra_element,crs:EPSG::EPSG",
+ dbContext),
+ ParsingException);
+ EXPECT_THROW(createFromUserInput("urn:ogc:def:coordinateOperation,"
+ "coordinateOperation:EPSG::3895,"
+ "unhandled_type:EPSG::1618",
+ dbContext),
+ ParsingException);
+ EXPECT_THROW(
+ createFromUserInput("urn:ogc:def:coordinateOperation,"
+ "coordinateOperation:EPSG::3895,"
+ "coordinateOperation:EPSG::unexisting_code",
+ dbContext),
+ NoSuchAuthorityCodeException);
+ EXPECT_THROW(
+ createFromUserInput("urn:ogc:def:coordinateOperation,"
+ "coordinateOperation:EPSG::3895::extra_element,"
+ "coordinateOperation:EPSG::1618",
+ dbContext),
+ ParsingException);
EXPECT_NO_THROW(createFromUserInput("+proj=longlat", nullptr));
EXPECT_NO_THROW(createFromUserInput("EPSG:4326", dbContext));
@@ -8789,6 +8822,31 @@ TEST(io, createFromUserInput) {
createFromUserInput("urn:ogc:def:meridian:EPSG::8901", dbContext));
EXPECT_NO_THROW(
createFromUserInput("urn:ogc:def:ellipsoid:EPSG::7030", dbContext));
+ {
+ auto obj = createFromUserInput("EPSG:2393+5717", dbContext);
+ auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(),
+ "KKJ / Finland Uniform Coordinate System + N60 height");
+ }
+ {
+ auto obj = createFromUserInput(
+ "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717", dbContext);
+ auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(),
+ "KKJ / Finland Uniform Coordinate System + N60 height");
+ }
+ {
+ auto obj = createFromUserInput("urn:ogc:def:coordinateOperation,"
+ "coordinateOperation:EPSG::3895,"
+ "coordinateOperation:EPSG::1618",
+ dbContext);
+ auto concat = nn_dynamic_pointer_cast<ConcatenatedOperation>(obj);
+ ASSERT_TRUE(concat != nullptr);
+ EXPECT_EQ(concat->nameStr(),
+ "MGI (Ferro) to MGI (1) + MGI to WGS 84 (3)");
+ }
EXPECT_NO_THROW(createFromUserInput(
"GEOGCRS[\"WGS 84\",\n"
" DATUM[\"World Geodetic System 1984\",\n"