pygeodesy 24.8.24__py2.py3-none-any.whl → 24.9.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 (49) hide show
  1. {PyGeodesy-24.8.24.dist-info → PyGeodesy-24.9.24.dist-info}/METADATA +7 -7
  2. {PyGeodesy-24.8.24.dist-info → PyGeodesy-24.9.24.dist-info}/RECORD +49 -48
  3. pygeodesy/__init__.py +7 -5
  4. pygeodesy/__main__.py +46 -47
  5. pygeodesy/auxilats/_CX_4.py +104 -181
  6. pygeodesy/auxilats/_CX_6.py +152 -277
  7. pygeodesy/auxilats/_CX_8.py +211 -438
  8. pygeodesy/auxilats/_CX_Rs.py +222 -0
  9. pygeodesy/auxilats/__init__.py +2 -2
  10. pygeodesy/auxilats/__main__.py +30 -38
  11. pygeodesy/auxilats/auxLat.py +28 -36
  12. pygeodesy/auxilats/auxily.py +30 -50
  13. pygeodesy/basics.py +24 -14
  14. pygeodesy/booleans.py +13 -14
  15. pygeodesy/clipy.py +7 -7
  16. pygeodesy/constants.py +44 -31
  17. pygeodesy/deprecated/__init__.py +1 -1
  18. pygeodesy/deprecated/functions.py +9 -1
  19. pygeodesy/elliptic.py +154 -88
  20. pygeodesy/errors.py +32 -5
  21. pygeodesy/etm.py +71 -59
  22. pygeodesy/fmath.py +125 -96
  23. pygeodesy/fstats.py +8 -12
  24. pygeodesy/fsums.py +802 -355
  25. pygeodesy/geodesici.py +6 -5
  26. pygeodesy/geodesicx/_C4_24.py +1 -3
  27. pygeodesy/geodesicx/_C4_27.py +1 -3
  28. pygeodesy/geodesicx/_C4_30.py +1 -3
  29. pygeodesy/geodesicx/__init__.py +1 -1
  30. pygeodesy/geodesicx/__main__.py +44 -46
  31. pygeodesy/geodesicx/gxarea.py +3 -3
  32. pygeodesy/geodesicx/gxbases.py +32 -18
  33. pygeodesy/internals.py +50 -9
  34. pygeodesy/interns.py +3 -2
  35. pygeodesy/karney.py +79 -60
  36. pygeodesy/ktm.py +4 -4
  37. pygeodesy/lazily.py +10 -5
  38. pygeodesy/mgrs.py +47 -42
  39. pygeodesy/named.py +4 -1
  40. pygeodesy/points.py +3 -3
  41. pygeodesy/props.py +7 -6
  42. pygeodesy/resections.py +2 -2
  43. pygeodesy/rhumb/__init__.py +1 -1
  44. pygeodesy/rhumb/aux_.py +42 -60
  45. pygeodesy/sphericalNvector.py +4 -4
  46. pygeodesy/sphericalTrigonometry.py +2 -2
  47. pygeodesy/triaxials.py +3 -3
  48. {PyGeodesy-24.8.24.dist-info → PyGeodesy-24.9.24.dist-info}/WHEEL +0 -0
  49. {PyGeodesy-24.8.24.dist-info → PyGeodesy-24.9.24.dist-info}/top_level.txt +0 -0
pygeodesy/karney.py CHANGED
@@ -10,7 +10,9 @@ C{attribute} name.
10
10
 
11
11
  With env variable C{PYGEODESY_GEOGRAPHICLIB} left undefined or set to C{"2"}, modules L{geodesicw},
12
12
  L{geodesicx} and this module will use U{GeographicLib 2.0+<https://GeographicLib.SourceForge.io/C++/doc/>}
13
- and newer transcoding, otherwise C{1.52} or older.
13
+ and newer transcoding, otherwise C{1.52} or older. Set C{PYGEODESY_GEOGRAPHICLIB=2.4} to default to the
14
+ C{Jacobi amplitude} instead of C{Bulirsch}' function in methods L{ExactTransverseMercator.forward
15
+ <pygeodesy.ExactTransverseMercator.forward>} and L{reverse <pygeodesy.ExactTransverseMercator.reverse>}.
14
16
 
15
17
  Karney-based functionality
16
18
  ==========================
@@ -145,8 +147,8 @@ from pygeodesy.basics import _copysign, isint, neg, unsigned0, _xgeographiclib,
145
147
  _zip, _version_info
146
148
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
147
149
  _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
148
- from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get1
149
- from pygeodesy.fmath import cbrt, fremainder, norm2
150
+ from pygeodesy.errors import GeodesicError, _ValueError, _xkwds
151
+ from pygeodesy.fmath import cbrt, fremainder, norm2 # Fhorner, Fsum
150
152
  # from pygeodesy.internals import _version_info # from .basics
151
153
  from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
152
154
  _composite_, _lat1_, _lat2_, _lon1_, _lon2_, \
@@ -154,7 +156,8 @@ from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
154
156
  _UNDER_, _X_, _BAR_ # PYCHOK used!
155
157
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
156
158
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
157
- from pygeodesy.props import deprecated_method, Property_RO, property_ROnce
159
+ from pygeodesy.props import deprecated_method, Property_RO, property_RO, \
160
+ property_ROnce
158
161
  from pygeodesy.units import Azimuth as _Azi, Degrees as _Deg, Lat, Lon, \
159
162
  Meter as _M, Meter2 as _M2, Number_
160
163
  from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
@@ -162,9 +165,11 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
162
165
  # from math import fabs # from .utily
163
166
 
164
167
  __all__ = _ALL_LAZY.karney
165
- __version__ = '24.07.25'
168
+ __version__ = '24.09.13'
166
169
 
167
- _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_) == _2_
170
+ _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_)
171
+ _K_2_4 = _K_2_0 == '2.4'
172
+ _K_2_0 = _K_2_0 == _2_ or _K_2_4
168
173
  _perimeter_ = 'perimeter'
169
174
 
170
175
 
@@ -285,7 +290,7 @@ class Caps(object):
285
290
 
286
291
  Caps = Caps() # PYCHOK singleton
287
292
  '''I{Enum}-style masks to be bit-C{or}'ed to specify geodesic or
288
- rhumb capabilities (C{caps}) and expected results (C{outmask}).
293
+ rhumb capabilities (C{caps}) and results (C{outmask}).
289
294
 
290
295
  C{AREA} - compute area C{S12},
291
296
 
@@ -569,6 +574,11 @@ class _kWrapped(object): # in .geodesicw
569
574
  M = None
570
575
  return M
571
576
 
577
+ @property_RO
578
+ def Math_K_2(self):
579
+ return ('_K_2_4' if _K_2_4 else
580
+ ('_K_2_0' if _K_2_0 else '_K_1_0')) if self.Math else NN
581
+
572
582
  _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
573
583
 
574
584
 
@@ -805,25 +815,40 @@ def _polygon(geodesic, points, closed, line, wrap):
805
815
  return gP.Compute(False, True)[1 if line else 2]
806
816
 
807
817
 
818
+ try:
819
+ from math import fma as _fma # since 3.13
820
+
821
+ def _poly_fma(x, s, *cs):
822
+ for c in cs:
823
+ s = _fma(s, x, c)
824
+ return s
825
+
826
+ except ImportError: # Python 3.12-
827
+
828
+ def _poly_fma(x, s, *cs): # PYCHOK redef
829
+ t = _0_0
830
+ for c in cs:
831
+ s, t, _ = _sum3(s * x, t * x, c)
832
+ return s + t
833
+
834
+ # def _poly_fma(x, *cs):
835
+ # S = Fhorner(x, *cs, incx=False)
836
+ # return float(S)
837
+
808
838
  def _polynomial(x, cs, i, j): # PYCHOK shared
809
839
  '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but with a
810
- different signature and cascaded summation as C{karney._sum2_}.
840
+ signature and cascaded summation different from C{karney._sum3}.
811
841
 
812
- @return: M{sum(cs[k] * x**(j - k - 1) for k in range(i, j)}
842
+ @return: M{sum(x**(j - k - 1) * cs[k] for k in range(i, j)}
813
843
  '''
814
- # assert 0 <= i <= j <= len(cs)
815
- # try:
816
- # return _wrapped.Math.polyval(j - i - 1, cs, i, x)
817
- # except AttributeError:
818
- # s, t = cs[i], _0_0
819
- # for c in cs[i+1:j]:
820
- # s, t = _sum2_(s * x, t * x, c)
821
- # return s # + t
822
- s = cs[i]
823
- i += 1
824
- if x and i < j:
825
- s, _ = _sum2_(s, _0_0, x=x, *cs[i:j])
826
- return s # + t
844
+ if (i + 1) < j <= len(cs): # load _Rtuple._tuple
845
+ try:
846
+ r = _wrapped.Math.polyval(j - i - 1, cs, i, x)
847
+ except AttributeError:
848
+ r = _poly_fma(x, *cs[i:j])
849
+ else:
850
+ r = cs[i]
851
+ return float(r)
827
852
 
828
853
 
829
854
  def _remainder(x, y):
@@ -875,67 +900,60 @@ def _sincos2de(deg, t):
875
900
  return sincos2d(deg, adeg=t)
876
901
 
877
902
 
878
- def _sum2(u, v): # mimick geomath.Math.sum, actually sum2
903
+ def _sum2(a, b): # mimick geomath.Math.sum, actually sum2
879
904
  '''Error-free summation like C{geomath.Math.sum}.
880
905
 
881
- @return: 2-Tuple C{(B{u} + B{v}, residual)}.
906
+ @return: 2-Tuple C{(B{a} + B{b}, residual)}.
882
907
 
883
- @note: The C{residual} can be the same as B{C{u}} or B{C{v}}.
908
+ @note: The C{residual} can be the same as B{C{a}} or B{C{b}}.
884
909
 
885
- @see: U{Algorithm 3.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
910
+ @see: U{TwoSum<https://accurate-algorithms.readthedocs.io/en/latest/ch04summation.html>}
911
+ and I{Knuth}'s U{Algorithm 3.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
886
912
  '''
887
913
  try:
888
- return _wrapped.Math.sum(u, v)
914
+ return _wrapped.Math.sum(a, b)
889
915
  except AttributeError:
890
- s = u + v
891
- r = s - v
892
- t = s - r
893
916
  # if Algorithm_3_1:
894
- # t = (u - t) + (v + r)
917
+ s = a + b
918
+ r = s - b
919
+ t = s - r
895
920
  # elif C_CPP: # Math::sum C/C++
896
- # r -= u
897
- # t -= v
898
- # t += r
899
- # t = -t
921
+ # r -= a; t -= b; t += r; t = -t
900
922
  # else:
901
- t = (u - r) + (v - t)
923
+ t = (a - r) + (b - t)
924
+ # assert fabs(s) >= fabs(t)
902
925
  return s, t
903
926
 
904
927
 
905
- def _sum2_(s, t, *vs, **x):
906
- '''Accumulate any B{C{vs}} into a previous C{_sum2(s, t)}.
907
-
908
- @kwarg x: Optional polynomial C{B{x}=1} (C{scalar}).
928
+ def _sum3(s, t, *xs):
929
+ '''Accumulate any B{C{xs}} into a previous C{_sum2(s, t)}.
909
930
 
910
- @return: 2-Tuple C{(B{s} + B{t} + sum(B{vs}), residual)}.
931
+ @return: 3-Tuple C{(s, t, n)} where C{s} is the sum of B{s}, B{t} and all
932
+ B{xs}, C{t} the residual and C{n} the number of zero C{xs}.
911
933
 
912
934
  @see: I{Karney's} C++ U{Accumulator<https://GeographicLib.SourceForge.io/
913
935
  C++/doc/Accumulator_8hpp_source.html>} comments for more details and
914
936
  function C{_sum2} above.
915
937
 
916
- @note: NOT "error-free", see C{pygeodesy.test/testKarney.py}.
938
+ @note: Not "error-free", see C{pygeodesy.test/testKarney.py}.
917
939
  '''
918
- x = _xkwds_get1(x, x=_1_0)
919
- p = x != _1_0
920
-
921
- _s2, _u0 = _sum2, unsigned0
922
- for v in vs:
923
- if p:
924
- s *= x
925
- t *= x
926
- if v:
927
- t, u = _s2(t, v) # start at the least-
940
+ z = 0
941
+ for x in xs:
942
+ if x:
943
+ t, r = _sum2(t, x) # start at the least-
928
944
  if s:
929
- s, t = _s2(s, t) # significant end
945
+ s, t = _sum2(s, t) # -significant end
930
946
  if s:
931
- t += u # accumulate u into t
932
- # elif t: # s == 0 implies t == 0
933
- # raise _AssertionError(t=t, txt_not_=_0_)
947
+ t += r # accumulate r into t
934
948
  else:
935
- s = _u0(u) # result is u, t = 0
949
+ # assert t == 0 # s == 0 implies t == 0
950
+ s = unsigned0(r) # result is r, t = 0
936
951
  else:
937
- s, t = _u0(t), u
938
- return s, t
952
+ s, t = unsigned0(t), r
953
+ else:
954
+ z += 1
955
+ # assert fabs(s) >= fabs(t)
956
+ return s, t, z
939
957
 
940
958
 
941
959
  def _tand(x):
@@ -955,7 +973,8 @@ def _unroll2(lon1, lon2, wrap=False): # see .ellipsoidalBaseDI._intersects2
955
973
  '''
956
974
  if wrap:
957
975
  d, t = _diff182(lon1, lon2)
958
- lon2, _ = _sum2_(d, t, lon1) # (lon1 + d) + t
976
+ lon2, t, _ = _sum3(d, t, lon1) # (lon1 + d) + t
977
+ lon2 += t
959
978
  else:
960
979
  lon2 = _norm180(lon2)
961
980
  return (lon2 - lon1), lon2
pygeodesy/ktm.py CHANGED
@@ -67,7 +67,7 @@ from cmath import polar
67
67
  from math import atan2, asinh, cos, cosh, degrees, fabs, sin, sinh, sqrt, tanh
68
68
 
69
69
  __all__ = _ALL_LAZY.ktm
70
- __version__ = '24.07.16'
70
+ __version__ = '24.08.31'
71
71
 
72
72
 
73
73
  class KTMError(_ValueError):
@@ -505,11 +505,11 @@ def _Xs(_Coeffs, m, E, RA=False): # in .rhumb.ekx
505
505
  # constant, it cancels when evaluating a definite
506
506
  # integral. Don't bother computing it, it is unused
507
507
  # in C{_Cyxgk4} above and C{rhumb.ekx._sincosSeries}.
508
- _X, _p = X.append, _polynomial
509
- i = (m + 2) if RA else 0
508
+ i = (m + 2) if RA else 0
509
+ _p = _polynomial
510
510
  for r in _reverange(m): # [m-1 ... 0]
511
511
  j = i + r + 1
512
- _X(_p(n, Cs, i, j) * n_ / Cs[j])
512
+ X.append(_p(n, Cs, i, j) * n_ / Cs[j])
513
513
  i = j + 1
514
514
  n_ *= n
515
515
  X = tuple(X)
pygeodesy/lazily.py CHANGED
@@ -255,7 +255,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
255
255
  fmath=_i('Fdot', 'Fhorner', 'Fhypot', 'Fpolynomial', 'Fpowers', 'Fcbrt', 'Froot', 'Fsqrt',
256
256
  'bqrt', 'cbrt', 'cbrt2', 'euclid', 'euclid_',
257
257
  'facos1', 'fasin1', 'fatan', 'fatan1', 'fatan2', 'favg',
258
- 'fdot', 'fdot3', 'fmean', 'fmean_', 'fhorner', 'fidw', 'fpolynomial',
258
+ 'fdot', 'fdot3', 'fma', 'fmean', 'fmean_', 'fhorner', 'fidw', 'f2mul_', 'fpolynomial',
259
259
  'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
260
260
  'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
261
261
  'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
@@ -281,7 +281,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
281
281
  'frechet_'),
282
282
  fstats=_i('Fcook', 'Flinear', 'Fwelford'),
283
283
  fsums=_i('Fsum', 'DivMod2Tuple', 'Fsum2Tuple', 'ResidualError',
284
- 'fsum', 'fsum_', 'fsumf_', 'fsum1', 'fsum1_', 'fsum1f_'),
284
+ 'f2product', 'fsum', 'fsum_', 'fsumf_', 'fsum1', 'fsum1_', 'fsum1f_', 'nonfiniterrors'),
285
285
  gars=_i('Garef', 'GARSError'),
286
286
  geodesici=_i('Intersectool', 'Intersectool5Tuple', 'Intersect7Tuple',
287
287
  'Intersector', 'Intersector5Tuple', 'Middle5Tuple', 'XDict'),
@@ -420,8 +420,8 @@ _ALL_DEPRECATED = _NamedEnum_RO(_name='_ALL_DEPRECATED',
420
420
  'clipCS3', 'clipDMS', 'clipStr', 'collins', 'copysign', # ... and spherical flavors
421
421
  'decodeEPSG2', 'encodeEPSG', 'enStr2', 'equirectangular_', 'equirectangular3',
422
422
  'excessAbc', 'excessGirard', 'excessLHuilier',
423
- 'false2f', 'falsed2f', 'float0', 'fStr', 'fStrzs', 'hypot3',
424
- 'inStr', 'isenclosedby', 'istuplist',
423
+ 'false2f', 'falsed2f', 'float0', 'fStr', 'fStrzs', 'Fsum2product',
424
+ 'hypot3', 'inStr', 'isenclosedby', 'istuplist',
425
425
  'joined', 'joined_', 'nearestOn3', 'nearestOn4',
426
426
  'parseUTM', 'perimeterof', 'polygon', 'scalar', 'simplify2',
427
427
  'tienstra', 'toUtm', 'triAngle4',
@@ -486,6 +486,11 @@ class _ALL_MODS(_internals._MODS_Base):
486
486
  except KeyError:
487
487
  return _getmodule(name, parent)
488
488
 
489
+ def imported(self, name):
490
+ '''Return module or package C{name} if already imported.
491
+ '''
492
+ return _sys.modules.get(name, None)
493
+
489
494
  def into(self, **mod_dunder_name_):
490
495
  '''Lazily import module C{mod} into module C{_dunder_name_}
491
496
  and set C{_dunder_name_._mod} to module C{mod}, I{once}.
@@ -521,7 +526,7 @@ class _ALL_MODS(_internals._MODS_Base):
521
526
  _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
522
527
 
523
528
  __all__ = _ALL_LAZY.lazily
524
- __version__ = '24.08.18'
529
+ __version__ = '24.09.19'
525
530
 
526
531
 
527
532
  def _ALL_OTHER(*objs):
pygeodesy/mgrs.py CHANGED
@@ -43,7 +43,7 @@ from pygeodesy.errors import _AssertionError, MGRSError, _parseX, \
43
43
  from pygeodesy.interns import NN, _0_, _A_, _AtoZnoIO_, _band_, _B_, \
44
44
  _COMMASPACE_, _datum_, _easting_, _invalid_, \
45
45
  _northing_, _SPACE_, _W_, _Y_, _Z_, _zone_
46
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _PYGEODESY_GEOCONVERT_
46
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
47
47
  from pygeodesy.named import _name2__, _NamedBase, _NamedTuple, _Pass
48
48
  from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple
49
49
  from pygeodesy.props import deprecated_property_RO, property_RO, Property_RO
@@ -55,7 +55,7 @@ from pygeodesy.utm import toUtm8, _to3zBlat, Utm, _UTM_ZONE_MAX, _UTM_ZONE_MIN
55
55
  # from pygeodesy.utmupsBase import _UTM_ZONE_MAX, _UTM_ZONE_MIN # from .utm
56
56
 
57
57
  __all__ = _ALL_LAZY.mgrs
58
- __version__ = '24.06.11'
58
+ __version__ = '24.09.04'
59
59
 
60
60
  _AN_ = 'AN' # default south pole grid tile and band B
61
61
  _AtoPx_ = _AtoZnoIO_.tillP
@@ -652,51 +652,56 @@ def _um100km2(m):
652
652
 
653
653
  if __name__ == '__main__':
654
654
 
655
- from pygeodesy.ellipsoidalVincenty import fabs, LatLon
656
- # from pygeodesy.internals import printf # from .lazily
657
- from pygeodesy.lazily import _getenv, printf
655
+ def _main():
658
656
 
659
- # from math import fabs # from .ellipsoidalVincenty
660
- from os import access as _access, linesep as _NL, X_OK as _X_OK
657
+ from pygeodesy.ellipsoidalVincenty import fabs, LatLon
658
+ from pygeodesy.internals import _fper, printf
659
+ from pygeodesy.lazily import _getenv, _PYGEODESY_GEOCONVERT_
661
660
 
662
- # <https://GeographicLib.sourceforge.io/C++/doc/GeoConvert.1.html>
663
- _GeoConvert = _getenv(_PYGEODESY_GEOCONVERT_, '/opt/local/bin/GeoConvert')
664
- if _access(_GeoConvert, _X_OK):
665
- GC_m = _GeoConvert, '-m' # -m converts latlon to MGRS
666
- printf(' using: %s ...', _SPACE_.join(GC_m))
667
- from pygeodesy.solveBase import _popen2
668
- else:
669
- GC_m = _popen2 = None
661
+ # from math import fabs # from .ellipsoidalVincenty
662
+ from os import access as _access, linesep as _NL, X_OK as _X_OK
670
663
 
671
- e = n = 0
672
- try:
673
- for lat in range(-90, 91, 1):
674
- printf('%6s: lat %s ...', n, lat, end=NN, flush=True)
675
- nl = _NL
676
- for lon in range(-180, 181, 1):
677
- m = LatLon(lat, lon).toMgrs()
678
- if _popen2:
679
- t = '%s %s' % (lat, lon)
680
- g = _popen2(GC_m, stdin=t)[1]
681
- t = m.toStr() # sep=NN
682
- if t != g:
664
+ # <https://GeographicLib.sourceforge.io/C++/doc/GeoConvert.1.html>
665
+ _GeoConvert = _getenv(_PYGEODESY_GEOCONVERT_, '/opt/local/bin/GeoConvert')
666
+ if _access(_GeoConvert, _X_OK):
667
+ GC_m = _GeoConvert, '-m' # -m converts latlon to MGRS
668
+ printf(' using: %s ...', _SPACE_.join(GC_m))
669
+ from pygeodesy.solveBase import _popen2
670
+ else:
671
+ GC_m = _popen2 = None
672
+
673
+ e = n = 0
674
+ try:
675
+ for lat in range(-90, 91, 1):
676
+ printf('%6s: lat %s ...', n, lat, end=NN, flush=True)
677
+ nl = _NL
678
+ for lon in range(-180, 181, 1):
679
+ m = LatLon(lat, lon).toMgrs()
680
+ if _popen2:
681
+ t = '%s %s' % (lat, lon)
682
+ g = _popen2(GC_m, stdin=t)[1]
683
+ t = m.toStr() # sep=NN
684
+ if t != g:
685
+ e += 1
686
+ printf('%s%6s: %s: %r vs %r (lon %s)', nl, -e, m, t, g, lon)
687
+ nl = NN
688
+ t = m.toLatLon(LatLon=LatLon)
689
+ d = max(fabs(t.lat - lat), fabs(t.lon - lon))
690
+ if d > 1e-9 and -90 < lat < 90 and -180 < lon < 180:
683
691
  e += 1
684
- printf('%s%6s: %s: %r vs %r (lon %s)', nl, -e, m, t, g, lon)
692
+ printf('%s%6s: %s: %s vs %s %.6e', nl, -e, m, t.latlon,
693
+ (float(lat), float(lon)), d)
685
694
  nl = NN
686
- t = m.toLatLon(LatLon=LatLon)
687
- d = max(fabs(t.lat - lat), fabs(t.lon - lon))
688
- if d > 1e-9 and -90 < lat < 90 and -180 < lon < 180:
689
- e += 1
690
- printf('%s%6s: %s: %s vs %s %.6e', nl, -e, m, t.latlon, (float(lat), float(lon)), d)
691
- nl = NN
692
- n += 1
693
- if nl:
694
- printf(' OK')
695
- except KeyboardInterrupt:
696
- printf(nl)
697
-
698
- p = e * 100.0 / n
699
- printf('%6s: %s errors (%.2f%%)', n, (e if e else 'no'), p)
695
+ n += 1
696
+ if nl:
697
+ printf(' OK')
698
+ except KeyboardInterrupt:
699
+ printf(nl)
700
+
701
+ printf('%6s: %s errors (%s)', n, (e if e else 'no'), _fper(e, n, prec=2))
702
+
703
+ _main()
704
+
700
705
 
701
706
  # % python3 -m pygeodesy.mgrs
702
707
  # using: /opt/local/bin/GeoConvert -m ...
pygeodesy/named.py CHANGED
@@ -34,7 +34,7 @@ from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
34
34
  # from pygeodesy.units import _toUnit # _MODS
35
35
 
36
36
  __all__ = _ALL_LAZY.named
37
- __version__ = '24.08.13'
37
+ __version__ = '24.09.02'
38
38
 
39
39
  _COMMANL_ = _COMMA_ + _NL_
40
40
  _COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
@@ -891,6 +891,9 @@ class _NamedEnumItem(_NamedBase):
891
891
  raise _AssertionError(t)
892
892
 
893
893
 
894
+ # from pygeodesy.props import _NamedProperty
895
+
896
+
894
897
  class _NamedTuple(tuple, _Named):
895
898
  '''(INTERNAL) Base for named C{tuple}s with both index I{and}
896
899
  attribute name access to the items.
pygeodesy/points.py CHANGED
@@ -62,7 +62,7 @@ from pygeodesy.utily import atan2b, degrees90, degrees180, degrees2m, \
62
62
  from math import cos, fabs, fmod as _fmod, radians, sin
63
63
 
64
64
  __all__ = _ALL_LAZY.points
65
- __version__ = '24.08.13'
65
+ __version__ = '24.09.23'
66
66
 
67
67
  _ilat_ = 'ilat'
68
68
  _ilon_ = 'ilon'
@@ -1430,7 +1430,7 @@ def ispolar(points, wrap=False):
1430
1430
 
1431
1431
  # summation of course deltas around pole is 0° rather than normally ±360°
1432
1432
  # <https://blog.Element84.com/determining-if-a-spherical-polygon-contains-a-pole.html>
1433
- s = fsum(_cds(points, wrap), floats=True)
1433
+ s = fsum(_cds(points, wrap))
1434
1434
  # XXX fix (intermittant) edge crossing pole - eg (85,90), (85,0), (85,-90)
1435
1435
  return fabs(s) < 90 # "zero-ish"
1436
1436
 
@@ -1631,7 +1631,7 @@ def perimeterOf(points, closed=False, adjust=True, radius=R_M, wrap=True):
1631
1631
  d = points._sum1(perimeterOf, closed=True, adjust=adjust,
1632
1632
  radius=radius, wrap=wrap)
1633
1633
  else:
1634
- d = fsum(_degs(points, closed, adjust, wrap), floats=True)
1634
+ d = fsum(_degs(points, closed, adjust, wrap))
1635
1635
  return degrees2m(d, radius=radius)
1636
1636
 
1637
1637
 
pygeodesy/props.py CHANGED
@@ -25,12 +25,11 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, \
25
25
  from functools import wraps as _wraps
26
26
 
27
27
  __all__ = _ALL_LAZY.props
28
- __version__ = '24.07.23'
28
+ __version__ = '24.09.02'
29
29
 
30
30
  _class_ = 'class'
31
31
  _dont_use_ = _DEPRECATED_ + ", don't use."
32
32
  _function_ = 'function'
33
- _get_and_set_ = 'get and set'
34
33
  _has_been_ = 'has been' # PYCHOK used!
35
34
  _method_ = 'method'
36
35
  _not_an_inst_ = _not_(_an_, 'instance')
@@ -396,7 +395,9 @@ class property_ROver(_property_RO___):
396
395
  # No __doc__ on purpose
397
396
 
398
397
  def _fget(self, inst):
399
- '''Get the C{property} value I{once} and overwrite C{self}, this C{property} instance.
398
+ '''Get the C{property} value I{once} and overwrite C{self},
399
+ this C{property} instance in the (super-)class of C{self}
400
+ where this property is define as a L{property_ROver}.
400
401
  '''
401
402
  v = self.method(inst)
402
403
  n = self.name
@@ -411,8 +412,8 @@ class property_ROver(_property_RO___):
411
412
  return v
412
413
 
413
414
 
414
- class _NamedProperty(property):
415
- '''Class C{property} with retrievable name.
415
+ class _NamedProperty(property): # in .named
416
+ '''Class C{property} with a C{.name} attribute.
416
417
  '''
417
418
  @Property_RO
418
419
  def name(self):
@@ -445,7 +446,7 @@ def property_doc_(doc):
445
446
  def _documented_property(method):
446
447
  '''(INTERNAL) Return the documented C{property}.
447
448
  '''
448
- t = _get_and_set_ if doc.startswith(_SPACE_) else NN
449
+ t = 'get and set' if doc.startswith(_SPACE_) else NN
449
450
  return _NamedProperty(method, None, None, NN('Property to ', t, doc))
450
451
 
451
452
  return _documented_property
pygeodesy/resections.py CHANGED
@@ -34,7 +34,7 @@ from pygeodesy.vector3d import _otherV3d, Vector3d
34
34
  from math import cos, atan2, degrees, fabs, radians, sin, sqrt
35
35
 
36
36
  __all__ = _ALL_LAZY.resections
37
- __version__ = '24.08.18'
37
+ __version__ = '24.09.23'
38
38
 
39
39
  _concyclic_ = 'concyclic'
40
40
  _PA_ = 'PA'
@@ -664,7 +664,7 @@ def tienstra7(pointA, pointB, pointC, alpha, beta=None, gamma=None,
664
664
  dB = _deg_ks(_triAngle(a, c, b), sb, ks, _B_)
665
665
  dC = _deg_ks(_triAngle(a, b, c), sc, ks, _C_)
666
666
 
667
- k = fsum1(ks, floats=True)
667
+ k = fsum1(ks)
668
668
  if isnear0(k):
669
669
  raise ValueError(Fmt.EQUAL(K=k))
670
670
  x = Fdot(ks, A.x, B.x, C.x).fover(k)
@@ -9,7 +9,7 @@ u'''Package of lazily imported C{rhumb} modules L{rhumb.aux_}, L{rhumb.ekx} and
9
9
  from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER, _lazy_import_as, _unLazy0
10
10
 
11
11
  __all__ = _ALL_LAZY.rhumb
12
- __version__ = '24.06.18'
12
+ __version__ = '24.09.02'
13
13
 
14
14
  if _unLazy0: # or _isfrozen
15
15
  from pygeodesy.rhumb.aux_ import RhumbAux, RhumbLineAux