pygeodesy 24.12.12__py2.py3-none-any.whl → 25.1.9__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pygeodesy/formy.py CHANGED
@@ -11,14 +11,14 @@ from __future__ import division as _; del _ # PYCHOK semicolon
11
11
  from pygeodesy.constants import EPS, EPS0, EPS1, PI, PI2, PI3, PI_2, R_M, \
12
12
  _0_0s, float0_, isnon0, remainder, _umod_PI2, \
13
13
  _0_0, _0_125, _0_25, _0_5, _1_0, _2_0, _4_0, \
14
- _32_0, _90_0, _180_0, _360_0, _copysign
14
+ _90_0, _180_0, _360_0, _copysign
15
15
  from pygeodesy.datums import Datum, Ellipsoid, _ellipsoidal_datum, \
16
16
  _mean_radius, _spherical_datum, _WGS84, _EWGS84
17
17
  # from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
18
18
  from pygeodesy.errors import IntersectionError, LimitError, limiterrors, \
19
19
  _TypeError, _ValueError, _xattr, _xError, \
20
20
  _xcallable,_xkwds, _xkwds_pop2
21
- from pygeodesy.fmath import euclid, hypot, hypot2, sqrt0
21
+ from pygeodesy.fmath import euclid, fdot_, fprod, hypot, hypot2, sqrt0
22
22
  from pygeodesy.fsums import fsumf_, Fmt, unstr
23
23
  # from pygeodesy.internals import _DUNDER_nameof # from .named
24
24
  from pygeodesy.interns import _delta_, _distant_, _inside_, _SPACE_, _too_
@@ -32,20 +32,20 @@ from pygeodesy.namedTuples import Bearing2Tuple, Distance4Tuple, LatLon2Tuple, \
32
32
  from pygeodesy.units import _isDegrees, _isHeight, _isRadius, Bearing, Degrees_, \
33
33
  Distance, Distance_, Height, Lamd, Lat, Lon, Meter_, \
34
34
  Phid, Radians, Radians_, Radius, Radius_, Scalar, _100km
35
- from pygeodesy.utily import acos1, atan2, atan2b, degrees2m, _loneg, m2degrees, \
36
- tan_2, sincos2, sincos2_, _Wrap
35
+ from pygeodesy.utily import acos1, asin1, atan2, atan2b, degrees2m, hav, _loneg, \
36
+ m2degrees, tan_2, sincos2, sincos2_, _Wrap
37
37
  # from pygeodesy.vector3d import _otherV3d # _MODS
38
38
  # from pygeodesy.vector3dBase import _xyz_y_z3 # _MODS
39
39
  # from pygeodesy import ellipsoidalExact, ellipsoidalKarney, vector3d, \
40
40
  # sphericalNvector, sphericalTrigonometry # _MODS
41
41
 
42
42
  from contextlib import contextmanager
43
- from math import asin, atan, cos, degrees, fabs, radians, sin, sqrt # pow
43
+ from math import atan, cos, degrees, fabs, radians, sin, sqrt # pow
44
44
 
45
45
  __all__ = _ALL_LAZY.formy
46
- __version__ = '24.12.06'
46
+ __version__ = '25.01.05'
47
47
 
48
- _RADIANS2 = (PI / _180_0)**2 # degrees- to radians-squared
48
+ _RADIANS2 = radians(_1_0)**2 # degree to radians-squared
49
49
  _ratio_ = 'ratio'
50
50
  _xline_ = 'xline'
51
51
 
@@ -112,18 +112,17 @@ def antipode_(phi, lam, **name):
112
112
 
113
113
 
114
114
  def bearing(lat1, lon1, lat2, lon2, **final_wrap):
115
- '''Compute the initial or final bearing (forward or reverse azimuth)
116
- between two (spherical) points.
115
+ '''Compute the initial or final bearing (forward or reverse azimuth) between two
116
+ (spherical) points.
117
117
 
118
118
  @arg lat1: Start latitude (C{degrees}).
119
119
  @arg lon1: Start longitude (C{degrees}).
120
120
  @arg lat2: End latitude (C{degrees}).
121
121
  @arg lon2: End longitude (C{degrees}).
122
- @kwarg final_wrap: Optional keyword arguments for function
123
- L{pygeodesy.bearing_}.
122
+ @kwarg final_wrap: Optional keyword arguments for function L{pygeodesy.bearing_}.
124
123
 
125
- @return: Initial or final bearing (compass C{degrees360}) or zero if
126
- both points coincide.
124
+ @return: Initial or final bearing (compass C{degrees360}) or zero if both points
125
+ coincide.
127
126
  '''
128
127
  r = bearing_(Phid(lat1=lat1), Lamd(lon1=lon1),
129
128
  Phid(lat2=lat2), Lamd(lon2=lon2), **final_wrap)
@@ -131,20 +130,19 @@ def bearing(lat1, lon1, lat2, lon2, **final_wrap):
131
130
 
132
131
 
133
132
  def bearing_(phi1, lam1, phi2, lam2, final=False, wrap=False):
134
- '''Compute the initial or final bearing (forward or reverse azimuth) between
135
- two (spherical) points.
133
+ '''Compute the initial or final bearing (forward or reverse azimuth) between two
134
+ (spherical) points.
136
135
 
137
136
  @arg phi1: Start latitude (C{radians}).
138
137
  @arg lam1: Start longitude (C{radians}).
139
138
  @arg phi2: End latitude (C{radians}).
140
139
  @arg lam2: End longitude (C{radians}).
141
- @kwarg final: If C{True}, return the final, otherwise the initial bearing
142
- (C{bool}).
143
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{phi2}} and
144
- B{C{lam2}} (C{bool}).
140
+ @kwarg final: If C{True}, return the final, otherwise the initial bearing (C{bool}).
141
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{phi2}} and B{C{lam2}}
142
+ (C{bool}).
145
143
 
146
- @return: Initial or final bearing (compass C{radiansPI2}) or zero if both
147
- are coincident.
144
+ @return: Initial or final bearing (compass C{radiansPI2}) or zero if both points
145
+ coincide.
148
146
 
149
147
  @see: U{Bearing<https://www.Movable-Type.co.UK/scripts/latlong.html>}, U{Course
150
148
  between two points<https://www.EdWilliams.org/avform147.htm#Crs>} and
@@ -173,8 +171,9 @@ def _bearingTo2(p1, p2, wrap=False): # for points.ispolar, sphericalTrigonometr
173
171
  pass
174
172
  # XXX spherical version, OK for ellipsoidal ispolar?
175
173
  t = p1.philam + p2.philam
176
- return Bearing2Tuple(degrees(bearing_(*t, final=False, wrap=wrap)),
177
- degrees(bearing_(*t, final=True, wrap=wrap)),
174
+ i = bearing_(*t, final=False, wrap=wrap)
175
+ f = bearing_(*t, final=True, wrap=wrap)
176
+ return Bearing2Tuple(degrees(i), degrees(f),
178
177
  name__=_bearingTo2)
179
178
 
180
179
 
@@ -198,8 +197,8 @@ def chord2angle(chord, radius=R_M):
198
197
  if i > 0:
199
198
  r -= i
200
199
  i *= PI
201
- r = asin(r) + i
202
- return _copysign(r * _2_0, chord)
200
+ r = (asin1(r) + i) * _2_0
201
+ return _copysign(r, chord)
203
202
 
204
203
 
205
204
  def compassAngle(lat1, lon1, lat2, lon2, adjust=True, wrap=False):
@@ -213,10 +212,10 @@ def compassAngle(lat1, lon1, lat2, lon2, adjust=True, wrap=False):
213
212
  @arg lon1: From longitude (C{degrees}).
214
213
  @arg lat2: To latitude (C{degrees}).
215
214
  @arg lon2: To longitude (C{degrees}).
216
- @kwarg adjust: Adjust the longitudinal delta by the cosine of the
217
- mean latitude (C{bool}).
218
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}}
219
- and B{C{lon2}} (C{bool}).
215
+ @kwarg adjust: Adjust the longitudinal delta by the cosine of the mean
216
+ latitude (C{bool}).
217
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
218
+ B{C{lon2}} (C{bool}).
220
219
 
221
220
  @return: Compass angle from North (C{degrees360}).
222
221
 
@@ -231,230 +230,144 @@ def compassAngle(lat1, lon1, lat2, lon2, adjust=True, wrap=False):
231
230
  return atan2b(d_lon, lat2 - lat1)
232
231
 
233
232
 
234
- def cosineAndoyerLambert(lat1, lon1, lat2, lon2, datum=_WGS84, wrap=False):
235
- '''Compute the distance between two (ellipsoidal) points using the U{Andoyer-Lambert
236
- <https://books.google.com/books?id=x2UiAQAAIAAJ>} correction of the U{Law of
237
- Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula.
233
+ def cosineLaw(lat1, lon1, lat2, lon2, corr=0, earth=None, wrap=False,
234
+ datum=_WGS84, radius=R_M):
235
+ '''Compute the distance between two points using the U{Law of Cosines
236
+ <https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>}
237
+ formula, optionally corrected.
238
238
 
239
239
  @arg lat1: Start latitude (C{degrees}).
240
240
  @arg lon1: Start longitude (C{degrees}).
241
241
  @arg lat2: End latitude (C{degrees}).
242
242
  @arg lon2: End longitude (C{degrees}).
243
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
244
- L{a_f2Tuple}) to use.
245
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
246
- B{C{lon2}} (C{bool}).
243
+ @kwarg corr: Use C{B{corr}=2} to apply the U{Forsythe-Andoyer-Lambert
244
+ <https://www2.UNB.CA/gge/Pubs/TR77.pdf>}, C{B{corr}=1} for the
245
+ U{Andoyer-Lambert<https://Books.Google.com/books?id=x2UiAQAAIAAJ>}
246
+ corrected (ellipsoidal) or keep C{B{corr}=0} for the uncorrected
247
+ (spherical) C{Law of Cosines} formula (C{int}).
248
+ @kwarg earth: Mean earth radius (C{meter}) or datum (L{Datum}) or ellipsoid
249
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) to use.
250
+ @kwarg wrap: If C{True}, wrap or I{normalize} and B{C{lat2}} and B{C{lon2}}
251
+ (C{bool}).
252
+ @kwarg datum: Default ellipsiodal B{C{earth}} (and for backward compatibility).
253
+ @kwarg radius: Default spherical B{C{earth}} (and for backward compatibility).
247
254
 
248
- @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes or
249
- C{radians} if C{B{datum} is None}).
255
+ @return: Distance (C{meter}, same units as B{C{radius}} or the datum's or
256
+ ellipsoid axes).
250
257
 
251
- @raise TypeError: Invalid B{C{datum}}.
258
+ @raise TypeError: Invalid B{C{earth}}, B{C{datum}} or B{C{radius}}.
259
+
260
+ @raise ValueError: Invalid B{C{corr}}.
252
261
 
253
- @see: Functions L{cosineAndoyerLambert_}, L{cosineForsytheAndoyerLambert},
254
- L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny},
255
- L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and method
256
- L{Ellipsoid.distance2}.
262
+ @see: Functions L{cosineLaw_}, L{equirectangular}, L{euclidean}, L{flatLocal} /
263
+ L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and
264
+ method L{Ellipsoid.distance2}.
265
+
266
+ @note: See note at function L{vincentys_}.
257
267
  '''
258
- return _dE(cosineAndoyerLambert_, datum, wrap, lat1, lon1, lat2, lon2)
268
+ return _dE(cosineLaw_, earth or datum, wrap, lat1, lon1, lat2, lon2, corr=corr) if corr else \
269
+ _dS(cosineLaw_, earth or radius, wrap, lat1, lon1, lat2, lon2)
259
270
 
260
271
 
261
- def cosineAndoyerLambert_(phi2, phi1, lam21, datum=_WGS84):
262
- '''Compute the I{angular} distance between two (ellipsoidal) points using the U{Andoyer-Lambert
263
- <https://books.google.com/books?id=x2UiAQAAIAAJ>} correction of the U{Law of
264
- Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula.
272
+ def cosineLaw_(phi2, phi1, lam21, corr=0, earth=None, datum=_WGS84):
273
+ '''Compute the I{angular} distance between two points using the U{Law of Cosines
274
+ <https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula,
275
+ optionally corrected.
265
276
 
266
277
  @arg phi2: End latitude (C{radians}).
267
278
  @arg phi1: Start latitude (C{radians}).
268
279
  @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
269
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
270
- L{a_f2Tuple}) to use.
280
+ @kwarg corr: Use C{B{corr}=2} to apply the U{Forsythe-Andoyer-Lambert
281
+ <https://www2.UNB.CA/gge/Pubs/TR77.pdf>}, C{B{corr}=1} for the
282
+ U{Andoyer-Lambert<https://Books.Google.com/books?id=x2UiAQAAIAAJ>}
283
+ corrected (ellipsoidal) or keep C{B{corr}=0} for the uncorrected
284
+ (spherical) C{Law of Cosines} formula (C{int}).
285
+ @kwarg earth: Mean earth radius (C{meter}) or datum (L{Datum}) or ellipsoid
286
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) to use.
287
+ @kwarg datum: Default ellipsoidal B{C{earth}} (and for backward compatibility).
271
288
 
272
289
  @return: Angular distance (C{radians}).
273
290
 
274
- @raise TypeError: Invalid B{C{datum}}.
291
+ @raise TypeError: Invalid B{C{earth}} or B{C{datum}}.
292
+
293
+ @raise ValueError: Invalid B{C{corr}}.
275
294
 
276
- @see: Functions L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert_},
277
- L{cosineLaw_}, L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{flatPolar_},
278
- L{haversine_}, L{thomas_} and L{vincentys_} and U{Geodesy-PHP
295
+ @see: Functions L{cosineLaw}, L{euclidean_}, L{flatLocal_} / L{hubeny_},
296
+ L{flatPolar_}, L{haversine_}, L{thomas_} and L{vincentys_} and U{Geodesy-PHP
279
297
  <https://GitHub.com/jtejido/geodesy-php/blob/master/src/Geodesy/Distance/
280
298
  AndoyerLambert.php>}.
281
299
  '''
282
300
  s2, c2, s1, c1, r, c21 = _sincosa6(phi2, phi1, lam21)
283
- if isnon0(c1) and isnon0(c2):
284
- E = _ellipsoidal(datum, cosineAndoyerLambert_)
285
- if E.f: # ellipsoidal
286
- r2 = atan2(E.b_a * s2, c2)
287
- r1 = atan2(E.b_a * s1, c1)
288
- s2, c2, s1, c1 = sincos2_(r2, r1)
289
- r = acos1(s1 * s2 + c1 * c2 * c21)
290
- if r:
291
- sr, _, sr_2, cr_2 = sincos2_(r, r * _0_5)
292
- if isnon0(sr_2) and isnon0(cr_2):
293
- s = (sr + r) * ((s1 - s2) / sr_2)**2
294
- c = (sr - r) * ((s1 + s2) / cr_2)**2
295
- r += (c - s) * E.f * _0_125
296
- return r
297
-
298
-
299
- def cosineForsytheAndoyerLambert(lat1, lon1, lat2, lon2, datum=_WGS84, wrap=False):
300
- '''Compute the distance between two (ellipsoidal) points using the U{Forsythe-Andoyer-Lambert
301
- <https://www2.UNB.Ca/gge/Pubs/TR77.pdf>} correction of the U{Law of Cosines
302
- <https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula.
303
-
304
- @arg lat1: Start latitude (C{degrees}).
305
- @arg lon1: Start longitude (C{degrees}).
306
- @arg lat2: End latitude (C{degrees}).
307
- @arg lon2: End longitude (C{degrees}).
308
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
309
- L{a_f2Tuple}) to use.
310
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
311
- B{C{lon2}} (C{bool}).
312
-
313
- @return: Distance (C{meter}, same units as the B{C{datum}}'s ellipsoid axes or
314
- C{radians} if C{B{datum} is None}).
315
-
316
- @raise TypeError: Invalid B{C{datum}}.
317
-
318
- @see: Functions L{cosineForsytheAndoyerLambert_}, L{cosineAndoyerLambert},
319
- L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny},
320
- L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and method
321
- L{Ellipsoid.distance2}.
322
- '''
323
- return _dE(cosineForsytheAndoyerLambert_, datum, wrap, lat1, lon1, lat2, lon2)
324
-
325
-
326
- def cosineForsytheAndoyerLambert_(phi2, phi1, lam21, datum=_WGS84):
327
- '''Compute the I{angular} distance between two (ellipsoidal) points using the
328
- U{Forsythe-Andoyer-Lambert<https://www2.UNB.Ca/gge/Pubs/TR77.pdf>} correction of
329
- the U{Law of Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>}
330
- formula.
331
-
332
- @arg phi2: End latitude (C{radians}).
333
- @arg phi1: Start latitude (C{radians}).
334
- @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
335
- @kwarg datum: Datum (L{Datum}) or ellipsoid to use (L{Ellipsoid},
336
- L{Ellipsoid2} or L{a_f2Tuple}).
337
-
338
- @return: Angular distance (C{radians}).
339
-
340
- @raise TypeError: Invalid B{C{datum}}.
341
-
342
- @see: Functions L{cosineForsytheAndoyerLambert}, L{cosineAndoyerLambert_},
343
- L{cosineLaw_}, L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{flatPolar_},
344
- L{haversine_}, L{thomas_} and L{vincentys_} and U{Geodesy-PHP
345
- <https://GitHub.com/jtejido/geodesy-php/blob/master/src/Geodesy/
346
- Distance/ForsytheCorrection.php>}.
347
- '''
348
- s2, c2, s1, c1, r, _ = _sincosa6(phi2, phi1, lam21)
349
- if r and isnon0(c1) and isnon0(c2):
350
- E = _ellipsoidal(datum, cosineForsytheAndoyerLambert_)
351
- if E.f: # ellipsoidal
352
- sr, cr, s2r, _ = sincos2_(r, r * 2)
353
- if isnon0(sr) and fabs(cr) < EPS1:
354
- s = (s1 + s2)**2 / (1 + cr)
355
- t = (s1 - s2)**2 / (1 - cr)
356
- x = s + t
357
- y = s - t
358
-
359
- s = 8 * r**2 / sr
360
- a = 64 * r + s * cr * 2 # 16 * r**2 / tan(r)
361
- d = 48 * sr + s # 8 * r**2 / tan(r)
362
- b = -2 * d
363
- e = 30 * s2r
364
- c = fsumf_(30 * r, e * _0_5, s * cr) # 8 * r**2 / tan(r)
365
- t = fsumf_( a * x, e * y**2, b * y, -c * x**2, d * x * y)
366
-
367
- r += fsumf_(-r * x, 3 * y * sr, t * E.f / _32_0) * E.f * _0_25
301
+ if corr and isnon0(c1) and isnon0(c2):
302
+ E = _ellipsoidal(earth or datum, cosineLaw_)
303
+ f = _0_25 * E.f
304
+ if f: # ellipsoidal
305
+ if corr == 1: # Andoyer-Lambert
306
+ r2 = atan2(E.b_a * s2, c2)
307
+ r1 = atan2(E.b_a * s1, c1)
308
+ s2, c2, s1, c1 = sincos2_(r2, r1)
309
+ r = acos1(s1 * s2 + c1 * c2 * c21)
310
+ if r:
311
+ sr, _, sr_2, cr_2 = sincos2_(r, r * _0_5)
312
+ if isnon0(sr_2) and isnon0(cr_2):
313
+ s = (sr + r) * ((s1 - s2) / sr_2)**2
314
+ c = (sr - r) * ((s1 + s2) / cr_2)**2
315
+ r += (c - s) * _0_5 * f
316
+
317
+ elif corr == 2: # Forsythe-Andoyer-Lambert
318
+ sr, cr, s2r, _ = sincos2_(r, r * 2)
319
+ if isnon0(sr) and fabs(cr) < EPS1:
320
+ s = (s1 + s2)**2 / (_1_0 + cr)
321
+ t = (s1 - s2)**2 / (_1_0 - cr)
322
+ x = s + t
323
+ y = s - t
324
+
325
+ s = 8 * r**2 / sr
326
+ a = 64 * r + s * cr * 2 # 16 * r**2 / tan(r)
327
+ d = 48 * sr + s # 8 * r**2 / tan(r)
328
+ b = -2 * d
329
+ e = 30 * s2r
330
+
331
+ c = fdot_(30, r, cr, s, e, _0_5) # 8 * r**2 / tan(r)
332
+ t = fdot_( a, x, b, y, e, y**2, -c, x**2, d, x * y) * _0_125
333
+ r += fdot_(-r, x, sr, y * 3, t, f) * f
334
+ else:
335
+ raise _ValueError(corr=corr)
368
336
  return r
369
337
 
370
338
 
371
- def cosineLaw(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
372
- '''Compute the distance between two points using the U{spherical Law of Cosines
373
- <https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula.
374
-
375
- @arg lat1: Start latitude (C{degrees}).
376
- @arg lon1: Start longitude (C{degrees}).
377
- @arg lat2: End latitude (C{degrees}).
378
- @arg lon2: End longitude (C{degrees}).
379
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
380
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
381
- L{a_f2Tuple}) to use.
382
- @kwarg wrap: If C{True}, wrap or I{normalize} and B{C{lat2}}
383
- and B{C{lon2}} (C{bool}).
384
-
385
- @return: Distance (C{meter}, same units as B{C{radius}} or the
386
- ellipsoid or datum axes).
387
-
388
- @raise TypeError: Invalid B{C{radius}}.
389
-
390
- @see: Functions L{cosineLaw_}, L{cosineAndoyerLambert},
391
- L{cosineForsytheAndoyerLambert}, L{equirectangular}, L{euclidean},
392
- L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and
393
- L{vincentys} and method L{Ellipsoid.distance2}.
394
-
395
- @note: See note at function L{vincentys_}.
396
- '''
397
- return _dS(cosineLaw_, radius, wrap, lat1, lon1, lat2, lon2)
398
-
399
-
400
- def cosineLaw_(phi2, phi1, lam21):
401
- '''Compute the I{angular} distance between two points using the U{spherical Law of
402
- Cosines<https://www.Movable-Type.co.UK/scripts/latlong.html#cosine-law>} formula.
403
-
404
- @arg phi2: End latitude (C{radians}).
405
- @arg phi1: Start latitude (C{radians}).
406
- @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
407
-
408
- @return: Angular distance (C{radians}).
409
-
410
- @see: Functions L{cosineLaw}, L{cosineAndoyerLambert_},
411
- L{cosineForsytheAndoyerLambert_}, L{euclidean_},
412
- L{flatLocal_}/L{hubeny_}, L{flatPolar_}, L{haversine_},
413
- L{thomas_} and L{vincentys_}.
414
-
415
- @note: See note at function L{vincentys_}.
416
- '''
417
- return _sincosa6(phi2, phi1, lam21)[4]
418
-
419
-
420
339
  def _d3(wrap, lat1, lon1, lat2, lon2):
421
- '''(INTERNAL) Helper for _dE, _dS and _eA.
340
+ '''(INTERNAL) Helper for _dE, _dS, ....
422
341
  '''
423
342
  if wrap:
424
343
  d_lon, lat2, _ = _Wrap.latlon3(lon1, lat2, lon2, wrap)
425
344
  return radians(lat2), Phid(lat1=lat1), radians(d_lon)
426
345
  else: # for backward compaibility
427
- return Phid(lat2=lat2), Phid(lat1=lat1), Phid(d_lon=lon2 - lon1)
346
+ return Phid(lat2=lat2), Phid(lat1=lat1), radians(lon2 - lon1)
428
347
 
429
348
 
430
- def _dE(func_, earth, *wrap_lls):
349
+ def _dE(fun_, earth, wrap, *lls, **corr):
431
350
  '''(INTERNAL) Helper for ellipsoidal distances.
432
351
  '''
433
- E = _ellipsoidal(earth, func_)
434
- r = func_(*_d3(*wrap_lls), datum=E)
352
+ E = _ellipsoidal(earth, fun_)
353
+ r = fun_(*_d3(wrap, *lls), datum=E, **corr)
435
354
  return r * E.a
436
355
 
437
356
 
438
- def _dS(func_, radius, *wrap_lls, **adjust):
357
+ def _dS(fun_, radius, wrap, *lls, **adjust):
439
358
  '''(INTERNAL) Helper for spherical distances.
440
359
  '''
441
- r = func_(*_d3(*wrap_lls), **adjust)
360
+ r = fun_(*_d3(wrap, *lls), **adjust)
442
361
  if radius is not R_M:
443
- _, lat1, _, lat2, _ = wrap_lls
362
+ try: # datum?
363
+ radius = radius.ellipsoid.R1
364
+ except AttributeError:
365
+ pass # scalar?
366
+ lat1, _, lat2, _ = lls
444
367
  radius = _mean_radius(radius, lat1, lat2)
445
368
  return r * radius
446
369
 
447
370
 
448
- def _eA(excess_, radius, *wrap_lls):
449
- '''(INTERNAL) Helper for spherical excess or area.
450
- '''
451
- r = excess_(*_d3(*wrap_lls))
452
- if radius:
453
- _, lat1, _, lat2, _ = wrap_lls
454
- r *= _mean_radius(radius, lat1, lat2)**2
455
- return r
456
-
457
-
458
371
  def _ellipsoidal(earth, where):
459
372
  '''(INTERNAL) Helper for distances.
460
373
  '''
@@ -474,26 +387,29 @@ def equirectangular(lat1, lon1, lat2, lon2, radius=R_M, **adjust_limit_wrap):
474
387
  @arg lon2: End longitude (C{degrees}).
475
388
  @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or ellipsoid
476
389
  (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
477
- @kwarg adjust_limit_wrap: Optional keyword arguments for function L{equirectangular4}.
390
+ @kwarg adjust_limit_wrap: Optionally, keyword arguments for function L{equirectangular4}.
478
391
 
479
- @return: Distance (C{meter}, same units as B{C{radius}} or the ellipsoid or datum axes).
392
+ @return: Distance (C{meter}, same units as B{C{radius}} or the datum's
393
+ ellipsoid axes).
480
394
 
481
395
  @raise TypeError: Invalid B{C{radius}}.
482
396
 
483
397
  @see: Function L{equirectangular4} for more details, the available B{C{options}},
484
398
  errors, restrictions and other, approximate or accurate distance functions.
485
399
  '''
486
- d = sqrt(equirectangular4(Lat(lat1=lat1), Lon(lon1=lon1),
487
- Lat(lat2=lat2), Lon(lon2=lon2),
488
- **adjust_limit_wrap).distance2) # PYCHOK 4 vs 2-3
489
- return degrees2m(d, radius=_mean_radius(radius, lat1, lat2))
400
+ r = _mean_radius(radius, lat1, lat2)
401
+ t = equirectangular4(Lat(lat1=lat1), Lon(lon1=lon1),
402
+ Lat(lat2=lat2), Lon(lon2=lon2),
403
+ **adjust_limit_wrap) # PYCHOK 4 vs 2-3
404
+ return degrees2m(sqrt(t.distance2), radius=r)
490
405
 
491
406
 
492
407
  def _equirectangular(lat1, lon1, lat2, lon2, **adjust_limit_wrap):
493
408
  '''(INTERNAL) Helper for classes L{frechet._FrechetMeterRadians} and
494
409
  L{hausdorff._HausdorffMeterRedians}.
495
410
  '''
496
- return equirectangular4(lat1, lon1, lat2, lon2, **adjust_limit_wrap).distance2 * _RADIANS2
411
+ t = equirectangular4(lat1, lon1, lat2, lon2, **adjust_limit_wrap)
412
+ return t.distance2 * _RADIANS2
497
413
 
498
414
 
499
415
  def equirectangular4(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False):
@@ -507,8 +423,8 @@ def equirectangular4(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False):
507
423
  @arg lon1: Start longitude (C{degrees}).
508
424
  @arg lat2: End latitude (C{degrees}).
509
425
  @arg lon2: End longitude (C{degrees}).
510
- @kwarg adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the mean
511
- latitude (C{bool}).
426
+ @kwarg adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the
427
+ mean latitude (C{bool}).
512
428
  @kwarg limit: Optional limit for lat- and longitudinal deltas (C{degrees}) or C{None}
513
429
  or C{0} for unlimited.
514
430
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and B{C{lon2}}
@@ -521,10 +437,9 @@ def equirectangular4(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False):
521
437
  range and L{limiterrors<pygeodesy.limiterrors>} is C{True}.
522
438
 
523
439
  @see: U{Local, flat earth approximation<https://www.EdWilliams.org/avform.htm#flat>},
524
- functions L{equirectangular}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
525
- L{cosineLaw}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine},
526
- L{thomas} and L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*}
527
- and C{LatLon.equirectangularTo}.
440
+ functions L{equirectangular}, L{cosineLaw}, L{euclidean}, L{flatLocal} /
441
+ L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys} and methods
442
+ L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}.
528
443
  '''
529
444
  if wrap:
530
445
  d_lon, lat2, ulon2 = _Wrap.latlon3(lon1, lat2, lon2, wrap)
@@ -554,25 +469,24 @@ def euclidean(lat1, lon1, lat2, lon2, radius=R_M, adjust=True, wrap=False):
554
469
  @arg lon1: Start longitude (C{degrees}).
555
470
  @arg lat2: End latitude (C{degrees}).
556
471
  @arg lon2: End longitude (C{degrees}).
557
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
558
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
559
- L{a_f2Tuple}) to use.
560
- @kwarg adjust: Adjust the longitudinal delta by the cosine of
561
- the mean latitude (C{bool}).
562
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}}
563
- and B{C{lon2}} (C{bool}).
472
+ @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or ellipsoid
473
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) to use.
474
+ @kwarg adjust: Adjust the longitudinal delta by the cosine of the mean
475
+ latitude (C{bool}).
476
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
477
+ B{C{lon2}} (C{bool}).
564
478
 
565
- @return: Distance (C{meter}, same units as B{C{radius}} or the
566
- ellipsoid or datum axes).
479
+ @return: Distance (C{meter}, same units as B{C{radius}} or the ellipsoid
480
+ or datum axes).
567
481
 
568
482
  @raise TypeError: Invalid B{C{radius}}.
569
483
 
570
484
  @see: U{Distance between two (spherical) points
571
485
  <https://www.EdWilliams.org/avform.htm#Dist>}, functions L{euclid},
572
- L{euclidean_}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
573
- L{cosineLaw}, L{equirectangular}, L{flatLocal}/L{hubeny}, L{flatPolar},
574
- L{haversine}, L{thomas} and L{vincentys} and methods L{Ellipsoid.distance2},
575
- C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}.
486
+ L{euclidean_}, L{cosineLaw}, L{equirectangular}, L{flatLocal} /
487
+ L{hubeny}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys}
488
+ and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and
489
+ C{LatLon.equirectangularTo}.
576
490
  '''
577
491
  return _dS(euclidean_, radius, wrap, lat1, lon1, lat2, lon2, adjust=adjust)
578
492
 
@@ -583,15 +497,13 @@ def euclidean_(phi2, phi1, lam21, adjust=True):
583
497
  @arg phi2: End latitude (C{radians}).
584
498
  @arg phi1: Start latitude (C{radians}).
585
499
  @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
586
- @kwarg adjust: Adjust the longitudinal delta by the cosine
587
- of the mean latitude (C{bool}).
500
+ @kwarg adjust: Adjust the longitudinal delta by the cosine of the mean
501
+ latitude (C{bool}).
588
502
 
589
503
  @return: Angular distance (C{radians}).
590
504
 
591
- @see: Functions L{euclid}, L{euclidean}, L{cosineAndoyerLambert_},
592
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_},
593
- L{flatLocal_}/L{hubeny_}, L{flatPolar_}, L{haversine_},
594
- L{thomas_} and L{vincentys_}.
505
+ @see: Functions L{euclid}, L{euclidean}, L{cosineLaw_}, L{flatLocal_} /
506
+ L{hubeny_}, L{flatPolar_}, L{haversine_}, L{thomas_} and L{vincentys_}.
595
507
  '''
596
508
  if adjust:
597
509
  lam21 *= _scale_rad(phi2, phi1)
@@ -618,7 +530,9 @@ def excessAbc_(A, b, c):
618
530
  c = Radians_(c=c) * _0_5
619
531
 
620
532
  sA, cA, sb, cb, sc, cc = sincos2_(A, b, c)
621
- return atan2(sA * sb * sc, cb * cc + cA * sb * sc) * _2_0
533
+ s = sA * sb * sc
534
+ c = cA * sb * sc + cc * cb
535
+ return atan2(s, c) * _2_0
622
536
 
623
537
 
624
538
  def excessCagnoli_(a, b, c):
@@ -640,11 +554,11 @@ def excessCagnoli_(a, b, c):
640
554
  b = Radians_(b=b)
641
555
  c = Radians_(c=c)
642
556
 
643
- s = fsumf_(a, b, c) * _0_5
644
- _s = sin
645
- r = _s(s) * _s(s - a) * _s(s - b) * _s(s - c)
646
- c = cos(a * _0_5) * cos(b * _0_5) * cos(c * _0_5)
647
- r = asin(sqrt(r) * _0_5 / c) if c and r > 0 else _0_0
557
+ r = _maprod(cos, a * _0_5, b * _0_5, c * _0_5)
558
+ if r:
559
+ s = fsumf_(a, b, c) * _0_5
560
+ t = _maprod(sin, s, s - a, s - b, s - c)
561
+ r = asin1(sqrt(t) * _0_5 / r) if t > 0 else _0_0
648
562
  return Radians(Cagnoli=r * _2_0)
649
563
 
650
564
 
@@ -663,9 +577,10 @@ def excessGirard_(A, B, C):
663
577
  @see: Function L{excessLHuilier_} and U{Spherical trigonometry
664
578
  <https://WikiPedia.org/wiki/Spherical_trigonometry>}.
665
579
  '''
666
- return Radians(Girard=fsumf_(Radians_(A=A),
667
- Radians_(B=B),
668
- Radians_(C=C), -PI))
580
+ r = fsumf_(Radians_(A=A),
581
+ Radians_(B=B),
582
+ Radians_(C=C), -PI)
583
+ return Radians(Girard=r)
669
584
 
670
585
 
671
586
  def excessLHuilier_(a, b, c):
@@ -687,10 +602,9 @@ def excessLHuilier_(a, b, c):
687
602
  b = Radians_(b=b)
688
603
  c = Radians_(c=c)
689
604
 
690
- s = fsumf_(a, b, c) * _0_5
691
- _t = tan_2
692
- r = _t(s) * _t(s - a) * _t(s - b) * _t(s - c)
693
- r = atan(sqrt(r)) if r > 0 else _0_0
605
+ s = fsumf_(a, b, c) * _0_5
606
+ r = _maprod(tan_2, s, s - a, s - b, s - c)
607
+ r = atan(sqrt(r)) if r > 0 else _0_0
694
608
  return Radians(LHuilier=r * _4_0)
695
609
 
696
610
 
@@ -704,11 +618,10 @@ def excessKarney(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
704
618
  @arg lon1: Start longitude (C{degrees}).
705
619
  @arg lat2: End latitude (C{degrees}).
706
620
  @arg lon2: End longitude (C{degrees}).
707
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
708
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
709
- L{a_f2Tuple}) or C{None}.
710
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
711
- B{C{lat2}} and B{C{lon2}} (C{bool}).
621
+ @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or ellipsoid
622
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) or C{None}.
623
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
624
+ B{C{lon2}} (C{bool}).
712
625
 
713
626
  @return: Surface area, I{signed} (I{square} C{meter} or the same units as
714
627
  B{C{radius}} I{squared}) or the I{spherical excess} (C{radians})
@@ -722,7 +635,10 @@ def excessKarney(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
722
635
 
723
636
  @see: Functions L{excessKarney_} and L{excessQuad}.
724
637
  '''
725
- return _eA(excessKarney_, radius, wrap, lat1, lon1, lat2, lon2)
638
+ r = excessKarney_(*_d3(wrap, lat1, lon1, lat2, lon2))
639
+ if radius:
640
+ r *= _mean_radius(radius, lat1, lat2)**2
641
+ return r
726
642
 
727
643
 
728
644
  def excessKarney_(phi2, phi1, lam21):
@@ -751,12 +667,11 @@ def excessKarney_(phi2, phi1, lam21):
751
667
  #
752
668
  # where E is the spherical excess of the trapezium obtained by extending
753
669
  # the edge to the equator-circle vector for each edge (see also ***).
754
- _t = tan_2
755
- t2 = _t(phi2)
756
- t1 = _t(phi1)
757
- t = _t(lam21, lam21=None)
758
- return Radians(Karney=atan2(t * (t1 + t2),
759
- _1_0 + (t1 * t2)) * _2_0)
670
+ t2 = tan_2(phi2)
671
+ t1 = tan_2(phi1)
672
+ c = (t1 * t2) + _1_0
673
+ s = (t1 + t2) * tan_2(lam21, lam21=None)
674
+ return Radians(Karney=atan2(s, c) * _2_0)
760
675
 
761
676
 
762
677
  # ***) Original post no longer available, following is a copy of the main part
@@ -806,11 +721,10 @@ def excessQuad(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
806
721
  @arg lon1: Start longitude (C{degrees}).
807
722
  @arg lat2: End latitude (C{degrees}).
808
723
  @arg lon2: End longitude (C{degrees}).
809
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
810
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
811
- L{a_f2Tuple}) or C{None}.
812
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
813
- B{C{lat2}} and B{C{lon2}} (C{bool}).
724
+ @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or ellipsoid
725
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) or C{None}.
726
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
727
+ B{C{lon2}} (C{bool}).
814
728
 
815
729
  @return: Surface area, I{signed} (I{square} C{meter} or the same units as
816
730
  B{C{radius}} I{squared}) or the I{spherical excess} (C{radians})
@@ -822,7 +736,10 @@ def excessQuad(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
822
736
 
823
737
  @see: Function L{excessQuad_} and L{excessKarney}.
824
738
  '''
825
- return _eA(excessQuad_, radius, wrap, lat1, lon1, lat2, lon2)
739
+ r = excessQuad_(*_d3(wrap, lat1, lon1, lat2, lon2))
740
+ if radius:
741
+ r *= _mean_radius(radius, lat1, lat2)**2
742
+ return r
826
743
 
827
744
 
828
745
  def excessQuad_(phi2, phi1, lam21):
@@ -838,9 +755,9 @@ def excessQuad_(phi2, phi1, lam21):
838
755
  @see: Function L{excessQuad} and U{Spherical trigonometry
839
756
  <https://WikiPedia.org/wiki/Spherical_trigonometry>}.
840
757
  '''
841
- s = sin((phi2 + phi1) * _0_5)
842
758
  c = cos((phi2 - phi1) * _0_5)
843
- return Radians(Quad=atan2(tan_2(lam21) * s, c) * _2_0)
759
+ s = sin((phi2 + phi1) * _0_5) * tan_2(lam21)
760
+ return Radians(Quad=atan2(s, c) * _2_0)
844
761
 
845
762
 
846
763
  def flatLocal(lat1, lon1, lat2, lon2, datum=_WGS84, scaled=True, wrap=False):
@@ -853,30 +770,28 @@ def flatLocal(lat1, lon1, lat2, lon2, datum=_WGS84, scaled=True, wrap=False):
853
770
  @arg lon1: Start longitude (C{degrees}).
854
771
  @arg lat2: End latitude (C{degrees}).
855
772
  @arg lon2: End longitude (C{degrees}).
856
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
857
- L{Ellipsoid2} or L{a_f2Tuple}) to use.
858
- @kwarg scaled: Scale prime_vertical by C{cos(B{phi})} (C{bool}),
859
- see method L{pygeodesy.Ellipsoid.roc2_}.
860
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
861
- B{C{lat2}} and B{C{lon2}} (C{bool}).
862
-
863
- @return: Distance (C{meter}, same units as the B{C{datum}}'s
864
- ellipsoid axes).
773
+ @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2}
774
+ or L{a_f2Tuple}) to use.
775
+ @kwarg scaled: Scale prime_vertical by C{cos(B{phi})} (C{bool}), see
776
+ method L{pygeodesy.Ellipsoid.roc2_}.
777
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
778
+ B{C{lon2}} (C{bool}).
779
+
780
+ @return: Distance (C{meter}, same units as the B{C{datum}}'s or ellipsoid axes).
865
781
 
866
782
  @raise TypeError: Invalid B{C{datum}}.
867
783
 
868
- @note: The meridional and prime_vertical radii of curvature
869
- are taken and scaled at the mean of both latitude.
784
+ @note: The meridional and prime_vertical radii of curvature are taken and
785
+ scaled at the mean of both latitude.
870
786
 
871
- @see: Functions L{flatLocal_} or L{hubeny_}, L{cosineLaw}, L{flatPolar},
872
- L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
873
- L{equirectangular}, L{euclidean}, L{haversine}, L{thomas},
874
- L{vincentys}, method L{Ellipsoid.distance2} and U{local, flat
875
- earth approximation<https://www.EdWilliams.org/avform.htm#flat>}.
787
+ @see: Functions L{flatLocal_} or L{hubeny_}, L{cosineLaw}, L{equirectangular},
788
+ L{euclidean}, L{flatPolar}, L{haversine}, L{thomas} and L{vincentys}, method
789
+ L{Ellipsoid.distance2} and U{local, flat earth approximation
790
+ <https://www.EdWilliams.org/avform.htm#flat>}.
876
791
  '''
792
+ t = _d3(wrap, lat1, lon1, lat2, lon2)
877
793
  E = _ellipsoidal(datum, flatLocal)
878
- return E._hubeny_2(*_d3(wrap, lat1, lon1, lat2, lon2),
879
- scaled=scaled, squared=False) * E.a
794
+ return E._hubeny_2(*t, scaled=scaled, squared=False) * E.a
880
795
 
881
796
  hubeny = flatLocal # PYCHOK for Karl Hubeny
882
797
 
@@ -890,23 +805,21 @@ def flatLocal_(phi2, phi1, lam21, datum=_WGS84, scaled=True):
890
805
  @arg phi2: End latitude (C{radians}).
891
806
  @arg phi1: Start latitude (C{radians}).
892
807
  @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
893
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
894
- L{Ellipsoid2} or L{a_f2Tuple}) to use.
895
- @kwarg scaled: Scale prime_vertical by C{cos(B{phi})} (C{bool}),
896
- see method L{pygeodesy.Ellipsoid.roc2_}.
808
+ @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2}
809
+ or L{a_f2Tuple}) to use.
810
+ @kwarg scaled: Scale prime_vertical by C{cos(B{phi})} (C{bool}), see
811
+ method L{pygeodesy.Ellipsoid.roc2_}.
897
812
 
898
813
  @return: Angular distance (C{radians}).
899
814
 
900
815
  @raise TypeError: Invalid B{C{datum}}.
901
816
 
902
- @note: The meridional and prime_vertical radii of curvature
903
- are taken and scaled I{at the mean of both latitude}.
817
+ @note: The meridional and prime_vertical radii of curvature are taken and
818
+ scaled I{at the mean of both latitude}.
904
819
 
905
- @see: Functions L{flatLocal} or L{hubeny}, L{cosineAndoyerLambert_},
906
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_}, L{flatPolar_},
907
- L{euclidean_}, L{haversine_}, L{thomas_} and L{vincentys_} and
908
- U{local, flat earth approximation
909
- <https://www.EdWilliams.org/avform.htm#flat>}.
820
+ @see: Functions L{flatLocal} or L{hubeny}, L{cosineLaw_}, L{flatPolar_},
821
+ L{euclidean_}, L{haversine_}, L{thomas_} and L{vincentys_} and U{local,
822
+ flat earth approximation<https://www.EdWilliams.org/avform.htm#flat>}.
910
823
  '''
911
824
  E = _ellipsoidal(datum, flatLocal_)
912
825
  return E._hubeny_2(phi2, phi1, lam21, scaled=scaled, squared=False)
@@ -915,40 +828,34 @@ hubeny_ = flatLocal_ # PYCHOK for Karl Hubeny
915
828
 
916
829
 
917
830
  def flatPolar(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
918
- '''Compute the distance between two (spherical) points using
919
- the U{polar coordinate flat-Earth <https://WikiPedia.org/wiki/
920
- Geographical_distance#Polar_coordinate_flat-Earth_formula>}
921
- formula.
831
+ '''Compute the distance between two (spherical) points using the U{polar
832
+ coordinate flat-Earth<https://WikiPedia.org/wiki/Geographical_distance
833
+ #Polar_coordinate_flat-Earth_formula>} formula.
922
834
 
923
835
  @arg lat1: Start latitude (C{degrees}).
924
836
  @arg lon1: Start longitude (C{degrees}).
925
837
  @arg lat2: End latitude (C{degrees}).
926
838
  @arg lon2: End longitude (C{degrees}).
927
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
928
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
929
- L{a_f2Tuple}) to use.
930
- @kwarg wrap: If C{True}, wrap or I{normalize} and B{C{lat2}}
931
- and B{C{lon2}} (C{bool}).
839
+ @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or ellipsoid
840
+ (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}) to use.
841
+ @kwarg wrap: If C{True}, wrap or I{normalize} and B{C{lat2}} and B{C{lon2}}
842
+ (C{bool}).
932
843
 
933
- @return: Distance (C{meter}, same units as B{C{radius}} or the
934
- ellipsoid or datum axes).
844
+ @return: Distance (C{meter}, same units as B{C{radius}} or the datum's or
845
+ ellipsoid axes).
935
846
 
936
847
  @raise TypeError: Invalid B{C{radius}}.
937
848
 
938
- @see: Functions L{flatPolar_}, L{cosineAndoyerLambert},
939
- L{cosineForsytheAndoyerLambert},L{cosineLaw},
940
- L{flatLocal}/L{hubeny}, L{equirectangular},
941
- L{euclidean}, L{haversine}, L{thomas} and
942
- L{vincentys}.
849
+ @see: Functions L{flatPolar_}, L{cosineLaw}, L{flatLocal} / L{hubeny},
850
+ L{equirectangular}, L{euclidean}, L{haversine}, L{thomas} and L{vincentys}.
943
851
  '''
944
852
  return _dS(flatPolar_, radius, wrap, lat1, lon1, lat2, lon2)
945
853
 
946
854
 
947
855
  def flatPolar_(phi2, phi1, lam21):
948
- '''Compute the I{angular} distance between two (spherical) points
949
- using the U{polar coordinate flat-Earth<https://WikiPedia.org/wiki/
950
- Geographical_distance#Polar_coordinate_flat-Earth_formula>}
951
- formula.
856
+ '''Compute the I{angular} distance between two (spherical) points using the
857
+ U{polar coordinate flat-Earth<https://WikiPedia.org/wiki/Geographical_distance
858
+ #Polar_coordinate_flat-Earth_formula>} formula.
952
859
 
953
860
  @arg phi2: End latitude (C{radians}).
954
861
  @arg phi1: Start latitude (C{radians}).
@@ -956,10 +863,8 @@ def flatPolar_(phi2, phi1, lam21):
956
863
 
957
864
  @return: Angular distance (C{radians}).
958
865
 
959
- @see: Functions L{flatPolar}, L{cosineAndoyerLambert_},
960
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_},
961
- L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{haversine_},
962
- L{thomas_} and L{vincentys_}.
866
+ @see: Functions L{flatPolar}, L{cosineLaw_}, L{euclidean_}, L{flatLocal_} /
867
+ L{hubeny_}, L{haversine_}, L{thomas_} and L{vincentys_}.
963
868
  '''
964
869
  a = fabs(PI_2 - phi1) # co-latitude
965
870
  b = fabs(PI_2 - phi2) # co-latitude
@@ -1001,14 +906,14 @@ def hartzell(pov, los=False, earth=_WGS84, **name_LatLon_and_kwds):
1001
906
  or C{None} to point to the center of the earth.
1002
907
  @kwarg earth: The earth model (L{Datum}, L{Ellipsoid}, L{Ellipsoid2},
1003
908
  L{a_f2Tuple} or a C{scalar} earth radius in C{meter}).
1004
- @kwarg name_LatLon_and_kwds: Optional, overriding C{B{name}="hartzell"}
1005
- (C{str}), class C{B{LatLon}=None} to return the intersection
1006
- plus additional C{LatLon} keyword arguments, include the
1007
- B{C{datum}} if different and to convert from B{C{earth}}.
909
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}="hartzell"} (C{str}), class
910
+ C{B{LatLon}=None} to return the intersection and optionally,
911
+ additional C{LatLon} keyword arguments, include the B{C{datum}}
912
+ if different from and to convert from B{C{earth}}.
1008
913
 
1009
- @return: The intersection (L{Vector3d}, B{C{pov}}'s C{cartesian type} or the
1010
- given B{C{LatLon}} instance) with attribute C{height} set to the
1011
- distance to the B{C{pov}}.
914
+ @return: The intersection (L{Vector3d}, B{C{pov}}'s C{cartesian type} or
915
+ the given B{C{LatLon}} instance) with attribute C{height} set to
916
+ the distance to the B{C{pov}}.
1012
917
 
1013
918
  @raise IntersectionError: Invalid B{C{pov}} or B{C{pov}} inside the earth or
1014
919
  invalid B{C{los}} or B{C{los}} points outside or
@@ -1017,30 +922,29 @@ def hartzell(pov, los=False, earth=_WGS84, **name_LatLon_and_kwds):
1017
922
  @raise TypeError: Invalid B{C{earth}}, C{ellipsoid} or C{datum}.
1018
923
 
1019
924
  @see: Class L{Los}, functions L{tyr3d} and L{hartzell4} and methods
1020
- L{Ellipsoid.hartzell4} and any C{Cartesian.hartzell} and C{LatLon.hartzell}.
925
+ L{Ellipsoid.hartzell4}, any C{Cartesian.hartzell} and C{LatLon.hartzell}.
1021
926
  '''
1022
- n, LatLon_and_kwds = _name2__(name_LatLon_and_kwds, name__=hartzell)
927
+ n, kwds = _name2__(name_LatLon_and_kwds, name__=hartzell)
1023
928
  try:
1024
929
  D = _spherical_datum(earth, name__=hartzell)
1025
930
  r, h, i = _MODS.triaxials._hartzell3(pov, los, D.ellipsoid._triaxial)
1026
931
 
1027
932
  C = _MODS.cartesianBase.CartesianBase
1028
- if LatLon_and_kwds:
933
+ if kwds:
1029
934
  c = C(r, datum=D)
1030
- r = c.toLatLon(**_xkwds(LatLon_and_kwds, height=h))
935
+ r = c.toLatLon(**_xkwds(kwds, height=h))
1031
936
  elif isinstance(r, C):
1032
937
  r.height = h
1033
938
  if i:
1034
939
  r._iteration = i
1035
940
  except Exception as x:
1036
- raise IntersectionError(pov=pov, los=los, earth=earth, cause=x,
1037
- **LatLon_and_kwds)
941
+ raise IntersectionError(pov=pov, los=los, earth=earth, cause=x, **kwds)
1038
942
  return _xnamed(r, n) if n else r
1039
943
 
1040
944
 
1041
945
  def haversine(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
1042
- '''Compute the distance between two (spherical) points using the
1043
- U{Haversine<https://www.Movable-Type.co.UK/scripts/latlong.html>} formula.
946
+ '''Compute the distance between two (spherical) points using the U{Haversine
947
+ <https://www.Movable-Type.co.UK/scripts/latlong.html>} formula.
1044
948
 
1045
949
  @arg lat1: Start latitude (C{degrees}).
1046
950
  @arg lon1: Start longitude (C{degrees}).
@@ -1056,9 +960,8 @@ def haversine(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
1056
960
  @raise TypeError: Invalid B{C{radius}}.
1057
961
 
1058
962
  @see: U{Distance between two (spherical) points
1059
- <https://www.EdWilliams.org/avform.htm#Dist>}, functions
1060
- L{cosineLaw}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
1061
- L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar},
963
+ <https://www.EdWilliams.org/avform.htm#Dist>}, functions L{cosineLaw},
964
+ L{equirectangular}, L{euclidean}, L{flatLocal} / L{hubeny}, L{flatPolar},
1062
965
  L{thomas} and L{vincentys} and methods L{Ellipsoid.distance2},
1063
966
  C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}.
1064
967
 
@@ -1077,18 +980,13 @@ def haversine_(phi2, phi1, lam21):
1077
980
 
1078
981
  @return: Angular distance (C{radians}).
1079
982
 
1080
- @see: Functions L{haversine}, L{cosineAndoyerLambert_},
1081
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_},
1082
- L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{flatPolar_},
1083
- L{thomas_} and L{vincentys_}.
983
+ @see: Functions L{haversine}, L{cosineLaw_}, L{euclidean_}, L{flatLocal_} /
984
+ L{hubeny_}, L{flatPolar_}, L{thomas_} and L{vincentys_}.
1084
985
 
1085
986
  @note: See note at function L{vincentys_}.
1086
987
  '''
1087
- def _hsin(rad):
1088
- return sin(rad * _0_5)**2
1089
-
1090
- h = _hsin(phi2 - phi1) + cos(phi1) * cos(phi2) * _hsin(lam21) # haversine
1091
- return atan2(sqrt0(h), sqrt0(_1_0 - h)) * _2_0 # == asin(sqrt(h)) * 2
988
+ h = hav(phi2 - phi1) + cos(phi1) * cos(phi2) * hav(lam21) # haversine
989
+ return atan2(sqrt0(h), sqrt0(_1_0 - h)) * _2_0 # == asin1(sqrt(h)) * 2
1092
990
 
1093
991
 
1094
992
  def heightOf(angle, distance, radius=R_M):
@@ -1125,22 +1023,23 @@ def heightOf(angle, distance, radius=R_M):
1125
1023
  raise _ValueError(angle=angle, distance=distance, radius=radius)
1126
1024
 
1127
1025
 
1128
- def heightOrthometric(h_ll, N):
1026
+ def heightOrthometric(h_loc, N):
1129
1027
  '''Get the I{orthometric} height B{H}, the height above the geoid, earth surface.
1130
1028
 
1131
- @arg h_ll: The height above the ellipsoid (C{meter}) or an I{ellipsoidal}
1132
- location (C{LatLon} with a C{height} or C{h} attribute).
1029
+ @arg h_loc: The height above the ellipsoid (C{meter}) or an I{ellipsoidal}
1030
+ location (C{LatLon} or C{Cartesian} with a C{height} or C{h}
1031
+ attribute), otherwise C{0 meter}.
1133
1032
  @arg N: The I{geoid} height (C{meter}), the height of the geoid above the
1134
- ellipsoid at the same B{C{h_ll}} location.
1033
+ ellipsoid at the same B{C{h_loc}} location.
1135
1034
 
1136
1035
  @return: I{Orthometric} height C{B{H} = B{h} - B{N}} (C{meter}, same units
1137
1036
  as B{C{h}} and B{C{N}}).
1138
1037
 
1139
- @see: U{Ellipsoid, Geoid, and Othometric Heights<https://www.NGS.NOAA.gov/
1038
+ @see: U{Ellipsoid, Geoid, and Orthometric Heights<https://www.NGS.NOAA.gov/
1140
1039
  GEOID/PRESENTATIONS/2007_02_24_CCPS/Roman_A_PLSC2007notes.pdf>}, page
1141
1040
  6 and module L{pygeodesy.geoids}.
1142
1041
  '''
1143
- h = h_ll if _isHeight(h_ll) else _xattr(h_ll, height=_xattr(h_ll, h=0))
1042
+ h = h_loc if _isHeight(h_loc) else _xattr(h_loc, height=_xattr(h_loc, h=0))
1144
1043
  return Height(H=Height(h=h) - Height(N=N))
1145
1044
 
1146
1045
 
@@ -1162,9 +1061,11 @@ def horizon(height, radius=R_M, refraction=False):
1162
1061
  if min(h, r) < 0:
1163
1062
  raise _ValueError(height=height, radius=radius)
1164
1063
 
1165
- d2 = ((r * 2.415750694528) if refraction else # 2.0 / 0.8279
1166
- fsumf_(r, r, h)) * h
1167
- return sqrt0(d2)
1064
+ if refraction:
1065
+ r *= 2.415750694528 # 2.0 / 0.8279
1066
+ else:
1067
+ r += r + h
1068
+ return sqrt0(r * h)
1168
1069
 
1169
1070
 
1170
1071
  class _idllmn6(object): # see also .geodesicw._wargs, .latlonBase._toCartesian3, .vector2d._numpy
@@ -1211,8 +1112,8 @@ _idllmn6 = _idllmn6() # PYCHOK singleton
1211
1112
 
1212
1113
  def intersection2(lat1, lon1, bearing1,
1213
1114
  lat2, lon2, bearing2, datum=None, wrap=False, small=_100km): # was=True
1214
- '''I{Conveniently} compute the intersection of two lines each defined
1215
- by a (geodetic) point and a bearing from North, using either ...
1115
+ '''I{Conveniently} compute the intersection of two lines each defined by
1116
+ a (geodetic) point and a bearing from North, using either ...
1216
1117
 
1217
1118
  1) L{vector3d.intersection3d3} for B{C{small}} distances (below 100 Km
1218
1119
  or about 0.88 degrees) or if I{no} B{C{datum}} is specified, or ...
@@ -1232,33 +1133,29 @@ def intersection2(lat1, lon1, bearing1,
1232
1133
 
1233
1134
  @arg lat1: Latitude of the first point (C{degrees}).
1234
1135
  @arg lon1: Longitude of the first point (C{degrees}).
1235
- @arg bearing1: Bearing at the first point (compass C{degrees}).
1136
+ @arg bearing1: Bearing at the first point (compass C{degrees360}).
1236
1137
  @arg lat2: Latitude of the second point (C{degrees}).
1237
1138
  @arg lon2: Longitude of the second point (C{degrees}).
1238
- @arg bearing2: Bearing at the second point (compass C{degrees}).
1139
+ @arg bearing2: Bearing at the second point (compass C{degrees360}).
1239
1140
  @kwarg datum: Optional datum (L{Datum}) or ellipsoid (L{Ellipsoid},
1240
- L{Ellipsoid2} or L{a_f2Tuple}) or C{scalar} earth
1241
- radius (C{meter}, same units as B{C{radius1}} and
1242
- B{C{radius2}}) or C{None}.
1243
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}}
1244
- and B{C{lon2}} (C{bool}).
1141
+ L{Ellipsoid2} or L{a_f2Tuple}) or C{scalar} earth radius
1142
+ (C{meter}, same units as B{C{radius1}} and B{C{radius2}})
1143
+ or C{None}.
1144
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
1145
+ B{C{lon2}} (C{bool}).
1245
1146
  @kwarg small: Upper limit for small distances (C{meter}).
1246
1147
 
1247
- @return: A L{LatLon2Tuple}C{(lat, lon)} with the lat- and
1248
- longitude of the intersection point.
1148
+ @return: Intersection point (L{LatLon2Tuple}C{(lat, lon)}).
1249
1149
 
1250
- @raise IntersectionError: Ambiguous or infinite intersection
1251
- or colinear, parallel or otherwise
1252
- non-intersecting lines.
1150
+ @raise IntersectionError: No or an ambiguous intersection or colinear,
1151
+ parallel or otherwise non-intersecting lines.
1253
1152
 
1254
1153
  @raise TypeError: Invalid B{C{datum}}.
1255
1154
 
1256
- @raise UnitError: Invalid B{C{lat1}}, B{C{lon1}}, B{C{bearing1}},
1257
- B{C{lat2}}, B{C{lon2}} or B{C{bearing2}}.
1155
+ @raise UnitError: Invalid B{C{lat1}}, B{C{lon1}}, B{C{bearing1}}, B{C{lat2}},
1156
+ B{C{lon2}} or B{C{bearing2}}.
1258
1157
 
1259
1158
  @see: Method L{RhumbLine.intersection2}.
1260
-
1261
- @note: The returned intersections may be near-antipodal.
1262
1159
  '''
1263
1160
  b1 = Bearing(bearing1=bearing1)
1264
1161
  b2 = Bearing(bearing2=bearing2)
@@ -1304,26 +1201,24 @@ def intersections2(lat1, lon1, radius1,
1304
1201
  @arg lat2: Latitude of the second circle center (C{degrees}).
1305
1202
  @arg lon2: Longitude of the second circle center (C{degrees}).
1306
1203
  @arg radius2: Radius of the second circle (C{meter}, same units as B{C{radius1}}).
1307
- @kwarg datum: Optional datum (L{Datum}) or ellipsoid (L{Ellipsoid},
1308
- L{Ellipsoid2} or L{a_f2Tuple}) or C{scalar} earth
1309
- radius (C{meter}, same units as B{C{radius1}} and
1310
- B{C{radius2}}) or C{None}.
1311
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}}
1312
- and B{C{lon2}} (C{bool}).
1204
+ @kwarg datum: Optional datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2}
1205
+ or L{a_f2Tuple}) or C{scalar} earth radius (C{meter}, same units as
1206
+ B{C{radius1}} and B{C{radius2}}) or C{None}.
1207
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and B{C{lon2}}
1208
+ (C{bool}).
1313
1209
  @kwarg small: Upper limit for small distances (C{meter}).
1314
1210
 
1315
- @return: 2-Tuple of the intersection points, each a
1316
- L{LatLon2Tuple}C{(lat, lon)}. For abutting circles, the
1317
- points are the same instance, aka the I{radical center}.
1211
+ @return: 2-Tuple of the intersection points, each a L{LatLon2Tuple}C{(lat, lon)}.
1212
+ Both points are the same instance, aka the I{radical center} if the
1213
+ circles are abutting
1318
1214
 
1319
- @raise IntersectionError: Concentric, antipodal, invalid or
1320
- non-intersecting circles or no
1321
- convergence.
1215
+ @raise IntersectionError: Concentric, antipodal, invalid or non-intersecting
1216
+ circles or no convergence.
1322
1217
 
1323
1218
  @raise TypeError: Invalid B{C{datum}}.
1324
1219
 
1325
- @raise UnitError: Invalid B{C{lat1}}, B{C{lon1}}, B{C{radius1}},
1326
- B{C{lat2}}, B{C{lon2}} or B{C{radius2}}.
1220
+ @raise UnitError: Invalid B{C{lat1}}, B{C{lon1}}, B{C{radius1}}, B{C{lat2}},
1221
+ B{C{lon2}} or B{C{radius2}}.
1327
1222
  '''
1328
1223
  r1 = Radius_(radius1=radius1)
1329
1224
  r2 = Radius_(radius2=radius2)
@@ -1397,7 +1292,7 @@ def _isequalTo(p1, p2, eps=EPS):
1397
1292
  fabs(p1.lon - p2.lon) <= eps) if eps else (p1.latlon == p2.latlon)
1398
1293
 
1399
1294
 
1400
- def _isequalTo_(p1, p2, eps=EPS):
1295
+ def _isequalTo_(p1, p2, eps=EPS): # underscore_!
1401
1296
  '''(INTERNAL) Compare 2 point phi-/lams ignoring C{class}.
1402
1297
  '''
1403
1298
  return (fabs(p1.phi - p2.phi) <= eps and
@@ -1413,11 +1308,11 @@ def isnormal(lat, lon, eps=0):
1413
1308
  @kwarg eps: Optional tolerance C{degrees}).
1414
1309
 
1415
1310
  @return: C{True} if C{(abs(B{lat}) + B{eps}) <= 90} and
1416
- C{(abs(B{lon}) + B{eps}) <= 180}, C{False} othwerwise.
1311
+ C{(abs(B{lon}) + B{eps}) <= 180}, C{False} otherwise.
1417
1312
 
1418
1313
  @see: Functions L{isnormal_} and L{normal}.
1419
1314
  '''
1420
- return (_90_0 - fabs(lat)) >= eps and _loneg(fabs(lon)) >= eps
1315
+ return _loneg(fabs(lon)) >= eps and (_90_0 - fabs(lat)) >= eps # co-latitude
1421
1316
 
1422
1317
 
1423
1318
  def isnormal_(phi, lam, eps=0):
@@ -1436,6 +1331,12 @@ def isnormal_(phi, lam, eps=0):
1436
1331
  return (PI_2 - fabs(phi)) >= eps and (PI - fabs(lam)) >= eps
1437
1332
 
1438
1333
 
1334
+ def _maprod(fun_, *ts):
1335
+ '''(INTERNAL) Helper for C{excessCagnoli_} and C{excessLHuilier_}.
1336
+ '''
1337
+ return fprod(map(fun_, ts))
1338
+
1339
+
1439
1340
  def _normal2(a, b, n_2, n, n2):
1440
1341
  '''(INTERNAL) Helper for C{normal} and C{normal_}.
1441
1342
  '''
@@ -1454,10 +1355,10 @@ def normal(lat, lon, **name):
1454
1355
 
1455
1356
  @arg lat: Latitude (C{degrees}).
1456
1357
  @arg lon: Longitude (C{degrees}).
1457
- @kwarg name: Optional, overriding C{B{name}="normal"} (C{str}).
1358
+ @kwarg name: Optional C{B{name}="normal"} (C{str}).
1458
1359
 
1459
- @return: L{LatLon2Tuple}C{(lat, lon)} with C{abs(lat) <= 90}
1460
- and C{abs(lon) <= 180}.
1360
+ @return: L{LatLon2Tuple}C{(lat, lon)} with C{-90 <= lat <= 90}
1361
+ and C{-180 <= lon <= 180}.
1461
1362
 
1462
1363
  @see: Functions L{normal_} and L{isnormal}.
1463
1364
  '''
@@ -1470,7 +1371,7 @@ def normal_(phi, lam, **name):
1470
1371
 
1471
1372
  @arg phi: Latitude (C{radians}).
1472
1373
  @arg lam: Longitude (C{radians}).
1473
- @kwarg name: Optional, overriding C{B{name}="normal_"} (C{str}).
1374
+ @kwarg name: Optional C{B{name}="normal_"} (C{str}).
1474
1375
 
1475
1376
  @return: L{PhiLam2Tuple}C{(phi, lam)} with C{abs(phi) <= PI/2}
1476
1377
  and C{abs(lam) <= PI}.
@@ -1544,29 +1445,24 @@ def _radical2(d, r1, r2, **name): # in .ellipsoidalBaseDI, .sphericalTrigonomet
1544
1445
 
1545
1446
 
1546
1447
  def radical2(distance, radius1, radius2, **name):
1547
- '''Compute the I{radical ratio} and I{radical line} of two
1548
- U{intersecting circles<https://MathWorld.Wolfram.com/
1549
- Circle-CircleIntersection.html>}.
1448
+ '''Compute the I{radical ratio} and I{radical line} of two U{intersecting
1449
+ circles<https://MathWorld.Wolfram.com/Circle-CircleIntersection.html>}.
1550
1450
 
1551
- The I{radical line} is perpendicular to the axis thru the
1552
- centers of the circles at C{(0, 0)} and C{(B{distance}, 0)}.
1451
+ The I{radical line} is perpendicular to the axis thru the centers of
1452
+ the circles at C{(0, 0)} and C{(B{distance}, 0)}.
1553
1453
 
1554
1454
  @arg distance: Distance between the circle centers (C{scalar}).
1555
1455
  @arg radius1: Radius of the first circle (C{scalar}).
1556
1456
  @arg radius2: Radius of the second circle (C{scalar}).
1557
1457
  @kwarg name: Optional C{B{name}=NN} (C{str}).
1558
1458
 
1559
- @return: A L{Radical2Tuple}C{(ratio, xline)} where C{0.0 <=
1560
- ratio <= 1.0} and C{xline} is along the B{C{distance}}.
1561
-
1562
- @raise IntersectionError: The B{C{distance}} exceeds the sum
1563
- of B{C{radius1}} and B{C{radius2}}.
1459
+ @return: A L{Radical2Tuple}C{(ratio, xline)} where C{0.0 <= ratio <=
1460
+ 1.0} and C{xline} is along the B{C{distance}}.
1564
1461
 
1565
- @raise UnitError: Invalid B{C{distance}}, B{C{radius1}} or
1566
- B{C{radius2}}.
1462
+ @raise IntersectionError: The B{C{distance}} exceeds the sum of
1463
+ B{C{radius1}} and B{C{radius2}}.
1567
1464
 
1568
- @see: U{Circle-Circle Intersection
1569
- <https://MathWorld.Wolfram.com/Circle-CircleIntersection.html>}.
1465
+ @raise UnitError: Invalid B{C{distance}}, B{C{radius1}} or B{C{radius2}}.
1570
1466
  '''
1571
1467
  d = Distance_(distance, low=_0_0)
1572
1468
  r1 = Radius_(radius1=radius1)
@@ -1633,57 +1529,53 @@ def _sincosa6(phi2, phi1, lam21): # [4] in cosineLaw
1633
1529
 
1634
1530
 
1635
1531
  def thomas(lat1, lon1, lat2, lon2, datum=_WGS84, wrap=False):
1636
- '''Compute the distance between two (ellipsoidal) points using
1637
- U{Thomas'<https://apps.DTIC.mil/dtic/tr/fulltext/u2/703541.pdf>}
1638
- formula.
1532
+ '''Compute the distance between two (ellipsoidal) points using U{Thomas'
1533
+ <https://apps.DTIC.mil/dtic/tr/fulltext/u2/703541.pdf>} formula.
1639
1534
 
1640
1535
  @arg lat1: Start latitude (C{degrees}).
1641
1536
  @arg lon1: Start longitude (C{degrees}).
1642
1537
  @arg lat2: End latitude (C{degrees}).
1643
1538
  @arg lon2: End longitude (C{degrees}).
1644
- @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid},
1645
- L{Ellipsoid2} or L{a_f2Tuple}) to use.
1646
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
1647
- B{C{lat2}} and B{C{lon2}} (C{bool}).
1539
+ @kwarg datum: Datum (L{Datum}) or ellipsoid (L{Ellipsoid}, L{Ellipsoid2}
1540
+ or L{a_f2Tuple}) to use.
1541
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
1542
+ B{C{lon2}} (C{bool}).
1648
1543
 
1649
- @return: Distance (C{meter}, same units as the B{C{datum}}'s
1650
- ellipsoid axes).
1544
+ @return: Distance (C{meter}, same units as the B{C{datum}}'s or ellipsoid axes).
1651
1545
 
1652
1546
  @raise TypeError: Invalid B{C{datum}}.
1653
1547
 
1654
- @see: Functions L{thomas_}, L{cosineAndoyerLambert}, L{cosineForsytheAndoyerLambert},
1655
- L{cosineLaw}, L{equirectangular}, L{euclidean}, L{flatLocal}/L{hubeny},
1656
- L{flatPolar}, L{haversine}, L{vincentys} and method L{Ellipsoid.distance2}.
1548
+ @see: Functions L{thomas_}, L{cosineLaw}, L{equirectangular}, L{euclidean},
1549
+ L{flatLocal} / L{hubeny}, L{flatPolar}, L{haversine}, L{vincentys} and
1550
+ method L{Ellipsoid.distance2}.
1657
1551
  '''
1658
1552
  return _dE(thomas_, datum, wrap, lat1, lon1, lat2, lon2)
1659
1553
 
1660
1554
 
1661
1555
  def thomas_(phi2, phi1, lam21, datum=_WGS84):
1662
1556
  '''Compute the I{angular} distance between two (ellipsoidal) points using
1663
- U{Thomas'<https://apps.DTIC.mil/dtic/tr/fulltext/u2/703541.pdf>}
1664
- formula.
1557
+ U{Thomas'<https://apps.DTIC.mil/dtic/tr/fulltext/u2/703541.pdf>} formula.
1665
1558
 
1666
1559
  @arg phi2: End latitude (C{radians}).
1667
1560
  @arg phi1: Start latitude (C{radians}).
1668
1561
  @arg lam21: Longitudinal delta, M{end-start} (C{radians}).
1669
- @kwarg datum: Datum or ellipsoid to use (L{Datum}, L{Ellipsoid},
1562
+ @kwarg datum: Datum (L{Datum}) ?or ellipsoid to use (L{Ellipsoid},
1670
1563
  L{Ellipsoid2} or L{a_f2Tuple}).
1671
1564
 
1672
1565
  @return: Angular distance (C{radians}).
1673
1566
 
1674
1567
  @raise TypeError: Invalid B{C{datum}}.
1675
1568
 
1676
- @see: Functions L{thomas}, L{cosineAndoyerLambert_},
1677
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_},
1678
- L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{flatPolar_},
1679
- L{haversine_} and L{vincentys_} and U{Geodesy-PHP
1680
- <https://GitHub.com/jtejido/geodesy-php/blob/master/src/Geodesy/
1681
- Distance/ThomasFormula.php>}.
1569
+ @see: Functions L{thomas}, L{cosineLaw_}, L{euclidean_}, L{flatLocal_} /
1570
+ L{hubeny_}, L{flatPolar_}, L{haversine_} and L{vincentys_} and
1571
+ U{Geodesy-PHP<https://GitHub.com/jtejido/geodesy-php/blob/master/
1572
+ src/Geodesy/Distance/ThomasFormula.php>}.
1682
1573
  '''
1683
1574
  s2, c2, s1, c1, r, _ = _sincosa6(phi2, phi1, lam21)
1684
1575
  if r and isnon0(c1) and isnon0(c2):
1685
1576
  E = _ellipsoidal(datum, thomas_)
1686
- if E.f:
1577
+ f = E.f * _0_25
1578
+ if f: # ellipsoidal
1687
1579
  r1 = atan2(E.b_a * s1, c1)
1688
1580
  r2 = atan2(E.b_a * s2, c2)
1689
1581
 
@@ -1697,21 +1589,20 @@ def thomas_(phi2, phi1, lam21, datum=_WGS84):
1697
1589
  r = atan(sqrt0(h / u)) * 2 # == acos(1 - 2 * h)
1698
1590
  sr, cr = sincos2(r)
1699
1591
  if isnon0(sr):
1700
- u = 2 * (sj * ck)**2 / u
1701
- h = 2 * (sk * cj)**2 / h
1592
+ u = (sj * ck)**2 * 2 / u
1593
+ h = (sk * cj)**2 * 2 / h
1702
1594
  x = u + h
1703
1595
  y = u - h
1704
1596
 
1597
+ b = r * 2
1705
1598
  s = r / sr
1706
1599
  e = 4 * s**2
1707
1600
  d = 2 * cr
1708
1601
  a = e * d
1709
- b = 2 * r
1710
1602
  c = s - (a - d) * _0_5
1711
- f = E.f * _0_25
1712
1603
 
1713
- t = fsumf_(a * x, -b * y, c * x**2, -d * y**2, e * x * y)
1714
- r -= fsumf_(s * x, -y, -t * f * _0_25) * f * sr
1604
+ t = fdot_(a, x, -b, y, -d, y**2, c, x**2, e, x * y) * _0_25
1605
+ r -= fdot_(s, x, -1, y, -t, f) * f * sr
1715
1606
  return r
1716
1607
 
1717
1608
 
@@ -1724,21 +1615,20 @@ def vincentys(lat1, lon1, lat2, lon2, radius=R_M, wrap=False):
1724
1615
  @arg lon1: Start longitude (C{degrees}).
1725
1616
  @arg lat2: End latitude (C{degrees}).
1726
1617
  @arg lon2: End longitude (C{degrees}).
1727
- @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum})
1728
- or ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or
1729
- L{a_f2Tuple}) to use.
1730
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
1731
- B{C{lat2}} and B{C{lon2}} (C{bool}).
1618
+ @kwarg radius: Mean earth radius (C{meter}), datum (L{Datum}) or
1619
+ ellipsoid (L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple})
1620
+ to use.
1621
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{lat2}} and
1622
+ B{C{lon2}} (C{bool}).
1732
1623
 
1733
1624
  @return: Distance (C{meter}, same units as B{C{radius}}).
1734
1625
 
1735
1626
  @raise UnitError: Invalid B{C{radius}}.
1736
1627
 
1737
- @see: Functions L{vincentys_}, L{cosineAndoyerLambert},
1738
- L{cosineForsytheAndoyerLambert},L{cosineLaw}, L{equirectangular},
1739
- L{euclidean}, L{flatLocal}/L{hubeny}, L{flatPolar},
1740
- L{haversine} and L{thomas} and methods L{Ellipsoid.distance2},
1741
- C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}.
1628
+ @see: Functions L{vincentys_}, L{cosineLaw}, L{equirectangular}, L{euclidean},
1629
+ L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine} and L{thomas} and
1630
+ methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and
1631
+ C{LatLon.equirectangularTo}.
1742
1632
 
1743
1633
  @note: See note at function L{vincentys_}.
1744
1634
  '''
@@ -1756,17 +1646,14 @@ def vincentys_(phi2, phi1, lam21):
1756
1646
 
1757
1647
  @return: Angular distance (C{radians}).
1758
1648
 
1759
- @see: Functions L{vincentys}, L{cosineAndoyerLambert_},
1760
- L{cosineForsytheAndoyerLambert_}, L{cosineLaw_},
1761
- L{euclidean_}, L{flatLocal_}/L{hubeny_}, L{flatPolar_},
1762
- L{haversine_} and L{thomas_}.
1763
-
1764
- @note: Functions L{vincentys_}, L{haversine_} and L{cosineLaw_}
1765
- produce equivalent results, but L{vincentys_} is suitable
1766
- for antipodal points and slightly more expensive (M{3 cos,
1767
- 3 sin, 1 hypot, 1 atan2, 6 mul, 2 add}) than L{haversine_}
1768
- (M{2 cos, 2 sin, 2 sqrt, 1 atan2, 5 mul, 1 add}) and
1769
- L{cosineLaw_} (M{3 cos, 3 sin, 1 acos, 3 mul, 1 add}).
1649
+ @see: Functions L{vincentys}, L{cosineLaw_}, L{euclidean_}, L{flatLocal_} /
1650
+ L{hubeny_}, L{flatPolar_}, L{haversine_} and L{thomas_}.
1651
+
1652
+ @note: Functions L{vincentys_}, L{haversine_} and L{cosineLaw_} produce
1653
+ equivalent results, but L{vincentys_} is suitable for antipodal
1654
+ points and slightly more expensive (M{3 cos, 3 sin, 1 hypot, 1 atan2,
1655
+ 6 mul, 2 add}) than L{haversine_} (M{2 cos, 2 sin, 2 sqrt, 1 atan2, 5
1656
+ mul, 1 add}) and L{cosineLaw_} (M{3 cos, 3 sin, 1 acos, 3 mul, 1 add}).
1770
1657
  '''
1771
1658
  s1, c1, s2, c2, s21, c21 = sincos2_(phi1, phi2, lam21)
1772
1659