aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/iso19111/factory.cpp65
-rw-r--r--test/unit/proj_angular_io_test.cpp11
-rw-r--r--test/unit/test_crs.cpp24
3 files changed, 91 insertions, 9 deletions
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index c6c25f36..32ed6abb 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -6051,8 +6051,15 @@ AuthorityFactory::createProjectedCRSFromExisting(
params.emplace_back(d->authority());
}
- int iParam = 1;
+ int iParam = 0;
+ bool hasLat1stStd = false;
+ double lat1stStd = 0;
+ int iParamLat1stStd = 0;
+ bool hasLat2ndStd = false;
+ double lat2ndStd = 0;
+ int iParamLat2ndStd = 0;
for (const auto &genOpParamvalue : conv->parameterValues()) {
+ iParam++;
auto opParamvalue =
dynamic_cast<const operation::OperationParameterValue *>(
genOpParamvalue.get());
@@ -6070,6 +6077,23 @@ AuthorityFactory::createProjectedCRSFromExisting(
const auto &unit = measure.unit();
if (unit == common::UnitOfMeasure::DEGREE &&
geogCRS->coordinateSystem()->axisList()[0]->unit() == unit) {
+ if (methodEPSGCode ==
+ EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP) {
+ // Special case for standard parallels of LCC_2SP. See below
+ if (paramEPSGCode ==
+ EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL) {
+ hasLat1stStd = true;
+ lat1stStd = measure.value();
+ iParamLat1stStd = iParam;
+ continue;
+ } else if (paramEPSGCode ==
+ EPSG_CODE_PARAMETER_LATITUDE_2ND_STD_PARALLEL) {
+ hasLat2ndStd = true;
+ lat2ndStd = measure.value();
+ iParamLat2ndStd = iParam;
+ continue;
+ }
+ }
const auto iParamAsStr(toString(iParam));
sql += " AND conv.param";
sql += iParamAsStr;
@@ -6084,7 +6108,44 @@ AuthorityFactory::createProjectedCRSFromExisting(
params.emplace_back(measure.value() - 1);
params.emplace_back(measure.value() + 1);
}
- iParam++;
+ }
+
+ // Special case for standard parallels of LCC_2SP: they can be switched
+ if (methodEPSGCode == EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP &&
+ hasLat1stStd && hasLat2ndStd) {
+ const auto iParam1AsStr(toString(iParamLat1stStd));
+ const auto iParam2AsStr(toString(iParamLat2ndStd));
+ sql += " AND conv.param";
+ sql += iParam1AsStr;
+ sql += "_code = ? AND conv.param";
+ sql += iParam1AsStr;
+ sql += "_auth_name = 'EPSG' AND conv.param";
+ sql += iParam2AsStr;
+ sql += "_code = ? AND conv.param";
+ sql += iParam2AsStr;
+ sql += "_auth_name = 'EPSG' AND ((";
+ params.emplace_back(
+ toString(EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL));
+ params.emplace_back(
+ toString(EPSG_CODE_PARAMETER_LATITUDE_2ND_STD_PARALLEL));
+ double val1 = lat1stStd;
+ double val2 = lat2ndStd;
+ for (int i = 0; i < 2; i++) {
+ if (i == 1) {
+ sql += ") OR (";
+ std::swap(val1, val2);
+ }
+ sql += "conv.param";
+ sql += iParam1AsStr;
+ sql += "_value BETWEEN ? AND ? AND conv.param";
+ sql += iParam2AsStr;
+ sql += "_value BETWEEN ? AND ?";
+ params.emplace_back(val1 - 1);
+ params.emplace_back(val1 + 1);
+ params.emplace_back(val2 - 1);
+ params.emplace_back(val2 + 1);
+ }
+ sql += "))";
}
auto sqlRes = d->run(sql, params);
diff --git a/test/unit/proj_angular_io_test.cpp b/test/unit/proj_angular_io_test.cpp
index 30eae298..6a32c8a6 100644
--- a/test/unit/proj_angular_io_test.cpp
+++ b/test/unit/proj_angular_io_test.cpp
@@ -100,12 +100,10 @@ TEST(AngularUnits, Pipelines3) {
TEST(AngularUnits, Degrees) {
auto ctx = proj_context_create();
- auto P = proj_create(
- ctx,
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=32 +ellps=GRS80 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- );
+ auto P =
+ proj_create(ctx, "+proj=pipeline "
+ "+step +inv +proj=utm +zone=32 +ellps=GRS80 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg ");
EXPECT_FALSE(proj_degree_input(P, PJ_FWD));
EXPECT_TRUE(proj_degree_input(P, PJ_INV));
@@ -114,7 +112,6 @@ TEST(AngularUnits, Degrees) {
proj_destroy(P);
proj_context_destroy(ctx);
-
}
} // namespace
diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp
index 2bde8ee3..ad32d98b 100644
--- a/test/unit/test_crs.cpp
+++ b/test/unit/test_crs.cpp
@@ -2550,6 +2550,30 @@ TEST(crs, projectedCRS_identify_db) {
EXPECT_EQ(res.front().first->getEPSGCode(), 2954);
EXPECT_EQ(res.front().second, 100);
}
+ {
+ // Test identification of LCC_2SP with switched standard parallels.
+ auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(
+ "PROJCS[\"foo\",\n"
+ " GEOGCS[\"RGF93\",\n"
+ " DATUM[\"Reseau_Geodesique_Francais_1993\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"degree\",0.0174532925199433]],\n"
+ " PROJECTION[\"Lambert_Conformal_Conic_2SP\"],\n"
+ " PARAMETER[\"latitude_of_origin\",46.5],\n"
+ " PARAMETER[\"central_meridian\",3],\n"
+ " PARAMETER[\"standard_parallel_1\",44],\n"
+ " PARAMETER[\"standard_parallel_2\",49],\n"
+ " PARAMETER[\"false_easting\",700000],\n"
+ " PARAMETER[\"false_northing\",6600000],\n"
+ " UNIT[\"metre\",1]]");
+ auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ auto res = crs->identify(factoryEPSG);
+ ASSERT_EQ(res.size(), 1U);
+ EXPECT_EQ(res.front().first->getEPSGCode(), 2154);
+ EXPECT_EQ(res.front().second, 70);
+ }
}
// ---------------------------------------------------------------------------