Skip to content

Commit 2d8cf76

Browse files
authored
Merge pull request #3265 from rouault/optimize_opposite_helmert
PROJ pipeline generator: recognize opposite Helmert transformations using a different convention
2 parents 6109096 + b80ed2a commit 2d8cf76

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

src/iso19111/io.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -8399,6 +8399,68 @@ const std::string &PROJStringFormatter::toString() const {
83998399
}
84008400
}
84018401

8402+
// The following should be optimized as a no-op
8403+
// +step +proj=helmert +x=25 +y=-141 +z=-78.5 +rx=0 +ry=-0.35
8404+
// +rz=-0.736 +s=0 +convention=coordinate_frame
8405+
// +step +inv +proj=helmert +x=25 +y=-141 +z=-78.5 +rx=0 +ry=0.35
8406+
// +rz=0.736 +s=0 +convention=position_vector
8407+
if (curStep.name == "helmert" && prevStep.name == "helmert" &&
8408+
((curStep.inverted && !prevStep.inverted) ||
8409+
(!curStep.inverted && prevStep.inverted)) &&
8410+
curStepParamCount == prevStepParamCount) {
8411+
std::set<std::string> leftParamsSet;
8412+
std::set<std::string> rightParamsSet;
8413+
std::map<std::string, std::string> leftParamsMap;
8414+
std::map<std::string, std::string> rightParamsMap;
8415+
for (const auto &kv : prevStep.paramValues) {
8416+
leftParamsSet.insert(kv.key);
8417+
leftParamsMap[kv.key] = kv.value;
8418+
}
8419+
for (const auto &kv : curStep.paramValues) {
8420+
rightParamsSet.insert(kv.key);
8421+
rightParamsMap[kv.key] = kv.value;
8422+
}
8423+
if (leftParamsSet == rightParamsSet) {
8424+
bool doErase = true;
8425+
try {
8426+
for (const auto &param : leftParamsSet) {
8427+
if (param == "convention") {
8428+
// Convention must be different
8429+
if (leftParamsMap[param] ==
8430+
rightParamsMap[param]) {
8431+
doErase = false;
8432+
break;
8433+
}
8434+
} else if (param == "rx" || param == "ry" ||
8435+
param == "rz" || param == "drx" ||
8436+
param == "dry" || param == "drz") {
8437+
// Rotational parameters should have opposite
8438+
// value
8439+
if (c_locale_stod(leftParamsMap[param]) !=
8440+
-c_locale_stod(rightParamsMap[param])) {
8441+
doErase = false;
8442+
break;
8443+
}
8444+
} else {
8445+
// Non rotational parameters should have the
8446+
// same value
8447+
if (leftParamsMap[param] !=
8448+
rightParamsMap[param]) {
8449+
doErase = false;
8450+
break;
8451+
}
8452+
}
8453+
}
8454+
} catch (const std::invalid_argument &) {
8455+
break;
8456+
}
8457+
if (doErase) {
8458+
deletePrevAndCurIter();
8459+
continue;
8460+
}
8461+
}
8462+
}
8463+
84028464
// detect a step and its inverse
84038465
if (curStep.inverted != prevStep.inverted &&
84048466
curStep.name == prevStep.name &&

test/unit/test_io.cpp

+152
Original file line numberDiff line numberDiff line change
@@ -8476,6 +8476,158 @@ TEST(io, projstringformatter_merge_consecutive_helmert_3_param_noop) {
84768476

84778477
// ---------------------------------------------------------------------------
84788478

8479+
TEST(io, projstringformatter_merge_inverted_helmert_with_opposite_conventions) {
8480+
{
8481+
auto fmt = PROJStringFormatter::create();
8482+
fmt->addStep("helmert");
8483+
fmt->addParam("x", 10);
8484+
fmt->addParam("y", 20);
8485+
fmt->addParam("z", 30);
8486+
fmt->addParam("rx", 1);
8487+
fmt->addParam("ry", 2);
8488+
fmt->addParam("rz", 3);
8489+
fmt->addParam("s", 4);
8490+
fmt->addParam("convention", "position_vector");
8491+
fmt->addStep("helmert");
8492+
fmt->setCurrentStepInverted(true);
8493+
fmt->addParam("x", 10);
8494+
fmt->addParam("y", 20);
8495+
fmt->addParam("z", 30);
8496+
fmt->addParam("rx", -1);
8497+
fmt->addParam("ry", -2);
8498+
fmt->addParam("rz", -3);
8499+
fmt->addParam("s", 4);
8500+
fmt->addParam("convention", "coordinate_frame");
8501+
EXPECT_EQ(fmt->toString(), "+proj=noop");
8502+
}
8503+
8504+
{
8505+
auto fmt = PROJStringFormatter::create();
8506+
fmt->addStep("helmert");
8507+
fmt->setCurrentStepInverted(true);
8508+
fmt->addParam("x", 10);
8509+
fmt->addParam("y", 20);
8510+
fmt->addParam("z", 30);
8511+
fmt->addParam("rx", 1);
8512+
fmt->addParam("ry", 2);
8513+
fmt->addParam("rz", 3);
8514+
fmt->addParam("s", 4);
8515+
fmt->addParam("convention", "coordinate_frame");
8516+
fmt->addStep("helmert");
8517+
fmt->addParam("x", 10);
8518+
fmt->addParam("y", 20);
8519+
fmt->addParam("z", 30);
8520+
fmt->addParam("rx", -1);
8521+
fmt->addParam("ry", -2);
8522+
fmt->addParam("rz", -3);
8523+
fmt->addParam("s", 4);
8524+
fmt->addParam("convention", "position_vector");
8525+
EXPECT_EQ(fmt->toString(), "+proj=noop");
8526+
}
8527+
8528+
// Cannot be optimized
8529+
{
8530+
auto fmt = PROJStringFormatter::create();
8531+
fmt->addStep("helmert");
8532+
fmt->addParam("x", 10);
8533+
fmt->addParam("y", 20);
8534+
fmt->addParam("z", 30);
8535+
fmt->addParam("rx", 1);
8536+
fmt->addParam("ry", 2);
8537+
fmt->addParam("rz", 3);
8538+
fmt->addParam("s", 4);
8539+
fmt->addParam("convention", "position_vector");
8540+
fmt->addStep("helmert");
8541+
// fmt->setCurrentStepInverted(true); <== CAUSE
8542+
fmt->addParam("x", 10);
8543+
fmt->addParam("y", 20);
8544+
fmt->addParam("z", 30);
8545+
fmt->addParam("rx", -1);
8546+
fmt->addParam("ry", -2);
8547+
fmt->addParam("rz", -3);
8548+
fmt->addParam("s", 4);
8549+
fmt->addParam("convention", "coordinate_frame");
8550+
EXPECT_TRUE(fmt->toString() != "+proj=noop");
8551+
}
8552+
8553+
// Cannot be optimized
8554+
{
8555+
auto fmt = PROJStringFormatter::create();
8556+
fmt->addStep("helmert");
8557+
fmt->addParam("x", 10);
8558+
fmt->addParam("y", 20);
8559+
fmt->addParam("z", 30);
8560+
fmt->addParam("rx", 1);
8561+
fmt->addParam("ry", 2);
8562+
fmt->addParam("rz", 3);
8563+
fmt->addParam("s", 4);
8564+
fmt->addParam("convention", "position_vector");
8565+
fmt->addStep("helmert");
8566+
fmt->setCurrentStepInverted(true);
8567+
fmt->addParam("x", 10);
8568+
fmt->addParam("y", 20);
8569+
fmt->addParam("z", 30);
8570+
fmt->addParam("rx", -1);
8571+
fmt->addParam("ry", -2);
8572+
fmt->addParam("rz", -3);
8573+
fmt->addParam("s", 4);
8574+
fmt->addParam("convention", "position_vector"); // <== CAUSE
8575+
EXPECT_TRUE(fmt->toString() != "+proj=noop");
8576+
}
8577+
8578+
// Cannot be optimized
8579+
{
8580+
auto fmt = PROJStringFormatter::create();
8581+
fmt->addStep("helmert");
8582+
fmt->addParam("x", 10);
8583+
fmt->addParam("y", 20);
8584+
fmt->addParam("z", 30);
8585+
fmt->addParam("rx", 1);
8586+
fmt->addParam("ry", 2);
8587+
fmt->addParam("rz", 3);
8588+
fmt->addParam("s", 4);
8589+
fmt->addParam("convention", "position_vector");
8590+
fmt->addStep("helmert");
8591+
fmt->setCurrentStepInverted(true);
8592+
fmt->addParam("x", -10); // <== CAUSE
8593+
fmt->addParam("y", 20);
8594+
fmt->addParam("z", 30);
8595+
fmt->addParam("rx", -1);
8596+
fmt->addParam("ry", -2);
8597+
fmt->addParam("rz", -3);
8598+
fmt->addParam("s", 4);
8599+
fmt->addParam("convention", "coordinate_frame");
8600+
EXPECT_TRUE(fmt->toString() != "+proj=noop");
8601+
}
8602+
8603+
// Cannot be optimized
8604+
{
8605+
auto fmt = PROJStringFormatter::create();
8606+
fmt->addStep("helmert");
8607+
fmt->addParam("x", 10);
8608+
fmt->addParam("y", 20);
8609+
fmt->addParam("z", 30);
8610+
fmt->addParam("rx", 1);
8611+
fmt->addParam("ry", 3);
8612+
fmt->addParam("rz", 2);
8613+
fmt->addParam("s", 4);
8614+
fmt->addParam("convention", "position_vector");
8615+
fmt->addStep("helmert");
8616+
fmt->setCurrentStepInverted(true);
8617+
fmt->addParam("x", 10);
8618+
fmt->addParam("y", 20);
8619+
fmt->addParam("z", 30);
8620+
fmt->addParam("rx", 1); // <== CAUSE
8621+
fmt->addParam("ry", -2);
8622+
fmt->addParam("rz", -3);
8623+
fmt->addParam("s", 4);
8624+
fmt->addParam("convention", "coordinate_frame");
8625+
EXPECT_TRUE(fmt->toString() != "+proj=noop");
8626+
}
8627+
}
8628+
8629+
// ---------------------------------------------------------------------------
8630+
84798631
TEST(io, projstringformatter_cart_grs80_wgs84) {
84808632
auto fmt = PROJStringFormatter::create();
84818633
fmt->addStep("cart");

0 commit comments

Comments
 (0)