pygeodesy 24.5.8__py2.py3-none-any.whl → 24.5.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 (83) hide show
  1. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.5.24.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +16 -12
  4. pygeodesy/__main__.py +9 -10
  5. pygeodesy/albers.py +42 -42
  6. pygeodesy/auxilats/__init__.py +1 -1
  7. pygeodesy/auxilats/__main__.py +7 -10
  8. pygeodesy/auxilats/auxAngle.py +32 -31
  9. pygeodesy/auxilats/auxLat.py +81 -51
  10. pygeodesy/azimuthal.py +123 -124
  11. pygeodesy/basics.py +165 -176
  12. pygeodesy/booleans.py +14 -15
  13. pygeodesy/cartesianBase.py +25 -23
  14. pygeodesy/clipy.py +3 -3
  15. pygeodesy/constants.py +8 -6
  16. pygeodesy/css.py +50 -42
  17. pygeodesy/datums.py +50 -48
  18. pygeodesy/dms.py +6 -6
  19. pygeodesy/ecef.py +27 -27
  20. pygeodesy/elevations.py +2 -2
  21. pygeodesy/ellipsoidalBase.py +28 -27
  22. pygeodesy/ellipsoidalBaseDI.py +8 -7
  23. pygeodesy/ellipsoidalNvector.py +11 -12
  24. pygeodesy/ellipsoids.py +41 -35
  25. pygeodesy/elliptic.py +12 -10
  26. pygeodesy/epsg.py +4 -3
  27. pygeodesy/errors.py +35 -13
  28. pygeodesy/etm.py +62 -53
  29. pygeodesy/fmath.py +48 -41
  30. pygeodesy/formy.py +93 -65
  31. pygeodesy/frechet.py +117 -102
  32. pygeodesy/fstats.py +52 -46
  33. pygeodesy/fsums.py +169 -145
  34. pygeodesy/gars.py +10 -9
  35. pygeodesy/geodesicw.py +32 -30
  36. pygeodesy/geodesicx/__init__.py +1 -1
  37. pygeodesy/geodesicx/__main__.py +4 -4
  38. pygeodesy/geodesicx/gx.py +40 -32
  39. pygeodesy/geodesicx/gxarea.py +15 -12
  40. pygeodesy/geodesicx/gxbases.py +3 -4
  41. pygeodesy/geodesicx/gxline.py +6 -8
  42. pygeodesy/geodsolve.py +28 -26
  43. pygeodesy/geohash.py +47 -44
  44. pygeodesy/geoids.py +37 -35
  45. pygeodesy/hausdorff.py +112 -99
  46. pygeodesy/heights.py +136 -129
  47. pygeodesy/internals.py +576 -0
  48. pygeodesy/interns.py +6 -207
  49. pygeodesy/iters.py +22 -19
  50. pygeodesy/karney.py +18 -15
  51. pygeodesy/ktm.py +31 -24
  52. pygeodesy/latlonBase.py +12 -11
  53. pygeodesy/lazily.py +140 -218
  54. pygeodesy/lcc.py +24 -25
  55. pygeodesy/ltp.py +83 -71
  56. pygeodesy/ltpTuples.py +7 -5
  57. pygeodesy/mgrs.py +5 -4
  58. pygeodesy/named.py +136 -49
  59. pygeodesy/namedTuples.py +33 -25
  60. pygeodesy/nvectorBase.py +10 -9
  61. pygeodesy/osgr.py +14 -12
  62. pygeodesy/points.py +13 -13
  63. pygeodesy/props.py +7 -7
  64. pygeodesy/rhumb/__init__.py +1 -1
  65. pygeodesy/rhumb/bases.py +3 -2
  66. pygeodesy/rhumb/solve.py +2 -2
  67. pygeodesy/solveBase.py +8 -7
  68. pygeodesy/sphericalTrigonometry.py +5 -5
  69. pygeodesy/streprs.py +8 -7
  70. pygeodesy/trf.py +8 -8
  71. pygeodesy/triaxials.py +67 -63
  72. pygeodesy/units.py +48 -50
  73. pygeodesy/unitsBase.py +24 -11
  74. pygeodesy/ups.py +7 -6
  75. pygeodesy/utily.py +4 -4
  76. pygeodesy/utm.py +53 -52
  77. pygeodesy/utmupsBase.py +11 -8
  78. pygeodesy/vector2d.py +6 -7
  79. pygeodesy/vector3d.py +16 -17
  80. pygeodesy/vector3dBase.py +5 -5
  81. PyGeodesy-24.5.8.dist-info/RECORD +0 -115
  82. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/WHEEL +0 -0
  83. {PyGeodesy-24.5.8.dist-info → PyGeodesy-24.5.24.dist-info}/top_level.txt +0 -0
pygeodesy/interns.py CHANGED
@@ -5,14 +5,11 @@ modules and function L{pygeodesy.machine}.
5
5
  '''
6
6
  import sys as _sys
7
7
  try:
8
- _intern = intern # PYCHOK in .lazily
8
+ _intern = intern # PYCHOK in .lazily, .trf
9
9
  except NameError: # Python 3+
10
10
  _intern = _sys.intern
11
11
 
12
12
  _COMMASPACE_ = ', ' # overriden below
13
- _pf2List = [] # cached _platform2 list
14
- _Py3List = [] # cached _pythonarchine list
15
-
16
13
  _sub_packages = 'auxilats', 'deprecated', 'geodesicx', 'rhumb' # PYCHOK in .lazily,
17
14
  # ... make._dist, MANIFEST, setup.setup, test.bases, test.testModules
18
15
 
@@ -204,11 +201,10 @@ _distance_ = 'distance' # PYCHOK OK
204
201
  _distant_ = _Prefix('distant') # PYCHOK OK
205
202
  _doesn_t_exist_ = "doesn't exist" # PYCHOK OK
206
203
  _DOT_ = Str_('.') # PYCHOK OK
207
- _down_ = 'down' # PYCHOK OK
204
+ _dunder_name_ = '__name__' # PYCHOK _DUNDER_(NN, _name_, NN)
208
205
  _e_ = 'e' # PYCHOK OK
209
206
  _E_ = 'E' # PYCHOK OK
210
207
  _earth_ = 'earth' # PYCHOK OK
211
- _east_ = 'east' # PYCHOK OK
212
208
  _easting_ = 'easting' # PYCHOK OK
213
209
  _ecef_ = 'ecef' # PYCHOK OK
214
210
  _edge_ = 'edge' # PYCHOK OK
@@ -262,8 +258,8 @@ _isclockwise_ = 'isclockwise' # PYCHOK OK
262
258
  _ispolar_ = 'ispolar' # PYCHOK OK
263
259
  _j_ = 'j' # PYCHOK OK
264
260
  _k0_ = 'k0' # PYCHOK OK
261
+ _keyword_ = 'keyword' # PYCHOK OK
265
262
  _kind_ = 'kind' # PYCHOK OK
266
- _knots_ = 'knots' # PYCHOK OK
267
263
  _Krassovski1940_ = 'Krassovski1940' # PYCHOK OK
268
264
  _Krassowsky1940_ = 'Krassowsky1940' # PYCHOK OK
269
265
  _LANGLE_ = '<' # PYCHOK OK
@@ -320,7 +316,6 @@ _NLHASH_ = Str_(_NL_ + '# ') # PYCHOK OK
320
316
  # _NLNL_ = _DNL_ # PYCHOK OK
321
317
  _NN_ = 'NN' # PYCHOK OK
322
318
  _no_ = _Prefix('no') # PYCHOK OK
323
- _north_ = 'north' # PYCHOK OK
324
319
  _northing_ = 'northing' # PYCHOK OK
325
320
  _NorthPole_ = 'NorthPole' # PYCHOK OK
326
321
  _not_ = _Prefix('not') # PYCHOK OK
@@ -397,7 +392,6 @@ _STAR_ = Str_('*') # PYCHOK OK
397
392
  _start_ = 'start' # PYCHOK OK
398
393
  _std_ = 'std' # PYCHOK OK
399
394
  _stdev_ = 'stdev' # PYCHOK OK
400
- _supported_ = 'supported' # PYCHOK OK
401
395
  _tbd_ = 'tbd' # PYCHOK OK
402
396
  _TILDE_ = '~' # PYCHOK OK
403
397
  _to_ = 'to' # PYCHOK OK
@@ -451,204 +445,9 @@ _LR_PAIRS = {_LANGLE_: _RANGLE_,
451
445
  _LPAREN_: _RPAREN_,
452
446
  _LSQUARE_: _RSQUARE_} # PYCHOK OK
453
447
 
454
-
455
- def _dunder_nameof(inst, *dflt):
456
- '''(INTERNAL) Get the double_underscore __name__ attr.
457
- '''
458
- try:
459
- return inst.__name__
460
- except AttributeError:
461
- pass
462
- return dflt[0] if dflt else inst.__class__.__name__
463
-
464
-
465
- def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
466
- '''(INTERNAL) Enquote a string containing whitespace or replace
467
- whitespace by C{white} if specified.
468
- '''
469
- if strs:
470
- t = strs.split()
471
- if len(t) > 1:
472
- strs = white.join(t if white else (quote, strs, quote))
473
- return strs
474
-
475
-
476
- def _headof(name):
477
- '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
478
- '''
479
- i = name.find(_DOT_)
480
- return name if i < 0 else name[:i]
481
-
482
-
483
- def _is(a, b): # PYCHOK no cover
484
- '''(INTERNAL) C{a is b}? in C{PyPy}
485
- '''
486
- return (a == b) if _isPyPy() else (a is b)
487
-
488
-
489
- def _isPyPy():
490
- '''(INTERNAL) Is this C{PyPy}?
491
- '''
492
- # platform.python_implementation() == 'PyPy'
493
- return _pythonarchine()[0].startswith(_PyPy__)
494
-
495
-
496
- def _load_lib(name):
497
- '''(INTERNAL) Load a C{dylib}, B{C{name}} must startwith('lib').
498
- '''
499
- # macOS 11+ (aka 10.16) no longer provides direct loading of
500
- # system libraries. As a result, C{ctypes.util.find_library}
501
- # will not find any library, unless previously installed by a
502
- # low-level dlopen(name) call (with the library base C{name}).
503
- from ctypes import CDLL
504
- from ctypes.util import find_library
505
-
506
- ns = find_library(name), name
507
- if _sys.platform[:6] == 'darwin': # and os.name == 'posix'
508
- from ctypes import _dlopen, DEFAULT_MODE
509
- from os.path import join
510
- ns += (_DOT_(name, 'dylib'),
511
- _DOT_(name, 'framework'), join(
512
- _DOT_(name, 'framework'), name))
513
- else: # non-macOS
514
- DEFAULT_MODE = 0
515
-
516
- def _dlopen(*unused):
517
- return True
518
-
519
- for n in ns:
520
- try:
521
- if n and _dlopen(n, DEFAULT_MODE): # pre-load handle
522
- lib = CDLL(n) # == ctypes.cdll.LoadLibrary(n)
523
- if lib._name: # has a qualified name
524
- return lib
525
- except (AttributeError, OSError):
526
- pass
527
-
528
- return None # raise OSError
529
-
530
-
531
- def machine():
532
- '''Return standard C{platform.machine}, but distinguishing Intel I{native}
533
- from Intel I{emulation} on Apple Silicon (on macOS only).
534
-
535
- @return: Machine C{'arm64'} for Apple Silicon I{native}, C{'x86_64'}
536
- for Intel I{native}, C{"arm64_x86_64"} for Intel I{emulation},
537
- etc. (C{str} with C{comma}s replaced by C{underscore}s).
538
- '''
539
- return _platform2()[1]
540
-
541
-
542
- def _platform2(sep=NN):
543
- '''(INTERNAL) Get platform architecture and machine as C{2-list} or C{str}.
544
- '''
545
- L = _pf2List
546
- if not L:
547
- import platform
548
- m = platform.machine() # ARM64, arm64, x86_64, iPhone13,2, etc.
549
- m = m.replace(_COMMA_, _UNDER_)
550
- if m.lower() == 'x86_64': # on Intel or Rosetta2 ...
551
- v = platform.mac_ver() # ... and only on macOS ...
552
- if v and _version2(v[0]) > (10, 15): # ... 11+ aka 10.16
553
- # <https://Developer.Apple.com/forums/thread/659846>
554
- if _sysctl_uint('sysctl.proc_translated') == 1: # and \
555
- # _sysctl_uint('hw.optional.arm64') == 1: # PYCHOK indent
556
- m = _UNDER_('arm64', m) # Apple Si emulating Intel x86-64
557
- L[:] = [platform.architecture()[0], # bits
558
- m] # arm64, arm64_x86_64, x86_64, etc.
559
- return sep.join(L) if sep else L # 2-list()
560
-
561
-
562
- def _pythonarchine(sep=NN): # in test/bases.py versions
563
- '''(INTERNAL) Get PyPy and Python versions and C{_platform2} as C{3- or 4-list} or C{str}.
564
- '''
565
- L = _Py3List
566
- if not L:
567
- v = _sys.version
568
- L[:] = [_Python_(v)] + _platform2()
569
- pypy = _PyPy__(v)
570
- if pypy:
571
- L.insert(0, pypy)
572
- return sep.join(L) if sep else L # 3- or 4-list
573
-
574
-
575
- def _sysctl_uint(name):
576
- '''(INTERNAL) Get an unsigned int sysctl item by name, use on macOS ONLY!
577
- '''
578
- libc = _load_lib('libc')
579
- if libc: # <https://StackOverflow.com/questions/759892/python-ctypes-and-sysctl>
580
- from ctypes import byref, c_char_p, c_size_t, c_uint, sizeof # get_errno
581
- n = name if str is bytes else bytes(name, _utf_8_) # PYCHOK isPython2 = str is bytes
582
- u = c_uint(0)
583
- z = c_size_t(sizeof(u))
584
- r = libc.sysctlbyname(c_char_p(n), byref(u), byref(z), None, c_size_t(0))
585
- else: # could find or load 'libc'
586
- r = -2
587
- return int(r if r else u.value) # -1 ENOENT error, -2 no libc
588
-
589
-
590
- def _tailof(name):
591
- '''(INTERNAL) Get the base name of qualified C{name} or the C{name}.
592
- '''
593
- i = name.rfind(_DOT_) + 1
594
- return name[i:] if i > 0 else name
595
-
596
-
597
- def _under(name): # PYCHOK in .datums, .auxilats, .ups, .utm, .utmupsBase, ...
598
- '''(INTERNAL) Prefix C{name} with I{underscore}.
599
- '''
600
- return name if name.startswith(_UNDER_) else NN(_UNDER_, name)
601
-
602
-
603
- def _usage(file_py, *args): # in .etm
604
- '''(INTERNAL) Build "usage: python -m ..." cmd line for module B{C{file_py}}.
605
- '''
606
- import os
607
- m = os.path.dirname(file_py).replace(os.getcwd(), _ELLIPSIS_) \
608
- .replace(os.sep, _DOT_).strip()
609
- b, x = os.path.splitext(os.path.basename(file_py))
610
- if x == '.py' and b != '__main__':
611
- m = _DOT_(m or _pygeodesy_, b)
612
- p = NN(_python_, _sys.version_info[0])
613
- return NN('usage', _SPACE_(_COLON_, p, '-m', _enquote(m), *args))
614
-
615
-
616
- def _version2(version, n=2):
617
- '''(INTERNAL) Split C{B{version} str} into a C{1-, 2- or 3-tuple} of C{int}s.
618
- '''
619
- t = _version_ints(version.split(_DOT_, 2))
620
- if len(t) < n:
621
- t += (0,) * n
622
- return t[:n]
623
-
624
-
625
- def _version_info(package): # in .Base.karney, .basics
626
- '''(INTERNAL) Get the C{package.__version_info__} as a 2- or
627
- 3-tuple C{(major, minor, revision)} if C{int}s.
628
- '''
629
- try:
630
- return _version_ints(package.__version_info__)
631
- except AttributeError:
632
- return _version2(package.__version__.strip(), n=3)
633
-
634
-
635
- def _version_ints(vs):
636
- # helper for _version2 and _version_info above
637
-
638
- def _ints(vs):
639
- for v in vs:
640
- try:
641
- yield int(v.strip())
642
- except (TypeError, ValueError):
643
- pass
644
-
645
- return tuple(_ints(vs))
646
-
647
-
648
- __all__ = (_NN_, # not MISSING!
649
- Str_.__name__, # classes
650
- machine.__name__) # in .lazily
651
- __version__ = '24.05.08'
448
+ __all__ = (_NN_, # NOT MISSING!
449
+ Str_.__name__) # classes
450
+ __version__ = '24.05.21'
652
451
 
653
452
  if __name__ == '__main__':
654
453
 
pygeodesy/iters.py CHANGED
@@ -9,15 +9,16 @@ the initial items, skipping of duplicate items and copying of the
9
9
  iterated items.
10
10
  '''
11
11
 
12
- from pygeodesy.basics import islistuple, issubclassof, \
13
- len2, map2, _passarg
12
+ from pygeodesy.basics import islistuple, issubclassof, len2, \
13
+ map2, _passarg
14
14
  # from pygeodesy.constants import _1_0 # from .utily
15
15
  from pygeodesy.errors import _IndexError, LenError, PointsError, \
16
16
  _TypeError, _ValueError
17
- from pygeodesy.interns import NN, _0_, _composite_, _few_, \
18
- _latlon_, _points_, _too_
17
+ # from pygeodesy.internals import _passarg # from .basics
18
+ from pygeodesy.interns import _0_, _composite_, _few_, _latlon_, \
19
+ _points_, _too_
19
20
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
20
- from pygeodesy.named import Fmt, _Named, property_RO
21
+ from pygeodesy.named import _Named, property_RO, Fmt
21
22
  from pygeodesy.namedTuples import Point3Tuple, Points2Tuple
22
23
  # from pygeodesy.props import property_RO # from .named
23
24
  # from pygeodesy.streprs import Fmt # from .named
@@ -25,7 +26,7 @@ from pygeodesy.units import Int, Radius
25
26
  from pygeodesy.utily import degrees2m, _Wrap, _1_0
26
27
 
27
28
  __all__ = _ALL_LAZY.iters
28
- __version__ = '23.12.14'
29
+ __version__ = '24.05.23'
29
30
 
30
31
  _items_ = 'items'
31
32
  _iterNumpy2len = 1 # adjustable for testing purposes
@@ -49,7 +50,7 @@ class _BaseIter(_Named):
49
50
  _prev = _NOTHING
50
51
  _wrap = False
51
52
 
52
- def __init__(self, items, loop=0, dedup=False, Error=None, name=NN):
53
+ def __init__(self, items, loop=0, dedup=False, Error=None, **name):
53
54
  '''New iterator over an iterable of B{C{items}}.
54
55
 
55
56
  @arg items: Iterable (any C{type}, except composites).
@@ -57,7 +58,7 @@ class _BaseIter(_Named):
57
58
  iterate index (non-negative C{int}).
58
59
  @kwarg dedup: Skip duplicate items (C{bool}).
59
60
  @kwarg Error: Error to raise (L{LenError}).
60
- @kwarg name: Optional name (C{str}).
61
+ @kwarg name: Optional C{B{name}="items"} (C{str}).
61
62
 
62
63
  @raise Error: Invalid B{C{items}} or sufficient number of B{C{items}}.
63
64
 
@@ -237,10 +238,11 @@ class _BaseIter(_Named):
237
238
  class PointsIter(_BaseIter):
238
239
  '''Iterator for C{points} with optional loop-back and copies.
239
240
  '''
240
- _base = None
241
- _Error = PointsError
241
+ _base = None
242
+ _Error = PointsError
243
+ _name = _points_
242
244
 
243
- def __init__(self, points, loop=0, base=None, dedup=False, wrap=False, name=NN):
245
+ def __init__(self, points, loop=0, base=None, dedup=False, wrap=False, **name):
244
246
  '''New L{PointsIter} iterator.
245
247
 
246
248
  @arg points: C{Iterable} or C{list}, C{sequence}, C{set}, C{tuple},
@@ -251,13 +253,13 @@ class PointsIter(_BaseIter):
251
253
  @kwarg dedup: Skip duplicate points (C{bool}).
252
254
  @kwarg wrap: If C{True}, wrap or I{normalize} the enum-/iterated
253
255
  B{C{points}} (C{bool}).
254
- @kwarg name: Optional name (C{str}).
256
+ @kwarg name: Optional C{B{name}="points"} (C{str}).
255
257
 
256
258
  @raise PointsError: Insufficient number of B{C{points}}.
257
259
 
258
260
  @raise TypeError: Some B{C{points}} are not B{C{base}}.
259
261
  '''
260
- _BaseIter.__init__(self, points, loop=loop, dedup=dedup, name=name or _points_)
262
+ _BaseIter.__init__(self, points, loop=loop, dedup=dedup, **name)
261
263
 
262
264
  if base and not (isNumpy2(points) or isTuple2(points)):
263
265
  self._base = base
@@ -309,12 +311,13 @@ class PointsIter(_BaseIter):
309
311
  class LatLon2PsxyIter(PointsIter):
310
312
  '''Iterate and convert for C{points} with optional loop-back and copies.
311
313
  '''
312
- _deg2m = None
313
- _radius = None # keep degrees
314
- _wrap = True
314
+ _deg2m = None
315
+ _name = _latlon_
316
+ _radius = None # keep degrees
317
+ _wrap = True
315
318
 
316
319
  def __init__(self, points, loop=0, base=None, wrap=True, radius=None,
317
- dedup=False, name=_latlon_):
320
+ dedup=False, **name):
318
321
  '''New L{LatLon2PsxyIter} iterator.
319
322
 
320
323
  @note: The C{LatLon} latitude is considered the I{pseudo-y} and
@@ -330,13 +333,13 @@ class LatLon2PsxyIter(PointsIter):
330
333
  @kwarg radius: Mean earth radius (C{meter}) for conversion from
331
334
  C{degrees} to C{meter} (or C{radians} if C{B{radius}=1}).
332
335
  @kwarg dedup: Skip duplicate points (C{bool}).
333
- @kwarg name: Optional name (C{str}).
336
+ @kwarg name: Optional C{B{name}="latlon"} (C{str}).
334
337
 
335
338
  @raise PointsError: Insufficient number of B{C{points}}.
336
339
 
337
340
  @raise TypeError: Some B{C{points}} are not B{C{base}}-compatible.
338
341
  '''
339
- PointsIter.__init__(self, points, loop=loop, base=base, dedup=dedup, name=name)
342
+ PointsIter.__init__(self, points, loop=loop, base=base, dedup=dedup, **name)
340
343
  if not wrap:
341
344
  self._wrap = False
342
345
  if radius:
pygeodesy/karney.py CHANGED
@@ -140,15 +140,15 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
140
140
  from __future__ import division as _; del _ # PYCHOK semicolon
141
141
 
142
142
  from pygeodesy.basics import _copysign, int1s, isint, itemsorted, neg, unsigned0, \
143
- _xgeographiclib, _zip
143
+ _xgeographiclib, _zip, _version_info
144
144
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
145
- _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
145
+ _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
146
146
  from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get
147
147
  from pygeodesy.fmath import cbrt, fremainder, norm2
148
+ # from pygeodesy.internals import _version_info # from .basics
148
149
  from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi2_, _azi12_, _composite_, \
149
150
  _lat1_, _lat2_, _lon1_, _lon2_, _m12_, _M12_, _M21_, \
150
- _number_, _s12_, _S12_, _UNDER_, _version_info, \
151
- _BAR_ # PYCHOK used!
151
+ _number_, _s12_, _S12_, _UNDER_, _BAR_ # PYCHOK used!
152
152
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
153
153
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
154
154
  from pygeodesy.props import deprecated_method, Property_RO
@@ -159,7 +159,7 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
159
159
  # from math import fabs # from .utily
160
160
 
161
161
  __all__ = _ALL_LAZY.karney
162
- __version__ = '24.03.22'
162
+ __version__ = '24.05.20'
163
163
 
164
164
  _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_) == _2_
165
165
  _perimeter_ = 'perimeter'
@@ -168,7 +168,7 @@ _perimeter_ = 'perimeter'
168
168
  class _GTuple(_NamedTuple): # in .testNamedTuples
169
169
  '''(INTERNAL) Helper.
170
170
  '''
171
- def toGDict(self, **updates):
171
+ def toGDict(self, **updates): # NO name=NN
172
172
  '''Convert this C{*Tuple} to a L{GDict}.
173
173
 
174
174
  @kwarg updates: Optional items to apply (C{nam=value} pairs)
@@ -359,12 +359,11 @@ class _CapsBase(_NamedBase): # in .auxilats, .geodesicx.gxbases
359
359
  '''
360
360
  self._debug = Caps._DEBUG_ALL if debug else 0
361
361
 
362
- def _iter2tion(self, r, s):
362
+ def _iter2tion(self, r, iter=None, **unused):
363
363
  '''(INTERNAL) Copy C{C{s}.iter} into C{B{r}._iteration}.
364
364
  '''
365
- i = _xkwds_get(s, iter=None)
366
- if i is not None:
367
- self._iteration = r._iteration = i
365
+ if iter is not None:
366
+ self._iteration = r._iteration = iter
368
367
  return r
369
368
 
370
369
 
@@ -468,7 +467,7 @@ class Inverse10Tuple(_GTuple):
468
467
 
469
468
  @kwarg updates: Optional items to apply (C{nam=value} pairs)
470
469
  '''
471
- return _GTuple.toGDict(self, azi1=atan2d(self.salp1, self.calp1), # PYCHOK indent, namedTuple
470
+ return _GTuple.toGDict(self, azi1=atan2d(self.salp1, self.calp1), # PYCHOK namedTuple
472
471
  azi2=atan2d(self.salp2, self.calp2), # PYCHOK namedTuple
473
472
  **updates) # PYCHOK indent
474
473
 
@@ -750,7 +749,10 @@ def _polynomial(x, cs, i, j): # PYCHOK shared
750
749
  # for c in cs[i+1:j]:
751
750
  # s, t = _sum2_(s * x, t * x, c)
752
751
  # return s # + t
753
- s, _ = _sum2_(cs[i], _0_0, x=x, *cs[i+1:j])
752
+ s = cs[i]
753
+ i += 1
754
+ if x and i < j:
755
+ s, _ = _sum2_(s, _0_0, x=x, *cs[i:j])
754
756
  return s # + t
755
757
 
756
758
 
@@ -843,11 +845,12 @@ def _sum2_(s, t, *vs, **x):
843
845
 
844
846
  @note: NOT "error-free", see C{pygeodesy.test/testKarney.py}.
845
847
  '''
846
- x = _xkwds_get(x, x=0)
848
+ x = _xkwds_get(x, x=_1_0)
849
+ p = x != _1_0
847
850
 
848
851
  _s2, _u0 = _sum2, unsigned0
849
852
  for v in vs:
850
- if x:
853
+ if p:
851
854
  s *= x
852
855
  t *= x
853
856
  if v:
@@ -857,7 +860,7 @@ def _sum2_(s, t, *vs, **x):
857
860
  if s:
858
861
  t += u # accumulate u into t
859
862
  # elif t: # s == 0 implies t == 0
860
- # raise _AssertionError(t=t, txt=_not_(_0_))
863
+ # raise _AssertionError(t=t, txt_not_=_0_)
861
864
  else:
862
865
  s = _u0(u) # result is u, t = 0
863
866
  else:
pygeodesy/ktm.py CHANGED
@@ -48,18 +48,18 @@ from pygeodesy.constants import INF, _K0_UTM, PI, PI_2, _0_0s, _0_0, \
48
48
  _1_0, _90_0, _copysignINF
49
49
  from pygeodesy.datums import Datum, _spherical_datum, _WGS84, _EWGS84
50
50
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
51
- from pygeodesy.errors import _ValueError, _xkwds_get, _Xorder
51
+ from pygeodesy.errors import _ValueError, _xkwds_pop2, _Xorder
52
52
  from pygeodesy.fmath import hypot, hypot1
53
53
  from pygeodesy.fsums import fsum1f_
54
- from pygeodesy.interns import NN, _COMMASPACE_, _singular_
54
+ from pygeodesy.interns import _COMMASPACE_, _singular_
55
55
  from pygeodesy.karney import _atan2d, _diff182, _fix90, _norm180, \
56
- _polynomial, _unsigned2, _NamedBase
57
- from pygeodesy.lazily import _ALL_LAZY, _pairs
58
- # from pygeodesy.named import _NamedBase # from .karney
56
+ _polynomial, _unsigned2
57
+ # from pygeodesy.lazily import _ALL_LAZY # from .named
58
+ from pygeodesy.named import _NamedBase, pairs, _ALL_LAZY
59
59
  from pygeodesy.namedTuples import Forward4Tuple, Reverse4Tuple
60
60
  from pygeodesy.props import property_doc_, Property, Property_RO, \
61
61
  _update_all
62
- # from pygeodesy.streprs import pairs as _pairs # from .lazily
62
+ # from pygeodesy.streprs import pairs # from .named
63
63
  from pygeodesy.units import Degrees, Scalar_, _1mm as _TOL_10 # PYCHOK used!
64
64
  from pygeodesy.utily import atan1d, _loneg, sincos2, sincos2d_
65
65
 
@@ -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.01.02'
70
+ __version__ = '24.05.24'
71
71
 
72
72
 
73
73
  class KTMError(_ValueError):
@@ -115,24 +115,33 @@ class KTransverseMercator(_NamedBase):
115
115
  _mTM = 6
116
116
  _raiser = False # throw Error
117
117
 
118
- def __init__(self, a_earth=_EWGS84, f=None, lon0=0, k0=_K0_UTM, name=NN,
119
- raiser=False, **TMorder):
118
+ def __init__(self, a_earth=_EWGS84, f=None, lon0=0, k0=_K0_UTM,
119
+ raiser=False, **TMorder_name):
120
120
  '''New L{KTransverseMercator}.
121
121
 
122
122
  @kwarg a_earth: This rhumb's earth (L{Ellipsoid}, L{Ellipsoid2},
123
123
  L{a_f2Tuple}, L{Datum}, 2-tuple (C{a, f})) or the
124
124
  equatorial radius (C{scalar}, C{meter}).
125
- @kwarg f: The ellipsoid's flattening (C{scalar}), iff B{C{a_earth}} is
126
- a C{scalar}, ignored otherwise.
125
+ @kwarg f: The ellipsoid's flattening (C{scalar}), iff B{C{a_earth}}
126
+ is a C{scalar}, ignored otherwise.
127
127
  @kwarg lon0: The central meridian (C{degrees180}).
128
128
  @kwarg k0: Central scale factor (C{scalar}).
129
- @kwarg name: Optional name (C{str}).
130
129
  @kwarg raiser: If C{True}, throw a L{KTMError} for C{forward}
131
130
  singularities (C{bool}).
132
- @kwarg TMorder: Keyword argument B{C{TMorder}}, see property C{TMorder}.
131
+ @kwarg TMorder_name: Optional C{B{name}=NN} (C{str}) and optional
132
+ keyword argument C{B{TMorder}=6} for the order of
133
+ this L{KTransverseMercator}, see property C{TMorder}.
133
134
 
134
135
  @raise KTMError: Invalid B{C{a_earth}}, B{C{f}} or B{C{TMorder}}.
135
136
  '''
137
+ if TMorder_name:
138
+ M = self._mTM
139
+ m, name = _xkwds_pop2(TMorder_name, TMorder=M)
140
+ if m != M:
141
+ self.TMorder = m
142
+ if name:
143
+ self.name = name
144
+
136
145
  if f is not None:
137
146
  self.ellipsoid = a_earth, f
138
147
  elif a_earth in (_EWGS84, _WGS84, None):
@@ -141,14 +150,11 @@ class KTransverseMercator(_NamedBase):
141
150
  self.datum = a_earth
142
151
  else:
143
152
  self.ellipsoid = a_earth
153
+
144
154
  self.lon0 = lon0
145
155
  self.k0 = k0
146
- if name: # PYCHOK no cover
147
- self.name = name
148
156
  if raiser:
149
157
  self.raiser = True
150
- if TMorder:
151
- self.TMorder = _xkwds_get(TMorder, TMorder=self._mTM)
152
158
 
153
159
  @Property_RO
154
160
  def _Alp(self):
@@ -215,13 +221,13 @@ class KTransverseMercator(_NamedBase):
215
221
 
216
222
  f = flattening
217
223
 
218
- def forward(self, lat, lon, lon0=None, name=NN):
224
+ def forward(self, lat, lon, lon0=None, **name):
219
225
  '''Forward projection, from geographic to transverse Mercator.
220
226
 
221
227
  @arg lat: Latitude of point (C{degrees90}).
222
228
  @arg lon: Longitude of point (C{degrees180}).
223
229
  @arg lon0: Central meridian of the projection (C{degrees180}).
224
- @kwarg name: Optional name (C{str}).
230
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
225
231
 
226
232
  @return: L{Forward4Tuple}C{(easting, northing, gamma, scale)}
227
233
  with C{easting} and C{northing} in C{meter}, unfalsed, the
@@ -272,7 +278,7 @@ class KTransverseMercator(_NamedBase):
272
278
  y, g = neg_(y, g)
273
279
  if _lon:
274
280
  x, g = neg_(x, g)
275
- return Forward4Tuple(x, y, _norm180(g), k, name=name or self.name)
281
+ return Forward4Tuple(x, y, _norm180(g), k, name=self._name__(name))
276
282
 
277
283
  @property_doc_(''' the central scale factor (C{float}).''')
278
284
  def k0(self):
@@ -347,12 +353,13 @@ class KTransverseMercator(_NamedBase):
347
353
  self. lon0 = lon0
348
354
  return t
349
355
 
350
- def reverse(self, x, y, lon0=None, name=NN):
356
+ def reverse(self, x, y, lon0=None, **name):
351
357
  '''Reverse projection, from transverse Mercator to geographic.
352
358
 
353
359
  @arg x: Easting of point (C{meter}).
354
360
  @arg y: Northing of point (C{meter}).
355
361
  @arg lon0: Central meridian of the projection (C{degrees180}).
362
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
356
363
 
357
364
  @return: L{Reverse4Tuple}C{(lat, lon, gamma, scale)} with
358
365
  C{lat}- and C{lon}gitude in C{degrees}, I{unfalsed}.
@@ -394,7 +401,7 @@ class KTransverseMercator(_NamedBase):
394
401
  lat += self._lat0
395
402
  lon += self._lon0 if lon0 is None else _norm180(lon0)
396
403
  return Reverse4Tuple(lat, _norm180(lon), _norm180(g), k,
397
- name=name or self.name)
404
+ name=self._name__(name))
398
405
 
399
406
  @Property
400
407
  def TMorder(self):
@@ -419,7 +426,7 @@ class KTransverseMercator(_NamedBase):
419
426
  d = dict(ellipsoid=self.ellipsoid, k0=self.k0, TMorder=self.TMorder)
420
427
  if self.name: # PYCHOK no cover
421
428
  d.update(name=self.name)
422
- return _COMMASPACE_.join(_pairs(d, **kwds))
429
+ return _COMMASPACE_.join(pairs(d, **kwds))
423
430
 
424
431
 
425
432
  def _cma(a, b0, b1, Cn):
@@ -605,7 +612,7 @@ assert set(_AlpCoeffs.keys()) == set(_BetCoeffs.keys())
605
612
 
606
613
  if __name__ == '__main__':
607
614
 
608
- from pygeodesy.interns import _usage
615
+ from pygeodesy.internals import _usage
609
616
  from sys import argv, exit as _exit
610
617
 
611
618
  _exit(_usage(*argv).replace('.ktm', '.etm -series'))