Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for calculations on the spheroid on PostGIS & SpatiaLite #26

Open
BenMorel opened this issue Feb 24, 2021 · 1 comment
Open

Comments

@BenMorel
Copy link
Member

I'd like to introduce support for calculations on the spheroid on both PostGIS and SpatiaLite.

This would solve #24, and probably give some hints on how to solve #23 in an elegant way.

The problem

Unlike MySQL that returns distances in meters for geometries with SRID 4326 (GPS coordinates), PostGIS & SpatiaLite require to pass an explicit use_spheroid=true parameter to functions that support it, like ST_Distance(g1, g2, true) to get the result in meters, otherwise the result is in degrees.

In other words, currently, all brick/geo calculations are returned in degrees on these 2 platforms, with no way to get meters instead.

PostGIS also has a Geography type that defaults to using the spheroid. If I'm not mistaken though, everything a Geography can do, a Geometry can do it as well, provided that an extra use_spheroid=true parameter is given to every function that's supposed to calculate on the spheroid. Someone please correct me if I'm wrong here.

Solution 1

This is the first solution I came up with when I only had PostGIS in mind, so its obvious issue is to be PostGIS-specific. I'll write it down anyway for posterity:

  • take an optional $usePostgisGeography parameter in PDOEngine
  • when this parameter is true, replace all ST_GeomFromText() calls with ST_GeographyFromText()

Pros

  • The current Geometry method signatures are unchanged

Cons

  • This is not as easy. Why? Because some functions that are implemented for Geometries do not exist for Geographies. The intro to the Geography type gives an example: the basic ST_X() function is not defined with Geography parameters. So we would need to maintain a list of PostGIS functions for which Geography parameters are acceptable, and those for which they are not.
  • You now have to decide whether calculations will be performed in meters or degrees at project level, when configuring your geometry engine; this may not be flexible enough for some use cases.
  • This would only work for PostGIS, and not SpatiaLite.

Solution 2

We could add a $useSpheroid parameter to all methods that support it:

public function distance(Geometry $geometry, bool $useSpheroid = false) : float

Pros

  • You can select the behaviour on every method call, instead of relying on global configuration
  • This would make it also compatible with SpatiaLite, which has similar use_ellipsoid parameters

Cons

  • The behaviour of the method becomes highly dependent on the underlying geometry engine:
    • for MySQL, the parameter would be ignored, plain and simple. The result would only depend on the SRID in use;
    • for GEOS, the parameter would also be ignored, but the result always be in degrees;
    • for PostGIS and SpatiaLite, the parameter would be honored.

This is a reasonably attractive solution, but I'm not comfortable with the fact that the parameter is ignored for MySQL / GEOS. A way to harden this a bit would be to make it throw an exception if:

  • the engine is GEOS and $useSpheroid is true
  • or the engine is MySQL and:
    • the SRID is 4326 and $useSpheroid is false
    • the SRID is not 4326 and $useSpheroid is true

But this again has downsides:

  • MySQL returns a distance in meters not only for SRID 4326, but also for many others (4324, for example); it's a rather bad idea IMO to try to keep a hardcoded list of SRIDs supposed to calculate on the spheroid;
  • if $useSpheroid defaults to false, this would be a BC break for MySQL users where the method would start throwing exceptions with the default parameters; OTOH if it defaults to true, this would be a BC break for GEOS users.

I don't have a definitive answer as to what solution is the way to go, so I'm opening this issue to brainstorm ideas.

What's your take on this, @cevou, @michaelcurry, @dchaffin, @zlanich, @Kolyunya, @EbashuOnHolidays?

Any better ideas?

@BenMorel
Copy link
Member Author

Some alternatives I'm thinking of:

Alternative to solution 1

  • a global $useSpheroid flag on the DatabaseEngine
  • if set, all functions that accept use_spheroid=true (PostGIS) or use_ellipsoid=true (SpatiaLite) are automatically flagged when called

The downside of having a global configuration still stands, though. Also, the list of functions accepting this parameter may need to be hardcoded if they differ from one platform to another.

Alternative to solution 2

Make $useSpheroid nullable, and be null by default:

public function distance(Geometry $geometry, ?bool $useSpheroid = null) : float
  • if null, the behaviour is the same as now (BC preserved)
  • if true or false:
    • on GEOS: throw (setting not supported) (or throw on true only?)
    • on MySQL: throw (setting not supported)
    • on PostGIS & SpatiaLite: apply the spheroid flag if true - false and null being equivalent here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant