diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-10-23 10:28:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-23 10:28:05 +0200 |
| commit | aaa159247b5595b84c05f603bebc07201be335f4 (patch) | |
| tree | 9394fb47beeb183279d30faba6d531035e596f0a /src | |
| parent | 4fa0c250c125b8b034e0a17d2d03909dafdb6813 (diff) | |
| parent | 6351422cc2108072162f7b8cdff12916723ccc20 (diff) | |
| download | PROJ-aaa159247b5595b84c05f603bebc07201be335f4.tar.gz PROJ-aaa159247b5595b84c05f603bebc07201be335f4.zip | |
Merge pull request #2389 from rouault/wkt_parse_implict_compound_crs_esri
WKT1_ESRI: fix import and export of CompoundCRS
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/crs.cpp | 122 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 19 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 88 | ||||
| -rw-r--r-- | src/wkt1_generated_parser.c | 369 | ||||
| -rw-r--r-- | src/wkt1_grammar.y | 19 |
5 files changed, 399 insertions, 218 deletions
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 52b10119..edc8a71f 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -1578,6 +1578,49 @@ GeodeticCRS::create(const util::PropertyMap &properties, // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress + +// Try to format a Geographic/ProjectedCRS 3D CRS as a +// GEOGCS[]/PROJCS[],VERTCS[...,DATUM[],...] if we find corresponding objects +static bool exportAsESRIWktCompoundCRSWithEllipsoidalHeight( + const CRS *self, const GeodeticCRS *geodCRS, io::WKTFormatter *formatter) { + const auto &dbContext = formatter->databaseContext(); + if (!dbContext) { + return false; + } + const auto l_datum = geodCRS->datumNonNull(formatter->databaseContext()); + auto l_alias = dbContext->getAliasFromOfficialName( + l_datum->nameStr(), "geodetic_datum", "ESRI"); + if (l_alias.empty()) { + return false; + } + auto authFactory = + io::AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); + auto list = authFactory->createObjectsFromName( + l_alias, {io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, + false /* approximate=false*/); + if (list.empty()) { + return false; + } + auto gdatum = util::nn_dynamic_pointer_cast<datum::Datum>(list.front()); + if (gdatum == nullptr || gdatum->identifiers().empty()) { + return false; + } + const auto &gdatum_ids = gdatum->identifiers(); + auto vertCRSList = authFactory->createVerticalCRSFromDatum( + "ESRI", "from_geogdatum_" + *gdatum_ids[0]->codeSpace() + '_' + + gdatum_ids[0]->code()); + if (vertCRSList.size() != 1) { + return false; + } + self->demoteTo2D(std::string(), dbContext)->_exportToWKT(formatter); + vertCRSList.front()->_exportToWKT(formatter); + return true; +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; const bool isGeographic = @@ -1589,11 +1632,21 @@ void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { auto l_name = nameStr(); const auto &dbContext = formatter->databaseContext(); - if (formatter->useESRIDialect()) { - if (axisList.size() != 2) { + if (!isWKT2 && formatter->useESRIDialect() && axisList.size() == 3) { + if (!isGeographic) { io::FormattingException::Throw( - "Only export of Geographic 2D CRS is supported in WKT1_ESRI"); + "Geocentric CRS not supported in WKT1_ESRI"); + } + // Try to format the Geographic 3D CRS as a GEOGCS[],VERTCS[...,DATUM[]] + // if we find corresponding objects + if (dbContext) { + if (exportAsESRIWktCompoundCRSWithEllipsoidalHeight(this, this, + formatter)) { + return; + } } + io::FormattingException::Throw( + "Cannot export this Geographic 3D CRS in WKT1_ESRI"); } if (!isWKT2 && formatter->isStrict() && isGeographic && @@ -2853,9 +2906,9 @@ void VerticalCRS::_exportToWKT(io::WKTFormatter *formatter) const { !identifiers().empty()); auto l_name = nameStr(); + const auto &dbContext = formatter->databaseContext(); if (formatter->useESRIDialect()) { bool aliasFound = false; - const auto &dbContext = formatter->databaseContext(); if (dbContext) { auto l_alias = dbContext->getAliasFromOfficialName( l_name, "vertical_crs", "ESRI"); @@ -2870,7 +2923,34 @@ void VerticalCRS::_exportToWKT(io::WKTFormatter *formatter) const { } formatter->addQuotedString(l_name); - exportDatumOrDatumEnsembleToWkt(formatter); + + const auto l_datum = datum(); + if (formatter->useESRIDialect() && l_datum && + l_datum->getWKT1DatumType() == "2002") { + bool foundMatch = false; + if (dbContext) { + auto authFactory = io::AuthorityFactory::create( + NN_NO_CHECK(dbContext), std::string()); + auto list = authFactory->createObjectsFromName( + l_datum->nameStr(), + {io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, + false /* approximate=false*/); + if (!list.empty()) { + auto gdatum = + util::nn_dynamic_pointer_cast<datum::Datum>(list.front()); + if (gdatum) { + gdatum->_exportToWKT(formatter); + foundMatch = true; + } + } + } + if (!foundMatch) { + // We should export a geodetic datum, but we cannot really do better + l_datum->_exportToWKT(formatter); + } + } else { + exportDatumOrDatumEnsembleToWkt(formatter); + } const auto &cs = SingleCRS::getPrivate()->coordinateSystem; const auto &axisList = cs->axisList(); @@ -3497,6 +3577,16 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { } } + if (formatter->useESRIDialect() && dbContext) { + // Try to format the ProjecteD 3D CRS as a + // PROJCS[],VERTCS[...,DATUM[]] + // if we find corresponding objects + if (exportAsESRIWktCompoundCRSWithEllipsoidalHeight( + this, baseCRS().as_nullable().get(), formatter)) { + return; + } + } + if (!formatter->useESRIDialect() && CRS::getPrivate()->allowNonConformantWKT1Export_) { formatter->startNode(io::WKTConstants::COMPD_CS, false); @@ -4528,15 +4618,21 @@ CRSNNPtr CompoundCRS::createLax(const util::PropertyMap &properties, //! @cond Doxygen_Suppress void CompoundCRS::_exportToWKT(io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; - formatter->startNode(isWKT2 ? io::WKTConstants::COMPOUNDCRS - : io::WKTConstants::COMPD_CS, - !identifiers().empty()); - formatter->addQuotedString(nameStr()); - for (const auto &crs : componentReferenceSystems()) { - crs->_exportToWKT(formatter); + const auto &l_components = componentReferenceSystems(); + if (!isWKT2 && formatter->useESRIDialect() && l_components.size() == 2) { + l_components[0]->_exportToWKT(formatter); + l_components[1]->_exportToWKT(formatter); + } else { + formatter->startNode(isWKT2 ? io::WKTConstants::COMPOUNDCRS + : io::WKTConstants::COMPD_CS, + !identifiers().empty()); + formatter->addQuotedString(nameStr()); + for (const auto &crs : l_components) { + crs->_exportToWKT(formatter); + } + ObjectUsage::baseExportToWKT(formatter); + formatter->endNode(); } - ObjectUsage::baseExportToWKT(formatter); - formatter->endNode(); } //! @endcond diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index ef5c6e02..211eb586 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -2100,6 +2100,9 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { if (!publication_date.empty()) { props.set("PUBLICATION_DATE", publication_date); } + if (d->authority() == "ESRI" && starts_with(code, "from_geogdatum_")) { + props.set("VERT_DATUM_TYPE", "2002"); + } auto anchor = util::optional<std::string>(); if (frame_reference_epoch.empty()) { return datum::VerticalReferenceFrame::create(props, anchor); @@ -5719,9 +5722,12 @@ AuthorityFactory::createObjectsFromNameEx( "SELECT table_name, auth_name, code, name, deprecated, is_alias " "FROM ("); - const auto getTableAndTypeConstraints = [&allowedObjectTypes]() { + const auto getTableAndTypeConstraints = [&allowedObjectTypes, + &searchedName]() { typedef std::pair<std::string, std::string> TableType; std::list<TableType> res; + // Hide ESRI D_ vertical datums + const bool startsWithDUnderscore = starts_with(searchedName, "D_"); if (allowedObjectTypes.empty()) { for (const auto &tableName : {"prime_meridian", "ellipsoid", "geodetic_datum", @@ -5729,7 +5735,10 @@ AuthorityFactory::createObjectsFromNameEx( "vertical_crs", "compound_crs", "conversion", "helmert_transformation", "grid_transformation", "other_transformation", "concatenated_operation"}) { - res.emplace_back(TableType(tableName, std::string())); + if (!(startsWithDUnderscore && + strcmp(tableName, "vertical_datum") == 0)) { + res.emplace_back(TableType(tableName, std::string())); + } } } else { for (const auto type : allowedObjectTypes) { @@ -5744,8 +5753,10 @@ AuthorityFactory::createObjectsFromNameEx( case ObjectType::DATUM: res.emplace_back( TableType("geodetic_datum", std::string())); - res.emplace_back( - TableType("vertical_datum", std::string())); + if (!startsWithDUnderscore) { + res.emplace_back( + TableType("vertical_datum", std::string())); + } break; case ObjectType::GEODETIC_REFERENCE_FRAME: res.emplace_back( diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 0f4ffba0..b8e835d7 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -4145,11 +4145,19 @@ createBoundCRSSourceTransformationCRS(const crs::CRSPtr &sourceCRS, CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { const auto *nodeP = node->GP(); - auto &datumNode = + const auto &nodeValue = nodeP->value(); + auto &vdatumNode = nodeP->lookForChild(WKTConstants::VDATUM, WKTConstants::VERT_DATUM, WKTConstants::VERTICALDATUM, WKTConstants::VRF); auto &ensembleNode = nodeP->lookForChild(WKTConstants::ENSEMBLE); - if (isNull(datumNode) && isNull(ensembleNode)) { + // like in ESRI VERTCS["WGS_1984",DATUM["D_WGS_1984", + // SPHEROID["WGS_1984",6378137.0,298.257223563]], + // PARAMETER["Vertical_Shift",0.0], + // PARAMETER["Direction",1.0],UNIT["Meter",1.0] + auto &geogDatumNode = ci_equal(nodeValue, WKTConstants::VERTCS) + ? nodeP->lookForChild(WKTConstants::DATUM) + : null_node; + if (isNull(vdatumNode) && isNull(geogDatumNode) && isNull(ensembleNode)) { throw ParsingException("Missing VDATUM or ENSEMBLE node"); } @@ -4164,28 +4172,50 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { } auto &dynamicNode = nodeP->lookForChild(WKTConstants::DYNAMIC); - auto datum = - !isNull(datumNode) - ? buildVerticalReferenceFrame(datumNode, dynamicNode).as_nullable() - : nullptr; + auto vdatum = + !isNull(geogDatumNode) + ? VerticalReferenceFrame::create( + PropertyMap() + .set(IdentifiedObject::NAME_KEY, + buildGeodeticReferenceFrame(geogDatumNode, + PrimeMeridian::GREENWICH, + null_node) + ->nameStr()) + .set("VERT_DATUM_TYPE", "2002")) + .as_nullable() + : !isNull(vdatumNode) + ? buildVerticalReferenceFrame(vdatumNode, dynamicNode) + .as_nullable() + : nullptr; auto datumEnsemble = !isNull(ensembleNode) ? buildDatumEnsemble(ensembleNode, nullptr, false).as_nullable() : nullptr; auto &csNode = nodeP->lookForChild(WKTConstants::CS_); - const auto &nodeValue = nodeP->value(); if (isNull(csNode) && !ci_equal(nodeValue, WKTConstants::VERT_CS) && !ci_equal(nodeValue, WKTConstants::VERTCS) && !ci_equal(nodeValue, WKTConstants::BASEVERTCRS)) { ThrowMissing(WKTConstants::CS_); } - auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); - auto verticalCS = nn_dynamic_pointer_cast<VerticalCS>(cs); + auto verticalCS = nn_dynamic_pointer_cast<VerticalCS>( + buildCS(csNode, node, UnitOfMeasure::NONE)); if (!verticalCS) { ThrowNotExpectedCSType("vertical"); } + if (vdatum && vdatum->getWKT1DatumType() == "2002" && + &(verticalCS->axisList()[0]->direction()) == &(AxisDirection::UP)) { + verticalCS = + VerticalCS::create( + util::PropertyMap(), + CoordinateSystemAxis::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, + "ellipsoidal height"), + "h", AxisDirection::UP, verticalCS->axisList()[0]->unit())) + .as_nullable(); + } + auto &props = buildProperties(node); if (esriStyle_ && dbContext_) { @@ -4246,10 +4276,10 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { "North American Vertical Datum 1988"); propsDatum.set(Identifier::CODE_KEY, 5103); propsDatum.set(Identifier::CODESPACE_KEY, Identifier::EPSG); - datum = + vdatum = VerticalReferenceFrame::create(propsDatum).as_nullable(); const auto dummyCRS = - VerticalCRS::create(PropertyMap(), datum, datumEnsemble, + VerticalCRS::create(PropertyMap(), vdatum, datumEnsemble, NN_NO_CHECK(verticalCS)); const auto model(Transformation::create( propsModel, dummyCRS, dummyCRS, nullptr, @@ -4265,7 +4295,7 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { if (!isNull(geoidModelNode)) { auto &propsModel = buildProperties(geoidModelNode); const auto dummyCRS = VerticalCRS::create( - PropertyMap(), datum, datumEnsemble, NN_NO_CHECK(verticalCS)); + PropertyMap(), vdatum, datumEnsemble, NN_NO_CHECK(verticalCS)); const auto model(Transformation::create( propsModel, dummyCRS, dummyCRS, nullptr, OperationMethod::create(PropertyMap(), @@ -4275,10 +4305,10 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { } auto crs = nn_static_pointer_cast<CRS>(VerticalCRS::create( - props, datum, datumEnsemble, NN_NO_CHECK(verticalCS))); + props, vdatum, datumEnsemble, NN_NO_CHECK(verticalCS))); - if (!isNull(datumNode)) { - auto &extensionNode = datumNode->lookForChild(WKTConstants::EXTENSION); + if (!isNull(vdatumNode)) { + auto &extensionNode = vdatumNode->lookForChild(WKTConstants::EXTENSION); const auto &extensionChildren = extensionNode->GP()->children(); if (extensionChildren.size() == 2) { if (ci_equal(stripQuotes(extensionChildren[0]), "PROJ4_GRIDS")) { @@ -6507,6 +6537,34 @@ BaseObjectNNPtr WKTParser::createFromWKT(const std::string &wkt) { } return d->buildGeodeticReferenceFrame(root, primeMeridian, null_node); + } else if (ci_equal(name, WKTConstants::GEOGCS) || + ci_equal(name, WKTConstants::PROJCS)) { + // Parse implicit compoundCRS from ESRI that is + // "PROJCS[...],VERTCS[...]" or "GEOGCS[...],VERTCS[...]" + if (indexEnd < wkt.size()) { + indexEnd = skipSpace(wkt, indexEnd); + if (indexEnd < wkt.size() && wkt[indexEnd] == ',') { + ++indexEnd; + indexEnd = skipSpace(wkt, indexEnd); + if (indexEnd < wkt.size() && + ci_starts_with(wkt.c_str() + indexEnd, + WKTConstants::VERTCS.c_str())) { + auto horizCRS = d->buildCRS(root); + if (horizCRS) { + auto vertCRS = + d->buildVerticalCRS(WKTNode::createFrom( + wkt, indexEnd, 0, indexEnd)); + return CompoundCRS::createLax( + util::PropertyMap().set( + IdentifiedObject::NAME_KEY, + horizCRS->nameStr() + " + " + + vertCRS->nameStr()), + {NN_NO_CHECK(horizCRS), vertCRS}, + d->dbContext_); + } + } + } + } } return d->build(root); }; diff --git a/src/wkt1_generated_parser.c b/src/wkt1_generated_parser.c index 2785ec9f..0bcffe31 100644 --- a/src/wkt1_generated_parser.c +++ b/src/wkt1_generated_parser.c @@ -422,18 +422,18 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 30 +#define YYFINAL 32 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 222 +#define YYLAST 230 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 36 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 67 +#define YYNNTS 70 /* YYNRULES -- Number of rules. */ -#define YYNRULES 101 +#define YYNRULES 107 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 267 +#define YYNSTATES 274 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -484,15 +484,15 @@ static const yytype_uint16 yyrline[] = { 0, 80, 80, 92, 92, 95, 98, 98, 101, 101, 101, 101, 104, 107, 109, 110, 113, 115, 116, 119, - 122, 126, 131, 131, 131, 131, 131, 131, 134, 134, - 138, 142, 143, 146, 147, 149, 150, 151, 152, 154, - 155, 158, 161, 164, 168, 170, 171, 172, 173, 176, - 180, 183, 186, 189, 192, 195, 198, 201, 204, 207, - 208, 209, 210, 213, 216, 219, 220, 222, 223, 224, - 227, 230, 232, 233, 234, 237, 240, 243, 246, 248, - 251, 256, 259, 261, 264, 267, 270, 273, 276, 279, - 282, 285, 288, 291, 294, 297, 300, 302, 304, 305, - 306, 309 + 122, 126, 131, 131, 131, 131, 131, 131, 134, 135, + 138, 138, 142, 146, 147, 150, 151, 153, 154, 155, + 156, 158, 159, 162, 165, 168, 172, 174, 175, 176, + 177, 180, 184, 187, 190, 193, 196, 199, 202, 205, + 208, 211, 212, 213, 214, 217, 220, 223, 224, 227, + 229, 230, 231, 234, 236, 236, 239, 241, 242, 243, + 246, 249, 252, 257, 257, 259, 262, 267, 270, 272, + 275, 278, 281, 284, 287, 290, 293, 296, 299, 302, + 305, 308, 311, 313, 315, 316, 317, 320 }; #endif @@ -512,20 +512,20 @@ static const char *const yytname[] = "begin_node", "begin_node_name", "end_node", "math_transform", "param_mt", "parameter", "opt_parameter_list", "concat_mt", "opt_math_transform_list", "inv_mt", "passthrough_mt", "integer", - "coordinate_system", "horz_cs", "projected_cs", - "opt_parameter_list_linear_unit", "parameter_list_linear_unit", - "opt_twin_axis_extension_authority", "opt_authority", "extension", - "projection", "geographic_cs", "datum", + "coordinate_system", "horz_cs_with_opt_esri_vertcs", "horz_cs", + "projected_cs", "opt_parameter_list_linear_unit", + "parameter_list_linear_unit", "opt_twin_axis_extension_authority", + "opt_authority", "extension", "projection", "geographic_cs", "datum", "opt_towgs84_authority_extension", "spheroid", "semi_major_axis", "inverse_flattening", "prime_meridian", "longitude", "angular_unit", "linear_unit", "unit", "conversion_factor", "geocentric_cs", "opt_three_axis_extension_authority", "three_axis", "authority", - "vert_cs", "opt_axis_authority", "vert_datum", "vdatum", - "opt_extension_authority", "datum_type", "compd_cs", "head_cs", - "tail_cs", "twin_axis", "axis", "towgs84", "towgs84_parameters", - "three_parameters", "seven_parameters", "dx", "dy", "dz", "ex", "ey", - "ez", "ppm", "fitted_cs", "to_base", "base_cs", "local_cs", - "opt_axis_list_authority", "local_datum", YY_NULLPTR + "vert_cs", "esri_vert_cs", "opt_axis_authority", "vert_datum", + "vdatum_or_datum", "vdatum", "opt_extension_authority", "datum_type", + "compd_cs", "head_cs", "tail_cs", "twin_axis", "axis", "towgs84", + "towgs84_parameters", "three_parameters", "seven_parameters", "dx", "dy", + "dz", "ex", "ey", "ez", "ppm", "fitted_cs", "to_base", "base_cs", + "local_cs", "opt_axis_list_authority", "local_datum", YY_NULLPTR }; #endif @@ -541,10 +541,10 @@ static const yytype_uint16 yytoknum[] = }; # endif -#define YYPACT_NINF -127 +#define YYPACT_NINF -141 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-127))) + (!!((Yystate) == (-141))) #define YYTABLE_NINF -1 @@ -555,33 +555,34 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 125, 1, 1, 1, 1, 1, 1, 1, 1, 25, - -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, - -127, 8, 9, 18, 28, 37, 46, 50, 51, 43, - -127, -127, 61, 77, 77, 71, 74, 125, 132, -127, - -127, 65, -127, 60, 1, 64, 66, 1, 67, 1, - 69, -127, 70, 1, 1, 1, 1, -127, -127, -127, - -127, -127, 72, 1, 76, 88, 83, 97, 97, 85, - 99, 33, -7, 125, 86, 132, 132, 95, 125, 90, - 99, 1, 91, 118, 1, 96, 108, 101, 1, 109, - -127, -127, 1, 112, 33, -127, -127, -127, 115, 126, - 33, 116, 33, -127, 119, -127, 33, 101, 120, 121, - -7, 1, 122, 123, 99, 99, -127, 115, 124, -3, - 33, 130, -7, -127, 0, 33, 86, -127, 132, 33, - -127, 132, -127, 121, 139, 146, 33, 131, 133, -1, - 33, 138, 131, -127, 134, 33, 141, 1, 1, -127, - 121, -127, 142, -127, -127, 1, 121, -127, -127, -127, - 116, -127, 33, 33, 137, -127, -127, 7, 33, 144, - 1, 121, -127, 115, -127, -127, 121, 33, 7, 33, - -127, -127, 121, 143, 145, -127, 33, 149, -127, -127, - -127, -127, -3, 33, 121, -127, 115, 150, -127, -127, - 151, 147, -127, -127, 33, -127, 121, 115, -127, 152, - -127, 33, 153, 158, -127, 161, -127, 137, -127, -127, - -127, 139, 148, -127, 33, -127, -127, 156, -127, -127, - -127, 139, -127, 33, 33, 33, -127, -127, -127, 121, - -127, 163, 159, -127, -127, -127, 33, -127, 160, 139, - -127, 164, -127, -127, 162, 167, -127, 165, 169, -127, - 166, 170, -127, 168, 173, -127, -127 + 119, 41, 41, 41, 41, 41, 41, 41, 41, 31, + -141, -141, 6, -141, -141, -141, -141, -141, -141, -141, + -141, -141, -141, 16, 32, 34, 42, 55, 68, 69, + 70, 23, -141, 37, -141, 99, 101, 101, 95, 19, + 4, 141, -141, -141, 89, -141, -141, 80, 41, 82, + 85, 41, 86, 41, -141, 87, -141, -141, 90, 41, + 41, 41, 41, -141, -141, -141, -141, -141, 92, 41, + 94, 123, 97, 125, 125, 103, 127, 63, -4, 30, + 113, 141, 141, 120, 119, 115, 127, 41, 116, 142, + 41, 117, 121, 126, 41, 124, -141, -141, 41, 133, + 63, -141, -141, -141, -141, 134, 132, 63, 135, 63, + -141, 136, -141, 63, 126, 137, 138, -4, 41, 140, + 143, 127, 127, -141, 134, 144, 28, 63, 145, -4, + -141, -3, 63, 113, -141, 141, 63, -141, 141, -141, + 138, 139, 146, 63, 147, 148, 13, 63, 152, 147, + -141, 149, 63, 156, 41, 41, -141, 138, -141, 157, + -141, -141, 41, 138, -141, -141, -141, 135, -141, 63, + 63, 153, -141, -141, 61, 63, 158, 41, 138, -141, + 134, -141, -141, 138, 63, 61, 63, -141, -141, 138, + 154, 155, -141, 63, 159, -141, -141, -141, -141, 28, + 63, 138, -141, 134, 160, -141, -141, 161, 162, -141, + -141, 63, -141, 138, 134, -141, 163, -141, 63, 164, + 167, -141, 165, -141, 153, -141, -141, -141, 139, 170, + -141, 63, -141, -141, 166, -141, -141, -141, 139, -141, + 63, 63, 63, -141, -141, -141, 138, -141, 171, 168, + -141, -141, -141, 63, -141, 169, 139, -141, 173, -141, + -141, 172, 176, -141, 174, 177, -141, 175, 179, -141, + 178, 182, -141, -141 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -590,56 +591,57 @@ static const yytype_int16 yypact[] = static const yytype_uint8 yydefact[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 22, 29, 28, 23, 24, 25, 26, 27, 3, - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 5, 0, 0, 0, 0, 0, 0, 0, 6, - 7, 0, 97, 0, 0, 0, 0, 0, 0, 0, - 0, 77, 0, 0, 0, 0, 0, 94, 8, 9, - 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, - 55, 71, 0, 0, 0, 32, 31, 78, 72, 0, - 0, 17, 0, 21, 0, 95, 0, 0, 0, 39, - 0, 0, 45, 0, 0, 0, 75, 72, 0, 0, - 0, 0, 0, 66, 0, 0, 14, 12, 0, 0, - 19, 0, 93, 39, 0, 0, 0, 35, 0, 0, - 0, 0, 35, 54, 59, 0, 0, 0, 0, 69, - 39, 65, 0, 33, 34, 0, 39, 74, 76, 15, - 17, 16, 0, 0, 98, 40, 42, 0, 0, 0, - 0, 39, 48, 72, 44, 53, 39, 0, 0, 0, - 70, 57, 39, 0, 0, 68, 0, 0, 73, 18, - 20, 101, 0, 0, 39, 38, 72, 0, 30, 50, - 0, 0, 47, 46, 0, 43, 39, 72, 62, 0, - 58, 0, 0, 0, 13, 0, 99, 98, 96, 37, - 36, 0, 0, 86, 0, 83, 82, 0, 52, 61, - 60, 0, 56, 0, 0, 0, 100, 79, 51, 39, - 81, 0, 0, 64, 80, 41, 0, 87, 0, 0, - 49, 0, 63, 88, 84, 0, 89, 0, 0, 90, - 0, 0, 91, 0, 0, 92, 85 + 2, 22, 28, 31, 30, 23, 24, 68, 25, 26, + 27, 3, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 6, 7, 0, 103, 29, 0, 0, 0, + 0, 0, 0, 0, 75, 0, 74, 82, 0, 0, + 0, 0, 0, 100, 8, 9, 10, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, 57, 76, 0, 0, + 0, 34, 33, 83, 84, 77, 0, 0, 17, 0, + 21, 0, 101, 0, 0, 0, 41, 0, 0, 47, + 0, 0, 0, 80, 77, 0, 0, 0, 0, 0, + 69, 0, 0, 14, 12, 0, 0, 19, 0, 99, + 41, 0, 0, 0, 37, 0, 0, 0, 0, 37, + 56, 61, 0, 0, 0, 0, 72, 41, 67, 0, + 35, 36, 0, 41, 79, 81, 15, 17, 16, 0, + 0, 104, 42, 44, 0, 0, 0, 0, 41, 50, + 77, 46, 55, 41, 0, 0, 0, 73, 59, 41, + 0, 0, 71, 0, 0, 78, 18, 20, 107, 0, + 0, 41, 40, 77, 0, 32, 52, 0, 0, 49, + 48, 0, 45, 41, 77, 64, 0, 60, 0, 0, + 0, 13, 0, 105, 104, 102, 39, 38, 0, 0, + 92, 0, 89, 88, 0, 54, 63, 62, 0, 58, + 0, 0, 0, 106, 85, 53, 41, 87, 0, 0, + 66, 86, 43, 0, 93, 0, 0, 51, 0, 65, + 94, 90, 0, 95, 0, 0, 96, 0, 0, 97, + 0, 0, 98, 91 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -127, -127, -53, 35, -71, -67, -127, 75, 53, -127, - 44, -127, -127, -127, -26, -127, -127, 98, 84, 63, - -126, -64, -127, 175, 176, -127, -127, -127, -127, 154, - -127, -127, -60, -63, -127, -127, -127, -127, -119, -127, - -127, -127, -127, -113, 102, -127, -127, -127, -127, -121, - -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, - -127, -127, -127, -127, -127, -6, -127 + -141, -141, -59, 12, -77, -55, -141, 56, 44, -141, + 45, -141, -141, -141, 130, -141, 180, -141, 98, 88, + 67, -89, -140, -141, -27, 48, -141, -141, -141, -141, + 150, -141, -141, -43, -79, -141, -141, -141, -141, -121, + 151, 185, -141, -141, -141, -141, -119, 105, -141, -141, + -141, -141, -137, -141, -141, -141, -141, -141, -141, -141, + -141, -141, -141, -141, -141, -141, -141, -141, -2, -141 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 9, 21, 22, 42, 57, 58, 93, 100, 59, - 129, 60, 61, 104, 10, 11, 12, 94, 95, 168, - 136, 156, 82, 13, 45, 140, 112, 200, 239, 85, - 176, 142, 96, 90, 182, 14, 179, 207, 149, 15, - 120, 48, 50, 125, 117, 16, 52, 98, 196, 150, - 173, 224, 225, 226, 227, 248, 254, 257, 260, 263, - 266, 17, 62, 106, 18, 193, 64 + -1, 9, 23, 24, 45, 63, 64, 99, 107, 65, + 136, 66, 67, 111, 10, 11, 12, 13, 100, 101, + 175, 143, 163, 88, 14, 49, 147, 119, 207, 246, + 91, 183, 149, 102, 96, 189, 15, 186, 214, 156, + 16, 17, 127, 52, 55, 56, 132, 124, 18, 58, + 105, 203, 157, 180, 231, 232, 233, 234, 255, 261, + 264, 267, 270, 273, 19, 68, 113, 20, 200, 70 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -647,56 +649,58 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint16 yytable[] = { - 91, 75, 76, 77, 145, 157, 88, 163, 101, 102, - 89, 51, 147, 164, 147, 147, 165, 108, 148, 92, - 172, 170, 147, 123, 185, 30, 155, 155, 148, 127, - 188, 130, 19, 20, 155, 132, 31, 23, 24, 25, - 26, 27, 28, 29, 32, 202, 197, 97, 195, 151, - 204, 143, 105, 33, 158, 144, 211, 209, 161, 208, - 203, 160, 154, 34, 162, 166, 39, 40, 219, 174, - 2, 217, 35, 216, 180, 171, 39, 40, 41, 66, - 229, 36, 69, 220, 71, 37, 38, 44, 74, 47, - 63, 190, 191, 49, 230, 65, 81, 198, 79, 67, - 237, 68, 70, 194, 72, 73, 205, 78, 210, 84, - 242, 80, 88, 246, 206, 214, 109, 201, 83, 113, - 87, 99, 218, 118, 103, 107, 110, 121, 252, 111, - 116, 114, 1, 228, 2, 53, 54, 55, 56, 3, - 232, 4, 5, 115, 119, 6, 138, 122, 7, 8, - 124, 128, 92, 240, 131, 134, 135, 139, 141, 146, - 148, 147, 243, 244, 245, 152, 167, 175, 169, 178, - 181, 186, 192, 199, 126, 250, 223, 238, 212, 159, - 213, 233, 183, 184, 215, 221, 222, 231, 234, 235, - 187, 241, 247, 253, 249, 251, 256, 255, 259, 262, - 258, 261, 265, 264, 189, 177, 153, 43, 137, 133, - 46, 236, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 86 + 97, 81, 82, 83, 171, 152, 178, 115, 47, 94, + 164, 1, 154, 2, 25, 26, 27, 28, 29, 30, + 31, 172, 98, 130, 162, 179, 108, 109, 154, 48, + 134, 32, 137, 95, 201, 177, 139, 204, 53, 2, + 162, 33, 150, 154, 34, 213, 4, 5, 216, 155, + 158, 170, 103, 202, 5, 165, 42, 43, 44, 168, + 72, 210, 224, 75, 215, 77, 173, 35, 192, 36, + 181, 80, 21, 22, 195, 187, 154, 37, 223, 151, + 167, 85, 155, 169, 227, 50, 161, 54, 162, 209, + 38, 244, 197, 198, 211, 237, 42, 43, 205, 116, + 218, 249, 120, 39, 40, 41, 125, 212, 2, 217, + 128, 48, 226, 51, 69, 71, 221, 73, 208, 259, + 74, 76, 78, 225, 236, 79, 1, 84, 2, 86, + 145, 87, 89, 3, 235, 4, 5, 90, 93, 6, + 94, 239, 7, 8, 59, 60, 61, 62, 106, 110, + 114, 117, 121, 118, 247, 123, 122, 253, 98, 126, + 155, 154, 133, 250, 251, 252, 190, 191, 129, 131, + 135, 138, 141, 142, 194, 146, 257, 166, 148, 153, + 159, 182, 174, 176, 185, 188, 193, 206, 199, 219, + 220, 230, 240, 242, 222, 228, 229, 241, 238, 245, + 254, 248, 260, 256, 258, 263, 266, 262, 269, 265, + 268, 272, 196, 271, 112, 144, 184, 160, 46, 140, + 57, 0, 243, 0, 92, 0, 0, 0, 0, 0, + 104 }; static const yytype_int16 yycheck[] = { - 71, 54, 55, 56, 117, 124, 13, 133, 75, 76, - 70, 37, 15, 134, 15, 15, 135, 80, 21, 26, - 139, 22, 15, 94, 150, 0, 27, 27, 21, 100, - 156, 102, 31, 32, 27, 106, 28, 2, 3, 4, - 5, 6, 7, 8, 35, 171, 167, 73, 167, 120, - 176, 114, 78, 35, 125, 115, 182, 178, 129, 178, - 173, 128, 122, 35, 131, 136, 33, 34, 194, 140, - 9, 192, 35, 192, 145, 139, 33, 34, 35, 44, - 206, 35, 47, 196, 49, 35, 35, 10, 53, 18, - 25, 162, 163, 19, 207, 35, 8, 168, 63, 35, - 221, 35, 35, 167, 35, 35, 177, 35, 179, 12, - 231, 35, 13, 239, 178, 186, 81, 170, 35, 84, - 35, 35, 193, 88, 29, 35, 35, 92, 249, 11, - 29, 35, 7, 204, 9, 3, 4, 5, 6, 14, - 211, 16, 17, 35, 35, 20, 111, 35, 23, 24, - 35, 35, 26, 224, 35, 35, 35, 35, 35, 35, - 21, 15, 233, 234, 235, 35, 35, 29, 35, 35, - 29, 29, 35, 29, 99, 246, 29, 29, 35, 126, - 35, 28, 147, 148, 35, 35, 35, 35, 30, 28, - 155, 35, 29, 29, 35, 35, 29, 35, 29, 29, - 35, 35, 29, 35, 160, 142, 122, 32, 110, 107, - 34, 217, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 68 + 77, 60, 61, 62, 141, 124, 146, 86, 35, 13, + 131, 7, 15, 9, 2, 3, 4, 5, 6, 7, + 8, 142, 26, 100, 27, 146, 81, 82, 15, 10, + 107, 0, 109, 76, 174, 22, 113, 174, 19, 9, + 27, 35, 121, 15, 28, 185, 16, 17, 185, 21, + 127, 140, 79, 174, 17, 132, 33, 34, 35, 136, + 48, 180, 199, 51, 185, 53, 143, 35, 157, 35, + 147, 59, 31, 32, 163, 152, 15, 35, 199, 122, + 135, 69, 21, 138, 203, 37, 129, 39, 27, 178, + 35, 228, 169, 170, 183, 214, 33, 34, 175, 87, + 189, 238, 90, 35, 35, 35, 94, 184, 9, 186, + 98, 10, 201, 18, 25, 35, 193, 35, 177, 256, + 35, 35, 35, 200, 213, 35, 7, 35, 9, 35, + 118, 8, 35, 14, 211, 16, 17, 12, 35, 20, + 13, 218, 23, 24, 3, 4, 5, 6, 35, 29, + 35, 35, 35, 11, 231, 29, 35, 246, 26, 35, + 21, 15, 106, 240, 241, 242, 154, 155, 35, 35, + 35, 35, 35, 35, 162, 35, 253, 133, 35, 35, + 35, 29, 35, 35, 35, 29, 29, 29, 35, 35, + 35, 29, 28, 28, 35, 35, 35, 30, 35, 29, + 29, 35, 29, 35, 35, 29, 29, 35, 29, 35, + 35, 29, 167, 35, 84, 117, 149, 129, 33, 114, + 40, -1, 224, -1, 74, -1, -1, -1, -1, -1, + 79 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -704,32 +708,33 @@ static const yytype_int16 yycheck[] = static const yytype_uint8 yystos[] = { 0, 7, 9, 14, 16, 17, 20, 23, 24, 37, - 50, 51, 52, 59, 71, 75, 81, 97, 100, 31, - 32, 38, 39, 39, 39, 39, 39, 39, 39, 39, - 0, 28, 35, 35, 35, 35, 35, 35, 35, 33, - 34, 35, 40, 59, 10, 60, 60, 18, 77, 19, - 78, 50, 82, 3, 4, 5, 6, 41, 42, 45, - 47, 48, 98, 25, 102, 35, 39, 35, 35, 39, - 35, 39, 35, 35, 39, 38, 38, 38, 35, 39, - 35, 8, 58, 35, 12, 65, 65, 35, 13, 68, - 69, 40, 26, 43, 53, 54, 68, 50, 83, 35, - 44, 41, 41, 29, 49, 50, 99, 35, 69, 39, - 35, 11, 62, 39, 35, 35, 29, 80, 39, 35, - 76, 39, 35, 40, 35, 79, 43, 40, 35, 46, - 40, 35, 40, 80, 35, 35, 56, 53, 39, 35, - 61, 35, 67, 69, 68, 79, 35, 15, 21, 74, - 85, 40, 35, 54, 68, 27, 57, 74, 40, 44, - 41, 40, 41, 56, 85, 74, 40, 35, 55, 35, - 22, 57, 74, 86, 40, 29, 66, 55, 35, 72, - 40, 29, 70, 39, 39, 56, 29, 39, 56, 46, - 40, 40, 35, 101, 57, 74, 84, 85, 40, 29, - 63, 38, 56, 79, 56, 40, 57, 73, 74, 85, - 40, 56, 35, 35, 40, 35, 74, 85, 40, 56, - 79, 35, 35, 29, 87, 88, 89, 90, 40, 56, - 79, 35, 40, 28, 30, 28, 101, 85, 29, 64, - 40, 35, 85, 40, 40, 40, 56, 29, 91, 35, - 40, 35, 85, 29, 92, 35, 29, 93, 35, 29, - 94, 35, 29, 95, 35, 29, 96 + 50, 51, 52, 53, 60, 72, 76, 77, 84, 100, + 103, 31, 32, 38, 39, 39, 39, 39, 39, 39, + 39, 39, 0, 35, 28, 35, 35, 35, 35, 35, + 35, 35, 33, 34, 35, 40, 77, 60, 10, 61, + 61, 18, 79, 19, 61, 80, 81, 52, 85, 3, + 4, 5, 6, 41, 42, 45, 47, 48, 101, 25, + 105, 35, 39, 35, 35, 39, 35, 39, 35, 35, + 39, 38, 38, 38, 35, 39, 35, 8, 59, 35, + 12, 66, 66, 35, 13, 69, 70, 40, 26, 43, + 54, 55, 69, 60, 76, 86, 35, 44, 41, 41, + 29, 49, 50, 102, 35, 70, 39, 35, 11, 63, + 39, 35, 35, 29, 83, 39, 35, 78, 39, 35, + 40, 35, 82, 43, 40, 35, 46, 40, 35, 40, + 83, 35, 35, 57, 54, 39, 35, 62, 35, 68, + 70, 69, 82, 35, 15, 21, 75, 88, 40, 35, + 55, 69, 27, 58, 75, 40, 44, 41, 40, 41, + 57, 88, 75, 40, 35, 56, 35, 22, 58, 75, + 89, 40, 29, 67, 56, 35, 73, 40, 29, 71, + 39, 39, 57, 29, 39, 57, 46, 40, 40, 35, + 104, 58, 75, 87, 88, 40, 29, 64, 38, 57, + 82, 57, 40, 58, 74, 75, 88, 40, 57, 35, + 35, 40, 35, 75, 88, 40, 57, 82, 35, 35, + 29, 90, 91, 92, 93, 40, 57, 82, 35, 40, + 28, 30, 28, 104, 88, 29, 65, 40, 35, 88, + 40, 40, 40, 57, 29, 94, 35, 40, 35, 88, + 29, 95, 35, 29, 96, 35, 29, 97, 35, 29, + 98, 35, 29, 99 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -738,14 +743,14 @@ static const yytype_uint8 yyr1[] = 0, 36, 37, 38, 38, 39, 40, 40, 41, 41, 41, 41, 42, 43, 44, 44, 45, 46, 46, 47, 48, 49, 50, 50, 50, 50, 50, 50, 51, 51, - 52, 53, 53, 54, 54, 55, 55, 55, 55, 56, - 56, 57, 58, 59, 60, 61, 61, 61, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 72, 72, 72, 73, 74, 75, 75, 76, 76, 76, - 77, 78, 79, 79, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 100, 101, 101, - 101, 102 + 52, 52, 53, 54, 54, 55, 55, 56, 56, 56, + 56, 57, 57, 58, 59, 60, 61, 62, 62, 62, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 73, 73, 73, 74, 75, 76, 76, 77, + 78, 78, 78, 79, 80, 80, 81, 82, 82, 82, + 83, 84, 85, 86, 86, 87, 88, 89, 90, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 103, 104, 104, 104, 105 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -753,15 +758,15 @@ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 4, 5, 0, 3, 5, 0, 3, 4, - 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 10, 1, 1, 3, 3, 0, 3, 3, 2, 0, - 2, 5, 4, 10, 6, 0, 3, 3, 2, 8, - 1, 1, 6, 1, 1, 1, 6, 1, 10, 0, - 3, 3, 2, 5, 5, 8, 7, 0, 3, 2, - 6, 3, 0, 3, 2, 1, 8, 1, 1, 3, - 5, 4, 1, 1, 5, 13, 1, 1, 1, 1, - 1, 1, 1, 7, 1, 1, 10, 3, 0, 2, - 3, 6 + 6, 1, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 10, 1, 1, 3, 3, 0, 3, 3, + 2, 0, 2, 5, 4, 10, 6, 0, 3, 3, + 2, 8, 1, 1, 6, 1, 1, 1, 6, 1, + 10, 0, 3, 3, 2, 5, 5, 8, 1, 7, + 0, 3, 2, 6, 1, 1, 3, 0, 3, 2, + 1, 8, 1, 1, 1, 3, 5, 4, 1, 1, + 5, 13, 1, 1, 1, 1, 1, 1, 1, 7, + 1, 1, 10, 3, 0, 2, 3, 6 }; diff --git a/src/wkt1_grammar.y b/src/wkt1_grammar.y index e17135c6..b5f27e61 100644 --- a/src/wkt1_grammar.y +++ b/src/wkt1_grammar.y @@ -128,7 +128,11 @@ integer: /* 7.2 Coordinate System WKT */ coordinate_system: - horz_cs | geocentric_cs | vert_cs | compd_cs | fitted_cs | local_cs + horz_cs_with_opt_esri_vertcs | geocentric_cs | vert_cs | compd_cs | fitted_cs | local_cs + +horz_cs_with_opt_esri_vertcs: + horz_cs + | horz_cs ',' esri_vert_cs horz_cs: geographic_cs | projected_cs @@ -217,7 +221,10 @@ authority: vert_cs: T_VERT_CS begin_node_name ',' vert_datum ',' linear_unit opt_axis_authority end_node - | T_VERTCS begin_node_name ',' vdatum ',' opt_parameter_list_linear_unit end_node + | esri_vert_cs + +esri_vert_cs: + T_VERTCS begin_node_name ',' vdatum_or_datum ',' opt_parameter_list_linear_unit end_node opt_axis_authority: | ',' axis opt_authority @@ -226,6 +233,8 @@ opt_axis_authority: vert_datum: T_VERT_DATUM begin_node_name ',' datum_type opt_extension_authority end_node +vdatum_or_datum: vdatum | datum + vdatum: T_VDATUM begin_node_name end_node @@ -240,10 +249,12 @@ compd_cs: T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_extension_authority end_node head_cs: - coordinate_system + horz_cs +// Accepting a geographic CRS as part of the second CRS of a COMPD_CS is horrible +// but found in LAS WKT tail_cs: - coordinate_system + geographic_cs | vert_cs twin_axis: axis ',' axis |
