aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-11-25 15:12:33 +0100
committerEven Rouault <even.rouault@spatialys.com>2019-11-25 15:12:33 +0100
commitd1945ecbafc202a0034ad1aa1bb5f38cd10ee74c (patch)
treedb4aee752c09b1bda8d47c08536c262178a96263
parentd81ffc6fa8a32db72bdfd1ff034c705222d0cdb3 (diff)
downloadPROJ-d1945ecbafc202a0034ad1aa1bb5f38cd10ee74c.tar.gz
PROJ-d1945ecbafc202a0034ad1aa1bb5f38cd10ee74c.zip
PROJStringFormatter::toString(): optimize hgridshift, vgridshift, hgridshift inv constructs
Given an initial pipeline with +step +proj=hgridshift +grids=foo +step +proj=vgridshift +grids=bar +step +inv +proj=hgridshift +grids=foo Transform it as +step +proj=push +v_1 +v_2 +step +proj=hgridshift +grids=foo +omit_inv +step +proj=vgridshift +grids=bar +step +inv +proj=hgridshift +grids=foo +omit_fwd +step +proj=pop +v_1 +v_2 So as to avoid doing a double application of the hgridshift.
-rw-r--r--src/iso19111/io.cpp44
-rw-r--r--test/unit/test_io.cpp89
2 files changed, 133 insertions, 0 deletions
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index d994277b..0d98e2de 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -6278,6 +6278,10 @@ struct Step {
return key == otherKey && value == otherVal;
}
+ bool operator==(const KeyValue &other) const noexcept {
+ return key == other.key && value == other.value;
+ }
+
bool operator!=(const KeyValue &other) const noexcept {
return key != other.key || value != other.value;
}
@@ -6799,6 +6803,46 @@ const std::string &PROJStringFormatter::toString() const {
}
}
+ // +step +proj=hgridshift +grids=grid_A
+ // +step +proj=vgridshift [...] <== curStep
+ // +step +inv +proj=hgridshift +grids=grid_A
+ // ==>
+ // +step +proj=push +v_1 +v_2
+ // +step +proj=hgridshift +grids=grid_A +omit_inv
+ // +step +proj=vgridshift [...]
+ // +step +inv +proj=hgridshift +grids=grid_A +omit_fwd
+ // +step +proj=pop +v_1 +v_2
+ if (i + 1 < d->steps_.size() && prevStep.name == "hgridshift" &&
+ prevStepParamCount == 1 && curStep.name == "vgridshift") {
+ auto iterNext = iterCur;
+ ++iterNext;
+ auto &nextStep = *iterNext;
+ if (nextStep.name == "hgridshift" &&
+ nextStep.inverted != prevStep.inverted &&
+ nextStep.paramValues.size() == 1 &&
+ prevStep.paramValues[0] == nextStep.paramValues[0]) {
+ Step pushStep;
+ pushStep.name = "push";
+ pushStep.paramValues.emplace_back("v_1");
+ pushStep.paramValues.emplace_back("v_2");
+ d->steps_.insert(iterPrev, pushStep);
+
+ prevStep.paramValues.emplace_back("omit_inv");
+
+ nextStep.paramValues.emplace_back("omit_fwd");
+
+ Step popStep;
+ popStep.name = "pop";
+ popStep.paramValues.emplace_back("v_1");
+ popStep.paramValues.emplace_back("v_2");
+ ++iterNext;
+ d->steps_.insert(iterNext, popStep);
+
+ changeDone = true;
+ break;
+ }
+ }
+
// detect a step and its inverse
if (curStep.inverted != prevStep.inverted &&
curStep.name == prevStep.name &&
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 07c4c6f1..0dc0dc1c 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -6832,6 +6832,95 @@ TEST(io, projstringformatter_axisswap_unitconvert_axisswap) {
// ---------------------------------------------------------------------------
+TEST(io, projstringformatter_optim_hgridshift_vgridshift_hgridshift_inv) {
+ // Nominal case
+ {
+ auto fmt = PROJStringFormatter::create();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+
+ fmt->addStep("vgridshift");
+ fmt->addParam("grids", "bar");
+
+ fmt->startInversion();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+ fmt->stopInversion();
+
+ EXPECT_EQ(fmt->toString(),
+ "+proj=pipeline "
+ "+step +proj=push +v_1 +v_2 "
+ "+step +proj=hgridshift +grids=foo +omit_inv "
+ "+step +proj=vgridshift +grids=bar "
+ "+step +inv +proj=hgridshift +grids=foo +omit_fwd "
+ "+step +proj=pop +v_1 +v_2");
+ }
+
+ // Variant with first hgridshift inverted, and second forward
+ {
+ auto fmt = PROJStringFormatter::create();
+
+ fmt->startInversion();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+ fmt->stopInversion();
+
+ fmt->addStep("vgridshift");
+ fmt->addParam("grids", "bar");
+
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+
+ EXPECT_EQ(fmt->toString(),
+ "+proj=pipeline "
+ "+step +proj=push +v_1 +v_2 "
+ "+step +inv +proj=hgridshift +grids=foo +omit_inv "
+ "+step +proj=vgridshift +grids=bar "
+ "+step +proj=hgridshift +grids=foo +omit_fwd "
+ "+step +proj=pop +v_1 +v_2");
+ }
+
+ // Do not apply ! not same grid name
+ {
+ auto fmt = PROJStringFormatter::create();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+
+ fmt->addStep("vgridshift");
+ fmt->addParam("grids", "bar");
+
+ fmt->startInversion();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo2");
+ fmt->stopInversion();
+
+ EXPECT_EQ(fmt->toString(), "+proj=pipeline "
+ "+step +proj=hgridshift +grids=foo "
+ "+step +proj=vgridshift +grids=bar "
+ "+step +inv +proj=hgridshift +grids=foo2");
+ }
+
+ // Do not apply ! missing inversion
+ {
+ auto fmt = PROJStringFormatter::create();
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+
+ fmt->addStep("vgridshift");
+ fmt->addParam("grids", "bar");
+
+ fmt->addStep("hgridshift");
+ fmt->addParam("grids", "foo");
+
+ EXPECT_EQ(fmt->toString(), "+proj=pipeline "
+ "+step +proj=hgridshift +grids=foo "
+ "+step +proj=vgridshift +grids=bar "
+ "+step +proj=hgridshift +grids=foo");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
TEST(io, projparse_longlat) {
auto expected = "GEODCRS[\"unknown\",\n"