Index: contrib/earthdistance/README.earthdistance =================================================================== RCS file: /cvsroot/contrib/earthdistance/README.earthdistance,v retrieving revision 1.2 diff -c -c -r1.2 README.earthdistance *** contrib/earthdistance/README.earthdistance 20 Sep 2002 03:47:22 -0000 1.2 --- contrib/earthdistance/README.earthdistance 8 Nov 2002 20:18:25 -0000 *************** *** 1,13 **** ! --------------------------------------------------------------------- ! I corrected a bug in the geo_distance code where two double constants ! were declared as int. I changed the distance function to use the ! haversine formula which is more accurate for small distances. ! I added a regression test to the package. I added a grant statement ! to give execute access for geo_distance to public. Bruno Wolff III September 2002 --------------------------------------------------------------------- Date: Wed, 1 Apr 1998 15:19:32 -0600 (CST) From: Hal Snyder To: vmehr@ctp.com --- 1,107 ---- ! This contrib package contains two different approaches to calculating ! great circle distances on the surface of the Earth. The one described ! first depends on the contrib/cube package (which MUST be installed before ! earthdistance is installed). The second one is based on the point ! datatype using latitude and longitude for the coordinates. The install ! script makes the defined functions executable by anyone. ! ! Make sure contrib/cube has been installed. ! make ! make install ! make installcheck ! ! To use these functions in a particular database as a postgres superuser do: ! psql databasename < earthdistance.sql + ------------------------------------------- + contrib/cube based Earth distance functions Bruno Wolff III September 2002 + + A spherical model of the Earth is used. + + Data is stored in cubes that are points (both corners are the same) using 3 + coordinates representing the distance from the center of the Earth. + + The radius of the Earth is obtained from the earth() function. It is + given in meters. But by changing this one function you can change it + to use some other units or to use a different value of the radius + that you feel is more appropiate. + + This package also has applications to astronomical databases as well. + Astronomers will probably want to change earth() to return a radius of + 180/pi() so that distances are in degrees. + + Functions are provided to allow for input in latitude and longitude (in + degrees), to allow for output of latitude and longitude, to calculate + the great circle distance between two points and to easily specify a + bounding box usable for index searches. + + The functions are all 'sql' functions. If you want to make these functions + executable by other people you will also have to make the referenced + cube functions executable. cube(text), cube_distance(cube,cube), + cube_ll_coord(cube,int) and cube_enlarge(cube,float8,int) are used indirectly + by the earth distance functions. is_point(cube) and cube_dim(cube) are used + in suggested constraints for data in domain earth. cube_ur_coord(cube,int) + is used in the regression tests and might be useful for looking at bounding + box coordinates in user applications. + + A domain of type cube named earth is defined. Since check constraints + are not supported for domains yet, this isn't as useful as it might be. + However the checks that should be supplied to all data of type earth are: + + constraint not_point check(is_point(earth)) + constraint not_3d check(cube_dim(earth) <= 3) + constraint on_surface check(abs(cube_distance(earth, '(0)'::cube) / + earth() - 1) < '10e-12'::float8); + + The following functions are provided: + + earth() - Returns the radius of the earth in meters. + + sec_to_gc(float8) - Converts the normal straight line (secant) distance between + between two points on the surface of the Earth to the great circle distance + between them. + + gc_to_sec(float8) - Converts the great circle distance between two points + on the surface of the Earth to the normal straight line (secant) distance + between them. + + ll_to_cube(float8, float8) - Returns the location of a point on the surface of + the Earth given its latitude (argument 1) and longitude (argument 2) in degrees. + + latitude(earth) - Returns the latitude in degrees of a point on the surface + of the Earth. + + longitude(earth) - Returns the longitude in degrees of a point on the surface + of the Earth. + + earth_distance(earth, earth) - Returns the great circle distance between + two points on the surface of the Earth. + + earth_box(earth, float8) - Returns a box suitable for an indexed search using + the cube @ operator for points within a given great circle distance of a + location. Some points in this box are further than the specified great circle + distance from the location so a second check using earth_distance should be + made at the same time. + + One advantage of using cube representation over a point using latitude and + longitude for coordinates, is that you don't have to worry about special + conditions at +/- 180 degrees of longitude or near the poles. + + Below is the documentation for the Earth distance operator that works + with the point data type. + + --------------------------------------------------------------------- + + I corrected a bug in the geo_distance code where two double constants + were declared as int. I also changed the distance function to use + the haversine formula which is more accurate for small distances. + Bruno Wolff + September 2002 + --------------------------------------------------------------------- + Date: Wed, 1 Apr 1998 15:19:32 -0600 (CST) From: Hal Snyder To: vmehr@ctp.com Index: contrib/earthdistance/earthdistance.c =================================================================== RCS file: /cvsroot/contrib/earthdistance/earthdistance.c,v retrieving revision 1.6 diff -c -c -r1.6 earthdistance.c *** contrib/earthdistance/earthdistance.c 20 Sep 2002 03:47:22 -0000 1.6 --- contrib/earthdistance/earthdistance.c 8 Nov 2002 20:18:25 -0000 *************** *** 50,56 **** long2, lat2; double longdiff; ! double sino; double *resultp = palloc(sizeof(double)); /* convert degrees to radians */ --- 50,56 ---- long2, lat2; double longdiff; ! double sino; double *resultp = palloc(sizeof(double)); /* convert degrees to radians */ Index: contrib/earthdistance/earthdistance.sql.in =================================================================== RCS file: /cvsroot/contrib/earthdistance/earthdistance.sql.in,v retrieving revision 1.4 diff -c -c -r1.4 earthdistance.sql.in *** contrib/earthdistance/earthdistance.sql.in 18 Oct 2002 18:41:20 -0000 1.4 --- contrib/earthdistance/earthdistance.sql.in 8 Nov 2002 20:18:25 -0000 *************** *** 3,8 **** --- 3,79 ---- SET autocommit TO 'on'; + -- The earth functions rely on contrib/cube having been installed and loaded. + + -- earth() returns the radius of the earth in meters. This is the only + -- place you need to change things for the cube base distance functions + -- in order to use different units (or a better value for the Earth's radius). + + CREATE OR REPLACE FUNCTION earth() RETURNS float8 + LANGUAGE 'sql' IMMUTABLE + AS 'SELECT \'6378168\'::float8'; + + -- Astromers may want to change the earth function so that distances will be + -- returned in degrees. To do this comment out the above definition and + -- uncomment the one below. Note that doing this will break the regression + -- tests. + -- + -- CREATE OR REPLACE FUNCTION earth() RETURNS float8 + -- LANGUAGE 'sql' IMMUTABLE + -- AS 'SELECT 180/pi()'; + + -- Define domain for locations on the surface of the earth using a cube + -- datatype with constraints. cube provides 3D indexing. + -- Check constraints aren't currently supported. + + CREATE DOMAIN earth AS cube; + -- CONSTRAINT not_point check(is_point(earth)) + -- CONSTRAINT not_3d check(cube_dim(earth) <= 3) + -- CONSTRAINT on_surface check(abs(cube_distance(earth, '(0)'::cube) / + -- earth() - 1) < '10e-12'::float8); + + CREATE OR REPLACE FUNCTION sec_to_gc(float8) + RETURNS float8 + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT CASE WHEN $1 < 0 THEN 0::float8 WHEN $1/(2*earth()) > 1 THEN pi()*earth() ELSE 2*earth()*asin($1/(2*earth())) END'; + + CREATE OR REPLACE FUNCTION gc_to_sec(float8) + RETURNS float8 + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT CASE WHEN $1 < 0 THEN 0::float8 WHEN $1/earth() > pi() THEN 2*earth() ELSE 2*earth()*sin($1/(2*earth())) END'; + + CREATE OR REPLACE FUNCTION ll_to_earth(float8, float8) + RETURNS earth + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT cube(\'(\'||earth()*cos(radians($1))*cos(radians($2))||\',\'||earth()*cos(radians($1))*sin(radians($2))||\',\'||earth()*sin(radians($1))||\')\')'; + + CREATE OR REPLACE FUNCTION latitude(earth) + RETURNS float8 + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT CASE WHEN cube_ll_coord($1, 3)/earth() < -1 THEN -90::float8 WHEN cube_ll_coord($1, 3)/earth() > 1 THEN 90::float8 ELSE degrees(asin(cube_ll_coord($1, 3)/earth())) END'; + + CREATE OR REPLACE FUNCTION longitude(earth) + RETURNS float8 + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT degrees(atan2(cube_ll_coord($1, 2), cube_ll_coord($1, 1)))'; + + CREATE OR REPLACE FUNCTION earth_distance(earth, earth) + RETURNS float8 + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT sec_to_gc(cube_distance($1, $2))'; + + CREATE OR REPLACE FUNCTION earth_box(earth, float8) + RETURNS cube + LANGUAGE 'sql' + IMMUTABLE STRICT + AS 'SELECT cube_enlarge($1, gc_to_sec($2), 3)'; + --------------- geo_distance CREATE OR REPLACE FUNCTION geo_distance (point, point) Index: contrib/earthdistance/expected/earthdistance.out =================================================================== RCS file: /cvsroot/contrib/earthdistance/expected/earthdistance.out,v retrieving revision 1.3 diff -c -c -r1.3 earthdistance.out *** contrib/earthdistance/expected/earthdistance.out 21 Oct 2002 20:33:21 -0000 1.3 --- contrib/earthdistance/expected/earthdistance.out 8 Nov 2002 20:18:26 -0000 *************** *** 3,81 **** -- -- -- first, define the datatype. Turn off echoing so that expected file ! -- does not depend on contents of earthdistance.sql. -- \set ECHO none -- -- Test getting the distance between two points using geo_distance. -- ! SELECT geo_distance('(0,0)'::point,'(0,0)'::point)::numeric(20,5); geo_distance -------------- 0.00000 (1 row) ! SELECT geo_distance('(0,0)'::point,'(180,0)'::point)::numeric(20,5); geo_distance -------------- 12436.77274 (1 row) ! SELECT geo_distance('(0,0)'::point,'(0,90)'::point)::numeric(20,5); geo_distance -------------- 6218.38637 (1 row) ! SELECT geo_distance('(0,0)'::point,'(90,0)'::point)::numeric(20,5); geo_distance -------------- 6218.38637 (1 row) ! SELECT geo_distance('(0,0)'::point,'(1,0)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! SELECT geo_distance('(0,0)'::point,'(0,1)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! SELECT geo_distance('(0,30)'::point,'(1,30)'::point)::numeric(20,5); geo_distance -------------- 59.83626 (1 row) ! SELECT geo_distance('(0,30)'::point,'(0,31)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! SELECT geo_distance('(0,60)'::point,'(1,60)'::point)::numeric(20,5); geo_distance -------------- 34.54626 (1 row) ! SELECT geo_distance('(0,60)'::point,'(0,61)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! SELECT geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)::numeric(20,5); geo_distance -------------- 1129.18983 (1 row) ! SELECT (geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); numeric --------------- 1817254.87730 --- 3,628 ---- -- -- -- first, define the datatype. Turn off echoing so that expected file ! -- does not depend on contents of earthdistance.sql or cube.sql. -- \set ECHO none + psql:../cube/cube.sql:12: NOTICE: ProcedureCreate: type cube is not yet defined + psql:../cube/cube.sql:17: NOTICE: Argument type "cube" is only a shell + -- + -- The radius of the Earth we are using. + -- + select earth()::numeric(20,5); + earth + --------------- + 6378168.00000 + (1 row) + + -- + -- Convert straight line distances to great circle distances. + -- + select (pi()*earth())::numeric(20,5); + numeric + ---------------- + 20037605.73216 + (1 row) + + select sec_to_gc(0)::numeric(20,5); + sec_to_gc + ----------- + 0.00000 + (1 row) + + select sec_to_gc(2*earth())::numeric(20,5); + sec_to_gc + ---------------- + 20037605.73216 + (1 row) + + select sec_to_gc(10*earth())::numeric(20,5); + sec_to_gc + ---------------- + 20037605.73216 + (1 row) + + select sec_to_gc(-earth())::numeric(20,5); + sec_to_gc + ----------- + 0.00000 + (1 row) + + select sec_to_gc(1000)::numeric(20,5); + sec_to_gc + ------------ + 1000.00000 + (1 row) + + select sec_to_gc(10000)::numeric(20,5); + sec_to_gc + ------------- + 10000.00102 + (1 row) + + select sec_to_gc(100000)::numeric(20,5); + sec_to_gc + -------------- + 100001.02426 + (1 row) + + select sec_to_gc(1000000)::numeric(20,5); + sec_to_gc + --------------- + 1001027.07131 + (1 row) + + -- + -- Convert great circle distances to straight line distances. + -- + select gc_to_sec(0)::numeric(20,5); + gc_to_sec + ----------- + 0.00000 + (1 row) + + select gc_to_sec(sec_to_gc(2*earth()))::numeric(20,5); + gc_to_sec + ---------------- + 12756336.00000 + (1 row) + + select gc_to_sec(10*earth())::numeric(20,5); + gc_to_sec + ---------------- + 12756336.00000 + (1 row) + + select gc_to_sec(pi()*earth())::numeric(20,5); + gc_to_sec + ---------------- + 12756336.00000 + (1 row) + + select gc_to_sec(-1000)::numeric(20,5); + gc_to_sec + ----------- + 0.00000 + (1 row) + + select gc_to_sec(1000)::numeric(20,5); + gc_to_sec + ------------ + 1000.00000 + (1 row) + + select gc_to_sec(10000)::numeric(20,5); + gc_to_sec + ------------ + 9999.99898 + (1 row) + + select gc_to_sec(100000)::numeric(20,5); + gc_to_sec + ------------- + 99998.97577 + (1 row) + + select gc_to_sec(1000000)::numeric(20,5); + gc_to_sec + -------------- + 998976.08618 + (1 row) + + -- + -- Set coordinates using latitude and longitude. + -- Extract each coordinate separately so we can round them. + -- + select cube_ll_coord(ll_to_earth(0,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,0),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+--------------- + 6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(360,360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(360,360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(360,360),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+--------------- + 6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(180,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,180),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+--------------- + 6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(180,360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,360),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ----------------+---------------+--------------- + -6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(-180,-360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-180,-360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-180,-360),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ----------------+---------------+--------------- + -6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(0,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,180),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ----------------+---------------+--------------- + -6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(0,-180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,-180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,-180),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ----------------+---------------+--------------- + -6378168.00000 | 0.00000 | 0.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(90,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,0),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+--------------- + 0.00000 | 0.00000 | 6378168.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(90,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,180),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+--------------- + 0.00000 | 0.00000 | 6378168.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(-90,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,0),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+---------------- + 0.00000 | 0.00000 | -6378168.00000 + (1 row) + + select cube_ll_coord(ll_to_earth(-90,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,180),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord + ---------------+---------------+---------------- + 0.00000 | 0.00000 | -6378168.00000 + (1 row) + + -- + -- Test getting the latitude of a location. + -- + select latitude(ll_to_earth(0,0))::numeric(20,10); + latitude + -------------- + 0.0000000000 + (1 row) + + select latitude(ll_to_earth(45,0))::numeric(20,10); + latitude + --------------- + 45.0000000000 + (1 row) + + select latitude(ll_to_earth(90,0))::numeric(20,10); + latitude + --------------- + 90.0000000000 + (1 row) + + select latitude(ll_to_earth(-45,0))::numeric(20,10); + latitude + ---------------- + -45.0000000000 + (1 row) + + select latitude(ll_to_earth(-90,0))::numeric(20,10); + latitude + ---------------- + -90.0000000000 + (1 row) + + select latitude(ll_to_earth(0,90))::numeric(20,10); + latitude + -------------- + 0.0000000000 + (1 row) + + select latitude(ll_to_earth(45,90))::numeric(20,10); + latitude + --------------- + 45.0000000000 + (1 row) + + select latitude(ll_to_earth(90,90))::numeric(20,10); + latitude + --------------- + 90.0000000000 + (1 row) + + select latitude(ll_to_earth(-45,90))::numeric(20,10); + latitude + ---------------- + -45.0000000000 + (1 row) + + select latitude(ll_to_earth(-90,90))::numeric(20,10); + latitude + ---------------- + -90.0000000000 + (1 row) + + select latitude(ll_to_earth(0,180))::numeric(20,10); + latitude + -------------- + 0.0000000000 + (1 row) + + select latitude(ll_to_earth(45,180))::numeric(20,10); + latitude + --------------- + 45.0000000000 + (1 row) + + select latitude(ll_to_earth(90,180))::numeric(20,10); + latitude + --------------- + 90.0000000000 + (1 row) + + select latitude(ll_to_earth(-45,180))::numeric(20,10); + latitude + ---------------- + -45.0000000000 + (1 row) + + select latitude(ll_to_earth(-90,180))::numeric(20,10); + latitude + ---------------- + -90.0000000000 + (1 row) + + select latitude(ll_to_earth(0,-90))::numeric(20,10); + latitude + -------------- + 0.0000000000 + (1 row) + + select latitude(ll_to_earth(45,-90))::numeric(20,10); + latitude + --------------- + 45.0000000000 + (1 row) + + select latitude(ll_to_earth(90,-90))::numeric(20,10); + latitude + --------------- + 90.0000000000 + (1 row) + + select latitude(ll_to_earth(-45,-90))::numeric(20,10); + latitude + ---------------- + -45.0000000000 + (1 row) + + select latitude(ll_to_earth(-90,-90))::numeric(20,10); + latitude + ---------------- + -90.0000000000 + (1 row) + + -- + -- Test getting the longitude of a location. + -- + select longitude(ll_to_earth(0,0))::numeric(20,10); + longitude + -------------- + 0.0000000000 + (1 row) + + select longitude(ll_to_earth(45,0))::numeric(20,10); + longitude + -------------- + 0.0000000000 + (1 row) + + select longitude(ll_to_earth(90,0))::numeric(20,10); + longitude + -------------- + 0.0000000000 + (1 row) + + select longitude(ll_to_earth(-45,0))::numeric(20,10); + longitude + -------------- + 0.0000000000 + (1 row) + + select longitude(ll_to_earth(-90,0))::numeric(20,10); + longitude + -------------- + 0.0000000000 + (1 row) + + select longitude(ll_to_earth(0,90))::numeric(20,10); + longitude + --------------- + 90.0000000000 + (1 row) + + select longitude(ll_to_earth(45,90))::numeric(20,10); + longitude + --------------- + 90.0000000000 + (1 row) + + select longitude(ll_to_earth(90,90))::numeric(20,10); + longitude + --------------- + 90.0000000000 + (1 row) + + select longitude(ll_to_earth(-45,90))::numeric(20,10); + longitude + --------------- + 90.0000000000 + (1 row) + + select longitude(ll_to_earth(-90,90))::numeric(20,10); + longitude + --------------- + 90.0000000000 + (1 row) + + select longitude(ll_to_earth(0,180))::numeric(20,10); + longitude + ---------------- + 180.0000000000 + (1 row) + + select longitude(ll_to_earth(45,180))::numeric(20,10); + longitude + ---------------- + 180.0000000000 + (1 row) + + select longitude(ll_to_earth(90,180))::numeric(20,10); + longitude + ---------------- + 180.0000000000 + (1 row) + + select longitude(ll_to_earth(-45,180))::numeric(20,10); + longitude + ---------------- + 180.0000000000 + (1 row) + + select longitude(ll_to_earth(-90,180))::numeric(20,10); + longitude + ---------------- + 180.0000000000 + (1 row) + + select longitude(ll_to_earth(0,-90))::numeric(20,10); + longitude + ---------------- + -90.0000000000 + (1 row) + + select longitude(ll_to_earth(45,-90))::numeric(20,10); + longitude + ---------------- + -90.0000000000 + (1 row) + + select longitude(ll_to_earth(90,-90))::numeric(20,10); + longitude + ---------------- + -90.0000000000 + (1 row) + + select longitude(ll_to_earth(-45,-90))::numeric(20,10); + longitude + ---------------- + -90.0000000000 + (1 row) + + select longitude(ll_to_earth(-90,-90))::numeric(20,10); + longitude + ---------------- + -90.0000000000 + (1 row) + + -- + -- For the distance tests the following is some real life data. + -- + -- Chicago has a latitude of 41.8 and a longitude of 87.6. + -- Albuquerque has a latitude of 35.1 and a longitude of 106.7. + -- (Note that latitude and longitude are specified differently + -- in the cube based functions than for the point based functions.) + -- + -- + -- Test getting the distance between two points using earth_distance. + -- + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,0))::numeric(20,5); + earth_distance + ---------------- + 0.00000 + (1 row) + + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,180))::numeric(20,5); + earth_distance + ---------------- + 20037605.73216 + (1 row) + + select earth_distance(ll_to_earth(0,0),ll_to_earth(90,0))::numeric(20,5); + earth_distance + ---------------- + 10018802.86608 + (1 row) + + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,90))::numeric(20,5); + earth_distance + ---------------- + 10018802.86608 + (1 row) + + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))::numeric(20,5); + earth_distance + ---------------- + 111320.03185 + (1 row) + + select earth_distance(ll_to_earth(0,0),ll_to_earth(1,0))::numeric(20,5); + earth_distance + ---------------- + 111320.03185 + (1 row) + + select earth_distance(ll_to_earth(30,0),ll_to_earth(30,1))::numeric(20,5); + earth_distance + ---------------- + 96405.66962 + (1 row) + + select earth_distance(ll_to_earth(30,0),ll_to_earth(31,0))::numeric(20,5); + earth_distance + ---------------- + 111320.03185 + (1 row) + + select earth_distance(ll_to_earth(60,0),ll_to_earth(60,1))::numeric(20,5); + earth_distance + ---------------- + 55659.48608 + (1 row) + + select earth_distance(ll_to_earth(60,0),ll_to_earth(61,0))::numeric(20,5); + earth_distance + ---------------- + 111320.03185 + (1 row) + + select earth_distance(ll_to_earth(41.8,87.6),ll_to_earth(35.1,106.7))::numeric(20,5); + earth_distance + ---------------- + 1819303.21265 + (1 row) + + select (earth_distance(ll_to_earth(41.8,87.6),ll_to_earth(35.1,106.7))* + 100./2.54/12./5280.)::numeric(20,5); + numeric + ------------ + 1130.46261 + (1 row) + -- -- Test getting the distance between two points using geo_distance. -- ! select geo_distance('(0,0)'::point,'(0,0)'::point)::numeric(20,5); geo_distance -------------- 0.00000 (1 row) ! select geo_distance('(0,0)'::point,'(180,0)'::point)::numeric(20,5); geo_distance -------------- 12436.77274 (1 row) ! select geo_distance('(0,0)'::point,'(0,90)'::point)::numeric(20,5); geo_distance -------------- 6218.38637 (1 row) ! select geo_distance('(0,0)'::point,'(90,0)'::point)::numeric(20,5); geo_distance -------------- 6218.38637 (1 row) ! select geo_distance('(0,0)'::point,'(1,0)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! select geo_distance('(0,0)'::point,'(0,1)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! select geo_distance('(0,30)'::point,'(1,30)'::point)::numeric(20,5); geo_distance -------------- 59.83626 (1 row) ! select geo_distance('(0,30)'::point,'(0,31)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! select geo_distance('(0,60)'::point,'(1,60)'::point)::numeric(20,5); geo_distance -------------- 34.54626 (1 row) ! select geo_distance('(0,60)'::point,'(0,61)'::point)::numeric(20,5); geo_distance -------------- 69.09318 (1 row) ! select geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)::numeric(20,5); geo_distance -------------- 1129.18983 (1 row) ! select (geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); numeric --------------- 1817254.87730 *************** *** 84,158 **** -- -- Test getting the distance between two points using the <@> operator. -- ! SELECT ('(0,0)'::point <@> '(0,0)'::point)::numeric(20,5); numeric --------- 0.00000 (1 row) ! SELECT ('(0,0)'::point <@> '(180,0)'::point)::numeric(20,5); numeric ------------- 12436.77274 (1 row) ! SELECT ('(0,0)'::point <@> '(0,90)'::point)::numeric(20,5); numeric ------------ 6218.38637 (1 row) ! SELECT ('(0,0)'::point <@> '(90,0)'::point)::numeric(20,5); numeric ------------ 6218.38637 (1 row) ! SELECT ('(0,0)'::point <@> '(1,0)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! SELECT ('(0,0)'::point <@> '(0,1)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! SELECT ('(0,30)'::point <@> '(1,30)'::point)::numeric(20,5); numeric ---------- 59.83626 (1 row) ! SELECT ('(0,30)'::point <@> '(0,31)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! SELECT ('(0,60)'::point <@> '(1,60)'::point)::numeric(20,5); numeric ---------- 34.54626 (1 row) ! SELECT ('(0,60)'::point <@> '(0,61)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! SELECT ('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)::numeric(20,5); numeric ------------ 1129.18983 (1 row) ! SELECT (('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); numeric --------------- 1817254.87730 (1 row) --- 631,948 ---- -- -- Test getting the distance between two points using the <@> operator. -- ! select ('(0,0)'::point <@> '(0,0)'::point)::numeric(20,5); numeric --------- 0.00000 (1 row) ! select ('(0,0)'::point <@> '(180,0)'::point)::numeric(20,5); numeric ------------- 12436.77274 (1 row) ! select ('(0,0)'::point <@> '(0,90)'::point)::numeric(20,5); numeric ------------ 6218.38637 (1 row) ! select ('(0,0)'::point <@> '(90,0)'::point)::numeric(20,5); numeric ------------ 6218.38637 (1 row) ! select ('(0,0)'::point <@> '(1,0)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! select ('(0,0)'::point <@> '(0,1)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! select ('(0,30)'::point <@> '(1,30)'::point)::numeric(20,5); numeric ---------- 59.83626 (1 row) ! select ('(0,30)'::point <@> '(0,31)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! select ('(0,60)'::point <@> '(1,60)'::point)::numeric(20,5); numeric ---------- 34.54626 (1 row) ! select ('(0,60)'::point <@> '(0,61)'::point)::numeric(20,5); numeric ---------- 69.09318 (1 row) ! select ('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)::numeric(20,5); numeric ------------ 1129.18983 (1 row) ! select (('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); numeric --------------- 1817254.87730 + (1 row) + + -- + -- Test getting a bounding box around points. + -- + select cube_ll_coord(earth_box(ll_to_earth(0,0),112000),1)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),112000),2)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),112000),3)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),112000),1)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),112000),2)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),112000),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord | cube_ur_coord | cube_ur_coord | cube_ur_coord + ---------------+---------------+---------------+---------------+---------------+--------------- + 6266169.43896 | -111998.56104 | -111998.56104 | 6490166.56104 | 111998.56104 | 111998.56104 + (1 row) + + select cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),1)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),2)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),3)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),1)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),2)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord | cube_ur_coord | cube_ur_coord | cube_ur_coord + ----------------+-----------------+-----------------+----------------+----------------+---------------- + -6378168.00000 | -12756336.00000 | -12756336.00000 | 19134504.00000 | 12756336.00000 | 12756336.00000 + (1 row) + + select cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),1)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),2)::numeric(20,5), + cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),3)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),1)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),2)::numeric(20,5), + cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),3)::numeric(20,5); + cube_ll_coord | cube_ll_coord | cube_ll_coord | cube_ur_coord | cube_ur_coord | cube_ur_coord + ----------------+-----------------+-----------------+----------------+----------------+---------------- + -6378168.00000 | -12756336.00000 | -12756336.00000 | 19134504.00000 | 12756336.00000 | 12756336.00000 + (1 row) + + -- + -- Test for points that should be in bounding boxes. + -- + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*1.00001) @ + ll_to_earth(0,1); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*1.00001) @ + ll_to_earth(0,0.1); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.01))*1.00001) @ + ll_to_earth(0,0.01); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.001))*1.00001) @ + ll_to_earth(0,0.001); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.0001))*1.00001) @ + ll_to_earth(0,0.0001); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0.0001,0.0001))*1.00001) @ + ll_to_earth(0.0001,0.0001); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(45,45), + earth_distance(ll_to_earth(45,45),ll_to_earth(45.0001,45.0001))*1.00001) @ + ll_to_earth(45.0001,45.0001); + ?column? + ---------- + t + (1 row) + + select earth_box(ll_to_earth(90,180), + earth_distance(ll_to_earth(90,180),ll_to_earth(90.0001,180.0001))*1.00001) @ + ll_to_earth(90.0001,180.0001); + ?column? + ---------- + t + (1 row) + + -- + -- Test for points that shouldn't be in bounding boxes. Note that we need + -- to make points way outside, since some points close may be in the box + -- but further away than the distance we are testing. + -- + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*.57735) @ + ll_to_earth(0,1); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*.57735) @ + ll_to_earth(0,0.1); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.01))*.57735) @ + ll_to_earth(0,0.01); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.001))*.57735) @ + ll_to_earth(0,0.001); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.0001))*.57735) @ + ll_to_earth(0,0.0001); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(0,0), + earth_distance(ll_to_earth(0,0),ll_to_earth(0.0001,0.0001))*.57735) @ + ll_to_earth(0.0001,0.0001); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(45,45), + earth_distance(ll_to_earth(45,45),ll_to_earth(45.0001,45.0001))*.57735) @ + ll_to_earth(45.0001,45.0001); + ?column? + ---------- + f + (1 row) + + select earth_box(ll_to_earth(90,180), + earth_distance(ll_to_earth(90,180),ll_to_earth(90.0001,180.0001))*.57735) @ + ll_to_earth(90.0001,180.0001); + ?column? + ---------- + f + (1 row) + + -- + -- Test the recommended constraints. + -- + select is_point(ll_to_earth(0,0)); + ERROR: Function is_point(earth) does not exist + Unable to identify a function that satisfies the given argument types + You may need to add explicit typecasts + select cube_dim(ll_to_earth(0,0)) <= 3; + ?column? + ---------- + t + (1 row) + + select abs(cube_distance(ll_to_earth(0,0), '(0)'::cube) / earth() - 1) < + '10e-12'::float8; + ?column? + ---------- + t + (1 row) + + select is_point(ll_to_earth(30,60)); + ERROR: Function is_point(earth) does not exist + Unable to identify a function that satisfies the given argument types + You may need to add explicit typecasts + select cube_dim(ll_to_earth(30,60)) <= 3; + ?column? + ---------- + t + (1 row) + + select abs(cube_distance(ll_to_earth(30,60), '(0)'::cube) / earth() - 1) < + '10e-12'::float8; + ?column? + ---------- + t + (1 row) + + select is_point(ll_to_earth(60,90)); + ERROR: Function is_point(earth) does not exist + Unable to identify a function that satisfies the given argument types + You may need to add explicit typecasts + select cube_dim(ll_to_earth(60,90)) <= 3; + ?column? + ---------- + t + (1 row) + + select abs(cube_distance(ll_to_earth(60,90), '(0)'::cube) / earth() - 1) < + '10e-12'::float8; + ?column? + ---------- + t + (1 row) + + select is_point(ll_to_earth(-30,-90)); + ERROR: Function is_point(earth) does not exist + Unable to identify a function that satisfies the given argument types + You may need to add explicit typecasts + select cube_dim(ll_to_earth(-30,-90)) <= 3; + ?column? + ---------- + t + (1 row) + + select abs(cube_distance(ll_to_earth(-30,-90), '(0)'::cube) / earth() - 1) < + '10e-12'::float8; + ?column? + ---------- + t (1 row) Index: contrib/earthdistance/sql/earthdistance.sql =================================================================== RCS file: /cvsroot/contrib/earthdistance/sql/earthdistance.sql,v retrieving revision 1.5 diff -c -c -r1.5 earthdistance.sql *** contrib/earthdistance/sql/earthdistance.sql 21 Oct 2002 20:33:21 -0000 1.5 --- contrib/earthdistance/sql/earthdistance.sql 8 Nov 2002 20:18:27 -0000 *************** *** 4,45 **** -- -- first, define the datatype. Turn off echoing so that expected file ! -- does not depend on contents of earthdistance.sql. -- \set ECHO none \i earthdistance.sql \set ECHO all -- -- Test getting the distance between two points using geo_distance. -- ! SELECT geo_distance('(0,0)'::point,'(0,0)'::point)::numeric(20,5); ! SELECT geo_distance('(0,0)'::point,'(180,0)'::point)::numeric(20,5); ! SELECT geo_distance('(0,0)'::point,'(0,90)'::point)::numeric(20,5); ! SELECT geo_distance('(0,0)'::point,'(90,0)'::point)::numeric(20,5); ! SELECT geo_distance('(0,0)'::point,'(1,0)'::point)::numeric(20,5); ! SELECT geo_distance('(0,0)'::point,'(0,1)'::point)::numeric(20,5); ! SELECT geo_distance('(0,30)'::point,'(1,30)'::point)::numeric(20,5); ! SELECT geo_distance('(0,30)'::point,'(0,31)'::point)::numeric(20,5); ! SELECT geo_distance('(0,60)'::point,'(1,60)'::point)::numeric(20,5); ! SELECT geo_distance('(0,60)'::point,'(0,61)'::point)::numeric(20,5); ! SELECT geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)::numeric(20,5); ! SELECT (geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); -- -- Test getting the distance between two points using the <@> operator. -- ! SELECT ('(0,0)'::point <@> '(0,0)'::point)::numeric(20,5); ! SELECT ('(0,0)'::point <@> '(180,0)'::point)::numeric(20,5); ! SELECT ('(0,0)'::point <@> '(0,90)'::point)::numeric(20,5); ! SELECT ('(0,0)'::point <@> '(90,0)'::point)::numeric(20,5); ! SELECT ('(0,0)'::point <@> '(1,0)'::point)::numeric(20,5); ! SELECT ('(0,0)'::point <@> '(0,1)'::point)::numeric(20,5); ! SELECT ('(0,30)'::point <@> '(1,30)'::point)::numeric(20,5); ! SELECT ('(0,30)'::point <@> '(0,31)'::point)::numeric(20,5); ! SELECT ('(0,60)'::point <@> '(1,60)'::point)::numeric(20,5); ! SELECT ('(0,60)'::point <@> '(0,61)'::point)::numeric(20,5); ! SELECT ('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)::numeric(20,5); ! SELECT (('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); --- 4,299 ---- -- -- first, define the datatype. Turn off echoing so that expected file ! -- does not depend on contents of earthdistance.sql or cube.sql. -- \set ECHO none + \i ../cube/cube.sql \i earthdistance.sql \set ECHO all -- + -- The radius of the Earth we are using. + -- + + select earth()::numeric(20,5); + + -- + -- Convert straight line distances to great circle distances. + -- + select (pi()*earth())::numeric(20,5); + select sec_to_gc(0)::numeric(20,5); + select sec_to_gc(2*earth())::numeric(20,5); + select sec_to_gc(10*earth())::numeric(20,5); + select sec_to_gc(-earth())::numeric(20,5); + select sec_to_gc(1000)::numeric(20,5); + select sec_to_gc(10000)::numeric(20,5); + select sec_to_gc(100000)::numeric(20,5); + select sec_to_gc(1000000)::numeric(20,5); + + -- + -- Convert great circle distances to straight line distances. + -- + + select gc_to_sec(0)::numeric(20,5); + select gc_to_sec(sec_to_gc(2*earth()))::numeric(20,5); + select gc_to_sec(10*earth())::numeric(20,5); + select gc_to_sec(pi()*earth())::numeric(20,5); + select gc_to_sec(-1000)::numeric(20,5); + select gc_to_sec(1000)::numeric(20,5); + select gc_to_sec(10000)::numeric(20,5); + select gc_to_sec(100000)::numeric(20,5); + select gc_to_sec(1000000)::numeric(20,5); + + -- + -- Set coordinates using latitude and longitude. + -- Extract each coordinate separately so we can round them. + -- + + select cube_ll_coord(ll_to_earth(0,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,0),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(360,360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(360,360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(360,360),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(180,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,180),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(180,360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(180,360),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(-180,-360),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-180,-360),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-180,-360),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(0,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,180),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(0,-180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,-180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(0,-180),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(90,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,0),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(90,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(90,180),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(-90,0),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,0),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,0),3)::numeric(20,5); + select cube_ll_coord(ll_to_earth(-90,180),1)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,180),2)::numeric(20,5), + cube_ll_coord(ll_to_earth(-90,180),3)::numeric(20,5); + + -- + -- Test getting the latitude of a location. + -- + + select latitude(ll_to_earth(0,0))::numeric(20,10); + select latitude(ll_to_earth(45,0))::numeric(20,10); + select latitude(ll_to_earth(90,0))::numeric(20,10); + select latitude(ll_to_earth(-45,0))::numeric(20,10); + select latitude(ll_to_earth(-90,0))::numeric(20,10); + select latitude(ll_to_earth(0,90))::numeric(20,10); + select latitude(ll_to_earth(45,90))::numeric(20,10); + select latitude(ll_to_earth(90,90))::numeric(20,10); + select latitude(ll_to_earth(-45,90))::numeric(20,10); + select latitude(ll_to_earth(-90,90))::numeric(20,10); + select latitude(ll_to_earth(0,180))::numeric(20,10); + select latitude(ll_to_earth(45,180))::numeric(20,10); + select latitude(ll_to_earth(90,180))::numeric(20,10); + select latitude(ll_to_earth(-45,180))::numeric(20,10); + select latitude(ll_to_earth(-90,180))::numeric(20,10); + select latitude(ll_to_earth(0,-90))::numeric(20,10); + select latitude(ll_to_earth(45,-90))::numeric(20,10); + select latitude(ll_to_earth(90,-90))::numeric(20,10); + select latitude(ll_to_earth(-45,-90))::numeric(20,10); + select latitude(ll_to_earth(-90,-90))::numeric(20,10); + + -- + -- Test getting the longitude of a location. + -- + + select longitude(ll_to_earth(0,0))::numeric(20,10); + select longitude(ll_to_earth(45,0))::numeric(20,10); + select longitude(ll_to_earth(90,0))::numeric(20,10); + select longitude(ll_to_earth(-45,0))::numeric(20,10); + select longitude(ll_to_earth(-90,0))::numeric(20,10); + select longitude(ll_to_earth(0,90))::numeric(20,10); + select longitude(ll_to_earth(45,90))::numeric(20,10); + select longitude(ll_to_earth(90,90))::numeric(20,10); + select longitude(ll_to_earth(-45,90))::numeric(20,10); + select longitude(ll_to_earth(-90,90))::numeric(20,10); + select longitude(ll_to_earth(0,180))::numeric(20,10); + select longitude(ll_to_earth(45,180))::numeric(20,10); + select longitude(ll_to_earth(90,180))::numeric(20,10); + select longitude(ll_to_earth(-45,180))::numeric(20,10); + select longitude(ll_to_earth(-90,180))::numeric(20,10); + select longitude(ll_to_earth(0,-90))::numeric(20,10); + select longitude(ll_to_earth(45,-90))::numeric(20,10); + select longitude(ll_to_earth(90,-90))::numeric(20,10); + select longitude(ll_to_earth(-45,-90))::numeric(20,10); + select longitude(ll_to_earth(-90,-90))::numeric(20,10); + + -- + -- For the distance tests the following is some real life data. + -- + -- Chicago has a latitude of 41.8 and a longitude of 87.6. + -- Albuquerque has a latitude of 35.1 and a longitude of 106.7. + -- (Note that latitude and longitude are specified differently + -- in the cube based functions than for the point based functions.) + -- + + -- + -- Test getting the distance between two points using earth_distance. + -- + + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,0))::numeric(20,5); + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,180))::numeric(20,5); + select earth_distance(ll_to_earth(0,0),ll_to_earth(90,0))::numeric(20,5); + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,90))::numeric(20,5); + select earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))::numeric(20,5); + select earth_distance(ll_to_earth(0,0),ll_to_earth(1,0))::numeric(20,5); + select earth_distance(ll_to_earth(30,0),ll_to_earth(30,1))::numeric(20,5); + select earth_distance(ll_to_earth(30,0),ll_to_earth(31,0))::numeric(20,5); + select earth_distance(ll_to_earth(60,0),ll_to_earth(60,1))::numeric(20,5); + select earth_distance(ll_to_earth(60,0),ll_to_earth(61,0))::numeric(20,5); + select earth_distance(ll_to_earth(41.8,87.6),ll_to_earth(35.1,106.7))::numeric(20,5); + select (earth_distance(ll_to_earth(41.8,87.6),ll_to_earth(35.1,106.7))* + 100./2.54/12./5280.)::numeric(20,5); + + -- -- Test getting the distance between two points using geo_distance. -- ! select geo_distance('(0,0)'::point,'(0,0)'::point)::numeric(20,5); ! select geo_distance('(0,0)'::point,'(180,0)'::point)::numeric(20,5); ! select geo_distance('(0,0)'::point,'(0,90)'::point)::numeric(20,5); ! select geo_distance('(0,0)'::point,'(90,0)'::point)::numeric(20,5); ! select geo_distance('(0,0)'::point,'(1,0)'::point)::numeric(20,5); ! select geo_distance('(0,0)'::point,'(0,1)'::point)::numeric(20,5); ! select geo_distance('(0,30)'::point,'(1,30)'::point)::numeric(20,5); ! select geo_distance('(0,30)'::point,'(0,31)'::point)::numeric(20,5); ! select geo_distance('(0,60)'::point,'(1,60)'::point)::numeric(20,5); ! select geo_distance('(0,60)'::point,'(0,61)'::point)::numeric(20,5); ! select geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)::numeric(20,5); ! select (geo_distance('(87.6,41.8)'::point,'(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); -- -- Test getting the distance between two points using the <@> operator. -- ! select ('(0,0)'::point <@> '(0,0)'::point)::numeric(20,5); ! select ('(0,0)'::point <@> '(180,0)'::point)::numeric(20,5); ! select ('(0,0)'::point <@> '(0,90)'::point)::numeric(20,5); ! select ('(0,0)'::point <@> '(90,0)'::point)::numeric(20,5); ! select ('(0,0)'::point <@> '(1,0)'::point)::numeric(20,5); ! select ('(0,0)'::point <@> '(0,1)'::point)::numeric(20,5); ! select ('(0,30)'::point <@> '(1,30)'::point)::numeric(20,5); ! select ('(0,30)'::point <@> '(0,31)'::point)::numeric(20,5); ! select ('(0,60)'::point <@> '(1,60)'::point)::numeric(20,5); ! select ('(0,60)'::point <@> '(0,61)'::point)::numeric(20,5); ! select ('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)::numeric(20,5); ! select (('(87.6,41.8)'::point <@> '(106.7,35.1)'::point)*5280.*12.*2.54/100.)::numeric(20,5); ! ! -- ! -- Test getting a bounding box around points. ! -- ! ! select cube_ll_coord(earth_box(ll_to_earth(0,0),112000),1)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),112000),2)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),112000),3)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),112000),1)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),112000),2)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),112000),3)::numeric(20,5); ! select cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),1)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),2)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),pi()*earth()),3)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),1)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),2)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),pi()*earth()),3)::numeric(20,5); ! select cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),1)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),2)::numeric(20,5), ! cube_ll_coord(earth_box(ll_to_earth(0,0),10*earth()),3)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),1)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),2)::numeric(20,5), ! cube_ur_coord(earth_box(ll_to_earth(0,0),10*earth()),3)::numeric(20,5); ! ! -- ! -- Test for points that should be in bounding boxes. ! -- ! ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*1.00001) @ ! ll_to_earth(0,1); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*1.00001) @ ! ll_to_earth(0,0.1); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.01))*1.00001) @ ! ll_to_earth(0,0.01); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.001))*1.00001) @ ! ll_to_earth(0,0.001); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.0001))*1.00001) @ ! ll_to_earth(0,0.0001); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0.0001,0.0001))*1.00001) @ ! ll_to_earth(0.0001,0.0001); ! select earth_box(ll_to_earth(45,45), ! earth_distance(ll_to_earth(45,45),ll_to_earth(45.0001,45.0001))*1.00001) @ ! ll_to_earth(45.0001,45.0001); ! select earth_box(ll_to_earth(90,180), ! earth_distance(ll_to_earth(90,180),ll_to_earth(90.0001,180.0001))*1.00001) @ ! ll_to_earth(90.0001,180.0001); ! ! -- ! -- Test for points that shouldn't be in bounding boxes. Note that we need ! -- to make points way outside, since some points close may be in the box ! -- but further away than the distance we are testing. ! -- ! ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*.57735) @ ! ll_to_earth(0,1); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*.57735) @ ! ll_to_earth(0,0.1); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.01))*.57735) @ ! ll_to_earth(0,0.01); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.001))*.57735) @ ! ll_to_earth(0,0.001); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.0001))*.57735) @ ! ll_to_earth(0,0.0001); ! select earth_box(ll_to_earth(0,0), ! earth_distance(ll_to_earth(0,0),ll_to_earth(0.0001,0.0001))*.57735) @ ! ll_to_earth(0.0001,0.0001); ! select earth_box(ll_to_earth(45,45), ! earth_distance(ll_to_earth(45,45),ll_to_earth(45.0001,45.0001))*.57735) @ ! ll_to_earth(45.0001,45.0001); ! select earth_box(ll_to_earth(90,180), ! earth_distance(ll_to_earth(90,180),ll_to_earth(90.0001,180.0001))*.57735) @ ! ll_to_earth(90.0001,180.0001); ! ! -- ! -- Test the recommended constraints. ! -- ! ! select is_point(ll_to_earth(0,0)); ! select cube_dim(ll_to_earth(0,0)) <= 3; ! select abs(cube_distance(ll_to_earth(0,0), '(0)'::cube) / earth() - 1) < ! '10e-12'::float8; ! select is_point(ll_to_earth(30,60)); ! select cube_dim(ll_to_earth(30,60)) <= 3; ! select abs(cube_distance(ll_to_earth(30,60), '(0)'::cube) / earth() - 1) < ! '10e-12'::float8; ! select is_point(ll_to_earth(60,90)); ! select cube_dim(ll_to_earth(60,90)) <= 3; ! select abs(cube_distance(ll_to_earth(60,90), '(0)'::cube) / earth() - 1) < ! '10e-12'::float8; ! select is_point(ll_to_earth(-30,-90)); ! select cube_dim(ll_to_earth(-30,-90)) <= 3; ! select abs(cube_distance(ll_to_earth(-30,-90), '(0)'::cube) / earth() - 1) < ! '10e-12'::float8;