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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions