pygeodesy 24.10.10__py2.py3-none-any.whl → 24.11.11__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.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
  2. PyGeodesy-24.11.11.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +14 -14
  5. pygeodesy/__main__.py +5 -5
  6. pygeodesy/albers.py +12 -17
  7. pygeodesy/azimuthal.py +51 -61
  8. pygeodesy/basics.py +60 -62
  9. pygeodesy/booleans.py +87 -79
  10. pygeodesy/cartesianBase.py +6 -6
  11. pygeodesy/constants.py +23 -19
  12. pygeodesy/css.py +7 -8
  13. pygeodesy/datums.py +3 -3
  14. pygeodesy/deprecated/__init__.py +1 -1
  15. pygeodesy/deprecated/classes.py +9 -9
  16. pygeodesy/deprecated/functions.py +6 -6
  17. pygeodesy/dms.py +250 -270
  18. pygeodesy/ecef.py +11 -14
  19. pygeodesy/ellipsoidalBase.py +106 -121
  20. pygeodesy/ellipsoidalBaseDI.py +114 -118
  21. pygeodesy/ellipsoidalExact.py +35 -37
  22. pygeodesy/ellipsoidalNvector.py +4 -4
  23. pygeodesy/ellipsoidalVincenty.py +2 -2
  24. pygeodesy/ellipsoids.py +10 -51
  25. pygeodesy/elliptic.py +14 -14
  26. pygeodesy/errors.py +28 -28
  27. pygeodesy/etm.py +92 -68
  28. pygeodesy/fmath.py +42 -40
  29. pygeodesy/formy.py +7 -6
  30. pygeodesy/fsums.py +72 -51
  31. pygeodesy/geodesici.py +43 -40
  32. pygeodesy/geodesicw.py +17 -16
  33. pygeodesy/geodesicx/__init__.py +2 -2
  34. pygeodesy/geodesicx/gxarea.py +3 -2
  35. pygeodesy/geodsolve.py +79 -39
  36. pygeodesy/geohash.py +2 -2
  37. pygeodesy/geoids.py +32 -31
  38. pygeodesy/heights.py +2 -2
  39. pygeodesy/internals.py +201 -147
  40. pygeodesy/interns.py +23 -20
  41. pygeodesy/karney.py +62 -13
  42. pygeodesy/ktm.py +11 -13
  43. pygeodesy/latlonBase.py +18 -20
  44. pygeodesy/lazily.py +210 -218
  45. pygeodesy/lcc.py +4 -4
  46. pygeodesy/ltp.py +10 -10
  47. pygeodesy/ltpTuples.py +74 -75
  48. pygeodesy/mgrs.py +20 -21
  49. pygeodesy/named.py +15 -10
  50. pygeodesy/nvectorBase.py +1 -1
  51. pygeodesy/osgr.py +9 -12
  52. pygeodesy/points.py +2 -2
  53. pygeodesy/props.py +35 -14
  54. pygeodesy/resections.py +9 -10
  55. pygeodesy/rhumb/__init__.py +1 -1
  56. pygeodesy/rhumb/bases.py +5 -5
  57. pygeodesy/rhumb/solve.py +9 -10
  58. pygeodesy/simplify.py +5 -5
  59. pygeodesy/solveBase.py +7 -25
  60. pygeodesy/sphericalBase.py +20 -23
  61. pygeodesy/sphericalNvector.py +103 -145
  62. pygeodesy/sphericalTrigonometry.py +68 -73
  63. pygeodesy/streprs.py +5 -5
  64. pygeodesy/trf.py +6 -4
  65. pygeodesy/triaxials.py +46 -9
  66. pygeodesy/units.py +5 -4
  67. pygeodesy/ups.py +6 -6
  68. pygeodesy/utily.py +2 -2
  69. pygeodesy/utm.py +7 -7
  70. pygeodesy/vector2d.py +13 -13
  71. pygeodesy/vector3d.py +19 -21
  72. pygeodesy/vector3dBase.py +21 -19
  73. pygeodesy/webmercator.py +4 -4
  74. pygeodesy/wgrs.py +4 -4
  75. PyGeodesy-24.10.10.dist-info/RECORD +0 -118
  76. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
pygeodesy/etm.py CHANGED
@@ -11,7 +11,7 @@ Class L{ExactTransverseMercator} provides C{Exact Transverse Mercator} projectio
11
11
  instances of class L{Etm} represent ETM C{(easting, northing)} locations. See also
12
12
  I{Karney}'s utility U{TransverseMercatorProj<https://GeographicLib.SourceForge.io/C++/doc/
13
13
  TransverseMercatorProj.1.html>} and use C{"python[3] -m pygeodesy.etm ..."} to compare
14
- the results.
14
+ the results, see usage C{"python[3] -m pygeodesy.etm -h"}.
15
15
 
16
16
  Following is a copy of I{Karney}'s U{TransverseMercatorExact.hpp
17
17
  <https://GeographicLib.SourceForge.io/C++/doc/TransverseMercatorExact_8hpp_source.html>}
@@ -65,23 +65,25 @@ from __future__ import division as _; del _ # PYCHOK semicolon
65
65
 
66
66
  from pygeodesy.basics import map1, neg, neg_, _xinstanceof
67
67
  from pygeodesy.constants import EPS, EPS02, PI_2, PI_4, _K0_UTM, \
68
- _1_EPS, _0_0, _0_1, _0_5, _1_0, _2_0, \
69
- _3_0, _4_0, _90_0, isnear0, isnear90
68
+ _1_EPS, _0_0, _0_1, _0_5, _1_0, _2_0, \
69
+ _3_0, _90_0, isnear0, isnear90
70
+ from pygeodesy.constants import _4_0 # PYCHOK used!
70
71
  from pygeodesy.datums import _ellipsoidal_datum, _WGS84, _EWGS84
71
72
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
72
- from pygeodesy.elliptic import _ALL_LAZY, Elliptic
73
+ # from pygeodesy.elliptic import Elliptic # _MODS
73
74
  # from pygeodesy.errors import _incompatible # from .named
74
75
  # from pygeodesy.fsums import Fsum # from .fmath
75
76
  from pygeodesy.fmath import cbrt, hypot, hypot1, hypot2, Fsum
76
77
  from pygeodesy.interns import _COMMASPACE_, _near_, _SPACE_, _spherical_
77
78
  from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, \
78
79
  _norm2, _norm180, _tand, _unsigned2
79
- # from pygeodesy.lazily import _ALL_LAZY # from .elliptic
80
- from pygeodesy.named import callername, _incompatible, _NamedBase
80
+ # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
81
+ from pygeodesy.named import callername, _incompatible, _NamedBase, \
82
+ _ALL_LAZY, _MODS
81
83
  from pygeodesy.namedTuples import Forward4Tuple, Reverse4Tuple
82
84
  from pygeodesy.props import deprecated_method, deprecated_property_RO, \
83
85
  Property_RO, property_RO, _update_all, \
84
- property_doc_
86
+ property_doc_, _allPropertiesOf_n
85
87
  from pygeodesy.streprs import Fmt, pairs, unstr
86
88
  from pygeodesy.units import Degrees, Scalar_
87
89
  from pygeodesy.utily import atan1d, atan2d, _loneg, sincos2
@@ -91,12 +93,12 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
91
93
  from math import asinh, atan2, degrees, radians, sinh, sqrt
92
94
 
93
95
  __all__ = _ALL_LAZY.etm
94
- __version__ = '24.09.06'
96
+ __version__ = '24.11.04'
95
97
 
96
- _OVERFLOW = _1_EPS**2 # about 2e+31
97
- _TAYTOL = pow(EPS, 0.6)
98
+ _OVERFLOW = _1_EPS**2 # ~2e+31
99
+ _TAYTOL = pow(EPS, 0.6)
98
100
  _TAYTOL2 = _TAYTOL * _2_0
99
- _TOL_10 = EPS * _0_1
101
+ _TOL_10 = EPS * _0_1
100
102
  _TRIPS = 21 # C++ 10
101
103
 
102
104
 
@@ -218,12 +220,12 @@ class Etm(Utm):
218
220
  class ExactTransverseMercator(_NamedBase):
219
221
  '''Pure Python version of Karney's C++ class U{TransverseMercatorExact
220
222
  <https://GeographicLib.SourceForge.io/C++/doc/TransverseMercatorExact_8cpp_source.html>},
221
- a numerically exact transverse Mercator projection, further referred to as C{TMExact}.
223
+ a numerically exact transverse Mercator projection, abbreviated as C{TMExact}.
222
224
  '''
223
225
  _datum = _WGS84 # Datum
224
226
  _E = _EWGS84 # Ellipsoid
225
227
  _extendp = False # use extended domain
226
- # _iteration = None # ._sigmaInv2 and ._zetaInv2
228
+ # _iteration = None # _NameBase, ._sigmaInv2 and ._zetaInv2
227
229
  _k0 = _K0_UTM # central scale factor
228
230
  _lat0 = _0_0 # central parallel
229
231
  _lon0 = _0_0 # central meridian
@@ -240,7 +242,7 @@ class ExactTransverseMercator(_NamedBase):
240
242
  L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
241
243
  @kwarg lon0: Central meridian, default (C{degrees180}).
242
244
  @kwarg k0: Central scale factor (C{float}).
243
- @kwarg extendp: Use the I{extended} domain (C{bool}), I{standard} otherwise.
245
+ @kwarg extendp: If C{True}, use the I{extended} domain, I{standard} otherwise (C{bool}).
244
246
  @kwarg raiser: If C{True}, throw an L{ETMError} for convergence failures (C{bool}).
245
247
  @kwarg name: Optional C{B{name}=NN} for the projection (C{str}).
246
248
 
@@ -349,7 +351,7 @@ class ExactTransverseMercator(_NamedBase):
349
351
  def _Eu(self):
350
352
  '''(INTERNAL) Get and cache C{Elliptic(_mu)}.
351
353
  '''
352
- return Elliptic(self._mu)
354
+ return _MODS.elliptic.Elliptic(self._mu)
353
355
 
354
356
  @Property_RO
355
357
  def _Eu_cE(self):
@@ -390,7 +392,7 @@ class ExactTransverseMercator(_NamedBase):
390
392
  def _Ev(self):
391
393
  '''(INTERNAL) Get and cache C{Elliptic(_mv)}.
392
394
  '''
393
- return Elliptic(self._mv)
395
+ return _MODS.elliptic.Elliptic(self._mv)
394
396
 
395
397
  @Property_RO
396
398
  def _Ev_cK(self):
@@ -416,7 +418,7 @@ class ExactTransverseMercator(_NamedBase):
416
418
  '''
417
419
  return self._Ev_cKE * 1.25 # _1_25
418
420
 
419
- @Property_RO
421
+ @property_RO
420
422
  def extendp(self):
421
423
  '''Get the domain (C{bool}), I{extended} or I{standard}.
422
424
  '''
@@ -635,7 +637,7 @@ class ExactTransverseMercator(_NamedBase):
635
637
  '''Set the central parallel and meridian.
636
638
 
637
639
  @arg lat0: Latitude of the central parallel (C{degrees90}).
638
- @arg lon0: Longitude of the central parallel (C{degrees180}).
640
+ @arg lon0: Longitude of the central meridian (C{degrees180}).
639
641
 
640
642
  @return: 2-Tuple C{(lat0, lon0)} of the previous central
641
643
  parallel and meridian.
@@ -644,7 +646,7 @@ class ExactTransverseMercator(_NamedBase):
644
646
  '''
645
647
  t = self._lat0, self.lon0
646
648
  self._lat0 = _fix90(Degrees(lat0=lat0, Error=ETMError))
647
- self. lon0 = lon0
649
+ self. lon0 = lon0 # lon0.setter
648
650
  return t
649
651
 
650
652
  def _resets(self, datum):
@@ -655,15 +657,15 @@ class ExactTransverseMercator(_NamedBase):
655
657
  @raise ETMError: Near-spherical B{C{datum}} or C{ellipsoid}.
656
658
  '''
657
659
  E = datum.ellipsoid
658
- mu = E.e2 # .eccentricity1st2
660
+ mu = E.e2 # E.eccentricity1st2
659
661
  mv = E.e21 # _1_0 - mu
660
662
  if isnear0(E.e) or isnear0(mu, eps0=EPS02) \
661
663
  or isnear0(mv, eps0=EPS02): # or sqrt(mu) != E.e
662
664
  raise ETMError(ellipsoid=E, txt=_near_(_spherical_))
663
665
 
664
666
  if self._datum or self._E:
665
- _i = ExactTransverseMercator.iteration._uname
666
- _update_all(self, _i, '_sigmaC', '_zetaC') # _under
667
+ _i = ExactTransverseMercator.iteration._uname # property_RO
668
+ _update_all(self, _i, '_sigmaC', '_zetaC', Base=Property_RO) # _under
667
669
 
668
670
  self._E = E
669
671
  self._mu = mu
@@ -757,7 +759,7 @@ class ExactTransverseMercator(_NamedBase):
757
759
  # k = sqrt(mv + mu / sec2) * sqrt(sec2) * sqrt(q2)
758
760
  # = sqrt(mv * sec2 + mu) * sqrt(q2)
759
761
  # = sqrt(mv + mv * tau**2 + mu) * sqrt(q2)
760
- k, q2 = _0_0, (mv * snv**2 + cnudnv**2)
762
+ k, q2 = _0_0, (snv**2 * mv + cnudnv**2)
761
763
  if q2 > 0:
762
764
  k2 = (tau**2 + _1_0) * mv + mu
763
765
  if k2 > 0:
@@ -809,9 +811,9 @@ class ExactTransverseMercator(_NamedBase):
809
811
  d = (cnv**2 + snuv**2 * mu)**2 * self._mv
810
812
  r = cnv * dnu * dnv
811
813
  i = cnu * snuv * mu
812
- du = (r**2 - i**2) / d # (r + i) * (r - i) / d
813
- dv = neg(r * i * _2_0 / d)
814
- return du, dv
814
+ du = (r + i) * (r - i) / d # (r**2 - i**2) / d
815
+ dv = r * i * _2_0 / d
816
+ return du, neg(dv)
815
817
 
816
818
  def _sigmaInv2(self, xi, eta):
817
819
  '''(INTERNAL) Invert C{sigma} using Newton's method.
@@ -874,7 +876,8 @@ class ExactTransverseMercator(_NamedBase):
874
876
  '''
875
877
  # snu, cnu, dnu = self._Eu.sncndn(u)
876
878
  # snv, cnv, dnv = self._Ev.sncndn(v)
877
- return self._Eu.sncndn(u, **jam) + self._Ev.sncndn(v, **jam)
879
+ return self._Eu.sncndn(u, **jam) + \
880
+ self._Ev.sncndn(v, **jam)
878
881
 
879
882
  def toStr(self, joined=_COMMASPACE_, **kwds): # PYCHOK signature
880
883
  '''Return a C{str} representation.
@@ -900,21 +903,19 @@ class ExactTransverseMercator(_NamedBase):
900
903
  real &taup, real &lam)}
901
904
  '''
902
905
  e, cnu2, mv = self._e, cnu**2, self._mv
903
- # Overflow value like atan(overflow) = pi/2
904
- t1 = t2 = _overflow(snu)
905
906
  # Lee 54.17 but write
906
907
  # atanh(snu * dnv) = asinh(snu * dnv / sqrt(cnu^2 + _mv * snu^2 * snv^2))
907
908
  # atanh(_e * snu / dnv) = asinh(_e * snu / sqrt(_mu * cnu^2 + _mv * cnv^2))
908
- d1 = cnu2 + mv * (snu * snv)**2
909
+ d1 = cnu2 + (snu * snv)**2 * mv
909
910
  if d1 > EPS02: # _EPSmin
910
911
  t1 = snu * dnv / sqrt(d1)
911
- else:
912
- d1 = 0
913
- d2 = self._mu * cnu2 + mv * cnv**2
912
+ else: # like atan(overflow) = pi/2
913
+ t1, d1 = _overflow(snu), 0
914
+ d2 = cnu2 * self._mu + cnv**2 * mv
914
915
  if d2 > EPS02: # _EPSmin
915
916
  t2 = sinh(e * asinh(e * snu / sqrt(d2)))
916
917
  else:
917
- d2 = 0
918
+ t2, d2 = _overflow(snu), 0
918
919
  # psi = asinh(t1) - asinh(t2)
919
920
  # taup = sinh(psi)
920
921
  taup = t1 * hypot1(t2) - t2 * hypot1(t1)
@@ -939,9 +940,9 @@ class ExactTransverseMercator(_NamedBase):
939
940
  snuv2 = snuv**2 * self._mu
940
941
  # Lee 54.21 but write (see A+S 16.21.4)
941
942
  # (1 - dnu^2 * snv^2) = (cnv^2 + _mu * snu^2 * snv^2)
942
- d = self._mv * (cnv2 + snuv2)**2 # max(d, EPS02)?
943
- du = cnu * dnuv * (cnv2 - snuv2) / d
944
- dv = cnv * snuv * (cnu2 + dnuv2) / d
943
+ d = (cnv2 + snuv2)**2 * self._mv # max(d, EPS02)?
944
+ du = (cnv2 - snuv2) * cnu * dnuv / d
945
+ dv = (cnu2 + dnuv2) * cnv * snuv / d
945
946
  return du, neg(dv)
946
947
 
947
948
  def _zetaInv2(self, taup, lam):
@@ -1021,6 +1022,9 @@ class ExactTransverseMercator(_NamedBase):
1021
1022
  g_k += atan1d(tau), degrees(lam)
1022
1023
  return g_k # or (g, k, lat, lon)
1023
1024
 
1025
+ _allPropertiesOf_n(22, ExactTransverseMercator, Property_RO) # PYCHOK assert
1026
+ del _0_1, _allPropertiesOf_n, EPS, _1_EPS, _EWGS84
1027
+
1024
1028
 
1025
1029
  def _overflow(x):
1026
1030
  '''(INTERNAL) Like C{copysign0(OVERFLOW, B{x})}.
@@ -1102,32 +1106,42 @@ if __name__ == '__main__': # MCCABE 16
1102
1106
  def _main():
1103
1107
 
1104
1108
  from pygeodesy import fstr, KTransverseMercator
1105
- # from pygeodesy.interns import _DASH_ # from internals
1106
- from pygeodesy.internals import printf, _usage, _DASH_
1109
+ from pygeodesy.interns import _BAR_, _COLONSPACE_, _DASH_, NN
1110
+ from pygeodesy.internals import printf, _usage
1107
1111
  from sys import argv, exit as _exit
1108
1112
 
1109
- def _help():
1110
- _exit(_usage(argv[0], '[-s | -t ]',
1111
- '[-p[recision] <ndigits>',
1112
- '[-f[orward] <lat> <lon>',
1113
- '|-r[everse] <easting> <northing>',
1114
- '|<lat> <lon>]',
1115
- '|-h[elp]'))
1113
+ def _error(why, _a=NN):
1114
+ if _a:
1115
+ why = 'option %r %s' % (_a, why)
1116
+ _exit(_COLONSPACE_(_usage(*argv), why))
1117
+
1118
+ def _help(*why):
1119
+ if why:
1120
+ printf(_COLONSPACE_(_usage(*argv), *why))
1121
+ _exit(_usage(argv[0], '[-s[eries]', _BAR_, '-t]',
1122
+ '[-p[recision] <ndigits>]',
1123
+ '[-f[orward] <lat> <lon>', _BAR_,
1124
+ '-r[everse] <easting> <northing>', _BAR_,
1125
+ '<lat> <lon>]', _BAR_,
1126
+ '-h[elp]'))
1127
+
1128
+ def _result(t4):
1129
+ printf(_COLONSPACE_(tm.classname, fstr(t4, prec=_p, sep=_SPACE_)))
1116
1130
 
1117
1131
  # mimick some of I{Karney}'s utility C{TransverseMercatorProj}
1118
1132
  _f = _r = _s = _t = False
1119
1133
  _p = -6
1120
- _as = argv[1:]
1121
- while _as and _as[0].startswith(_DASH_):
1122
- _a = _as.pop(0)
1134
+ args = argv[1:]
1135
+ while args and args[0].startswith(_DASH_):
1136
+ _a = args.pop(0)
1123
1137
  if len(_a) < 2:
1124
- _exit('%s: option %r invalid' % (_usage(*argv), _a))
1138
+ _error('invalid', _a)
1125
1139
  elif '-forward'.startswith(_a):
1126
1140
  _f, _r = True, False
1127
1141
  elif '-reverse'.startswith(_a):
1128
1142
  _f, _r = False, True
1129
- elif '-precision'.startswith(_a):
1130
- _p = int(_as.pop(0))
1143
+ elif '-precision'.startswith(_a) and args:
1144
+ _p = int(args.pop(0))
1131
1145
  elif '-series'.startswith(_a):
1132
1146
  _s, _t = True, False
1133
1147
  elif _a == '-t':
@@ -1135,39 +1149,49 @@ if __name__ == '__main__': # MCCABE 16
1135
1149
  elif '-help'.startswith(_a):
1136
1150
  _help()
1137
1151
  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)
1152
+ _error('not supported', _a)
1153
+ if len(args) < 2:
1154
+ _help('incomplete')
1150
1155
 
1156
+ f2 = map1(float, *args[:2])
1157
+ tm = KTransverseMercator() if _s else \
1158
+ ExactTransverseMercator(extendp=_t)
1151
1159
  if _f:
1152
1160
  t = tm.forward(*f2)
1153
1161
  elif _r:
1154
1162
  t = tm.reverse(*f2)
1155
1163
  else:
1156
1164
  t = tm.forward(*f2)
1157
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1165
+ _result(t)
1158
1166
  t = tm.reverse(t.easting, t.northing)
1159
- printf('%s: %s', tm.classname, fstr(t, prec=_p, sep=_SPACE_))
1167
+ _result(t)
1160
1168
 
1161
1169
  _main()
1162
1170
 
1163
- # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1171
+ # % python3.13 -m pygeodesy.etm -p 12 33.33 44.44
1172
+ # ExactTransverseMercator: 4276926.114803905599 4727193.767015309073 28.375536563148 1.233325101778
1173
+ # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1174
+
1175
+ # % python3.13 -m pygeodesy.etm -s -p 12 33.33 44.44
1176
+ # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1177
+ # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1178
+
1179
+ # % python3.12 -m pygeodesy.etm -p 12 33.33 44.44
1164
1180
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1165
1181
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1166
1182
 
1167
- # % python3.12 -s -m pygeodesy.etm -p 12 33.33 44.44
1183
+ # % python3.12 -m pygeodesy.etm -s -p 12 33.33 44.44
1184
+ # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1185
+ # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1186
+
1187
+ # % python2 -m pygeodesy.etm -p 12 33.33 44.44
1168
1188
  # ExactTransverseMercator: 4276926.11480390653 4727193.767015309073 28.375536563148 1.233325101778
1169
1189
  # ExactTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1170
1190
 
1191
+ # % python2 -m pygeodesy.etm -s -p 12 33.33 44.44
1192
+ # KTransverseMercator: 4276926.114803904667 4727193.767015310004 28.375536563148 1.233325101778
1193
+ # KTransverseMercator: 33.33 44.44 28.375536563148 1.233325101778
1194
+
1171
1195
  # % echo 33.33 44.44 | .../bin/TransverseMercatorProj
1172
1196
  # 4276926.114804 4727193.767015 28.375536563148 1.233325101778
1173
1197
 
pygeodesy/fmath.py CHANGED
@@ -12,11 +12,10 @@ from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
12
12
  _0_0, _0_125, _1_6th, _0_25, _1_3rd, _0_5, _1_0, \
13
13
  _1_5, _copysign_0_0, isfinite, remainder
14
14
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
- _xError, _xkwds_pop2, _xsError
16
- from pygeodesy.fsums import _2float, Fsum, fsum, _isFsum_2Tuple, _1primed, \
17
- Fmt, unstr
15
+ _xError, _xkwds, _xkwds_pop2, _xsError
16
+ from pygeodesy.fsums import _2float, Fsum, fsum, _isFsum_2Tuple, Fmt, unstr
18
17
  from pygeodesy.interns import MISSING, _negative_, _not_scalar_
19
- from pygeodesy.lazily import _ALL_LAZY, _sys_version_info2
18
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
20
19
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
21
20
  from pygeodesy.units import Int_, _isHeight, _isRadius, Float_ # PYCHOK for .heights
22
21
 
@@ -24,7 +23,7 @@ from math import fabs, sqrt # pow
24
23
  import operator as _operator # in .datums, .trf, .utm
25
24
 
26
25
  __all__ = _ALL_LAZY.fmath
27
- __version__ = '24.10.04'
26
+ __version__ = '24.11.08'
28
27
 
29
28
  # sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
30
29
  _0_4142 = 0.41421356237309504880 # ... ~ 3730904090310553 / 9007199254740992
@@ -62,14 +61,7 @@ class Fdot(Fsum):
62
61
  n = len(b)
63
62
  if len(a) != n: # PYCHOK no cover
64
63
  raise LenError(Fdot, a=len(a), b=n)
65
- self._faddot(n, a, b, **kwds)
66
-
67
- def _faddot(self, n, xs, ys, **kwds):
68
- if n > 0:
69
- _f = Fsum(**kwds)
70
- r = (_f(x).fmul(y) for x, y in zip(xs, ys)) # PYCHOK attr?
71
- self.fadd(_1primed(r) if n < 4 else r) # PYCHOK attr?
72
- return self
64
+ self._facc_dot(n, a, b, **kwds)
73
65
 
74
66
 
75
67
  class Fhorner(Fsum):
@@ -129,7 +121,7 @@ class Fhypot(Fsum):
129
121
  raise self._ErrorXs(X, xs, root=r)
130
122
 
131
123
 
132
- class Fpolynomial(Fdot):
124
+ class Fpolynomial(Fsum):
133
125
  '''Precision polynomial evaluation.
134
126
  '''
135
127
  def __init__(self, x, *cs, **name_f2product_nonfinites_RESIDUAL):
@@ -150,12 +142,10 @@ class Fpolynomial(Fdot):
150
142
 
151
143
  @see: Class L{Fhorner}, function L{fpolynomial} and method L{Fsum.fadd}.
152
144
  '''
153
- Fsum.__init__(self, *cs[:1], **name_f2product_nonfinites_RESIDUAL)
145
+ Fsum.__init__(self, **name_f2product_nonfinites_RESIDUAL)
154
146
  n = len(cs) - 1
155
- if n > 0:
156
- self._faddot(n, cs[1:], _powers(x, n), **name_f2product_nonfinites_RESIDUAL)
157
- elif n < 0:
158
- self(_0_0)
147
+ self(_0_0 if n < 0 else cs[0])
148
+ self._facc_dot(n, cs[1:], _powers(x, n), **name_f2product_nonfinites_RESIDUAL)
159
149
 
160
150
 
161
151
  class Fpowers(Fsum):
@@ -431,35 +421,48 @@ def favg(a, b, f=_0_5, nonfinites=True):
431
421
  return float(F)
432
422
 
433
423
 
434
- def fdot(a, *b, **start):
435
- '''Return the precision dot product M{sum(a[i] * b[i] for ni=0..len(a))}.
424
+ def fdot(xs, *ys, **start_f2product_nonfinites):
425
+ '''Return the precision dot product M{sum(xs[i] * ys[i] for i in range(len(xs)))}.
436
426
 
437
- @arg a: Iterable of values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
438
- @arg b: Other values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
427
+ @arg xs: Iterable of values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
428
+ @arg ys: Other values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
439
429
  positional.
440
- @kwarg start: Optional bias C{B{start}=0} (C{scalar}, an L{Fsum} or
441
- L{Fsum2Tuple}).
430
+ @kwarg start_f2product_nonfinites: Optional bias C{B{start}=0} (C{scalar}, an
431
+ L{Fsum} or L{Fsum2Tuple}) and settings C{B{f2product}=None} (C{bool})
432
+ and C{B{nonfinites=True}} (C{bool}), see class L{Fsum<Fsum.__init__>}.
442
433
 
443
434
  @return: Dot product (C{float}).
444
435
 
445
- @raise LenError: Unequal C{len(B{a})} and C{len(B{b})}.
436
+ @raise LenError: Unequal C{len(B{xs})} and C{len(B{ys})}.
446
437
 
447
438
  @see: Class L{Fdot}, U{Algorithm 5.10 B{DotK}
448
439
  <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>} and function
449
440
  C{math.sumprod} in Python 3.12 and later.
450
441
  '''
451
- D = Fdot(a, nonfinites=True, *b, **start)
442
+ D = Fdot(xs, *ys, **_xkwds(start_f2product_nonfinites, nonfinites=True))
452
443
  return float(D)
453
444
 
454
445
 
455
- def fdot3(xs, ys, zs, start=0):
456
- '''Return the precision dot product M{start + sum(a[i] * b[i] * c[i]
457
- for i=0..len(a)-1)}.
446
+ def fdot_(*xys, **start_f2product_nonfinites):
447
+ '''Return the (precision) dot product M{sum(xys[i] * xys[i+1] for i in range(0, len(xys), B{2}))}.
448
+
449
+ @arg xys: Pairwise values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all positional.
450
+
451
+ @see: Function L{fdot} for further details.
452
+
453
+ @return: Dot product (C{float}).
454
+ '''
455
+ return fdot(xys[0::2], *xys[1::2], **start_f2product_nonfinites)
456
+
457
+
458
+ def fdot3(xs, ys, zs, **start_f2product_nonfinites):
459
+ '''Return the (precision) dot product M{start + sum(xs[i] * ys[i] * zs[i] for i in range(len(xs)))}.
458
460
 
459
461
  @arg xs: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
460
462
  @arg ys: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
461
463
  @arg zs: Iterable (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
462
- @kwarg start: Optional bias (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
464
+
465
+ @see: Function L{fdot} for further details.
463
466
 
464
467
  @return: Dot product (C{float}).
465
468
 
@@ -469,17 +472,16 @@ def fdot3(xs, ys, zs, start=0):
469
472
  if not n == len(ys) == len(zs):
470
473
  raise LenError(fdot3, xs=n, ys=len(ys), zs=len(zs))
471
474
 
472
- D = Fdot((), nonfinites=True, start=start)
473
- _f = Fsum(nonfinites=True) # f2product=True
474
- r = (_f(x).f2mul_(y, z) for x, y, z in zip(xs, ys, zs))
475
- D = D.fadd(_1primed(r) if n < 4 else r)
475
+ D = Fdot((), **_xkwds(start_f2product_nonfinites, nonfinites=True))
476
+ kwds = dict(f2product=D.f2product(), nonfinites=D.nonfinites())
477
+ _f = Fsum(**kwds)
478
+ D = D._facc(_f(x).f2mul_(y, z, **kwds) for x, y, z in zip(xs, ys, zs))
476
479
  return float(D)
477
480
 
478
481
 
479
482
  def fhorner(x, *cs, **incx):
480
- '''Horner form evaluation of polynomial M{sum(cs[i] * x**i for
481
- i=0..n)} with in- or decreasing exponent M{sum(... i=n..0)},
482
- where C{n = len(cs) - 1}.
483
+ '''Horner form evaluation of polynomial M{sum(cs[i] * x**i for i=0..n)} as
484
+ in- or decreasing exponent M{sum(... i=n..0)}, where C{n = len(cs) - 1}.
483
485
 
484
486
  @return: Horner sum (C{float}).
485
487
 
@@ -804,7 +806,7 @@ def fremainder(x, y):
804
806
  return r
805
807
 
806
808
 
807
- if _sys_version_info2 < (3, 8): # PYCHOK no cover
809
+ if _MODS.sys_version_info2 < (3, 8): # PYCHOK no cover
808
810
  from math import hypot # OK in Python 3.7-
809
811
 
810
812
  def hypot_(*xs):
@@ -831,7 +833,7 @@ if _sys_version_info2 < (3, 8): # PYCHOK no cover
831
833
  '''
832
834
  return float(_Hypot(*xs))
833
835
 
834
- elif _sys_version_info2 < (3, 10):
836
+ elif _MODS.sys_version_info2 < (3, 10):
835
837
  # In Python 3.8 and 3.9 C{math.hypot} is inaccurate, see
836
838
  # U{agdhruv<https://GitHub.com/geopy/geopy/issues/466>},
837
839
  # U{cffk<https://Bugs.Python.org/issue43088>} and module
pygeodesy/formy.py CHANGED
@@ -20,11 +20,11 @@ from pygeodesy.errors import IntersectionError, LimitError, limiterrors, \
20
20
  _xcallable,_xkwds, _xkwds_pop2
21
21
  from pygeodesy.fmath import euclid, hypot, hypot2, sqrt0
22
22
  from pygeodesy.fsums import fsumf_, Fmt, unstr
23
- # from pygeodesy.internals import _dunder_nameof # from .named
23
+ # from pygeodesy.internals import _DUNDER_nameof # from .named
24
24
  from pygeodesy.interns import _delta_, _distant_, _inside_, _SPACE_, _too_
25
25
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
26
26
  from pygeodesy.named import _name__, _name2__, _NamedTuple, _xnamed, \
27
- _dunder_nameof
27
+ _DUNDER_nameof
28
28
  from pygeodesy.namedTuples import Bearing2Tuple, Distance4Tuple, LatLon2Tuple, \
29
29
  Intersection3Tuple, PhiLam2Tuple, Vector3Tuple
30
30
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
@@ -43,7 +43,7 @@ from contextlib import contextmanager
43
43
  from math import asin, atan, atan2, cos, degrees, fabs, radians, sin, sqrt # pow
44
44
 
45
45
  __all__ = _ALL_LAZY.formy
46
- __version__ = '24.09.27'
46
+ __version__ = '24.10.14'
47
47
 
48
48
  _RADIANS2 = (PI / _180_0)**2 # degrees- to radians-squared
49
49
  _ratio_ = 'ratio'
@@ -1136,7 +1136,7 @@ class _idllmn6(object): # see also .geodesicw._wargs, .latlonBase._toCartesian3
1136
1136
  _, lat2, lon2 = _Wrap.latlon3(lon1, lat2, lon2, wrap)
1137
1137
  kwds = _xkwds(kwds, wrap=wrap) # for _xError
1138
1138
  m = small if small is _100km else Meter_(small=small)
1139
- n = _dunder_nameof(intersections2 if s else intersection2)
1139
+ n = _DUNDER_nameof(intersections2 if s else intersection2)
1140
1140
  if datum is None or euclidean(lat1, lon1, lat2, lon2) < m:
1141
1141
  d, m = None, _MODS.vector3d
1142
1142
  _i = m._intersects2 if s else m._intersect3d3
@@ -1156,7 +1156,7 @@ class _idllmn6(object): # see also .geodesicw._wargs, .latlonBase._toCartesian3
1156
1156
  m = _MODS.ellipsoidalKarney
1157
1157
  except ImportError:
1158
1158
  m = _MODS.ellipsoidalExact
1159
- _i = m._intersections2 if s else m._intersection3 # ellispoidalBaseDI
1159
+ _i = m._intersections2 if s else m._intersection3 # ellipsoidalBaseDI
1160
1160
  else:
1161
1161
  raise _TypeError(datum=datum)
1162
1162
  yield _i, d, lat2, lon2, m, n
@@ -1231,7 +1231,8 @@ def intersection2(lat1, lon1, bearing1,
1231
1231
 
1232
1232
  else:
1233
1233
  t = _i(m.LatLon(lat1, lon1, datum=d), b1,
1234
- m.LatLon(lat2, lon2, datum=d), b2, height=0, wrap=False)
1234
+ m.LatLon(lat2, lon2, datum=d), b2,
1235
+ LatLon=None, height=0, wrap=False)
1235
1236
  if isinstance(t, Intersection3Tuple): # ellipsoidal
1236
1237
  t, _, _ = t
1237
1238
  t = LatLon2Tuple(t.lat, t.lon, name=n)