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
pygeodesy/elliptic.py CHANGED
@@ -65,7 +65,8 @@ in U{B. C. Carlson, Computation of real or complex elliptic integrals
65
65
  The computation of the Jacobi elliptic functions uses the algorithm
66
66
  given in U{R. Bulirsch, Numerical Calculation of Elliptic Integrals
67
67
  and Elliptic Functions<https://DOI.org/10.1007/BF01397975>},
68
- Numerische Mathematik 7, 78--90 (1965).
68
+ Numerische Mathematik 7, 78--90 (1965) or optionally the C{Jacobi
69
+ amplitude} in method L{Elliptic.sncndn<pygeodesy.Elliptic.sncndn>}.
69
70
 
70
71
  The notation follows U{NIST Digital Library of Mathematical Functions
71
72
  <https://DLMF.NIST.gov>} chapters U{19<https://DLMF.NIST.gov/19>} and
@@ -75,13 +76,13 @@ U{22<https://DLMF.NIST.gov/22>}.
75
76
  from __future__ import division as _; del _ # PYCHOK semicolon
76
77
 
77
78
  from pygeodesy.basics import copysign0, map2, neg, neg_
78
- from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, \
79
- _EPStol as _TolJAC, _0_0, _1_64th, \
80
- _0_25, _0_5, _1_0, _2_0, _N_2_0, \
81
- _3_0, _4_0, _6_0, _8_0, _180_0, \
82
- _360_0, _over
79
+ from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, _0_0, \
80
+ _0_25, _0_5, _1_0, _2_0, _N_2_0, _3_0, \
81
+ _4_0, _6_0, _8_0, _64_0, _180_0, _360_0, \
82
+ _EPStol as _TolJAC, _over, \
83
+ _EPSjam as _TolJAM # PYCHOK used!
83
84
  # from pygeodesy.errors import _ValueError # from .fmath
84
- from pygeodesy.fmath import fdot, hypot1, zqrt, _ValueError
85
+ from pygeodesy.fmath import favg, hypot1, zqrt, _ValueError
85
86
  from pygeodesy.fsums import Fsum, _sum
86
87
  # from pygeodesy.internals import _dunder_nameof # from .lazily
87
88
  from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, \
@@ -94,16 +95,16 @@ from pygeodesy.props import _allPropertiesOf_n, Property_RO, _update_all
94
95
  from pygeodesy.units import Scalar, Scalar_
95
96
  # from pygeodesy.utily import sincos2 as _sincos2 # from .karney
96
97
 
97
- from math import asinh, atan, atan2, ceil, cosh, fabs, floor, \
98
- radians, sin, sqrt, tanh
98
+ from math import asin, asinh, atan, atan2, ceil, cosh, fabs, floor, \
99
+ radians, sin, sinh, sqrt, tan, tanh
99
100
 
100
101
  __all__ = _ALL_LAZY.elliptic
101
- __version__ = '24.05.18'
102
+ __version__ = '24.09.06'
102
103
 
103
104
  _TolRD = zqrt(EPS * 0.002)
104
105
  _TolRF = zqrt(EPS * 0.030)
105
106
  _TolRG0 = _TolJAC * 2.7
106
- _TRIPS = 21 # Max depth, 7 might be sufficient
107
+ _TRIPS = 25 # Max depth, 6-7 might be sufficient
107
108
 
108
109
 
109
110
  class _Cs(object):
@@ -127,6 +128,19 @@ class _Dsum(list):
127
128
  return self
128
129
 
129
130
 
131
+ class _Dadd(_Dsum):
132
+ '''(INTERNAL) Deferred C{Fsum} for C{_List.amrs4}.
133
+ '''
134
+ def __init__(self, mul):
135
+ self._mul = mul
136
+
137
+ def __add__(self, x):
138
+ self += x
139
+ r = self(self._mul)
140
+ _ = self.pop()
141
+ return r # Fsum or float
142
+
143
+
130
144
  class Elliptic(_Named):
131
145
  '''Elliptic integrals and functions.
132
146
 
@@ -407,7 +421,6 @@ class Elliptic(_Named):
407
421
  # Applied Math. and Computation 218, 7005-7013 (2012)
408
422
  # <https://DOI.org/10.1016/j.amc.2011.12.021>
409
423
  _Phi2 = Phi.fsum2f_ # aggregate
410
- _abs = fabs
411
424
  for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
412
425
  sn, cn, dn = self._sncndn3(phi)
413
426
  if dn:
@@ -415,7 +428,7 @@ class Elliptic(_Named):
415
428
  phi, d = _Phi2((r - sn) / dn)
416
429
  else: # PYCHOK no cover
417
430
  d = _0_0 # XXX continue?
418
- if _abs(d) < _TolJAC: # 3-4 trips
431
+ if fabs(d) < _TolJAC: # 3-4 trips
419
432
  _iterations(self, i)
420
433
  break
421
434
  else: # PYCHOK no cover
@@ -505,7 +518,8 @@ class Elliptic(_Named):
505
518
  return ei
506
519
 
507
520
  return self._fXf(phi_or_sn, cn, dn, self.cE,
508
- self.deltaE, _fE)
521
+ self.deltaE, _fE,
522
+ k2_0=self.k2==0)
509
523
 
510
524
  def fEd(self, deg):
511
525
  '''The incomplete integral of the second kind with
@@ -561,7 +575,8 @@ class Elliptic(_Named):
561
575
  return r
562
576
 
563
577
  return self._fXf(phi_or_sn, cn, dn, self.cK,
564
- self.deltaF, _fF)
578
+ self.deltaF, _fF,
579
+ k2_0=self.k2==0, kp2_0=self.kp2==0)
565
580
 
566
581
  def fG(self, phi_or_sn, cn=None, dn=None):
567
582
  '''Legendre's geodesic longitude integral in terms of
@@ -648,12 +663,16 @@ class Elliptic(_Named):
648
663
 
649
664
  return self._fXf(phi_or_sn, cn, dn, cX, deltaX, _fX)
650
665
 
651
- def _fXf(self, phi_or_sn, cn, dn, cX, deltaX, fX):
666
+ def _fXf(self, phi_or_sn, cn, dn, cX, deltaX, fX, k2_0=False, kp2_0=False):
652
667
  '''(INTERNAL) Helper for C{.fD}, C{.fE}, C{.fF} and C{._fXa}.
653
668
  '''
654
669
  self._iteration = 0 # aggregate
655
670
  phi = sn = phi_or_sn
656
671
  if cn is dn is None: # fX(phi) call
672
+ if k2_0: # C++ version 2.4
673
+ return phi
674
+ elif kp2_0:
675
+ return asinh(tan(phi))
657
676
  sn, cn, dn = self._sncndn3(phi)
658
677
  if fabs(phi) >= PI:
659
678
  return (deltaX(sn, cn, dn) + phi) * cX / PI_2
@@ -668,6 +687,51 @@ class Elliptic(_Named):
668
687
  xi = fX(sn, cn, dn) if cn > 0 else cX
669
688
  return copysign0(xi, sn)
670
689
 
690
+ def _jam(self, x):
691
+ '''Jacobi amplitude function.
692
+
693
+ @return: C{phi} (C{float}).
694
+ '''
695
+ # implements DLMF Sec 22.20(ii), see also U{Sala
696
+ # (1989)<https://doi.org/10.1137/0520100>}, Sec 5
697
+ if self.k2:
698
+ if self.kp2:
699
+ r, ac = self._jamac2
700
+ x *= r # phi
701
+ for a, c in ac:
702
+ p = x
703
+ x = favg(asin(c * sin(x) / a), x)
704
+ if self.k2 < 0: # Sala Eq. 5.8
705
+ x = p - x
706
+ else: # PYCHOK no cover
707
+ x = atan(sinh(x)) # gd(x)
708
+ return x
709
+
710
+ @Property_RO
711
+ def _jamac2(self):
712
+ '''(INTERNAL) Get Jacobi amplitude 2-tuple C{(r, ac)}.
713
+ '''
714
+ a = r = _1_0
715
+ b, c = self.kp2, self.k2
716
+ # assert b and c
717
+ if c < 0: # Sala Eq. 5.8
718
+ r = sqrt(b)
719
+ b = _1_0 / b
720
+ # c *= b # unused
721
+ ac = [] # [(a, sqrt(c))] unused
722
+ for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
723
+ b = sqrt(a * b)
724
+ c = favg(a, -b)
725
+ a = favg(a, b) # == PI_2 / K
726
+ ac.append((a, c))
727
+ if c <= (a * _TolJAM): # 7 trips, quadratic
728
+ _iterations(self, i)
729
+ break
730
+ else: # PYCHOK no cover
731
+ raise _convergenceError(c / a, _TolJAM)
732
+ r *= a * float(1 << i) # 2**i == 2**len(ac)
733
+ return r, tuple(reversed(ac))
734
+
671
735
  @Property_RO
672
736
  def k2(self):
673
737
  '''Get k^2, the square of the modulus (C{float}).
@@ -723,38 +787,46 @@ class Elliptic(_Named):
723
787
  # Pi(alpha2, 1) = inf
724
788
  # G( alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
725
789
 
726
- def sncndn(self, x):
727
- '''The Jacobi elliptic function.
790
+ def sncndn(self, x, jam=False):
791
+ '''The Jacobi amplitude and elliptic function.
728
792
 
729
793
  @arg x: The argument (C{float}).
794
+ @kwarg jam: If C{True}, use the Jacobi amplitude otherwise the
795
+ Bulirsch' function (C{bool}).
730
796
 
731
- @return: An L{Elliptic3Tuple}C{(sn, cn, dn)} with
732
- C{*n(B{x}, k)}.
797
+ @return: An L{Elliptic3Tuple}C{(sn, cn, dn)} with C{*n(B{x}, k)}.
733
798
 
734
799
  @raise EllipticError: No convergence.
735
800
  '''
736
801
  self._iteration = 0 # reset
737
- try: # Bulirsch's sncndn routine, p 89.
802
+ try:
738
803
  if self.kp2:
739
- c, d, cd, mn = self._sncndn4
740
- dn = _1_0
741
- sn, cn = _sincos2(x * cd)
742
- if sn:
743
- a = cn / sn
744
- c *= a
745
- for m, n in reversed(mn):
746
- a *= c
747
- c *= dn
748
- dn = (n + a) / (m + a)
749
- a = c / m
750
- a = _1_0 / hypot1(c)
751
- sn = neg(a) if _signBit(sn) else a
752
- cn = c * sn
753
- if d and _signBit(self.kp2):
754
- cn, dn = dn, cn
755
- sn = sn / d # /= chokes PyChecker
804
+ if jam: # Jacobi amplitude, C++ version 2.4
805
+ sn, cn, dn = self._sncndn3(self._jam(x))
806
+
807
+ else: # Bulirsch's sncndn routine, p 89 of
808
+ # Numerische Mathematik 7, 78-90 (1965).
809
+ # Implements DLMF Eqs 22.17.2 - 22.17.4,
810
+ # but only good for .k2 > 1 or .kp2 < 0
811
+ c, d, cd, mn = self._sncndn4
812
+ dn = _1_0
813
+ sn, cn = _sincos2(x * cd)
814
+ if sn:
815
+ a = cn / sn
816
+ c *= a
817
+ for m, n in mn:
818
+ a *= c
819
+ c *= dn
820
+ dn = (n + a) / (m + a)
821
+ a = c / m
822
+ a = _1_0 / hypot1(c)
823
+ sn = neg(a) if _signBit(sn) else a
824
+ cn = sn * c
825
+ if d: # and _signBit(self.kp2): # implied
826
+ cn, dn = dn, cn
827
+ sn = sn / d # /= chokes PyChecker
756
828
  else:
757
- sn = tanh(x)
829
+ sn = tanh(x) # accurate for large abs(x)
758
830
  cn = dn = _1_0 / cosh(x)
759
831
 
760
832
  except Exception as e:
@@ -763,7 +835,7 @@ class Elliptic(_Named):
763
835
  return Elliptic3Tuple(sn, cn, dn, iteration=self._iteration)
764
836
 
765
837
  def _sncndn3(self, phi):
766
- '''(INTERNAL) Helper for C{.fEinv} and C{._fXf}.
838
+ '''(INTERNAL) Helper for C{.fEinv}, C{._fXf} and C{.sncndn}.
767
839
  '''
768
840
  sn, cn = _sincos2(phi)
769
841
  return sn, cn, self.fDelta(sn, cn)
@@ -772,29 +844,27 @@ class Elliptic(_Named):
772
844
  def _sncndn4(self):
773
845
  '''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
774
846
  '''
775
- # Bulirsch's sncndn routine, p 89.
776
- d, mc = 0, self.kp2
777
- if _signBit(mc):
778
- d = _1_0 - mc
779
- mc = neg(mc / d)
780
- d = sqrt(d)
781
-
782
- mn, a = [], _1_0
847
+ d, b = 0, self.kp2
848
+ if _signBit(b):
849
+ d = _1_0 - b
850
+ b = neg(b / d)
851
+ d = sqrt(d)
852
+ ab, a = [], _1_0
783
853
  for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
784
- mc = sqrt(mc)
785
- mn.append((a, mc))
786
- c = (a + mc) * _0_5
787
- r = fabs(mc - a)
788
- t = _TolJAC * a
789
- if r <= t: # 6 trips, quadratic
854
+ b = sqrt(b)
855
+ ab.append((a, b))
856
+ c = favg(a, b)
857
+ r = fabs(a - b)
858
+ if r <= (a * _TolJAC): # 6 trips, quadratic
790
859
  _iterations(self, i)
791
860
  break
792
- mc *= a
793
- a = c
861
+ t = a
862
+ b *= a
863
+ a = c
794
864
  else: # PYCHOK no cover
795
- raise _convergenceError(r, t)
865
+ raise _convergenceError(r / t, _TolJAC)
796
866
  cd = (c * d) if d else c
797
- return c, d, cd, mn
867
+ return c, d, cd, tuple(reversed(ab))
798
868
 
799
869
  @staticmethod
800
870
  def fRC(x, y):
@@ -882,7 +952,7 @@ class Elliptic(_Named):
882
952
  raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=e)
883
953
  return float(R)
884
954
 
885
- _allPropertiesOf_n(15, Elliptic) # # PYCHOK assert, see Elliptic.reset
955
+ _allPropertiesOf_n(16, Elliptic) # # PYCHOK assert, see Elliptic.reset
886
956
 
887
957
 
888
958
  class EllipticError(_ValueError):
@@ -901,25 +971,18 @@ class Elliptic3Tuple(_NamedTuple):
901
971
  class _List(list):
902
972
  '''(INTERNAL) Helper for C{_RD}, C{_RF3} and C{_RJ}.
903
973
  '''
904
- _a0 = None
905
- # _xyzp = ()
974
+ _a0 = None
906
975
 
907
976
  def __init__(self, *xyzp): # x, y, z [, p]
908
977
  list.__init__(self, xyzp)
909
- self._xyzp = xyzp
910
978
 
911
979
  def a0(self, n):
912
980
  '''Compute the initial C{a}.
913
981
  '''
914
- t = tuple(self)
915
- m = n - len(t)
916
- if m > 0:
917
- t += t[-1:] * m
918
- try:
919
- a = Fsum(*t).fover(n)
920
- except ValueError: # Fsum(NAN) exception
921
- a = _sum(t) / n
922
- self._a0 = a
982
+ A = _Dsum(self)
983
+ while len(A) < n:
984
+ A += A[-1]
985
+ self._a0 = a = float(A(_1_0 / n))
923
986
  return a
924
987
 
925
988
  def amrs4(self, inst, y, Tol):
@@ -929,20 +992,22 @@ class _List(list):
929
992
  L = self
930
993
  a = L.a0(5 if y else 3)
931
994
  m = 1
932
- t = max(fabs(a - _) for _ in L) / Tol
995
+ t = max(fabs(a - _) for _ in L) / Tol # thresh
933
996
  for i in range(_TRIPS):
934
997
  d = fabs(a * m)
935
998
  if d > t: # 3-6 trips
936
999
  _iterations(inst, i)
937
1000
  break
938
1001
  s = map2(sqrt, L) # sqrt(x), srqt(y), sqrt(z) [, sqrt(p)]
939
- try:
940
- r = fdot(s[:3], s[1], s[2], s[0]) # sqrt(x) * sqrt(y) + ...
941
- except ValueError: # Fsum(NAN) exception
942
- r = _sum(s[i] * s[(i + 1) % 3] for i in range(3))
943
- L[:] = ((r + _) * _0_25 for _ in L)
944
- a = (r + a) * _0_25
1002
+ # Deferred fdot(s[:3], s[1], s[2], s[0]) + ...
1003
+ Q = _Dadd(_0_25)
1004
+ Q += s[0] * s[1]
1005
+ Q += s[1] * s[2]
1006
+ Q += s[2] * s[0]
1007
+ L[:] = (float(Q + _) for _ in L)
1008
+ a = float(Q + a)
945
1009
  if y: # yield only if used
1010
+ r = _sum(Q) # fdot
946
1011
  yield a, m, r, s # L[2] is next z
947
1012
  m *= 4
948
1013
  else: # PYCHOK no cover
@@ -967,14 +1032,15 @@ def _ab2(inst, x, y):
967
1032
  b, a = a, b
968
1033
  for i in range(_TRIPS):
969
1034
  yield a, b # xi, yi
970
- d = fabs(a - b)
971
- t = _TolRG0 * a
972
- if d <= t: # 3-4 trips
1035
+ d = fabs(a - b)
1036
+ if d <= (a * _TolRG0): # 3-4 trips
973
1037
  _iterations(inst, i)
974
1038
  break
975
- a, b = ((a + b) * _0_5), sqrt(a * b)
1039
+ t = a
1040
+ a = favg(t, b)
1041
+ b = sqrt(t * b)
976
1042
  else: # PYCHOK no cover
977
- raise _convergenceError(d, t)
1043
+ raise _convergenceError(d / t, _TolRG0)
978
1044
 
979
1045
 
980
1046
  def _convergenceError(d, tol, **thresh):
@@ -1083,10 +1149,10 @@ def _RD(inst, x, y, z, *over):
1083
1149
  z = (x + y) / _3_0
1084
1150
  z2 = z**2
1085
1151
  return _Horner(S(_1_0), sqrt(a) * a * m,
1086
- xy - _6_0 * z2,
1087
- (xy * _3_0 - _8_0 * z2) * z,
1088
- (xy - z2) * _3_0 * z2,
1089
- xy * z2 * z, *over) # Fsum
1152
+ (xy - z2 * _6_0),
1153
+ (xy * _3_0 - z2 * _8_0) * z,
1154
+ (xy - z2) * z2 * _3_0,
1155
+ (xy * z2 * z), *over) # Fsum
1090
1156
 
1091
1157
 
1092
1158
  def _rF2(inst, x, y): # 2-arg version, z=0
@@ -1160,7 +1226,7 @@ def _RJ(inst, x, y, z, p, *over):
1160
1226
  if d:
1161
1227
  if n:
1162
1228
  rc = _rC(inst, _1_0, n / d**2 + _1_0)
1163
- n *= _1_64th # /= chokes PyChecker
1229
+ n = n / _64_0 # /= chokes PyChecker
1164
1230
  else:
1165
1231
  rc = _1_0 # == _rC(None, _1_0, _1_0)
1166
1232
  S += rc / (d * m)
pygeodesy/epsg.py CHANGED
@@ -17,7 +17,7 @@ including coverage of UPS as zone C{0}.
17
17
  from pygeodesy.basics import isint, isstr, _xinstanceof
18
18
  from pygeodesy.errors import _ValueError
19
19
  from pygeodesy.interns import NN, _N_, _NS_, _S_, _SPACE_
20
- from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER
20
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
21
21
  from pygeodesy.namedTuples import UtmUps2Tuple
22
22
  from pygeodesy.props import Property_RO
23
23
  from pygeodesy.streprs import Fmt
@@ -28,7 +28,7 @@ from pygeodesy.utmupsBase import _to3zBhp, _UPS_ZONE, _UTM_ZONE_MIN, \
28
28
  _UTM_ZONE_MAX, _UTMUPS_ZONE_INVALID
29
29
 
30
30
  __all__ = _ALL_LAZY.epsg
31
- __version__ = '24.05.18'
31
+ __version__ = '24.08.05'
32
32
 
33
33
  # _EPSG_INVALID = _UTMUPS_ZONE_INVALID
34
34
  _EPSG_N_01 = 32601 # EPSG code for UTM zone 01 N
@@ -219,7 +219,7 @@ def encode(zone, hemipole=NN, band=NN):
219
219
  return e
220
220
 
221
221
 
222
- __all__ += _ALL_OTHER(decode2, encode)
222
+ __all__ += _ALL_DOCS(decode2, encode)
223
223
 
224
224
  # **) MIT License
225
225
  #
pygeodesy/etm.py CHANGED
@@ -73,10 +73,9 @@ from pygeodesy.elliptic import _ALL_LAZY, Elliptic
73
73
  # from pygeodesy.errors import _incompatible # from .named
74
74
  # from pygeodesy.fsums import Fsum # from .fmath
75
75
  from pygeodesy.fmath import cbrt, hypot, hypot1, hypot2, Fsum
76
- from pygeodesy.interns import _COMMASPACE_, _DASH_, _near_, _SPACE_, \
77
- _spherical_
78
- from pygeodesy.karney import _copyBit, _diff182, _fix90, _norm2, _norm180, \
79
- _tand, _unsigned2
76
+ from pygeodesy.interns import _COMMASPACE_, _near_, _SPACE_, _spherical_
77
+ from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, \
78
+ _norm2, _norm180, _tand, _unsigned2
80
79
  # from pygeodesy.lazily import _ALL_LAZY # from .elliptic
81
80
  from pygeodesy.named import callername, _incompatible, _NamedBase
82
81
  from pygeodesy.namedTuples import Forward4Tuple, Reverse4Tuple
@@ -92,7 +91,7 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
92
91
  from math import asinh, atan2, degrees, radians, sinh, sqrt
93
92
 
94
93
  __all__ = _ALL_LAZY.etm
95
- __version__ = '24.06.11'
94
+ __version__ = '24.09.06'
96
95
 
97
96
  _OVERFLOW = _1_EPS**2 # about 2e+31
98
97
  _TAYTOL = pow(EPS, 0.6)
@@ -431,13 +430,15 @@ class ExactTransverseMercator(_NamedBase):
431
430
 
432
431
  f = flattening
433
432
 
434
- def forward(self, lat, lon, lon0=None, **name): # MCCABE 13
433
+ def forward(self, lat, lon, lon0=None, jam=_K_2_4, **name): # MCCABE 13
435
434
  '''Forward projection, from geographic to transverse Mercator.
436
435
 
437
436
  @arg lat: Latitude of point (C{degrees}).
438
437
  @arg lon: Longitude of point (C{degrees}).
439
438
  @kwarg lon0: Central meridian (C{degrees180}), overriding
440
439
  the default if not C{None}.
440
+ @kwarg jam: If C{True}, use the C{Jacobi amplitude}
441
+ otherwise C{Bulirsch}' function (C{bool}).
441
442
  @kwarg name: Optional C{B{name}=NN} (C{str}).
442
443
 
443
444
  @return: L{Forward4Tuple}C{(easting, northing, gamma, scale)}.
@@ -473,7 +474,7 @@ class ExactTransverseMercator(_NamedBase):
473
474
  tau, lam = _tand(lat), radians(lon)
474
475
  u, v = self._zetaInv2(self._E.es_taupf(tau), lam)
475
476
 
476
- sncndn6 = self._sncndn6(u, v)
477
+ sncndn6 = self._sncndn6(u, v, jam=jam)
477
478
  y, x, _ = self._sigma3(v, *sncndn6)
478
479
  g, k = (lon, self.k0) if isnear90(lat) else \
479
480
  self._zetaScaled(sncndn6, ll=False)
@@ -668,13 +669,15 @@ class ExactTransverseMercator(_NamedBase):
668
669
  self._mu = mu
669
670
  self._mv = mv
670
671
 
671
- def reverse(self, x, y, lon0=None, **name):
672
+ def reverse(self, x, y, lon0=None, jam=_K_2_4, **name):
672
673
  '''Reverse projection, from Transverse Mercator to geographic.
673
674
 
674
675
  @arg x: Easting of point (C{meters}).
675
676
  @arg y: Northing of point (C{meters}).
676
677
  @kwarg lon0: Optional central meridian (C{degrees180}),
677
678
  overriding the default (C{iff not None}).
679
+ @kwarg jam: If C{True}, use the C{Jacobi amplitude}
680
+ otherwise C{Bulirsch}' function (C{bool}).
678
681
  @kwarg name: Optional C{B{name}=NN} (C{str}).
679
682
 
680
683
  @return: L{Reverse4Tuple}C{(lat, lon, gamma, scale)}.
@@ -706,7 +709,7 @@ class ExactTransverseMercator(_NamedBase):
706
709
  v = self._Ev_cK
707
710
 
708
711
  if v or u != self._Eu_cK:
709
- g, k, lat, lon = self._zetaScaled(self._sncndn6(u, v))
712
+ g, k, lat, lon = self._zetaScaled(self._sncndn6(u, v, jam=jam))
710
713
  else: # PYCHOK no cover
711
714
  g, k, lat, lon = _0_0, self.k0, _90_0, _0_0
712
715
 
@@ -866,12 +869,12 @@ class ExactTransverseMercator(_NamedBase):
866
869
 
867
870
  return u, v, t, C
868
871
 
869
- def _sncndn6(self, u, v):
872
+ def _sncndn6(self, u, v, **jam):
870
873
  '''(INTERNAL) Get 6-tuple C{(snu, cnu, dnu, snv, cnv, dnv)}.
871
874
  '''
872
875
  # snu, cnu, dnu = self._Eu.sncndn(u)
873
876
  # snv, cnv, dnv = self._Ev.sncndn(v)
874
- return self._Eu.sncndn(u) + self._Ev.sncndn(v)
877
+ return self._Eu.sncndn(u, **jam) + self._Ev.sncndn(v, **jam)
875
878
 
876
879
  def toStr(self, joined=_COMMASPACE_, **kwds): # PYCHOK signature
877
880
  '''Return a C{str} representation.
@@ -1094,67 +1097,76 @@ def toEtm8(latlon, lon=None, datum=None, Etm=Etm, falsed=True,
1094
1097
  n, latlon, d.exactTM, Error=ETMError)
1095
1098
 
1096
1099
 
1097
- if __name__ == '__main__': # MCCABE 13
1098
-
1099
- from pygeodesy import fstr, KTransverseMercator, printf
1100
- from pygeodesy.internals import _usage
1101
- from sys import argv, exit as _exit
1102
-
1103
- # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1104
- _f = _r = _s = _t = False
1105
- _p = -6
1106
- _as = argv[1:]
1107
- while _as and _as[0].startswith(_DASH_):
1108
- _a = _as.pop(0)
1109
- if len(_a) < 2:
1110
- _exit('%s: option %r invalid' % (_usage(*argv), _a))
1111
- elif '-forward'.startswith(_a):
1112
- _f, _r = True, False
1113
- elif '-reverse'.startswith(_a):
1114
- _f, _r = False, True
1115
- elif '-precision'.startswith(_a):
1116
- _p = int(_as.pop(0))
1117
- elif '-series'.startswith(_a):
1118
- _s, _t = True, False
1119
- elif _a == '-t':
1120
- _s, _t = False, True
1121
- elif '-help'.startswith(_a):
1100
+ if __name__ == '__main__': # MCCABE 16
1101
+
1102
+ def _main():
1103
+
1104
+ from pygeodesy import fstr, KTransverseMercator
1105
+ # from pygeodesy.interns import _DASH_ # from internals
1106
+ from pygeodesy.internals import printf, _usage, _DASH_
1107
+ from sys import argv, exit as _exit
1108
+
1109
+ def _help():
1122
1110
  _exit(_usage(argv[0], '[-s | -t ]',
1123
1111
  '[-p[recision] <ndigits>',
1124
1112
  '[-f[orward] <lat> <lon>',
1125
1113
  '|-r[everse] <easting> <northing>',
1126
1114
  '|<lat> <lon>]',
1127
1115
  '|-h[elp]'))
1116
+
1117
+ # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1118
+ _f = _r = _s = _t = False
1119
+ _p = -6
1120
+ _as = argv[1:]
1121
+ while _as and _as[0].startswith(_DASH_):
1122
+ _a = _as.pop(0)
1123
+ if len(_a) < 2:
1124
+ _exit('%s: option %r invalid' % (_usage(*argv), _a))
1125
+ elif '-forward'.startswith(_a):
1126
+ _f, _r = True, False
1127
+ elif '-reverse'.startswith(_a):
1128
+ _f, _r = False, True
1129
+ elif '-precision'.startswith(_a):
1130
+ _p = int(_as.pop(0))
1131
+ elif '-series'.startswith(_a):
1132
+ _s, _t = True, False
1133
+ elif _a == '-t':
1134
+ _s, _t = False, True
1135
+ elif '-help'.startswith(_a):
1136
+ _help()
1137
+ else:
1138
+ _exit('%s: option %r not supported' % (_usage(*argv), _a))
1139
+
1140
+ if len(_as) > 1:
1141
+ f2 = map1(float, *_as[:2])
1142
+ else:
1143
+ printf('%s ...: incomplete', _usage(*argv))
1144
+ _help()
1145
+
1146
+ if _s: # -series
1147
+ tm = KTransverseMercator()
1148
+ else:
1149
+ tm = ExactTransverseMercator(extendp=_t)
1150
+
1151
+ if _f:
1152
+ t = tm.forward(*f2)
1153
+ elif _r:
1154
+ t = tm.reverse(*f2)
1128
1155
  else:
1129
- _exit('%s: option %r not supported' % (_usage(*argv), _a))
1130
- if len(_as) > 1:
1131
- f2 = map1(float, *_as[:2])
1132
- else:
1133
- _exit('%s ...: incomplete' % (_usage(*argv),))
1134
-
1135
- if _s: # -series
1136
- tm = KTransverseMercator()
1137
- else:
1138
- tm = ExactTransverseMercator(extendp=_t)
1139
-
1140
- if _f:
1141
- t = tm.forward(*f2)
1142
- elif _r:
1143
- t = tm.reverse(*f2)
1144
- else:
1145
- t = tm.forward(*f2)
1156
+ t = tm.forward(*f2)
1157
+ printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1158
+ t = tm.reverse(t.easting, t.northing)
1146
1159
  printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1147
- t = tm.reverse(t.easting, t.northing)
1148
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1149
1160
 
1161
+ _main()
1150
1162
 
1151
- # % python3 -m pygeodesy.etm -p 12 33.33 44.44
1163
+ # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1152
1164
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1153
1165
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1154
1166
 
1155
- # % python3 -m pygeodesy.etm -s -p 12 33.33 44.44
1156
- # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1157
- # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1167
+ # % python3.12 -s -m pygeodesy.etm -p 12 33.33 44.44
1168
+ # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1169
+ # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1158
1170
 
1159
1171
  # % echo 33.33 44.44 | .../bin/TransverseMercatorProj
1160
1172
  # 4276926.114804 4727193.767015 28.375536563148 1.233325101778