-
-
Notifications
You must be signed in to change notification settings - Fork 33
Description
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
$usePostgisGeographyparameter inPDOEngine - when this parameter is true, replace all
ST_GeomFromText()calls withST_GeographyFromText()
Pros
- The current
Geometrymethod 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) : floatPros
- 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_ellipsoidparameters
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
$useSpheroidistrue - or the engine is MySQL and:
- the SRID is
4326and$useSpheroidisfalse - the SRID is not
4326and$useSpheroidistrue
- the SRID is
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
$useSpheroiddefaults tofalse, this would be a BC break for MySQL users where the method would start throwing exceptions with the default parameters; OTOH if it defaults totrue, 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?