PostgreSQL Source Code  git master
earthdistance.c
Go to the documentation of this file.
1 /* contrib/earthdistance/earthdistance.c */
2
3 #include "postgres.h"
4
5 #include <math.h>
6
7 #include "utils/geo_decls.h" /* for Point */
8
9 #ifndef M_PI
10 #define M_PI 3.14159265358979323846
11 #endif
12
14
15 /* Earth's radius is in statute miles. */
16 static const double EARTH_RADIUS = 3958.747716;
17 static const double TWO_PI = 2.0 * M_PI;
18
19
20 /******************************************************
21  *
23  *
24  * arg: double, angle in degrees
25  *
26  * returns: double, same angle in radians
27  ******************************************************/
28
29 static double
31 {
32  return (degrees / 360.0) * TWO_PI;
33 }
34
35 /******************************************************
36  *
37  * geo_distance_internal - distance between points
38  *
39  * args:
40  * a pair of points - for each point,
41  * x-coordinate is longitude in degrees west of Greenwich
42  * y-coordinate is latitude in degrees above equator
43  *
44  * returns: double
45  * distance between the points in miles on earth's surface
46  ******************************************************/
47
48 static double
50 {
51  double long1,
52  lat1,
53  long2,
54  lat2;
55  double longdiff;
56  double sino;
57
58  /* convert degrees to radians */
59
62
65
66  /* compute difference in longitudes - want < 180 degrees */
67  longdiff = fabs(long1 - long2);
68  if (longdiff > M_PI)
69  longdiff = TWO_PI - longdiff;
70
71  sino = sqrt(sin(fabs(lat1 - lat2) / 2.) * sin(fabs(lat1 - lat2) / 2.) +
72  cos(lat1) * cos(lat2) * sin(longdiff / 2.) * sin(longdiff / 2.));
73  if (sino > 1.)
74  sino = 1.;
75
76  return 2. * EARTH_RADIUS * asin(sino);
77 }
78
79
80 /******************************************************
81  *
82  * geo_distance - distance between points
83  *
84  * args:
85  * a pair of points - for each point,
86  * x-coordinate is longitude in degrees west of Greenwich
87  * y-coordinate is latitude in degrees above equator
88  *
89  * returns: float8
90  * distance between the points in miles on earth's surface
91  *
92  * If float8 is passed-by-value, the oldstyle version-0 calling convention
93  * is unportable, so we use version-1. However, if it's passed-by-reference,
94  * continue to use oldstyle. This is just because we'd like earthdistance
95  * to serve as a canary for any unintentional breakage of version-0 functions
96  * with float8 results.
97  ******************************************************/
98
99 #ifdef USE_FLOAT8_BYVAL
100
102
103 Datum
105 {
106  Point *pt1 = PG_GETARG_POINT_P(0);
107  Point *pt2 = PG_GETARG_POINT_P(1);
108  float8 result;
109
110  result = geo_distance_internal(pt1, pt2);
111  PG_RETURN_FLOAT8(result);
112 }
113 #else /* !USE_FLOAT8_BYVAL */
114
115 double *geo_distance(Point *pt1, Point *pt2);
116
117 double *
119 {
120  double *resultp = palloc(sizeof(double));
121
122  *resultp = geo_distance_internal(pt1, pt2);
123  return resultp;
124 }
125
126 #endif /* USE_FLOAT8_BYVAL */
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:318
double y
Definition: geo_decls.h:60
return result
Definition: formatting.c:1618
double x
Definition: geo_decls.h:60
double float8
Definition: c.h:381
#define PG_GETARG_POINT_P(n)
Definition: geo_decls.h:139
Datum degrees(PG_FUNCTION_ARGS)
Definition: float.c:2374
uintptr_t Datum
Definition: postgres.h:372
static const double TWO_PI
Definition: earthdistance.c:17
#define PG_FUNCTION_INFO_V1(funcname)
Definition: fmgr.h:365
static double geo_distance_internal(Point *pt1, Point *pt2)
Definition: earthdistance.c:49
void * palloc(Size size)
Definition: mcxt.c:849