Skip to content

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

@BenMorel

Description

@BenMorel

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions