diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 86f21db765..21754a4462 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -1285,6 +1285,8 @@ struct WKTParser::Private { const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit); + static std::string getExtensionProj4(const WKTNode::Private *nodeP); + static void addExtensionProj4ToProp(const WKTNode::Private *nodeP, PropertyMap &props); @@ -2665,15 +2667,26 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */ // --------------------------------------------------------------------------- -void WKTParser::Private::addExtensionProj4ToProp(const WKTNode::Private *nodeP, - PropertyMap &props) { +std::string +WKTParser::Private::getExtensionProj4(const WKTNode::Private *nodeP) { auto &extensionNode = nodeP->lookForChild(WKTConstants::EXTENSION); const auto &extensionChildren = extensionNode->GP()->children(); if (extensionChildren.size() == 2) { if (ci_equal(stripQuotes(extensionChildren[0]), "PROJ4")) { - props.set("EXTENSION_PROJ4", stripQuotes(extensionChildren[1])); + return stripQuotes(extensionChildren[1]); } } + return std::string(); +} + +// --------------------------------------------------------------------------- + +void WKTParser::Private::addExtensionProj4ToProp(const WKTNode::Private *nodeP, + PropertyMap &props) { + const auto extensionProj4(getExtensionProj4(nodeP)); + if (!extensionProj4.empty()) { + props.set("EXTENSION_PROJ4", extensionProj4); + } } // --------------------------------------------------------------------------- @@ -4514,13 +4527,15 @@ CRSPtr WKTParser::Private::buildCRS(const WKTNodeNNPtr &node) { if (ci_equal(name, WKTConstants::PROJCS) || ci_equal(name, WKTConstants::PROJCRS) || ci_equal(name, WKTConstants::PROJECTEDCRS)) { - auto projCRS = - util::nn_static_pointer_cast(buildProjectedCRS(node)); - auto projString = projCRS->getExtensionProj4(); - if (starts_with(projString, "+proj=ob_tran +o_proj=longlat") || - starts_with(projString, "+proj=ob_tran +o_proj=lonlat") || - starts_with(projString, "+proj=ob_tran +o_proj=latlong") || - starts_with(projString, "+proj=ob_tran +o_proj=latlon")) { + // Get the EXTENSION "PROJ4" node before attempting to call + // buildProjectedCRS() since formulations of WKT1_GDAL from GDAL 2.x + // with the netCDF driver and the lack the required UNIT[] node + std::string projString = getExtensionProj4(nodeP); + if (!projString.empty() && + (starts_with(projString, "+proj=ob_tran +o_proj=longlat") || + starts_with(projString, "+proj=ob_tran +o_proj=lonlat") || + starts_with(projString, "+proj=ob_tran +o_proj=latlong") || + starts_with(projString, "+proj=ob_tran +o_proj=latlon"))) { // Those are not a projected CRS, but a DerivedGeographic one... if (projString.find(" +type=crs") == std::string::npos) { projString += " +type=crs"; @@ -4535,7 +4550,7 @@ CRSPtr WKTParser::Private::buildCRS(const WKTNodeNNPtr &node) { } catch (const io::ParsingException &) { } } - return projCRS.as_nullable(); + return util::nn_static_pointer_cast(buildProjectedCRS(node)); } if (ci_equal(name, WKTConstants::VERT_CS) || diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 2a262111e5..f829bf91ff 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -3626,6 +3626,7 @@ TEST(wkt_parse, DerivedGeodeticCRS) { // --------------------------------------------------------------------------- TEST(wkt_parse, DerivedGeographicCRS_GDAL_PROJ4_EXSTENSION_hack) { + // Note the lack of UNIT[] node auto wkt = "PROJCS[\"unnamed\"," " GEOGCS[\"unknown\"," @@ -3635,14 +3636,11 @@ TEST(wkt_parse, DerivedGeographicCRS_GDAL_PROJ4_EXSTENSION_hack) { " UNIT[\"degree\",0.0174532925199433," " AUTHORITY[\"EPSG\",\"9122\"]]]," " PROJECTION[\"Rotated_pole\"]," - " UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]]," - " AXIS[\"Easting\",EAST]," - " AXIS[\"Northing\",NORTH]," " EXTENSION[\"PROJ4\",\"+proj=ob_tran +o_proj=longlat +lon_0=18 " "+o_lon_p=0 +o_lat_p=39.25 +a=6367470 +b=6367470 " "+to_meter=0.0174532925199 +wktext\"]]"; - auto obj = WKTParser().createFromWKT(wkt); + auto obj = WKTParser().setStrict(false).createFromWKT(wkt); auto crs = nn_dynamic_pointer_cast(obj); ASSERT_TRUE(crs != nullptr);