GRASS 8 Programmer's Manual 8.6.0dev(2026)-41d63e587c
Loading...
Searching...
No Matches
geodist.c
Go to the documentation of this file.
1/*!
2 * \file lib/gis/geodist.c
3 *
4 * \brief GIS Library - Geodesic distance routines.
5 *
6 * Distance from point to point along a geodesic code from Paul
7 * D. Thomas, 1970 "Spheroidal Geodesics, Reference Systems, and Local
8 * Geometry" U.S. Naval Oceanographic Office, p. 162 Engineering
9 * Library 526.3 T36s
10 * http://stinet.dtic.mil/oai/oai?&verb=getRecord&metadataPrefix=html&identifier=AD0703541
11 *
12 * <b>WARNING:</b> this code is preliminary and may be changed,
13 * including calling sequences to any of the functions defined here.
14 *
15 * (C) 2001-2009 by the GRASS Development Team
16 *
17 * This program is free software under the GNU General Public License
18 * (>=v2). Read the file COPYING that comes with GRASS for details.
19 *
20 * \author Original author CERL
21 */
22
23#include <math.h>
24#include <grass/gis.h>
25#include <geodesic.h>
26#include "pi.h"
27
28static struct state {
29 double boa;
30 double f;
31 double ff64;
32 double al;
33 double t1, t2, t3, t4, t1r, t2r;
34 struct geod_geodesic g;
35} state;
36
37static struct state *st = &state;
38
39/*!
40 * \brief Begin geodesic distance.
41 *
42 * Initializes the distance calculations for the ellipsoid with
43 * semi-major axis <i>a</i> (in meters) and ellipsoid eccentricity squared
44 * <i>e2</i>. It is used only for the latitude-longitude projection.
45 *
46 * <b>Note:</b> Must be called once to establish the ellipsoid.
47 *
48 * \param a semi-major axis in meters
49 * \param e2 ellipsoid eccentricity
50 */
51void G_begin_geodesic_distance(double a, double e2)
52{
53 st->al = a;
54 st->boa = sqrt(1.0 - e2);
55 st->f = 1.0 - st->boa;
56 st->ff64 = st->f * st->f / 64.0;
57 /* GeographicLib */
58 geod_init(&st->g, st->al, st->f);
59}
60
61/*!
62 * \brief Sets geodesic distance lat1.
63 *
64 * Set the first latitude.
65 *
66 * <b>Note:</b> Must be called first.
67 *
68 * \param[in] lat1 first latitude
69 * \return
70 */
72{
73 st->t1r = atan(st->boa * tan(Radians(lat1)));
74}
75
76/*!
77 * \brief Sets geodesic distance lat2.
78 *
79 * Set the second latitude.
80 *
81 * <b>Note:</b> Must be called second.
82 *
83 * \param[in] lat2 second latitude
84 */
86{
87 double stm, ctm, sdtm, cdtm;
88 double tm, dtm;
89
90 st->t2r = atan(st->boa * tan(Radians(lat2)));
91
92 tm = (st->t1r + st->t2r) / 2;
93 dtm = (st->t2r - st->t1r) / 2;
94
95 stm = sin(tm);
96 ctm = cos(tm);
97 sdtm = sin(dtm);
98 cdtm = cos(dtm);
99
100 st->t1 = stm * cdtm;
101 st->t1 = st->t1 * st->t1 * 2;
102
103 st->t2 = sdtm * ctm;
104 st->t2 = st->t2 * st->t2 * 2;
105
106 st->t3 = sdtm * sdtm;
107 st->t4 = cdtm * cdtm - stm * stm;
108}
109
110/*!
111 * \brief Calculates geodesic distance.
112 *
113 * Calculates the geodesic distance from <i>lon1,lat1</i> to
114 * <i>lon2,lat2</i> in meters where <i>lat1</i> was the latitude
115 * passed to G_set_geodesic_distance_latl() and <i>lat2</i> was the
116 * latitude passed to G_set_geodesic_distance_lat2().
117 *
118 * \param[in] lon1 first longitude
119 * \param[in] lon2 second longitude
120 *
121 * \return double distance in meters
122 */
124{
125 double a, cd, d, e, /*dl, */
126 q, sd, sdlmr, t, u, v, x, y;
127
128 sdlmr = sin(Radians(lon2 - lon1) / 2);
129
130 /* special case - shapiro */
131 if (sdlmr == 0.0 && st->t1r == st->t2r)
132 return 0.0;
133
134 q = st->t3 + sdlmr * sdlmr * st->t4;
135
136 /* special case - shapiro */
137 if (q == 1.0)
138 return M_PI * st->al;
139
140 /* Mod: shapiro
141 * cd=1-2q is ill-conditioned if q is small O(10**-23)
142 * (for high lats? with lon1-lon2 < .25 degrees?)
143 * the computation of cd = 1-2*q will give cd==1.0.
144 * However, note that t=dl/sd is dl/sin(dl) which approaches 1 as dl->0.
145 * So the first step is to compute a good value for sd without using sin()
146 * and then check cd && q to see if we got cd==1.0 when we shouldn't.
147 * Note that dl isn't used except to get t,
148 * but both cd and sd are used later
149 */
150
151 /* original code
152 cd=1-2*q;
153 dl=acos(cd);
154 sd=sin(dl);
155 t=dl/sd;
156 */
157
158 cd = 1 - 2 * q; /* ill-conditioned subtraction for small q */
159 /* mod starts here */
160 sd = 2 * sqrt(q - q * q); /* sd^2 = 1 - cd^2 */
161 if (q != 0.0 && cd == 1.0) /* test for small q */
162 t = 1.0;
163 else if (sd == 0.0)
164 t = 1.0;
165 else
166 t = acos(cd) / sd; /* don't know how to fix acos(1-2*q) yet */
167 /* mod ends here */
168
169 u = st->t1 / (1 - q);
170 v = st->t2 / q;
171 d = 4 * t * t;
172 x = u + v;
173 e = -2 * cd;
174 y = u - v;
175 a = -d * e;
176
177 return st->al * sd *
178 (t - st->f / 4 * (t * x - y) +
179 st->ff64 * (x * (a + (t - (a + e) / 2) * x) + y * (-2 * d + e * y) +
180 d * x * y));
181}
182
183/*!
184 * \brief Calculates geodesic distance.
185 *
186 * Calculates the geodesic distance from <i>lon1,lat1</i> to
187 * <i>lon2,lat2</i> in meters.
188 *
189 * <b>Note:</b> The calculation of the geodesic distance is fairly
190 * costly.
191 *
192 * \param[in] lon1,lat1 longitude,latitude of first point
193 * \param[in] lon2,lat2 longitude,latitude of second point
194 *
195 * \return distance in meters
196 */
197double G_geodesic_distance(double lon1, double lat1, double lon2, double lat2)
198{
199 /* GeographicLib */
200 double ps12 = 0, pazi1 = 0, pazi2 = 0;
201
202 geod_inverse(&st->g, lat1, lon1, lat2, lon2, &ps12, &pazi1, &pazi2);
203
204 return ps12;
205
206#if 0
207 /* GRASS native */
211#endif
212}
void G_set_geodesic_distance_lat2(double lat2)
Sets geodesic distance lat2.
Definition geodist.c:85
void G_set_geodesic_distance_lat1(double lat1)
Sets geodesic distance lat1.
Definition geodist.c:71
double G_geodesic_distance(double lon1, double lat1, double lon2, double lat2)
Calculates geodesic distance.
Definition geodist.c:197
double G_geodesic_distance_lon_to_lon(double lon1, double lon2)
Calculates geodesic distance.
Definition geodist.c:123
void G_begin_geodesic_distance(double a, double e2)
Begin geodesic distance.
Definition geodist.c:51
#define M_PI
Definition gis.h:157
float g
Definition named_colr.c:7
#define Radians(x)
Definition pi.h:6
double t
Definition r_raster.c:39
#define x