Thomas,

| The main problem with PROJ's current push/pop functionality
is that the four-stack implementation makes it impossible
to push one dimension of a coordinate-tuple and pop it into
another, without an elaborate axisswap dance at both ends
of the push/pop-pair.

This is a consequence of the v_1 ... v_4 syntax used: Since
the order of operator arguments is not necessarily preserved
during the parsing process, a pair specified as "v_1 v_2"
may appear as "v_2 v_1" at parsing time.

While I agree with the theoretical problem, is it actually an issue in practice? I can't remember having been annoyed by that a single time. Axis swap issues mostly/only occur to get compliant with CRS official axis order, and that happens only at the early and final stages of a pipeline, whereas push/pop logic happens in between where we always speak longitude,latitude / easting, northing in that order. So during most of a pipeline execution, axis order remains quite stable. So while imperfect, I don't see a strong/immediate need to implement a new improved push/pop.



    proj=stack push=1,3
    proj=stack swap
    proj=stack pop=1,3

to essentially do the same as above and:

    proj=stack push=1,3
    proj=stack flip=3,1

stack swap, flip: sorry but my own imperfect brain of a programmer not having coded in Forth, I will have a very hard time to remember what they do exactly without referring to the doc :-)



The wish for named registers mentioned earlier in the
thread may be introduced using a similar syntax, where:

    proj=reg save=1,3 into=first,third
    proj=reg restore=1,3 from=third,first

I would be interested in implementing just save/restore.

Why not having 2 separate operations, since (save,into) and (restore,from) are mutually exclusive parameters.

So

- proj=save from=1,3 into=first,third

- proj=restore into=1,3 from=first,third

So my pipeline would become:

|proj=pipeline step proj=save from=3 into=etrs89_h omit_inv # skipped on reverse path step inv proj=vgridshift grids=CR2005.tif multiplier=1 step proj=save from=3 into=baltic57_h # reversed as restore step proj=restore from=etrs89_h into=3 omit_inv # skipped on reverse path step proj=cart ellps=GRS80 step inv proj=helmert x=572.213 rx=-4.9732 y=85.334 ry=-1.529 z=461.94 rz=-5.2484 s=3.5378 convention=coordinate_frame step inv proj=cart ellps=bessel step proj=restore from=baltic57_h into=3 # reversed as a save|

I find it reasonably readable.

But I can also live with your proposed syntax.

~~~~~

Or... at least for the sake of brainstorming.... I've also imagined that we could extent the existing "set" operator with new capabilities, that would bring it even closer to the syntax of most programming languages (destination=source)

- proj=set first=v_1  : assign v_1 component to "first" variable

- proj=set v_1=first  : restore v_1 component from "first" variable

This causes a few departures from actual PROJ operator logic in, but none of them are actually implementation issues:

- the parameter name is actually a variable for the "save" semantics (so we have to iterate over the list of parameters, instead of just querying a fixed set of parameter names)

- for the restore case (ie v_1=), we need to look at the value to determine the semantics. If it is a number, then use the current semantics. If it is a string, then it is a variable name. But not different from programming language with A=1 and A=B...

In the reverse path, proj=set first=v_1 would be interpreted as proj=set v_1=first, and vice-verca. That part is admitedly a bit hard to swallow... especially since it wouldn't apply to when you do the regular v_1=numeric_value, and would be my main hesitation to implement that.

If we'd go with the idea, we would likely need to exclude v_1, v_2, v_3, v_4 as valid variable names (that is assigning a component to another one, since that's generally the role of axisswap) mostly because it is not intuitive to me what should be done in the reverse path. We's also need to exclude "proj" as a variable name to avoid awkward and unparseable things like "proj=set proj=v_1".

~~~~~~~

[ side remark: Actually I believe the push/pop stack logic could be entirely replaced by named registers. If you look at programming languages, you use more often named variables than stacks. And in actual PROJ pipelines, I believe you have rarely have patterns where you have nested pushes of the same variable, that is something like "push 1", do X, "push 1", do Y "pop 1", do Z, "pop 1". And even if you have, that can be easily replaced with "save 1 as first_one", do X, "save 1 as second_one", do Y, "restore 1 from second_one", do Z, "restore 1 from first_one".

... but ... while my above remark is likely true for "optimized" / hand-written pipelines, looking at the code in createOperations() that compose pipelines, I wouldn't exclude that such situations could happen where it would generate a pipeline with nested pushes, some of them being likely redundant/no-op. I'm not sure really of what monstrosities that code can generate :-) Anyway the current push/pop will remain]



The problem, however, is when trying to interpret the
workings of a pipeline running in inverse mode:

In the inverse stack-case, we only need to flip the
abstract concepts of stack slots, and swap push for pop.

Whereas in the register case, we also need to "abstractly
swap the concrete concepts behind the concrete register
names" which, at least to my imperfect brain, is much
harder.

Understanding the inversion of a pipelines requires a fully awaken brain (Acually when you think of it, no programming language I'm aware of offers the possibility to execute a program in reverse order) - especially with omit_fwd/omit_inv, double negation of +inv, etc. , but the inverse of a save is a restore, and the inverse of into is from. So not terribly different from push / pop.

Even

--
http://www.spatialys.com
My software is free, but my time generally not.
_______________________________________________
PROJ mailing list
[email protected]
https://lists.osgeo.org/mailman/listinfo/proj

Reply via email to