pygeodesy 24.6.9__py2.py3-none-any.whl → 24.6.24__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.
Files changed (84) hide show
  1. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.6.24.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.6.24.dist-info/RECORD +117 -0
  3. pygeodesy/__init__.py +33 -32
  4. pygeodesy/albers.py +2 -2
  5. pygeodesy/auxilats/__init__.py +1 -1
  6. pygeodesy/auxilats/auxAngle.py +40 -39
  7. pygeodesy/auxilats/auxDLat.py +3 -2
  8. pygeodesy/auxilats/auxLat.py +16 -18
  9. pygeodesy/auxilats/auxily.py +1 -1
  10. pygeodesy/azimuthal.py +10 -10
  11. pygeodesy/basics.py +9 -1
  12. pygeodesy/booleans.py +4 -4
  13. pygeodesy/cartesianBase.py +11 -14
  14. pygeodesy/css.py +14 -18
  15. pygeodesy/datums.py +6 -6
  16. pygeodesy/deprecated/__init__.py +1 -1
  17. pygeodesy/deprecated/classes.py +16 -2
  18. pygeodesy/deprecated/datum.py +3 -3
  19. pygeodesy/deprecated/functions.py +6 -8
  20. pygeodesy/dms.py +23 -27
  21. pygeodesy/ecef.py +4 -4
  22. pygeodesy/elevations.py +4 -4
  23. pygeodesy/ellipsoidalBase.py +23 -28
  24. pygeodesy/ellipsoidalBaseDI.py +19 -23
  25. pygeodesy/ellipsoidalExact.py +3 -3
  26. pygeodesy/ellipsoidalGeodSolve.py +15 -23
  27. pygeodesy/ellipsoidalKarney.py +37 -60
  28. pygeodesy/ellipsoidalNvector.py +38 -44
  29. pygeodesy/ellipsoidalVincenty.py +11 -14
  30. pygeodesy/ellipsoids.py +107 -101
  31. pygeodesy/errors.py +100 -48
  32. pygeodesy/etm.py +32 -44
  33. pygeodesy/formy.py +55 -58
  34. pygeodesy/frechet.py +18 -20
  35. pygeodesy/fsums.py +3 -3
  36. pygeodesy/gars.py +3 -4
  37. pygeodesy/geodesici.py +909 -0
  38. pygeodesy/geodesicw.py +11 -13
  39. pygeodesy/geodesicx/__init__.py +4 -4
  40. pygeodesy/geodesicx/gx.py +18 -28
  41. pygeodesy/geodesicx/gxbases.py +20 -8
  42. pygeodesy/geodesicx/gxline.py +16 -22
  43. pygeodesy/geodsolve.py +80 -10
  44. pygeodesy/geohash.py +26 -34
  45. pygeodesy/geoids.py +28 -37
  46. pygeodesy/hausdorff.py +17 -18
  47. pygeodesy/heights.py +2 -2
  48. pygeodesy/internals.py +6 -0
  49. pygeodesy/interns.py +2 -2
  50. pygeodesy/karney.py +20 -4
  51. pygeodesy/ktm.py +13 -16
  52. pygeodesy/latlonBase.py +17 -19
  53. pygeodesy/lazily.py +7 -6
  54. pygeodesy/lcc.py +28 -31
  55. pygeodesy/ltp.py +7 -8
  56. pygeodesy/ltpTuples.py +68 -70
  57. pygeodesy/mgrs.py +8 -9
  58. pygeodesy/named.py +19 -10
  59. pygeodesy/nvectorBase.py +9 -10
  60. pygeodesy/osgr.py +9 -9
  61. pygeodesy/points.py +6 -6
  62. pygeodesy/rhumb/__init__.py +1 -1
  63. pygeodesy/rhumb/aux_.py +5 -5
  64. pygeodesy/rhumb/bases.py +30 -31
  65. pygeodesy/rhumb/ekx.py +3 -4
  66. pygeodesy/sphericalBase.py +10 -11
  67. pygeodesy/sphericalNvector.py +13 -13
  68. pygeodesy/sphericalTrigonometry.py +86 -97
  69. pygeodesy/streprs.py +4 -34
  70. pygeodesy/triaxials.py +48 -43
  71. pygeodesy/units.py +204 -271
  72. pygeodesy/unitsBase.py +115 -107
  73. pygeodesy/ups.py +26 -31
  74. pygeodesy/utily.py +8 -8
  75. pygeodesy/utm.py +35 -40
  76. pygeodesy/utmups.py +43 -46
  77. pygeodesy/utmupsBase.py +8 -9
  78. pygeodesy/vector3d.py +26 -27
  79. pygeodesy/vector3dBase.py +6 -7
  80. pygeodesy/webmercator.py +19 -21
  81. pygeodesy/wgrs.py +18 -20
  82. PyGeodesy-24.6.9.dist-info/RECORD +0 -116
  83. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.6.24.dist-info}/WHEEL +0 -0
  84. {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.6.24.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicw.py CHANGED
@@ -37,7 +37,7 @@ from contextlib import contextmanager
37
37
  # from math import fabs # from .utily
38
38
 
39
39
  __all__ = _ALL_LAZY.geodesicw
40
- __version__ = '24.05.24'
40
+ __version__ = '24.06.24'
41
41
 
42
42
  _plumb_ = 'plumb'
43
43
  _TRIPS = 65
@@ -71,8 +71,8 @@ class _gWrapped(_kWrapped):
71
71
 
72
72
  @arg a_ellipsoid: The equatorial radius I{a} (C{meter}, conventionally),
73
73
  an ellipsoid (L{Ellipsoid}) or a datum (L{Datum}).
74
- @arg f: The ellipsoid's flattening (C{scalar}), ignored if B{C{a_ellipsoid})
75
- is not C{meter}.
74
+ @arg f: The ellipsoid's flattening (C{scalar}), required if B{C{a_ellipsoid})
75
+ is C{meter}, ignored otherwise.
76
76
  @kwarg name: Optional C{B{name}=NN} (C{str}).
77
77
  '''
78
78
  _earth_datum(self, a_ellipsoid, f=f, **name) # raiser=NN
@@ -429,17 +429,16 @@ class _gWrapped(_kWrapped):
429
429
  _wrapped = _gWrapped() # PYCHOK singleton, .ellipsoids, .test/base.py
430
430
 
431
431
 
432
- def Geodesic(a_ellipsoid, f=None, **name):
432
+ def Geodesic(a_ellipsoid=_EWGS84, f=None, **name):
433
433
  '''Return a I{wrapped} C{geodesic.Geodesic} instance from I{Karney}'s
434
434
  Python U{geographiclib<https://PyPI.org/project/geographiclib>},
435
435
  provide the latter is installed, otherwise an C{ImportError}.
436
436
 
437
437
  @arg a_ellipsoid: An ellipsoid (L{Ellipsoid}) or datum (L{Datum})
438
438
  or the equatorial radius I{a} of the ellipsoid (C{meter}).
439
- @arg f: The flattening of the ellipsoid (C{scalar}), ignored if
440
- B{C{a_ellipsoid}}) is not specified as C{meter}.
441
- @kwarg name: Optional ellipsoid C{B{name}=NN} (C{str}), ignored
442
- like B{C{f}}.
439
+ @arg f: The flattening of the ellipsoid (C{scalar}), required if
440
+ B{C{a_ellipsoid}}) is C{meter}, ignored otherwise.
441
+ @kwarg name: Optional C{B{name}=NN} (C{str}), ignored like B{C{f}}.
443
442
  '''
444
443
  return _wrapped.Geodesic(a_ellipsoid, f=f, **name)
445
444
 
@@ -453,11 +452,10 @@ def GeodesicLine(geodesic, lat1, lon1, azi1, caps=Caps._STD_LINE):
453
452
  @arg lat1: Latitude of the first points (C{degrees}).
454
453
  @arg lon1: Longitude of the first points (C{degrees}).
455
454
  @arg azi1: Azimuth at the first points (compass C{degrees360}).
456
- @kwarg caps: Optional, bit-or'ed combination of L{Caps} values
457
- specifying the capabilities the C{GeodesicLine}
458
- instance should possess, i.e., which quantities can
459
- be returned by calls to C{GeodesicLine.Position}
460
- and C{GeodesicLine.ArcPosition}.
455
+ @kwarg caps: Optional, bit-or'ed combination of L{Caps} values specifying
456
+ the capabilities the C{GeodesicLine} instance should possess,
457
+ i.e., which quantities can be returned by methods
458
+ C{GeodesicLine.Position} and C{GeodesicLine.ArcPosition}.
461
459
  '''
462
460
  return _wrapped.GeodesicLine(geodesic, lat1, lon1, azi1, caps=caps)
463
461
 
@@ -2,7 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  u'''A pure Python version of I{Karney}'s C++ classes U{GeodesicExact
5
- <https://GeographicLib.SourceForge.io/C++/classGeographicLib_1_1GeodesicExact.html>}
5
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
6
6
  and U{GeodesicLineExact
7
7
  <https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1GeodesicLine.html>}.
8
8
 
@@ -13,8 +13,8 @@ and the background information at U{Geodesics on an ellipsoid of revolution
13
13
 
14
14
  Also, compare C{GeodesicExact} and C{GeodesicLineExact} to I{standard} classes C{Geodesic}
15
15
  respectively C{GeodesicLine} from I{Karney}'s Python implementation U{geographiclib
16
- <https://GeographicLib.SourceForge.io/C++/doc/other.html#python>}, see module
17
- L{pygeodesy.karney}.
16
+ <https://GeographicLib.SourceForge.io/C++/doc/other.html#python>}, see modules
17
+ L{pygeodesy.geodesicw} and L{pygeodesy.karney}.
18
18
  '''
19
19
 
20
20
  from pygeodesy.geodesicx.gx import GeodesicExact, GeodesicLineExact # PYCHOK exported
@@ -23,7 +23,7 @@ from pygeodesy.karney import Caps, GeodesicError
23
23
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
24
24
 
25
25
  __all__ = _ALL_LAZY.geodesicx + _ALL_DOCS(Caps, GeodesicError)
26
- __version__ = '24.05.31'
26
+ __version__ = '24.06.19'
27
27
 
28
28
  # **) MIT License
29
29
  #
pygeodesy/geodesicx/gx.py CHANGED
@@ -44,25 +44,26 @@ from pygeodesy.constants import EPS, EPS0, EPS02, MANT_DIG, NAN, PI, _EPSqrt, \
44
44
  from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
45
45
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
46
46
  from pygeodesy.errors import GeodesicError, _xkwds_pop2
47
- from pygeodesy.fmath import hypot as _hypot
47
+ from pygeodesy.fmath import hypot as _hypot, Fmt
48
48
  from pygeodesy.fsums import fsumf_, fsum1f_
49
49
  from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
50
- _sincos12, _sin1cos2, _xnC4
51
- from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _TINY, _update_glXs
52
- from pygeodesy.interns import NN, _COMMASPACE_, _DOT_, _UNDER_
50
+ _sincos12, _sin1cos2, _sinf1cos2d, \
51
+ _TINY, _xnC4
52
+ from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _update_glXs
53
+ from pygeodesy.interns import NN, _DOT_, _UNDER_
53
54
  from pygeodesy.karney import GDict, _around, _atan2d, Caps, _cbrt, _diff182, \
54
55
  _fix90, _K_2_0, _norm2, _norm180, _polynomial, \
55
56
  _signBit, _sincos2, _sincos2d, _sincos2de, _unsigned2
56
57
  from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
57
58
  from pygeodesy.namedTuples import Destination3Tuple, Distance3Tuple
58
59
  from pygeodesy.props import deprecated_Property, Property, Property_RO, property_RO
59
- from pygeodesy.streprs import Fmt, pairs
60
+ # from pygeodesy.streprs import Fmt # from .fmath
60
61
  from pygeodesy.utily import atan2d as _atan2d_reverse, _unrollon, _Wrap, wrap360
61
62
 
62
63
  from math import atan2, copysign, cos, degrees, fabs, radians, sqrt
63
64
 
64
65
  __all__ = ()
65
- __version__ = '24.05.31'
66
+ __version__ = '24.06.24'
66
67
 
67
68
  _MAXIT1 = 20
68
69
  _MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
@@ -553,10 +554,10 @@ class GeodesicExact(_GeodesicBase):
553
554
  # to check, e.g., on verifying quadrants in atan2. In addition,
554
555
  # this enforces some symmetries in the results returned.
555
556
 
556
- # Initialize for the meridian. No longitude calculation is
557
- # done in this case to let the parameter default to 0.
558
- sbet1, cbet1 = self._sinf1cos2d(lat1)
559
- sbet2, cbet2 = self._sinf1cos2d(lat2)
557
+ # Initialize for the meridian. No longitude calculation is done in
558
+ # this case to let the parameter default to 0.
559
+ sbet1, cbet1 = _sinf1cos2d(lat1, self.f1)
560
+ sbet2, cbet2 = _sinf1cos2d(lat2, self.f1)
560
561
  # If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure
561
562
  # of the |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1),
562
563
  # abs(sbet2) + sbet1 is a better measure. This logic is used
@@ -1241,27 +1242,16 @@ class GeodesicExact(_GeodesicBase):
1241
1242
 
1242
1243
  Polygon = Area # for C{geographiclib} compatibility
1243
1244
 
1244
- def _sinf1cos2d(self, lat):
1245
- '''(INTERNAL) Helper, also for C{_G_GeodesicLineExact}.
1246
- '''
1247
- sbet, cbet = _sincos2d(lat)
1248
- # ensure cbet1 = +epsilon at poles; doing the fix on beta means
1249
- # that sig12 will be <= 2*tiny for two points at the same pole
1250
- sbet, cbet = _norm2(sbet * self.f1, cbet)
1251
- return sbet, (cbet if fabs(cbet) > _TINY else _TINY)
1252
-
1253
- def toStr(self, prec=6, sep=_COMMASPACE_, **unused): # PYCHOK signature
1245
+ def toStr(self, **prec_sep_name): # PYCHOK signature
1254
1246
  '''Return this C{GeodesicExact} as string.
1255
1247
 
1256
- @kwarg prec: The C{float} precision, number of decimal digits (0..9).
1257
- Trailing zero decimals are stripped for B{C{prec}} values
1258
- of 1 and above, but kept for negative B{C{prec}} values.
1259
- @kwarg sep: Separator to join (C{str}).
1248
+ @see: L{Ellipsoid.toStr<pygeodesy.ellipsoids.Ellipsoid.toStr>}
1249
+ for further details.
1260
1250
 
1261
- @return: Tuple items (C{str}).
1251
+ @return: C{GeodesicExact} (C{str}).
1262
1252
  '''
1263
- d = dict(ellipsoid=self.ellipsoid, C4order=self.C4order)
1264
- return sep.join(pairs(d, prec=prec))
1253
+ return self._instr(props=(GeodesicExact.ellipsoid,),
1254
+ C4order=self.C4order, **prec_sep_name)
1265
1255
 
1266
1256
 
1267
1257
  class GeodesicLineExact(_GeodesicLineExact):
@@ -1290,7 +1280,7 @@ class GeodesicLineExact(_GeodesicLineExact):
1290
1280
  '''
1291
1281
  _xinstanceof(GeodesicExact, geodesic=geodesic)
1292
1282
  if (caps & Caps.LINE_OFF): # copy to avoid updates
1293
- geodesic = geodesic.copy(deep=False, name=_UNDER_(NN, geodesic.name)) # NOT _under!
1283
+ geodesic = geodesic.copy(deep=False, name=_UNDER_(NN, geodesic.name))
1294
1284
  # _update_all(geodesic)
1295
1285
  _GeodesicLineExact.__init__(self, geodesic, lat1, lon1, azi1, caps, 0, **name)
1296
1286
 
@@ -9,19 +9,21 @@ U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
9
9
  '''
10
10
 
11
11
  from pygeodesy.basics import isodd, _MODS
12
- from pygeodesy.constants import _0_0, _100_0
12
+ from pygeodesy.constants import _EPSmin as _TINY, _0_0, _100_0
13
13
  from pygeodesy.errors import _or, _xkwds_item2
14
14
  from pygeodesy.fmath import hypot as _hypot
15
- from pygeodesy.karney import _CapsBase, GeodesicError, _2cos2x, _sum2_
15
+ from pygeodesy.karney import _CapsBase, GeodesicError, _2cos2x, \
16
+ _norm2, _sincos2d, _sum2_
16
17
  # from pygeodesy.lazily import _MODS, printf # .basics, _MODS
17
18
 
18
- from math import ldexp as _ldexp
19
+ from math import fabs, ldexp as _ldexp
19
20
 
20
21
  __all__ = ()
21
- __version__ = '24.05.19'
22
+ __version__ = '24.06.16'
22
23
 
23
24
  # valid C{nC4}s and C{C4order}s, see _xnC4 below
24
25
  _nC4s = {24: 2900, 27: 4032, 30: 5425}
26
+ # assert (_TINY * EPS) > 0 and (_TINY + EPS) == EPS # underflow guard
25
27
 
26
28
 
27
29
  class _GeodesicBase(_CapsBase): # in .geodsolve
@@ -71,15 +73,15 @@ def _cosSeries(c4s, sx, cx): # PYCHOK shared .geodesicx.gx and -.gxline
71
73
  y0 = t0 = y1 = t1 = _0_0
72
74
  c4 = list(c4s)
73
75
  _c4 = c4.pop
74
- _s2 = _sum2_
75
76
  if isodd(len(c4)):
76
77
  y0 = _c4()
78
+ _s2 = _sum2_
77
79
  while c4:
78
80
  # y1 = ar * y0 - y1 + c4.pop()
79
81
  # y0 = ar * y1 - y0 + c4.pop()
80
82
  y1, t1 = _s2(ar * y0, ar * t0, -y1, -t1, _c4())
81
83
  y0, t0 = _s2(ar * y1, ar * t1, -y0, -t0, _c4())
82
- # s = cx * (y0 - y1)
84
+ # s = (y0 - y1) * cx
83
85
  s, _ = _s2(cx * y0, _0_0, cx * t0, -cx * y1, -cx * t1)
84
86
  return s
85
87
 
@@ -93,7 +95,7 @@ def _f2(hi, lo): # in .geodesicx._C4_24, _27 and _30
93
95
  return _ldexp(_f(hi), 52) + _f(lo)
94
96
 
95
97
 
96
- def _sincos12(sin1, cos1, sin2, cos2, sineg0=False): # PYCHOK shared
98
+ def _sincos12(sin1, cos1, sin2, cos2, sineg0=False):
97
99
  '''(INTERNAL) Compute the sine and cosine of angle
98
100
  M{ang12 = atan2(sin2, cos2) - atan2(sin1, cos1)}.
99
101
 
@@ -111,7 +113,7 @@ def _sincos12(sin1, cos1, sin2, cos2, sineg0=False): # PYCHOK shared
111
113
  return s, c
112
114
 
113
115
 
114
- def _sin1cos2(sin1, cos1, sin2, cos2): # PYCHOK shared
116
+ def _sin1cos2(sin1, cos1, sin2, cos2):
115
117
  '''(INTERNAL) Compute the C{sin1 * cos2} sine and its cosine.
116
118
 
117
119
  @return: 2-Tuple C{(sin1 * cos2, hypot(sin1 * sin2, cos1)}.
@@ -121,6 +123,16 @@ def _sin1cos2(sin1, cos1, sin2, cos2): # PYCHOK shared
121
123
  return s, c # _norm2(s, c)
122
124
 
123
125
 
126
+ def _sinf1cos2d(lat, f1):
127
+ '''(INTERNAL) See C{GeodesicExact} and C{_GeodesicLineExact}.
128
+ '''
129
+ sbet, cbet = _sincos2d(lat)
130
+ # ensure cbet1 = +epsilon at poles; doing the fix on beta means
131
+ # that sig12 will be <= 2*tiny for two points at the same pole
132
+ sbet, cbet = _norm2(sbet * f1, cbet)
133
+ return sbet, (cbet if fabs(cbet) > _TINY else _TINY)
134
+
135
+
124
136
  def _xnC4(**name_nC4):
125
137
  '''(INTERNAL) Validate C{C4order}.
126
138
  '''
@@ -37,30 +37,27 @@ from __future__ import division as _; del _ # PYCHOK semicolon
37
37
  # - s and c prefixes mean sin and cos
38
38
 
39
39
  # from pygeodesy.basics import _xinstanceof # _MODS
40
- from pygeodesy.constants import NAN, _EPSmin, _EPSqrt as _TOL, _0_0, \
41
- _1_0, _180_0, _2__PI, _copysign_1_0
42
- from pygeodesy.errors import _xError, _COMMASPACE_
40
+ from pygeodesy.constants import NAN, _EPSqrt as _TOL, _0_0, _1_0, \
41
+ _180_0, _2__PI, _copysign_1_0
42
+ # from pygeodesy.errors import _xError # _MODS
43
43
  from pygeodesy.fsums import fsumf_, fsum1f_
44
44
  from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
45
- _sincos12, _sin1cos2
45
+ _sincos12, _sin1cos2, \
46
+ _sinf1cos2d, _TINY
46
47
  # from pygeodesy.geodesicw import _Intersecant2 # _MODS
47
- # from pygeodesy.interns import _COMMASPACE_ # from .errors
48
48
  from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
49
49
  from pygeodesy.karney import _around, _atan2d, Caps, GDict, _fix90, \
50
50
  _K_2_0, _norm2, _norm180, _sincos2, _sincos2d
51
- from pygeodesy.props import Property_RO, _update_all
52
- # from pygeodesy.streprs import pairs # _MODS
51
+ from pygeodesy.named import Property_RO, _update_all
52
+ # from pygeodesy.props import Property_RO, _update_all # from .named
53
53
  from pygeodesy.utily import atan2d as _atan2d_reverse, sincos2
54
54
 
55
55
  from math import atan2, cos, degrees, fabs, floor, radians, sin
56
56
 
57
57
  __all__ = ()
58
- __version__ = '24.05.19'
58
+ __version__ = '24.06.24'
59
59
 
60
60
  _glXs = [] # instances of C{[_]GeodesicLineExact} to be updated
61
- # underflow guard, we require _TINY * EPS > 0, _TINY + EPS == EPS
62
- _TINY = _EPSmin
63
- # assert (_TINY * EPS) > 0 and (_TINY + EPS) == EPS
64
61
 
65
62
 
66
63
  def _update_glXs(gX): # see GeodesicExact.C4order and -._ef_reset_k2
@@ -122,7 +119,7 @@ class _GeodesicLineExact(_GeodesicBase):
122
119
  # allow lat, azimuth and unrolling of lon
123
120
  self._caps = caps | Cs._LINE
124
121
 
125
- sbet1, cbet1 = gX._sinf1cos2d(_around(lat1))
122
+ sbet1, cbet1 = _sinf1cos2d(_around(lat1), gX.f1)
126
123
  self._dn1 = gX._dn(sbet1, cbet1)
127
124
  # Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), with alp0
128
125
  # in [0, pi/2 - |bet1|]. Alt: calp0 = hypot(sbet1, calp1 * cbet1),
@@ -501,7 +498,7 @@ class _GeodesicLineExact(_GeodesicBase):
501
498
  try:
502
499
  return _MODS.geodesicw._Intersecant2(self, lat0, lon0, radius, tol=tol)
503
500
  except (TypeError, ValueError) as x:
504
- raise _xError(x, lat0, lon0, radius, tol=_TOL)
501
+ raise _MODS.errors._xError(x, lat0, lon0, radius, tol=_TOL)
505
502
 
506
503
  @Property_RO
507
504
  def _H0e2_f1(self):
@@ -626,20 +623,17 @@ class _GeodesicLineExact(_GeodesicBase):
626
623
  # unnecessary because Einv inverts E
627
624
  # return -self._eF.deltaEinv(stau1, ctau1)
628
625
 
629
- def toStr(self, prec=6, sep=_COMMASPACE_, **unused): # PYCHOK signature
626
+ def toStr(self, **prec_sep_name): # PYCHOK signature
630
627
  '''Return this C{GeodesicLineExact} as string.
631
628
 
632
- @kwarg prec: The C{float} precision, number of decimal digits (0..9).
633
- Trailing zero decimals are stripped for B{C{prec}} values
634
- of 1 and above, but kept for negative B{C{prec}} values.
635
- @kwarg sep: Separator to join (C{str}).
629
+ @see: L{Ellipsoid.toStr<pygeodesy.ellipsoids.Ellipsoid.toStr>}
630
+ for further details.
636
631
 
637
632
  @return: C{GeodesicLineExact} (C{str}).
638
633
  '''
639
- d = dict(geodesic=self.geodesic,
640
- lat1=self.lat1, lon1=self.lon1, azi1=self.azi1,
641
- a13=self.a13, s13=self.s13)
642
- return sep.join(_MODS.streprs.pairs(d, prec=prec))
634
+ C = _GeodesicLineExact
635
+ t = C.lat1, C.lon1, C.azi1, C.a13, C.s13, C.geodesic
636
+ return self._instr(props=t, **prec_sep_name)
643
637
 
644
638
 
645
639
  __all__ += _ALL_DOCS(_GeodesicLineExact)
pygeodesy/geodsolve.py CHANGED
@@ -10,30 +10,32 @@ of the C{GeodSolve} executable.
10
10
  '''
11
11
 
12
12
  from pygeodesy.basics import _xinstanceof
13
+ # from pygeodesy.constants import NAN, _0_0 # from .karney
13
14
  # from pygeodesy.geodesicx import GeodesicAreaExact # _MODS
14
15
  from pygeodesy.interns import NN, _a12_, _azi1_, _azi2_, \
15
16
  _lat1_, _lat2_, _lon1_, _lon2_, _m12_, \
16
17
  _M12_, _M21_, _s12_, _S12_, _UNDER_
17
18
  from pygeodesy.interns import _UNUSED_, _not_ # PYCHOK used!
18
19
  from pygeodesy.karney import _Azi, Caps, _Deg, GeodesicError, _GTuple, \
19
- _Pass, _Lat, _Lon, _M, _M2, _sincos2d
20
+ _Pass, _Lat, _Lon, _M, _M2, _sincos2d, \
21
+ _0_0, NAN
20
22
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, \
21
23
  _getenv, _PYGEODESY_GEODSOLVE_
22
24
  from pygeodesy.named import _name1__
23
25
  from pygeodesy.namedTuples import Destination3Tuple, Distance3Tuple
24
- from pygeodesy.props import Property, Property_RO
26
+ from pygeodesy.props import Property, Property_RO, property_RO
25
27
  from pygeodesy.solveBase import _SolveBase, _SolveLineBase
26
28
  from pygeodesy.utily import _unrollon, _Wrap, wrap360
27
29
 
28
30
  __all__ = _ALL_LAZY.geodsolve
29
- __version__ = '24.06.04'
31
+ __version__ = '24.06.26'
30
32
 
31
33
 
32
34
  class GeodSolve12Tuple(_GTuple):
33
35
  '''12-Tuple C{(lat1, lon1, azi1, lat2, lon2, azi2, s12, a12, m12, M12, M21, S12)} with
34
36
  angles C{lat1}, C{lon1}, C{azi1}, C{lat2}, C{lon2} and C{azi2} and arc C{a12} all in
35
37
  C{degrees}, initial C{azi1} and final C{azi2} forward azimuths, distance C{s12} and
36
- reduced length C{m12} in C{meter}, area C{S12} in C{meter} I{squared} and geodesic
38
+ reduced length C{m12} in C{meter}, area C{S12} in C{meter} I{squared} and geodesic
37
39
  scale factors C{M12} and C{M21}, both C{scalar}, see U{GeodSolve
38
40
  <https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}.
39
41
  '''
@@ -222,8 +224,11 @@ class GeodesicSolve(_GeodesicSolveBase):
222
224
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
223
225
  Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
224
226
  '''
225
- r = self.Inverse(lat1, lon1, lat2, lon2)
226
- return GeodesicLineSolve(self, lat1, lon1, r.azi1, **_name1__(caps_name, _or_nameof=self))
227
+ r = self.Inverse(lat1, lon1, lat2, lon2)
228
+ gl = GeodesicLineSolve(self, lat1, lon1, r.azi1, **_name1__(caps_name, _or_nameof=self))
229
+ gl._a13 = r.a12 # gl.SetArc(r.a12)
230
+ gl._s13 = r.s12 # gl.SetDistance(r.s12)
231
+ return gl
227
232
 
228
233
 
229
234
  class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
@@ -237,6 +242,8 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
237
242
  @note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve}
238
243
  executable for I{every} method call.
239
244
  '''
245
+ _a13 = \
246
+ _s13 = NAN # see GeodesicSolve._InverseLine
240
247
 
241
248
  def __init__(self, geodesic, lat1, lon1, azi1, caps=Caps.ALL, **name):
242
249
  '''New L{GeodesicLineSolve} instance, allowing points to be found along
@@ -268,7 +275,22 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
268
275
  except GeodesicError:
269
276
  pass
270
277
 
271
- def ArcPosition(self, a12, outmask=_UNUSED_): # PYCHOK unused
278
+ @Property_RO
279
+ def a13(self):
280
+ '''Get the arc length to reference point 3 (C{degrees}).
281
+
282
+ @see: Methods L{Arc} and L{SetArc}.
283
+ '''
284
+ return self._a13
285
+
286
+ def Arc(self):
287
+ '''Return the arc length to reference point 3 (C{degrees} or C{NAN}).
288
+
289
+ @see: Method L{SetArc} and property L{a13}.
290
+ '''
291
+ return self.a13
292
+
293
+ def ArcPosition(self, a12, outmask=Caps.STANDARD): # PYCHOK unused
272
294
  '''Find the position on the line given B{C{a12}}.
273
295
 
274
296
  @arg a12: Spherical arc length from the first point to the
@@ -277,7 +299,7 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
277
299
  @return: A C{GDict} with 12 items C{lat1, lon1, azi1, lat2, lon2,
278
300
  azi2, m12, a12, s12, M12, M21, S12}.
279
301
  '''
280
- return self._GDictInvoke(self._cmdArc, True, self._Names_Direct, a12)
302
+ return self._GDictInvoke(self._cmdArc, True, self._Names_Direct, a12)._unCaps(outmask)
281
303
 
282
304
  @Property_RO
283
305
  def azi1(self):
@@ -301,6 +323,17 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
301
323
  '''
302
324
  return self._cmdDistance + ('-a',)
303
325
 
326
+ def Distance(self):
327
+ '''Return the distance to reference point 3 (C{meter} or C{NAN}).
328
+ '''
329
+ return self.s13
330
+
331
+ @property_RO
332
+ def geodesic(self):
333
+ '''Get the geodesic (L{GeodesicSolve}).
334
+ '''
335
+ return self._solve # see .solveBase._SolveLineBase
336
+
304
337
  def Intersecant2(self, lat0, lon0, radius, **kwds): # PYCHOK no cover
305
338
  '''B{Not implemented}, throws a C{NotImplementedError} always.'''
306
339
  self._notImplemented(lat0, lon0, radius, **kwds)
@@ -309,7 +342,7 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
309
342
  '''B{Not implemented}, throws a C{NotImplementedError} always.'''
310
343
  self._notImplemented(lat0, lon0, **kwds)
311
344
 
312
- def Position(self, s12, outmask=_UNUSED_): # PYCHOK unused
345
+ def Position(self, s12, outmask=Caps.STANDARD):
313
346
  '''Find the position on the line given B{C{s12}}.
314
347
 
315
348
  @arg s12: Distance from the first point to the second (C{meter}).
@@ -317,7 +350,44 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
317
350
  @return: A C{GDict} with 12 items C{lat1, lon1, azi1, lat2, lon2,
318
351
  azi2, m12, a12, s12, M12, M21, S12}, possibly C{a12=NAN}.
319
352
  '''
320
- return self._GDictInvoke(self._cmdDistance, True, self._Names_Direct, s12)
353
+ return self._GDictInvoke(self._cmdDistance, True, self._Names_Direct, s12)._unCaps(outmask)
354
+
355
+ @Property_RO
356
+ def s13(self):
357
+ '''Get the distance to reference point 3 (C{meter} or C{NAN}).
358
+
359
+ @see: Methods L{Distance} and L{SetDistance}.
360
+ '''
361
+ return self._s13
362
+
363
+ def SetArc(self, a13):
364
+ '''Set reference point 3 in terms relative to the first point.
365
+
366
+ @arg a13: Spherical arc length from the first to the reference
367
+ point (C{degrees}).
368
+
369
+ @return: The distance C{s13} (C{meter}) between the first and
370
+ the reference point or C{NAN}.
371
+ '''
372
+ if self._a13 != a13:
373
+ self._a13 = a13
374
+ self._s13 = self.ArcPosition(a13, outmask=Caps.DISTANCE).s12 # if a13 else _0_0
375
+ # _update_all(self)
376
+ return self._s13
377
+
378
+ def SetDistance(self, s13):
379
+ '''Set reference point 3 in terms relative to the first point.
380
+
381
+ @arg s13: Distance from the first to the reference point (C{meter}).
382
+
383
+ @return: The arc length C{a13} (C{degrees}) between the first
384
+ and the reference point or C{NAN}.
385
+ '''
386
+ if self._s13 != s13:
387
+ self._s13 = s13
388
+ self._a13 = self.Position(s13, outmask=Caps.DISTANCE).a12 if s13 else _0_0
389
+ # _update_all(self)
390
+ return self._a13 # NAN for GeodesicLineExact without Cap.DISTANCE_IN
321
391
 
322
392
  def toStr(self, **prec_sep): # PYCHOK signature
323
393
  '''Return this C{GeodesicLineSolve} as string.
pygeodesy/geohash.py CHANGED
@@ -20,7 +20,7 @@ from pygeodesy.basics import isodd, isstr, map2
20
20
  from pygeodesy.constants import EPS, R_M, _floatuple, _0_0, _0_5, _180_0, \
21
21
  _360_0, _90_0, _N_90_0, _N_180_0 # PYCHOK used!
22
22
  from pygeodesy.dms import parse3llh # parseDMS2
23
- from pygeodesy.errors import _ValueError, _xkwds
23
+ from pygeodesy.errors import _ValueError, _xkwds, _xStrError
24
24
  from pygeodesy.fmath import favg
25
25
  # from pygeodesy import formy as _formy # _MODS
26
26
  from pygeodesy.interns import NN, _COMMA_, _DOT_, _E_, _N_, _NE_, _NW_, \
@@ -32,13 +32,12 @@ from pygeodesy.namedTuples import Bounds2Tuple, Bounds4Tuple, LatLon2Tuple, \
32
32
  from pygeodesy.props import deprecated_function, deprecated_method, \
33
33
  deprecated_property_RO, Property_RO
34
34
  from pygeodesy.streprs import fstr
35
- from pygeodesy.units import Degrees_, Int, Lat, Lon, Precision_, Str, \
36
- _xStrError
35
+ from pygeodesy.units import Degrees_, Int, Lat, Lon, Precision_, Str
37
36
 
38
37
  from math import fabs, ldexp, log10, radians
39
38
 
40
39
  __all__ = _ALL_LAZY.geohash
41
- __version__ = '24.06.10'
40
+ __version__ = '24.06.15'
42
41
 
43
42
  _formy = _MODS.into(formy=__name__)
44
43
 
@@ -237,7 +236,7 @@ class Geohash(Str):
237
236
  @kwarg LatLon: Optional class to return I{bounds} (C{LatLon})
238
237
  or C{None}.
239
238
  @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
240
- arguments, ignored if B{C{LatLon}} is C{None}.
239
+ arguments, ignored if C{B{LatLon} is None}.
241
240
 
242
241
  @return: A L{Bounds2Tuple}C{(latlonSW, latlonNE)} of B{C{LatLon}}s
243
242
  or a L{Bounds4Tuple}C{(latS, lonW, latN, lonE)} if
@@ -300,16 +299,15 @@ class Geohash(Str):
300
299
 
301
300
  @arg other: The other geohash (L{Geohash}, C{LatLon} or C{str}).
302
301
  @kwarg radius: Mean earth radius, ellipsoid or datum (C{meter},
303
- L{Ellipsoid}, L{Ellipsoid2}, L{Datum} or
304
- L{a_f2Tuple}) or C{None}, see function
305
- L{pygeodesy.equirectangular}.
302
+ L{Ellipsoid}, L{Ellipsoid2}, L{Datum} or L{a_f2Tuple})
303
+ or C{None}, see function L{pygeodesy.equirectangular}.
306
304
  @kwarg adjust_limit_wrap: Optional keyword arguments for function
307
305
  L{pygeodesy.equirectangular4}, overriding defaults
308
306
  C{B{adjust}=False, B{limit}=None} and C{B{wrap}=False}.
309
307
 
310
- @return: Distance (C{meter}, same units as B{C{radius}} or the
311
- ellipsoid or datum axes or C{radians I{squared}} if
312
- B{C{radius}} is C{None} or C{0}).
308
+ @return: Distance (C{meter}, same units as B{C{radius}} or the ellipsoid
309
+ or datum axes or C{radians I{squared}} if B{C{radius} is None}
310
+ or C{0}).
313
311
 
314
312
  @raise TypeError: The B{C{other}} is not a L{Geohash}, C{LatLon} or
315
313
  C{str} or invalid B{C{radius}}.
@@ -398,13 +396,11 @@ class Geohash(Str):
398
396
  as an instance of the supplied C{LatLon} class.
399
397
 
400
398
  @arg LatLon: Class to use (C{LatLon}) or C{None}.
401
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}}
402
- keyword arguments, ignored if
403
- C{B{LatLon} is None}.
399
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
400
+ arguments, ignored if C{B{LatLon} is None}.
404
401
 
405
- @return: This geohash location (B{C{LatLon}}) or a
406
- L{LatLon2Tuple}C{(lat, lon)} if B{C{LatLon}}
407
- is C{None}.
402
+ @return: This geohash location (B{C{LatLon}}) or if C{B{LatLon}
403
+ is None}, a L{LatLon2Tuple}C{(lat, lon)}.
408
404
 
409
405
  @raise TypeError: Invalid B{C{LatLon}} or B{C{LatLon_kwds}}.
410
406
  '''
@@ -500,19 +496,17 @@ _Neighbors8Defaults = dict(zip(Neighbors8Dict._Keys_, (None,) *
500
496
  def bounds(geohash, LatLon=None, **LatLon_kwds):
501
497
  '''Returns the lower-left SW and upper-right NE corners of a geohash.
502
498
 
503
- @arg geohash: To be bound (L{Geohash}).
504
- @kwarg LatLon: Optional class to return the bounds (C{LatLon})
505
- or C{None}.
506
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
507
- arguments, ignored if C{B{LatLon} is None}.
499
+ @arg geohash: To be "bound" (L{Geohash}).
500
+ @kwarg LatLon: Optional class to return the bounds (C{LatLon}) or C{None}.
501
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword arguments,
502
+ ignored if C{B{LatLon} is None}.
508
503
 
509
- @return: A L{Bounds2Tuple}C{(latlonSW, latlonNE)} of B{C{LatLon}}s
510
- or if B{C{LatLon}} is C{None}, a L{Bounds4Tuple}C{(latS,
511
- lonW, latN, lonE)}.
504
+ @return: A L{Bounds2Tuple}C{(latlonSW, latlonNE)}, each a B{C{LatLon}}
505
+ or if C{B{LatLon} is None}, a L{Bounds4Tuple}C{(latS, lonW,
506
+ latN, lonE)}.
512
507
 
513
- @raise TypeError: The B{C{geohash}} is not a L{Geohash}, C{LatLon}
514
- or C{str} or invalid B{C{LatLon}} or invalid
515
- B{C{LatLon_kwds}}.
508
+ @raise TypeError: The B{C{geohash}} is not a L{Geohash}, C{LatLon} or
509
+ C{str} or invalid B{C{LatLon}} or invalid B{C{LatLon_kwds}}.
516
510
 
517
511
  @raise GeohashError: Invalid or C{null} B{C{geohash}}.
518
512
  '''
@@ -847,14 +841,12 @@ def resolution2(prec1, prec2=None):
847
841
  def sizes(geohash):
848
842
  '''Return the lat- and longitudinal size of this L{Geohash} cell.
849
843
 
850
- @arg geohash: Cell for which size are required (L{Geohash} or
851
- C{str}).
844
+ @arg geohash: Cell for which size are required (L{Geohash} or C{str}).
852
845
 
853
- @return: A L{LatLon2Tuple}C{(lat, lon)} with the latitudinal
854
- height and longitudinal width in (C{meter}).
846
+ @return: A L{LatLon2Tuple}C{(lat, lon)} with the latitudinal height and
847
+ longitudinal width in (C{meter}).
855
848
 
856
- @raise TypeError: The B{C{geohash}} is not a L{Geohash},
857
- C{LatLon} or C{str}.
849
+ @raise TypeError: The B{C{geohash}} is not a L{Geohash}, C{LatLon} or C{str}.
858
850
  '''
859
851
  return _2Geohash(geohash).sizes
860
852