Subscribe to this thread
Home - General / All posts - Coord systems: EPSG YX -> XY
tjhb
10,094 post(s)
#29-Apr-17 05:48

The online manual has a essay topic 'General > Essays > That YX thing' (which Dimitri and Adam have pointed out before).

It's helpful, if you're patient enough to read it all (and assuming you like the tone).

Among other things it covers the main way that Radian attempts to reconcile correct EPSG specifications with real-world data that ignores correct axis order. That is, by generally assuming XY axis order, even when this is incorrect, subject to manual override by a checkbox Use vector data as either XY or YX according to coordinate system (which defaults to off, no override).

However, the essay topic does not mention where that checkbox appears, or when.

The checkbox appears in the New Data Source dialog, but only if we choose a type of data source to which Radian believes the override may apply. There is no list of applicable types (that I can see). The checkbox appears for most (but not all) of the true 'Database: ...' data sources, plus 'File database: dsn', 'File database: SQLite' and 'File database: UDL'.

It is discussed under the topic 'Dialogs > File menu >File - Create - New data source', in a paragraph about a quarter of the way down.

This could probably be made clearer and easier to find. That's one thing.


Second thing. I've only just noticed that the EPSG specification for New Zealand's main standard projected coordinate system, New Zealand Transverse Mercator / NZGD2000 (EPSG:2193), actually specifies YX axis order. Or more correctly, the definition of the NZGD2000 data does, by reference to Ellipsoidal 2D CS, EPSG:6422.

I don't think I've ever seen NZ data that claims to be in EPSG 2193 and has the 'correct' order of axes (which goes to show how right the content of the 'That YX thing' essay is). EPSG 2193 is generally used as if it were synonymous with other definitions of New Zealand Transverse Mercator / NZGD2000, which all (I think) use XY order.

This makes it a little bit tricky to use the EPSG 2193 code inside Radian, when working with shapefile data for example. (No checkbox.)

But it doesn't make EPSG codes like this (I'm sure there are others) useless, excactly because of the care with which Radian's SQL has been set up.

For example, data imported from shapefile in NZTM/NZGD2000 with a .prj file tends to come in to Radian with a CoordSystem property like this (JSON, line breaks added).

PROJCS[\"New_Zealand_Transverse_Mercator_2000\",

GEOGCS[\"GCS_NZGD_2000\",

DATUM[\"D_NZGD_2000\",

SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],

PRIMEM[\"Greenwich\",0.0],

UNIT[\"Degree\",0.0174532925199433]],

PROJECTION[\"Transverse_Mercator\"],

PARAMETER[\"False_Easting\",1600000.0],

PARAMETER[\"False_Northing\",10000000.0],

PARAMETER[\"Central_Meridian\",173.0],

PARAMETER[\"Scale_Factor\",0.9996],

PARAMETER[\"Latitude_Of_Origin\",0.0],

UNIT[\"Meter\",1.0]]

This corresponds to Radian's internal code 625, so instead of the above lengthy JSON we can use the expression

CoordSys(625)

(To get a filtered table of coordinate systems, showing their internal and EPSG codes and JSON definitions, we can use a quick query like

SELECT * FROM CALL CoordSystems()

WHERE [Value] LIKE '%Zealand%';

although that is lazily case-sensitive, and also overlooks that there is also a Zealand in Denmark.)

As well as using Radian's internal code, we can also use the expression

CoordSysEpsg(4163)

except that this will enforce the correct EPSG YX axis order, which in practice will often lead to flipped and rotated data.

Nevertheless it's still easy to use the EPSG code, if we add an explicit override for the parameter we know is (so to speak) too correct:

CoordSystemOverride(CoordSystemEpsg(2193), '{"Axes": "XY"}')

This works really well, and it makes clear it what we are doing and why.

tjhb
10,094 post(s)
#29-Apr-17 08:50

Sorry, being a bit thick here:

(JSON, line breaks added)

Not JSON at all, but WKT, naturally enough since taken directly from PRJ (in the example).

And how well that WKT matches the result of CoordSys(625)--that result is JSON--is an empirical matter (not to be assumed). Same for result of adjusted CoordSystemEpsg(2193).

By the way though, remember how laborious it can be in Manifold 8 to assign the same projection to all components in a project or folder. There are scripts to do this on the forum, which is fine.

But in Radian it's absurdly straightforward.

UPDATE [mfd_meta]

SET [Value] = CoordSystemOverride(CoordSystemEpsg(2193), '{"Axes": "XY"}')

WHERE [Property] = 'FieldCoordSystem.Geom'

;

That's a bit brutish--more filtering would be nicer, sometimes necessary. E.g. we could use a self join to just overwrite the projection of tables just in a given folder. Or use CoordConverterIsIdentity() or CoordConverterIsScaleShift() to check expected projections of drawings or images and list surprises.

Dimitri


7,413 post(s)
#29-Apr-17 18:48

Dealing with YX/XY issues at the beginning with the coordinate system is best, but just a quick note that if data has already been imported and you need to swap coords, that can be done on the fly with the VectorValues function. The example for the function in the SQL Functions topic shows how.

adamw


10,447 post(s)
#29-Apr-17 08:55

Two minor notes.

We will perhaps add a list of data sources to which the option regarding whether to uphold or ignore axis ordering specified by the coordinate system applies. But whenever the option is not shown, that means that there are generally no issues - we don't show the option because the data source type mandates that we have to either always uphold axis ordering (example: GML) or always ignore it (example: SQL Server).

Also, instead of:

--SQL

CoordSystemOverride(CoordSystemEpsg(2193), '{"Axes": "XY"}')

it is better to use:

--SQL

CoordSystemOverride('EPSG:2193''{"Axes": "XY"}')

The two forms are mostly equivalent, but if, say, one day we embed some more data into the definition of EPSG coordinate systems, the definition produced by the second line will automatically get them, while the definition produced by the first one won't. (I realize sometimes one might specifically want such changes not to propagate to already defined coordinate system. If that's the case, use the first form.)

The second form is also friendlier to exports (although we are working to eliminate the difference) and perhaps more readable / searchable.

tjhb
10,094 post(s)
#29-Apr-17 23:57

Thanks Adam. It took me a moment to fully understand the second point.

it is better to use:

--SQL

CoordSystemOverride('EPSG:2193''{"Axes": "XY"}')

[reasons]

The explanation is more visible if we compare the result of the two expressions:

? CoordSystemOverride(CoordSystemEpsg(2193), '{"Axes": "XY"}')

nvarchar: { "Accuracy": 1, "Axes": "XY", "Base": "NZGD2000 (EPSG:4167)",

"CenterLat": 0, "CenterLon": 173, "Eccentricity": 0.08181919104281579,

"FalseEasting": 1600000, "FalseNorthing": 10000000, "MajorAxis": 6378137,

"Name": "NZGD2000 \/ New Zealand Transverse Mercator 2000 (EPSG:2193)",

"Rect": [ 160.6, -55.95, -171.2, -25.88 ], "ScaleX": 0.9996, "ScaleY": 0.9996,

"System": "Transverse Mercator", "Transform": "Molodensky-Badekas",

"Unit": "Meter", "UnitScale": 1, "UnitShort": "m" }

and

? CoordSystemOverride('EPSG:2193', '{"Axes": "XY"}')

nvarchar: EPSG:2193,mfd:{ "Axes": "XY" }

The result of Adam's approach is to set the FieldCoordSystem.Geom property to, literally, 'EPSG:2193,mfd:{ "Axes": "XY" }'. I didn't know this hydrid format was possible.

That leaves the full detail of the coordinate system to be generated dynamically from the EPSG code (including any future revisions, additions, extensions), subject to the override to replace the standard EPSG axis order with XY order.

By contrast, my approach creates a new static JSON definition, from the current EPSG definition plus the axis override. Any future revisions to EPSG:2193, or changes in the way Radian interprets EPSG, will not affect the coordinate system assigned to the components--because future changes could not affect the static JSON.

As Adam says, there may be reasons to choose the static adjusted definition over dynamic adjustment. (In a nutshell, if I want to ignore future changes to EPSG or its interpretation).

But usually, assuming I do want to rely on EPSG standards (not only borrow them as a handy shortcut), the dynamic definition is going to be better. It's also more succinct and readable, definitely.

Thanks!

tjhb
10,094 post(s)
#30-Apr-17 00:26

Similarly, if we want to assign a dynamic version of Radian's built-in definition of (in this case) New Zealand Transverse Mercator / NZGD2000 (mfd:625), then we can set FieldCoordSystem.Geom to a string literal like this

UPDATE [mfd_meta]

SET [Value] = 'CoordSystem(625)' -- literal

WHERE [Property] = 'FieldCoordSystem.Geom';

or, equivalently

UPDATE [mfd_meta]

SET [Value] = 'mfd:625' -- literal

WHERE [Property] = 'FieldCoordSystem.Geom';

I didn't know that before, either.

Here, as with Adam's dynamic EPSG example, any future changes to the Radian/Manifold definition of the NZTM/NZGD2000 projection (however unlikely) will apply automatically to the target components.

By contrast, with the static approach

...

SET [Value] = CoordSystem(625) -- expression

...

the coordinate system definition assigned to the tables is a JSON string, fixed according to the current definition of coordinate system 625, regardless of future changes to the definition.

Again, the dynamic approach is also more succinct and readable than static JSON. Unlike the EPSG definition, the internal definition does not need axis order to be inverted. On the other hand, EPSG:2193 is more widely known and used (and therefore easier to remember) than mfd:625.

Extreme flexibility, everywhere you look.

adamw


10,447 post(s)
#01-May-17 07:44

Not so fast. :-)

'mfd:XXX' won't work as a definition of a coordinate system. We use 'mfd:XXX' syntax for overriding coordinate system parameters where such syntax makes sense (ie, for codes, not for JSON / WKT / XML). But we don't use 'mfd:XXX' to define a whole coordinate system.

The reason is very simple - we don't really want to use our internal codes for coordinate systems. First, there are already too many types of codes as it stands: EPSG, legacy OGC, ESRI, OSGEO, every database, etc. XKCD 927 comes to mind. Second, we want to be able to change our internal codes if we need to (eg, to convey some info out of band). The internal codes aren't guaranteed to be stable right now. Obviously, we aren't going to change them without a good reason (we didn't change them even once up to this moment), and maybe we are never going to change them and will instead commit to them being stable forever, but maybe we will change them.

PS: 'CoordSystem(625)' as a definition in the first query won't work either. There is no way to write a definition of the coordinate system that would translate an internal code dynamically. Because the code is internal, it is not guaranteed to be stable.

tjhb
10,094 post(s)
#07-May-17 00:31

Very belated thanks for this correction Adam.

I'm not entirely sure whether you're saying that what (I thought) seemed to work does not work, or rather, that it cannot be relied upon to work (now or in the future).

I thought that what I tried did work--but this was at the end of a lot of testing and I was tired. In all likelihood I was just seeing things.

To hammer a recent theme--

'mfd:XXX' won't work as a definition of a coordinate system. We use 'mfd:XXX' syntax for overriding coordinate system parameters where such syntax makes sense (ie, for codes, not for JSON / WKT / XML). But we don't use 'mfd:XXX' to define a whole coordinate system.

--this needs documenting.

adamw


10,447 post(s)
#11-May-17 09:42

Clarifying:

Setting the coordinate system definition (in properties for some component) to the string returned by CoordSystem(625) is fine and will work. The 625 is our internal code, but the coordinate system definition returned by the call does not rely on that code at all, it is stable.

Setting the coordinate system definition to the literal string of 'CoordSystem(625)' - like in your first UPDATE - won't work. When we parse coordinate system definitions from properties we don't expect the properties to contain executable code. Here's how we are going to interpret this coordinate system:

--SQL

> ?CoordSystemParse('CoordSystem(625)')

nvarchar: { "System""Pseudo Mercator" }

Setting the coordinate system definition to 'mfd:625' - like in your second UPDATE - won't work either for the reasons discussed above (we currently only use the 'mfd:XXX' syntax for overrides). Here's how that is going to be interpreted:

--SQL

> ?CoordSystemParse('mfd:625')

nvarchar: { "System""Pseudo Mercator" }

We'll put the details of the syntax in the docs, including an explicit note not to use 'mfd:XXX' with our internal code.

danb

2,064 post(s)
#30-Apr-17 22:22

Great post Tim, and one which helps me lots. I hadn't realized the EPSG2193 ordering was YX as I have never encountered any purportedly 2193 data with YX ordering.


Landsystems Ltd ... Know your land | www.landsystems.co.nz

Manifold User Community Use Agreement Copyright (C) 2007-2021 Manifold Software Limited. All rights reserved.