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?
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=trueparameter to functions that support it, likeST_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
Geographycan do, aGeometrycan do it as well, provided that an extrause_spheroid=trueparameter 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:
$usePostgisGeographyparameter inPDOEngineST_GeomFromText()calls withST_GeographyFromText()Pros
Geometrymethod signatures are unchangedCons
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.Solution 2
We could add a
$useSpheroidparameter to all methods that support it:Pros
use_ellipsoidparametersCons
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:
$useSpheroidistrue4326and$useSpheroidisfalse4326and$useSpheroidistrueBut this again has downsides:
$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?