Skip to content

Commit 09751a5

Browse files
committed
First sketch of Rumination 9
1 parent aa384ac commit 09751a5

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed

ruminations/009-rumination.md

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# Teach yourself Geodesy in less than 600 seconds (of arc)
2+
3+
**Thomas Knudsen,** <thokn@sdfi.dk>, 2024-02-05
4+
5+
## Introduction
6+
7+
The following is a brief overview of the geodetic software package **Rust [Geodesy](https://github.com/busstoptaktik/geodesy)** (a.k.a. RG, or simply **Geodesy** - proper noun, capital G). The text is intended for consumption in its entirety, in one sitting, before trying out the software. It should provide you with a first feeling for the architecture, the concepts, and the syntax used, prior to taking the deep dive.
8+
9+
As a guide to further exploration, the text is followed by a collection of [usage examples](#examples), and a list of suggested [further reading](#further-reading).
10+
11+
**RG** shares many characteristics with the [PROJ](https://proj.org) transformation system, so the fundamental concepts are readily understood by PROJ users. The RG syntax is, however, slightly different, and much less verbose than its PROJ counterpart, so seasoned PROJ users may benefit from focusing primarily on the syntax descriptions below.
12+
13+
### About the title - and a bit about units
14+
15+
While in all likelihood it is impossible to teach yourself geodesy in 600 seconds, it is much more likely to teach yourself **Geodesy** in that amount of time.
16+
17+
The title, however, refers to 600 seconds *of arc*, which corresponds to *10 minutes* of arc. A minute of arc is the historical definition of one nautical mile, and a speed of one knot corresponds to one nautical mile per hour.
18+
19+
So to fit the 600 seconds of time to the 600 seconds of arc, you will have to navigate through this text at a speed of 60 knots. So better get going - see you at the finish line!
20+
21+
## Overview
22+
23+
At its most basic level, RG provides a number of elementary geodetic computational **operators**.
24+
25+
**Operators** read a stream of *input coordinates*, modify them by applying some specific algorithm, and write an identically sized stream of *output coordinates*.
26+
27+
Most operators exist in *forward* and *inverse* incarnations. For example:
28+
29+
- the **forward utm-operator** takes *geographical coordinates* as its input, and provides *utm coordinates* as its output, while
30+
- the **inverse utm-operator** does the opposite: takes *utm coordinates* as input, and provides the corresponding *geographical coordinates* as output.
31+
32+
The *elementary operators* can be combined into more *complex operations* using the RG **pipeline mechanism**, where the *output* of one operator provides the *input* of another.
33+
34+
Pipelines can be generalized in the form of **macros**, with or without *parameters*. The macros can be collected in **registers**, organizing and documenting collections of (preferably) related macros.
35+
36+
### Operators
37+
38+
Most operators take **parameters,** which may be *mandatory* or *optional*. For example, the `utm` operator takes a mandatory parameter, `zone`, indicating which utm-zone it should operate in, e.g.
39+
40+
```geodesy
41+
utm zone=32
42+
```
43+
44+
Since utm coordinates are ellipsoidal, the `utm`-operator also needs to be told *which* ellipsoid to refer to. But that parameter is optional, and defaults to GRS80. So this more elaborate version:
45+
46+
```geodesy
47+
utm zone=32 ellps=GRS80
48+
```
49+
50+
works identically to the previous.
51+
52+
#### Inverse operators
53+
54+
Inverse operators are instantiated by providing the `inv`-modifier:
55+
56+
```geodesy
57+
inv utm zone=32
58+
```
59+
60+
**Modifiers,** like `inv`, are *special kinds of parameters* which may be given anywhere in the operator definition (whereas *ordinary parameters* must be given *after* the operator name).
61+
62+
But since modifiers have such a drastic influence, it is useful to **place them in front** of the entire expression for better visibility.
63+
64+
Apart from `inv`, only two modifiers exist: `omit_fwd` and `omit_inv`. They are rare beasts though, and only used inside **pipelines**.
65+
66+
### Pipelines
67+
68+
**Pipelines** are collections of operators, (which are referred to as **steps**), organized in lockstep, such that the output of the first step goes to the input of the second, the output of the second to the input of the third, and so on.
69+
70+
Pipelines are built using the vertical bar syntax, e.g. to build a pipeline taking geocentric cartesian coordinates as input, and giving utm coordinates with ellipsoidal heights as output, you will say:
71+
72+
```geodesy
73+
inv cart | utm zone=32
74+
```
75+
76+
a syntax clearly mimicking the Unix shell pipe-construct, which is also the inspiration for the PROJ pipeline construct upon which Geodesy pipelines are modelled.
77+
78+
#### Inverted pipelines
79+
80+
Just Like elementary operators, a pipeline can also be inverted - at least as long as each of its steps can. When executing a pipeline in inverse mode, each step is inverted, and the pipeline is executed from back to front.
81+
82+
Hence, inverse execution of the pipeline above corresponds to forward execution of this pipeline:
83+
84+
```geodesy
85+
inv utm zone=32 | cart
86+
```
87+
88+
In some advanced use cases (out-of-scope for this text), you may need to omit some steps when executing a pipeline in either forward or inverse. Those steps should be modified using the `omit_fwd` or `omit_inv` modifiers mentioned above.
89+
90+
### Macros
91+
92+
**NOTE:** The impatient reader may now skip to the [**examples**](#examples), and return here when convenient.
93+
94+
If we often need the geocentric cartesian pipeline above, we may define it as a **macro**, so we don't have to type the entire definition every time we need it, but can make do with just typing a shorter macro name, e.g by defining `cart:utm` as:
95+
96+
```geodesy
97+
inv cart | utm zone=32
98+
```
99+
100+
This is, however, an unreasonably inflexible macro. Typically, we would want a macro to take parameters, fitting it to a given context. We can do that by marking parameter values as optional by wrapping them in parentheses:
101+
102+
```geodesy
103+
inv cart | utm zone=(32)
104+
```
105+
106+
In this case, invoking the macro as `cart:utm zone=42` will bring you zone 42 coordinates, while the plain `cart:utm` will bring you coordinates from the default zone 32.
107+
108+
You may even take the value from a differently named macro parameter, by using the dereference sigil '$':
109+
110+
```geodesy
111+
inv cart | utm zone=$foo
112+
```
113+
114+
Here, invoking the macro as `cart:utm foo=42` will bring you zone 42 coordinates, while the plain `cart:utm` will bring you a syntax error. This can be remedied by combining the two macro parameter value expansion functionalities:
115+
116+
```geodesy
117+
inv cart | utm zone=$foo(32)
118+
```
119+
120+
which will bring you zone 32 coordinates, unless the macro parameter `foo` is defined, in which case its value will be used for the zone parameter.
121+
122+
For completeness' sake, let us look at a case where we want to convert geographical coordinates defined on one ellipsoid, to geographical coordinates defined on another (typically these kinds of work will also involve a datum shift step, which we for simplicity leave out here). In this case, we have two steps, each taking en `ellps` parameter, but where we need different *values* for the twor parameters:
123+
124+
```geodesy
125+
cart ellps=$ellps_in(GRS80) | inv cart ellps=$ellps_out(GRS80)
126+
```
127+
128+
Which can be invoked as `cart:utm ellps_in=intl ellps_out=GRS80`, to convert from coordinates on the International (Hayford) Ellipsoid, to coordinates on the GRS80 ellipsoid
129+
130+
### Registers
131+
132+
Registers are collections of (preferably) related macros - e.g. macros implementing pipelines for transformation from a given coordinate system, to a number of other coordinate systems, or e.g. transformations originating from a given publisher of geodetic parameters (of which the [EPSG](https://epsg.org) is probably the most well known).
133+
134+
For improved readability of long pipelines, using the
135+
'step-separators-at-column-1' formatting, we introduce
136+
':' as line continuation characters. They are ignored,
137+
but potentially makes the pipeline slightly easier to
138+
read.
139+
140+
Tests in token.rs and parsed_parameters.rs extended
141+
correspondingly
142+
143+
Registers for the 'plain' context provider are now in MarkDown
144+
format, for better communication to end users. Single element
145+
resource files are still in the old format for rapid testing.
146+
147+
Tests for macro parameter defaults (foo=*0) and
148+
lookups (foo=$bar) have been enhanced.
149+
150+
## Examples
151+
152+
### How to use the examples
153+
154+
The examples below are based on the Geodesy coordinate processing tool [**kp**](https://github.com/busstoptaktik/geodesy/blob/main/ruminations/003-rumination.md).
155+
156+
While the Geodesy operators typically take angular input in radians and (longitude, latitude)-order, humans tend to be more familiar with degrees and the nautical convention of geographical coordinates in degrees and (latitude, longitude)-order.
157+
158+
To mediate between the different representations, Geodesy provides a number of macros. For now, we need only consider the `geo:in` macro, which converts human readable geographical coordinates to the internal representation.
159+
160+
Using `geo:in`, we may convert the approximate geographical coordinates of Copenhagen, Denmark (55 N, 12 E), to UTM zone 32 coordinates, by saying:
161+
162+
```console
163+
$ echo 55 12 | kp "geo:in | utm zone=32"
164+
165+
691875.63214 6098907.82501
166+
```
167+
168+
Note that the output is in (easting, northing) order. We can use the `neu:out` macro to switch to (northing, easting, up) order, where the "up" part is ignored, since the input is two-dimensional:
169+
170+
```console
171+
$ echo 55 12 | kp "geo:in | utm zone=32 | neu:out"
172+
173+
6098907.82501 691875.63214
174+
```
175+
176+
For three-dimensional input. we get three-dimensional output:
177+
178+
```console
179+
$ echo 55 12 100 | kp "geo:in | utm zone=32 | neu:out"
180+
181+
6098907.82501 691875.63214 100.00000
182+
```
183+
184+
If we leave out the unit conversion, the numbers are interpreted as 55 radians east, 12 radians north, and the output is garbage:
185+
186+
```console
187+
echo 55 12 | kp "utm zone=32"
188+
-7198047.1103082076 -11321644.2251116671
189+
```
190+
191+
## Further reading

0 commit comments

Comments
 (0)