pygeodesy 24.8.4__py2.py3-none-any.whl → 24.9.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.
Files changed (76) hide show
  1. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.9.9.dist-info}/METADATA +17 -16
  2. PyGeodesy-24.9.9.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.9.9.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +23 -23
  5. pygeodesy/__main__.py +46 -47
  6. pygeodesy/auxilats/_CX_4.py +104 -181
  7. pygeodesy/auxilats/_CX_6.py +152 -277
  8. pygeodesy/auxilats/_CX_8.py +211 -438
  9. pygeodesy/auxilats/_CX_Rs.py +222 -0
  10. pygeodesy/auxilats/__init__.py +2 -2
  11. pygeodesy/auxilats/__main__.py +30 -38
  12. pygeodesy/auxilats/auxDST.py +2 -2
  13. pygeodesy/auxilats/auxLat.py +28 -36
  14. pygeodesy/auxilats/auxily.py +30 -50
  15. pygeodesy/basics.py +18 -7
  16. pygeodesy/booleans.py +10 -11
  17. pygeodesy/cartesianBase.py +5 -5
  18. pygeodesy/constants.py +35 -34
  19. pygeodesy/ellipsoidalBase.py +18 -15
  20. pygeodesy/ellipsoidalExact.py +2 -2
  21. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  22. pygeodesy/ellipsoidalKarney.py +2 -2
  23. pygeodesy/ellipsoidalNvector.py +2 -2
  24. pygeodesy/ellipsoidalVincenty.py +7 -6
  25. pygeodesy/elliptic.py +154 -88
  26. pygeodesy/epsg.py +3 -3
  27. pygeodesy/etm.py +71 -59
  28. pygeodesy/fmath.py +99 -90
  29. pygeodesy/fsums.py +201 -14
  30. pygeodesy/gars.py +9 -8
  31. pygeodesy/geodesici.py +6 -5
  32. pygeodesy/geodesicx/_C4_24.py +1 -3
  33. pygeodesy/geodesicx/_C4_27.py +1 -3
  34. pygeodesy/geodesicx/_C4_30.py +1 -3
  35. pygeodesy/geodesicx/__init__.py +1 -1
  36. pygeodesy/geodesicx/__main__.py +44 -46
  37. pygeodesy/geodesicx/gx.py +3 -3
  38. pygeodesy/geodesicx/gxarea.py +5 -5
  39. pygeodesy/geodesicx/gxbases.py +32 -18
  40. pygeodesy/geodsolve.py +3 -3
  41. pygeodesy/geohash.py +18 -11
  42. pygeodesy/geoids.py +293 -315
  43. pygeodesy/heights.py +150 -158
  44. pygeodesy/internals.py +70 -9
  45. pygeodesy/interns.py +4 -4
  46. pygeodesy/karney.py +83 -60
  47. pygeodesy/ktm.py +4 -4
  48. pygeodesy/latlonBase.py +13 -7
  49. pygeodesy/lazily.py +13 -8
  50. pygeodesy/ltp.py +5 -6
  51. pygeodesy/ltpTuples.py +7 -1
  52. pygeodesy/mgrs.py +47 -42
  53. pygeodesy/named.py +8 -4
  54. pygeodesy/namedTuples.py +14 -1
  55. pygeodesy/osgr.py +7 -7
  56. pygeodesy/points.py +2 -2
  57. pygeodesy/props.py +7 -6
  58. pygeodesy/resections.py +7 -7
  59. pygeodesy/rhumb/__init__.py +1 -1
  60. pygeodesy/rhumb/aux_.py +42 -60
  61. pygeodesy/rhumb/solve.py +3 -3
  62. pygeodesy/simplify.py +10 -10
  63. pygeodesy/sphericalBase.py +3 -3
  64. pygeodesy/sphericalTrigonometry.py +2 -2
  65. pygeodesy/streprs.py +3 -3
  66. pygeodesy/triaxials.py +207 -201
  67. pygeodesy/units.py +3 -3
  68. pygeodesy/unitsBase.py +4 -4
  69. pygeodesy/utmupsBase.py +3 -3
  70. pygeodesy/vector2d.py +158 -51
  71. pygeodesy/vector3d.py +13 -52
  72. pygeodesy/vector3dBase.py +81 -63
  73. pygeodesy/webmercator.py +3 -3
  74. pygeodesy/wgrs.py +20 -22
  75. PyGeodesy-24.8.4.dist-info/RECORD +0 -117
  76. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.9.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,222 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''(INTERNAL) Classes C{_Rcoeffs}, C{_Rdict} and C{_Rtuple} to store the deferred
5
+ Python versions of coefficients from I{Karney}'s C++ class U{AuxLatitude
6
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxLatitude.html>}.
7
+
8
+ Copyright (C) Charles Karney (2022-2024) Karney@Alum.MIT.edu> and licensed under the
9
+ MIT/X11 License. For more information, see <https:#GeographicLib.SourceForge.io>.
10
+ '''
11
+ # make sure int/int division yields float quotient, see .basics
12
+ from __future__ import division as _; del _ # PYCHOK semicolon
13
+
14
+ from pygeodesy.constants import _floats
15
+ from pygeodesy.errors import _AssertionError, _MODS
16
+ from pygeodesy.interns import NN, MISSING, _COMMA_, _duplicate_, _NL_, \
17
+ _QUOTE3_, _SLASH_, _ELLIPSIS4_ # PYCHOK used!
18
+ # from pygeodesy.lazily import _ALL_MODS as _MODS # from .errors
19
+ from pygeodesy.named import ADict, Property_RO
20
+ # from pygeodesy.props import Property_RO # from .named
21
+
22
+ __all__ = ()
23
+ __version__ = '24.09.04'
24
+
25
+
26
+ class _Rcoeffs(ADict):
27
+ '''(INTERNAL) With string-ified C{keys}.
28
+ '''
29
+ def __init__(self, ALorder, coeffs):
30
+ '''New C{_Rcoeffs} from a C{coeffs} dict.
31
+ '''
32
+ try:
33
+ if not isinstance(coeffs, dict):
34
+ raise _RdictError(coeffs=type(coeffs))
35
+ n = 0
36
+ for k, d in coeffs.items():
37
+ if not isinstance(d, _Rdict):
38
+ raise _RdictError(k=k, d=type(d))
39
+ n += d.n
40
+
41
+ ADict.__init__(self, coeffs)
42
+ self.set_(ALorder=ALorder, n=n) # in .validate
43
+ except Exception as x:
44
+ raise _RdictError(ALorder=ALorder, cause=x)
45
+
46
+ def bnuz4(self): # in .auxilats.__main__ # PYCHOK no cover
47
+ # get C{(strB, number, unique, floatB)} rationals
48
+ b = n = u = z = 0
49
+ _zB = _MODS.internals._sizeof
50
+ for R in self._Rtuples():
51
+ _, _, rs = R.k_n_rs
52
+ b += _zB(rs)
53
+ t = R._tuple
54
+ z += _zB(t) # Float
55
+ # assert R.Rdict is None
56
+ n += len(t)
57
+ u += sum(1 for f in t if f in _floats)
58
+ return b, n, (n - u), z
59
+
60
+ def items(self): # string-ify keys # PYCHOK no cover
61
+ for n, v in ADict.items(self):
62
+ yield str(n), v
63
+
64
+ def _Rtuples(self): # PYCHOK no cover
65
+ for d in self.values():
66
+ if isinstance(d, _Rdict):
67
+ # yield from d.values()
68
+ for R in d.values():
69
+ yield R
70
+
71
+ def _validate(self, aL, lenAux):
72
+ # in .auxily.Aux._CXcoeffs(al, Aux.len(aL))
73
+ a, n = self.ALorder, self.n # PYCHOK Adict!
74
+ # for R in self._Rtuples():
75
+ # assert isinstance(R, _Rtuple)
76
+ if aL != a or lenAux != n:
77
+ raise _RdictError(aL=aL, ALorder=a, lenAux=lenAux, n=n)
78
+ return self
79
+
80
+
81
+ class _Rdict(dict): # in ._CX_#, .auxLat, .rhumb.aux_
82
+ '''(INTERNAL) Dict of C{_Rtuple}s.
83
+ '''
84
+ n = 0 # sum(R.k_n_k[1] for r in Rtuples)
85
+
86
+ def __init__(self, nt, *Rtuples):
87
+ '''New C{_Rdict}.
88
+ '''
89
+ if not Rtuples:
90
+ raise _RdictError(Rtuples=MISSING)
91
+
92
+ for R in Rtuples:
93
+ if not isinstance(R, _Rtuple):
94
+ raise _RdictError(R, R=type(R))
95
+ k, n, _ = R.k_n_rs
96
+ if k in self:
97
+ raise _RdictError(_duplicate_, k=k)
98
+ R.Rdict = self
99
+ self[k] = R # overwritten in self._floatuple
100
+ self.n += n
101
+ if self.n != nt:
102
+ raise _RdictError(n=n, nt=nt)
103
+
104
+ def _floats(self, rs):
105
+ # yield floats from a string of comma-separated rationals
106
+ def _p_q(p=NN, q=1, *x):
107
+ return (NN if x else p), q
108
+
109
+ _get = _floats.get
110
+ for r in NN(*rs.split()).split(_COMMA_):
111
+ p, q = _p_q(*r.split(_SLASH_))
112
+ if p:
113
+ f = int(p) / int(q) # fractions.Fraction?
114
+ if not isinstance(f, float):
115
+ raise _RdictError(rs, f=f, p=p, q=q, r=r)
116
+ yield _get(f, f) # from .constants?
117
+ else:
118
+ raise _RdictError(rs, r=r)
119
+
120
+ def _floatuple(self, Rtuple):
121
+ # return a tuple of floats from an C{_Rtuple}
122
+ k, n, rs = Rtuple.k_n_rs
123
+ t = tuple(f for m in map(self._floats, rs)
124
+ for f in m) # ... yield f
125
+ # @see: <https://StackOverflow.com/questions/10632839/>
126
+ # and <https://realPython.com/python-flatten-list/>
127
+ if len(t) != n:
128
+ raise _RdictError(*rs, len=len(t), n=n)
129
+ self[k] = t
130
+ return t
131
+
132
+
133
+ class _RdictError(_AssertionError):
134
+ '''(INTERNAL) For C{_Rdict} issues.
135
+ '''
136
+ def __init__(self, *rs, **kwds_cause): # PYCHOK no cover
137
+ if rs:
138
+ if len(rs) > 1:
139
+ t = _NL_(NN, *rs)
140
+ t = NN(_QUOTE3_, t, _QUOTE3_)
141
+ else: # single rs
142
+ t = repr(rs[0])
143
+ kwds_cause.update(txt=t)
144
+ _AssertionError.__init__(self, **kwds_cause)
145
+
146
+
147
+ class _Rtuple(list): # MUST be list, NOT tuple!
148
+ '''(INTERNAL) I{Pseudo-tuple} of float rationals used in C{_Rdict}s.
149
+ '''
150
+ Rdict = None
151
+ k_n_rs = None, 0, ()
152
+
153
+ def __init__(self, k, n, *rs):
154
+ '''New C{_Rtuple} with key C{k}, number of floats C{n} and with
155
+ each C{rs} a C{str} of comma-separated rationals C{"p/q, ..."}
156
+ where C{p} and C{q} are C{int} digits only.
157
+ '''
158
+ try:
159
+ if not rs:
160
+ raise _RdictError(rs=MISSING)
161
+ for t in rs:
162
+ if not isinstance(t, str):
163
+ raise _RdictError(rs=type(t))
164
+ if not (isinstance(n, int) and n > 0):
165
+ raise _RdictError(n=type(n))
166
+ self.k_n_rs = k, n, rs
167
+ except Exception as x:
168
+ raise _RdictError(*rs, k=k, n=n, cause=x)
169
+
170
+ def __getitem__(self, i):
171
+ return self._tuple[i]
172
+
173
+ def __iter__(self):
174
+ return iter(self._tuple)
175
+
176
+ def __len__(self):
177
+ return len(self._tuple)
178
+
179
+ @Property_RO
180
+ def _tuple(self):
181
+ # build the C{tuple} once, replace C{_Rdict}
182
+ # item at C{key} with the C{tuple} and fill
183
+ # this C{_Rlist} with the C{tuple} values
184
+ # for the initial __getitem__ retrieval[s]
185
+ try:
186
+ k, n, rs = self.k_n_rs
187
+ t = self.Rdict._floatuple(self)
188
+ self[:] = t # MUST copy into self!
189
+ except Exception as x:
190
+ if len(rs) > 1 and _QUOTE3_ in str(x):
191
+ rs = rs[0], _ELLIPSIS4_
192
+ raise _RdictError(k=k, n=n, rs=rs, cause=x)
193
+ del self.Rdict, self.k_n_rs # trash refs
194
+ return t
195
+
196
+ def append(self, arg):
197
+ raise _RdictError(append=arg)
198
+
199
+ def extend(self, arg):
200
+ raise _RdictError(extend=arg)
201
+
202
+ # **) MIT License
203
+ #
204
+ # Copyright (C) 2024-2024 -- mrJean1 at Gmail -- All Rights Reserved.
205
+ #
206
+ # Permission is hereby granted, free of charge, to any person obtaining a
207
+ # copy of this software and associated documentation files (the "Software"),
208
+ # to deal in the Software without restriction, including without limitation
209
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
210
+ # and/or sell copies of the Software, and to permit persons to whom the
211
+ # Software is furnished to do so, subject to the following conditions:
212
+ #
213
+ # The above copyright notice and this permission notice shall be included
214
+ # in all copies or substantial portions of the Software.
215
+ #
216
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
217
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
219
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
220
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
221
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
222
+ # OTHER DEALINGS IN THE SOFTWARE.
@@ -8,7 +8,7 @@ U{DST<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1DST.htm
8
8
  U{AuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxLatitude.html>} all
9
9
  in I{GeographicLib version 2.2+}.
10
10
 
11
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2022-2023) and licensed under the MIT/X11
11
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2022-2024) and licensed under the MIT/X11
12
12
  License. For more information, see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
13
13
 
14
14
  @note: Class L{AuxDST} requires U{numpy<https://PyPI.org/project/numpy>} to be installed, version 1.16
@@ -29,7 +29,7 @@ from pygeodesy.lazily import _ALL_OTHER
29
29
  # no modules: auxAngle, auxDLat, auxDST, auxily, auxLat
30
30
  __all__ = _ALL_OTHER(Aux, AuxAngle, AuxDLat, AuxDST, AuxLat,
31
31
  AuxBeta, AuxChi, AuxMu, AuxPhi, AuxTheta, AuxXi)
32
- __version__ = '24.06.16'
32
+ __version__ = '24.09.04'
33
33
 
34
34
  # **) MIT License
35
35
  #
@@ -5,57 +5,49 @@ u'''Print L{auxilats} version, etc. using C{python -m pygeodesy.auxilats}.
5
5
  '''
6
6
 
7
7
  __all__ = ()
8
- __version__ = '24.05.31'
8
+ __version__ = '24.09.04'
9
9
 
10
10
 
11
- def _CXstats(): # PYCHOK no cover
12
- '''(INTERNAL) Get the C{CP} stats.
13
- '''
14
- from pygeodesy.auxilats import Aux, AuxLat, auxLat
15
- from pygeodesy.datums import _WGS84
16
-
17
- A = AuxLat(_WGS84)
18
- ax = A._coeffs(Aux.XI, Aux.CHI)
19
- Cx = auxLat._CXcoeffs(A.ALorder)
20
- pc = '%.1f%%' % (Cx.u * 100.0 / Cx.n)
21
- return dict(ALorder=A.ALorder, CXlen=Cx.n, CXset=Cx.u, CXset_len=pc, CXx=len(ax))
22
-
23
-
24
- def _main(): # PYCHOK no cover
25
-
26
- import os.path as _os_path
11
+ def _main(**ALorder): # PYCHOK no cover
27
12
 
28
13
  try:
29
- from pygeodesy import auxilats, printf, pygeodesy_abspath
30
- from pygeodesy.internals import _name_version, _Pythonarchine, _usage
31
- from pygeodesy.interns import _COMMASPACE_, _DOT_, _version_
32
- from pygeodesy.streprs import Fmt
33
-
34
- def _dot_attr(name, value):
35
- return Fmt.DOT(Fmt.EQUAL(name, value))
36
-
37
- s = tuple(sorted(_CXstats().items()))
38
- p = [_dot_attr(*t) for t in (((_version_, auxilats.__version__),) + s)]
39
-
40
- v = _Pythonarchine()
14
+ from pygeodesy import auxilats
15
+ from pygeodesy.internals import _fper, _name_version, \
16
+ printf, _versions
17
+ from pygeodesy.interns import _COMMASPACE_, _EQUAL_
18
+
19
+ A = auxilats.AuxLat(**ALorder)
20
+ Cx = A._CXcoeffs # PropertyRO: Adict of _Rdicts
21
+ b, n, u, z = Cx.bnuz4()
22
+ p = dict(ALorder=A.ALorder,CXb=b, CXb_z=_fper(b, z),
23
+ CXn=n, CXu=u, CXu_n=_fper(u, n))
24
+ p = list(_EQUAL_(*t) for t in p.items())
41
25
  try:
42
26
  import geographiclib
43
- v.append(_name_version(geographiclib))
27
+ p.append(_name_version(geographiclib))
44
28
  except ImportError:
45
29
  pass
46
30
 
47
- a = auxilats.__name__
48
- x = _os_path.basename(pygeodesy_abspath)
49
- if not a.startswith(x):
50
- a = _DOT_(x, a)
51
- printf('%s%s (%s)', a, _COMMASPACE_.join(p), _COMMASPACE_.join(v))
31
+ a = _name_version(auxilats)
32
+ printf('%s: %s (%s)', a, _COMMASPACE_(*p), _versions())
52
33
 
53
34
  except ImportError:
54
- raise
55
- printf(_usage(__file__))
35
+ from pygeodesy.internals import _usage
36
+ print(_usage(__file__))
37
+
38
+
39
+ from sys import argv # .internals._isPyChecker
40
+ _main(ALorder=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
41
+
42
+ # % python3.12 -m pygeodesy.auxilats 8
43
+ # pygeodesy.auxilats 24.09.04: ALorder=8, CXb=20310, CXb_z=71.5%, CXn=888, CXu=780, CXu_n=87.8%, geographiclib 2.0 (pygeodesy 24.9.9 Python 3.12.5 64bit arm64 macOS 14.6.1)
44
+
45
+ # % python3.12 -m pygeodesy.auxilats 6
46
+ # pygeodesy.auxilats 24.09.04: ALorder=6, CXb=11099, CXb_z=64.1%, CXn=522, CXu=448, CXu_n=85.8%, geographiclib 2.0 (pygeodesy 24.9.9 Python 3.12.5 64bit arm64 macOS 14.6.1)
56
47
 
48
+ # % python3.12 -m pygeodesy.auxilats 4
49
+ # pygeodesy.auxilats 24.09.04: ALorder=4, CXb=5367, CXb_z=58.8%, CXn=252, CXu=203, CXu_n=80.6%, geographiclib 2.0 (pygeodesy 24.9.9 Python 3.12.5 64bit arm64 macOS 14.6.1)
57
50
 
58
- _main()
59
51
 
60
52
  # **) MIT License
61
53
  #
@@ -24,7 +24,7 @@ from pygeodesy.karney import _2cos2x, _ALL_DOCS
24
24
  from pygeodesy.props import property_RO, property_ROver
25
25
 
26
26
  __all__ = ()
27
- __version__ = '24.07.25'
27
+ __version__ = '24.08.13'
28
28
 
29
29
 
30
30
  class AuxDST(object):
@@ -92,7 +92,7 @@ class AuxDST(object):
92
92
 
93
93
  @arg data: Elements DST-III[0:N+1] or DST-IV[0:N] (C{float}[])
94
94
  with DST_III[0] = 0.
95
- @arg cIV: If C{True} DST-IV, otherwise DST-III.
95
+ @arg cIV: If C{True}, DST-IV, otherwise DST-III.
96
96
 
97
97
  @return: FFTransforms (C{float}[0:N]).
98
98
  '''
@@ -17,11 +17,12 @@ from __future__ import division as _; del _ # PYCHOK semicolon
17
17
 
18
18
  from pygeodesy.auxilats.auxAngle import AuxAngle, AuxBeta, AuxChi, _AuxClass, \
19
19
  AuxMu, AuxPhi, AuxTheta, AuxXi
20
- from pygeodesy.auxilats.auxily import Aux, _sc, _sn, _Ufloats, atan1
20
+ from pygeodesy.auxilats.auxily import Aux, _sc, _sn, atan1
21
+ from pygeodesy.auxilats._CX_Rs import _Rdict, _Rtuple
21
22
  from pygeodesy.basics import _reverange, _xinstanceof, _passarg
22
23
  from pygeodesy.constants import INF, MAX_EXP, MIN_EXP, NAN, PI_2, PI_4, _EPSqrt, \
23
- _0_0, _0_0s, _0_1, _0_25, _0_5, _1_0, _2_0, _3_0, \
24
- _360_0, isfinite, isinf, isnan, _log2, _over
24
+ _0_0, _0_0s, _0_1, _0_5, _1_0, _2_0, _3_0, _360_0, \
25
+ _log2, _over, isfinite, isinf, isnan
25
26
  from pygeodesy.datums import _ellipsoidal_datum, _WGS84, \
26
27
  Ellipsoid, _name__, _EWGS84
27
28
  # from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
@@ -30,9 +31,9 @@ from pygeodesy.errors import AuxError, _xkwds_not, _xkwds_pop2, _Xorder
30
31
  # from pygeodesy.fmath import cbrt # from .karney
31
32
  from pygeodesy.fsums import Fsum, _Fsumf_, _sum
32
33
  # from pygeodesy.internals import _passarg # from .basics
33
- from pygeodesy.interns import NN, _DOT_, _not_scalar_, _UNDER_
34
- from pygeodesy.karney import _2cos2x, _polynomial, _ALL_DOCS, cbrt, _MODS
35
- # from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS # from .karney
34
+ from pygeodesy.interns import NN, _not_scalar_, _UNDER_
35
+ from pygeodesy.karney import _2cos2x, _polynomial, _ALL_DOCS, cbrt
36
+ # from pygeodesy.lazily import _ALL_DOCS # from .karney
36
37
  # from pygeodesy.named import _name__ # from .datums
37
38
  from pygeodesy.props import Property, Property_RO, _update_all
38
39
  from pygeodesy.units import _isDegrees, _isRadius, Degrees, Meter
@@ -47,7 +48,7 @@ except ImportError: # Python 3.11-
47
48
  return pow(_2_0, x)
48
49
 
49
50
  __all__ = ()
50
- __version__ = '24.06.16'
51
+ __version__ = '24.09.03'
51
52
 
52
53
  _TRIPS = 1024 # XXX 2 or 3?
53
54
 
@@ -222,9 +223,8 @@ class AuxLat(AuxAngle):
222
223
  except KeyError:
223
224
  pass
224
225
 
225
- Cx = _CXcoeffs(aL)
226
226
  try:
227
- Cx = Cx[auxout][auxin]
227
+ Cx = self._CXcoeffs[auxout][auxin] # _Rtuple!
228
228
  except KeyError as x:
229
229
  raise AuxError(auxout=auxout, auxin=auxin, cause=x)
230
230
 
@@ -238,13 +238,12 @@ class AuxLat(AuxAngle):
238
238
  else:
239
239
  _m = _reverange # PYCHOK expected
240
240
 
241
- i = 0
241
+ i = 0
242
242
  cs = []
243
- _c = cs.append
244
243
  _p = _polynomial
245
244
  for m in _m(aL):
246
245
  j = i + m + 1 # order m = j - i - 1
247
- _c(_p(x, Cx, i, j) * d)
246
+ cs.append(_p(x, Cx, i, j) * d)
248
247
  d *= n
249
248
  i = j
250
249
  # assert i == len(Cx) and len(cs) == aL
@@ -378,6 +377,12 @@ class AuxLat(AuxAngle):
378
377
 
379
378
  raise AuxError(auxout=auxout, Zeta_d=Zeta_d, exact=exact)
380
379
 
380
+ @Property_RO
381
+ def _CXcoeffs(self): # in .auxilats.__main__, .testAuxilats
382
+ '''(INTERNAL) Get the C{CX_4}, C{_6} or C{_8} coefficients.
383
+ '''
384
+ return Aux._CXcoeffs(self.ALorder)
385
+
381
386
  def _Dq(self, tphi):
382
387
  # I{Divided Difference} of (q(1) - q(sphi)) / (1 - sphi).
383
388
  sphi = _sn(tphi)
@@ -763,19 +768,6 @@ def _Clenshaw(sinp, Zeta, cs, K):
763
768
  return x
764
769
 
765
770
 
766
- def _CXcoeffs(aL): # PYCHOK in .auxilats.__main__
767
- '''(INTERNAL) Get the C{CX_4}, C{_6} or C{_8} coefficients.
768
- '''
769
- try: # from pygeodesy.auxilats._CX_x import _coeffs_x as _coeffs
770
- _CX_x = _DOT_(_MODS.auxilats.__name__, _UNDER_('_CX', aL))
771
- _coeffs = _MODS.getattr(_CX_x, _UNDER_('_coeffs', aL))
772
- except (AttributeError, ImportError, KeyError, TypeError) as x:
773
- raise AuxError(ALorder=aL, cause=x)
774
- # assert _coeffs.ALorder == aL
775
- # assert _coeffs.n == Aux.len(aL)
776
- return _coeffs
777
-
778
-
779
771
  def _diff_name2(Phi, diff=False, **name):
780
772
  '''(INTERNAL) Get C{{Bdiff}=False} and C{B{name}=NN}.
781
773
  '''
@@ -836,17 +828,17 @@ def _Newton(tphi, Zeta, _toZeta, **name):
836
828
  return Phi
837
829
 
838
830
 
839
- _f, _u = float, _Ufloats()
840
- _1__f3 = -1 / _f(3) # XXX +1 / _f(3)
841
- _AR2Coeffs = {4: _u(4 / _f(315), 4 / _f(105), 4 / _f(15), _1__f3),
842
- 6: _u(4 / _f(1287), 4 / _f(693), 4 / _f(315), 4 / _f(105),
843
- 4 / _f(15), _1__f3),
844
- 8: _u(4 / _f(3315), 4 / _f(2145), 4 / _f(1287), 4 / _f(693),
845
- 4 / _f(315), 4 / _f(105), 4 / _f(15), _1__f3)}
846
- _RRCoeffs = {4: _u(1 / _f(64), _0_25),
847
- 6: _u(1 / _f(256), 1 / _f(64), _0_25),
848
- 8: _u(25 / _f(16384), 1 / _f(256), 1 / _f(64), _0_25)} # PYCHOK used!
849
- del _f, _u, _Ufloats, _1__f3
831
+ _AR2Coeffs = _Rdict(18,
832
+ _Rtuple(4, 4, '4/315, 4/105, 4/15, -1/3'),
833
+ _Rtuple(6, 6, '4/1287, 4/693, 4/15, 4/105, 4/315, -1/3'),
834
+ _Rtuple(8, 8, '4/3315, 4/2145, 4/1287, 4/693, 4/315, 4/105, 4/15, -1/3'))
835
+
836
+ _RRCoeffs = _Rdict(9,
837
+ _Rtuple(4, 2, '1/64, 1/4'),
838
+ _Rtuple(6, 3, '1/256, 1/64, 1/4'),
839
+ _Rtuple(8, 4, '25/16384, 1/256, 1/64, 1/4')) # PYCHOK used!
840
+
841
+ del _Rdict, _Rtuple
850
842
  # assert set(_AR2Coeffs.keys()) == set(_RRCoeffs.keys())
851
843
 
852
844
  # AuxLat._Lmax = max(_AR2Coeffs.keys()) # == max(ALorder)
@@ -14,25 +14,25 @@ under the MIT/X11 License. For more information, see the U{GeographicLib
14
14
  # make sure int/int division yields float quotient, see .basics
15
15
  from __future__ import division as _; del _ # PYCHOK semicolon
16
16
 
17
- from pygeodesy.constants import INF, NAN, isinf, isnan, _0_0, _0_5, \
18
- _1_0, _copysign_1_0, _over, _1_over
19
- from pygeodesy.errors import AuxError, NN
17
+ # from pygeodesy import auxilats # _MODS
18
+ from pygeodesy.constants import INF, NAN, isinf, isnan, _0_0, _0_5, _1_0, \
19
+ _copysign_1_0, _over, _1_over
20
+ from pygeodesy.errors import AuxError
20
21
  from pygeodesy.fmath import hypot1 as _sc, hypot2_
21
- # from pygeodesy.interns import NN # from .errors
22
- from pygeodesy.karney import ADict, _ALL_DOCS, _MODS # PYCHOK used!
23
- # from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS # from .karney
24
- # from pygeodesy.named import ADict # from .karney
22
+ from pygeodesy.interns import NN, _DOT_, _UNDER_ # PYCHOK used!
23
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS # PYCHOK used!
25
24
  from pygeodesy.utily import atan1
26
25
 
27
26
  from math import asinh, copysign
28
27
 
29
28
  __all__ = ()
30
- __version__ = '24.07.12'
29
+ __version__ = '24.09.03'
31
30
 
32
31
 
33
32
  class Aux(object):
34
33
  '''Enum-style Aux names.
35
34
  '''
35
+ _coeffs = {}
36
36
  GEOGRAPHIC = PHI = GEODETIC = 0
37
37
  PARAMETRIC = BETA = REDUCED = 1
38
38
  GEOCENTRIC = THETA = 2 # all ...
@@ -44,18 +44,33 @@ class Aux(object):
44
44
 
45
45
  def __index__(self, aux):
46
46
  # throws KeyError, not IndexError
47
- return _MODS.auxilats.auxLat._Aux2Greek[aux]
47
+ return _Aux2Greek[aux]
48
48
 
49
49
  def __len__(self):
50
50
  return Aux.N
51
51
 
52
+ def _CXcoeffs(self, aL): # in .auxLat.AuxLat._CXcoeffs
53
+ '''(INTERNAL) Get the C{_CX_4._coeffs_4}, C{_CX_6._coeffs_6}
54
+ or C{_CS_8._coeffs_8} coefficients, once.
55
+ '''
56
+ try:
57
+ _coeffs = Aux._coeffs[aL]
58
+ except KeyError:
59
+ try: # from pygeodesy.auxilats._CX_x import _coeffs_x as _coeffs
60
+ _CX_x = _DOT_(_MODS.auxilats.__name__, _UNDER_('_CX', aL))
61
+ _coeffs = _MODS.getattr(_CX_x, _UNDER_('_coeffs', aL))
62
+ except (AttributeError, ImportError, KeyError, TypeError) as x:
63
+ raise AuxError(ALorder=aL, cause=x)
64
+ Aux._coeffs[aL] = _coeffs._validate(aL, Aux.len(aL))
65
+ return _coeffs
66
+
52
67
  def _1d(self, auxout, auxin):
53
68
  '''Get the 1-d index into N^2 coeffs.
54
69
  '''
55
70
  N = Aux.N
56
71
  if 0 <= auxout < N and 0 <= auxin < N:
57
72
  return N * auxout + auxin
58
- raise AuxError(auxout=auxout, auxin=auxin, N=N) # == AssertionError
73
+ raise AuxError(auxout=auxout, auxin=auxin, N=N)
59
74
 
60
75
  def Greek(self, aux):
61
76
  '''Get an angle's name (C{str}).
@@ -65,9 +80,9 @@ class Aux(object):
65
80
  def len(self, ALorder): # PYCHOK no cover
66
81
  aL = ALorder # aka Lmax
67
82
  mu = Aux.MU * (Aux.MU + 1)
68
- ns = Aux.N2 - Aux.N
69
- return (mu * (aL * (aL + 3) - 2 * (aL // 2)) // 4 +
70
- (ns - mu) * (aL * (aL + 1)) // 2)
83
+ nu = Aux.N2 - Aux.N - mu
84
+ return (mu * (aL * (aL + 3) - (aL // 2) * 2) // 4 +
85
+ nu * (aL * (aL + 1)) // 2)
71
86
 
72
87
  def power(self, auxout, auxin):
73
88
  '''Get the C{convert} exponent (C{int} or C{None}).
@@ -83,21 +98,13 @@ Aux = Aux() # PYCHOK singleton
83
98
  _Aux2Greek = {Aux.AUTHALIC: 'Xi',
84
99
  Aux.CONFORMAL: 'Chi',
85
100
  Aux.GEOCENTRIC: 'Theta',
86
- Aux.GEODETIC: 'Phi', # == .GEOGRAPHIC
87
- Aux.PARAMETRIC: 'Beta',
101
+ Aux.GEODETIC: 'Phi', # == .GEOGRAPHIC
102
+ Aux.PARAMETRIC: 'Beta', # == .REDUCED
88
103
  Aux.RECTIFYING: 'Mu'}
89
104
  _Greek2Aux = dict(map(reversed, _Aux2Greek.items())) # PYCHOK exported
90
105
  # _Greek2Aux.update((_g.upper(), _x) for _g, _x in _Greek2Aux.items())
91
106
 
92
107
 
93
- class _Coeffs(ADict):
94
- '''(INTERNAL) With C{items keys} string-ified.
95
- '''
96
- def items(self):
97
- for n, v in ADict.items(self):
98
- yield str(n), v
99
-
100
-
101
108
  def _Dasinh(x, y):
102
109
  d = y - x
103
110
  if isinf(d): # PYCHOK no cover
@@ -220,33 +227,6 @@ def _sn(tx):
220
227
  return tx # preserve signed-0
221
228
 
222
229
 
223
- class _Ufloats(dict): # in .auxilats.auxily
224
- '''(INTERNAL) "Uniquify" floats.
225
- '''
226
- n = 0 # total number of floats
227
-
228
- def __call__(self, *fs):
229
- '''Return a tuple of "uniquified" floats.
230
- '''
231
- self.n += len(fs)
232
- _f = self.setdefault
233
- return tuple(_f(f, f) for f in map(float, fs)) # PYCHOK as attr
234
-
235
- def _Coeffs(self, ALorder, coeffs):
236
- '''Return C{coeffs} (C{_Coeffs}, I{embellished}).
237
- '''
238
- # if True:
239
- # n = 0
240
- # for d in coeffs.values():
241
- # n += sum(d.values())
242
- # assert n == self.n
243
- Cx = _Coeffs(coeffs)
244
- Cx.set_(ALorder=ALorder, # used in .auxilats.__main__
245
- n=self.n, # total number of floats
246
- u=len(self.keys())) # unique floats
247
- return Cx
248
-
249
-
250
230
  __all__ += _ALL_DOCS(Aux.__class__)
251
231
 
252
232
  # **) MIT License
pygeodesy/basics.py CHANGED
@@ -37,7 +37,7 @@ from math import copysign as _copysign
37
37
  import inspect as _inspect
38
38
 
39
39
  __all__ = _ALL_LAZY.basics
40
- __version__ = '24.07.06'
40
+ __version__ = '24.09.02'
41
41
 
42
42
  _below_ = 'below'
43
43
  _list_tuple_types = (list, tuple)
@@ -68,8 +68,8 @@ except ImportError:
68
68
  _Seqs = list, _Sequence # range for function len2 below
69
69
 
70
70
  try:
71
- _Bytes = unicode, bytearray # PYCHOK expected
72
- _Strs = basestring, str # XXX , bytes
71
+ _Bytes = unicode, bytearray # PYCHOK in .internals
72
+ _Strs = basestring, str # XXX str == bytes
73
73
  str2ub = ub2str = _passarg # avoids UnicodeDecodeError
74
74
 
75
75
  def _Xstr(exc): # PYCHOK no cover
@@ -93,7 +93,7 @@ try:
93
93
  except NameError: # Python 3+
94
94
  from pygeodesy.interns import _utf_8_
95
95
 
96
- _Bytes = bytes, bytearray
96
+ _Bytes = bytes, bytearray # in .internals
97
97
  _Strs = str, # tuple
98
98
  _Xstr = str
99
99
 
@@ -166,7 +166,7 @@ def clips(sb, limit=50, white=NN, length=False):
166
166
  @arg sb: String (C{str} or C{bytes}).
167
167
  @kwarg limit: Length limit (C{int}).
168
168
  @kwarg white: Optionally, replace all whitespace (C{str}).
169
- @kwarg len: IF C{True} append the original I{[length]} (C{bool}).
169
+ @kwarg length: If C{True}, append the original I{[length]} (C{bool}).
170
170
 
171
171
  @return: The clipped or unclipped B{C{sb}}.
172
172
  '''
@@ -733,7 +733,7 @@ def _xcopy(obj, deep=False):
733
733
  '''(INTERNAL) Copy an object, shallow or deep.
734
734
 
735
735
  @arg obj: The object to copy (any C{type}).
736
- @kwarg deep: If C{True} make a deep, otherwise
736
+ @kwarg deep: If C{True}, make a deep, otherwise
737
737
  a shallow copy (C{bool}).
738
738
 
739
739
  @return: The copy of B{C{obj}}.
@@ -741,11 +741,22 @@ def _xcopy(obj, deep=False):
741
741
  return _deepcopy(obj) if deep else _copy(obj)
742
742
 
743
743
 
744
+ def _xcoverage(where, *required):
745
+ '''(INTERNAL) Import C{coverage} and check required version.
746
+ '''
747
+ try:
748
+ _xpackage(_xcoverage)
749
+ import coverage
750
+ except ImportError as x:
751
+ raise _xImportError(x, where)
752
+ return _xversion(coverage, where, *required)
753
+
754
+
744
755
  def _xdup(obj, deep=False, **items):
745
756
  '''(INTERNAL) Duplicate an object, replacing some attributes.
746
757
 
747
758
  @arg obj: The object to copy (any C{type}).
748
- @kwarg deep: If C{True} copy deep, otherwise shallow.
759
+ @kwarg deep: If C{True}, copy deep, otherwise shallow (C{bool}).
749
760
  @kwarg items: Attributes to be changed (C{any}).
750
761
 
751
762
  @return: A duplicate of B{C{obj}} with modified