pygeodesy 24.5.24__py2.py3-none-any.whl → 24.6.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 (71) hide show
  1. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/METADATA +6 -5
  2. PyGeodesy-24.6.9.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +4 -4
  4. pygeodesy/auxilats/__init__.py +1 -1
  5. pygeodesy/auxilats/__main__.py +2 -2
  6. pygeodesy/auxilats/auxAngle.py +4 -4
  7. pygeodesy/basics.py +39 -5
  8. pygeodesy/booleans.py +54 -67
  9. pygeodesy/cartesianBase.py +138 -147
  10. pygeodesy/constants.py +3 -3
  11. pygeodesy/deprecated/functions.py +9 -3
  12. pygeodesy/ecef.py +67 -72
  13. pygeodesy/ellipsoidalBase.py +18 -56
  14. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  15. pygeodesy/ellipsoidalKarney.py +3 -3
  16. pygeodesy/ellipsoidalNvector.py +7 -7
  17. pygeodesy/ellipsoids.py +6 -5
  18. pygeodesy/errors.py +20 -10
  19. pygeodesy/etm.py +16 -21
  20. pygeodesy/fmath.py +9 -20
  21. pygeodesy/formy.py +60 -74
  22. pygeodesy/frechet.py +13 -14
  23. pygeodesy/fsums.py +60 -26
  24. pygeodesy/geodesicx/__init__.py +1 -1
  25. pygeodesy/geodesicx/__main__.py +2 -2
  26. pygeodesy/geodesicx/gx.py +3 -5
  27. pygeodesy/geodsolve.py +24 -26
  28. pygeodesy/geohash.py +27 -40
  29. pygeodesy/geoids.py +1 -1
  30. pygeodesy/hausdorff.py +17 -18
  31. pygeodesy/heights.py +17 -30
  32. pygeodesy/internals.py +15 -14
  33. pygeodesy/interns.py +3 -9
  34. pygeodesy/iters.py +2 -2
  35. pygeodesy/karney.py +8 -7
  36. pygeodesy/latlonBase.py +189 -176
  37. pygeodesy/lazily.py +92 -56
  38. pygeodesy/lcc.py +2 -2
  39. pygeodesy/ltp.py +93 -55
  40. pygeodesy/ltpTuples.py +304 -240
  41. pygeodesy/mgrs.py +51 -24
  42. pygeodesy/named.py +159 -136
  43. pygeodesy/namedTuples.py +43 -14
  44. pygeodesy/nvectorBase.py +20 -23
  45. pygeodesy/osgr.py +40 -48
  46. pygeodesy/points.py +11 -11
  47. pygeodesy/props.py +29 -16
  48. pygeodesy/rhumb/aux_.py +13 -15
  49. pygeodesy/rhumb/bases.py +12 -5
  50. pygeodesy/rhumb/ekx.py +24 -18
  51. pygeodesy/rhumb/solve.py +20 -70
  52. pygeodesy/simplify.py +16 -16
  53. pygeodesy/solveBase.py +35 -32
  54. pygeodesy/sphericalBase.py +33 -31
  55. pygeodesy/sphericalTrigonometry.py +17 -17
  56. pygeodesy/streprs.py +6 -4
  57. pygeodesy/trf.py +11 -9
  58. pygeodesy/triaxials.py +71 -50
  59. pygeodesy/units.py +40 -65
  60. pygeodesy/unitsBase.py +2 -2
  61. pygeodesy/ups.py +66 -70
  62. pygeodesy/utily.py +7 -6
  63. pygeodesy/utm.py +152 -156
  64. pygeodesy/utmups.py +38 -38
  65. pygeodesy/utmupsBase.py +102 -106
  66. pygeodesy/vector3d.py +34 -36
  67. pygeodesy/vector3dBase.py +12 -9
  68. pygeodesy/webmercator.py +43 -51
  69. PyGeodesy-24.5.24.dist-info/RECORD +0 -116
  70. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/WHEEL +0 -0
  71. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.9.dist-info}/top_level.txt +0 -0
pygeodesy/namedTuples.py CHANGED
@@ -8,26 +8,27 @@ are all instances of some C{Named...Tuple} class, all sub-classes
8
8
  of C{_NamedTuple} defined in C{pygeodesy.named}.
9
9
  '''
10
10
 
11
- from pygeodesy.basics import map1, _xinstanceof
11
+ from pygeodesy.basics import isinstanceof, map1, _xinstanceof
12
12
  # from pygeodesy.constants import INT0 # from .units
13
- from pygeodesy.errors import _ALL_LAZY, _MODS, _xattr, _xkwds_not # _xkwds
14
- from pygeodesy.interns import _1_, _2_, _a_, _A_, _area_, _angle_, _b_, _B_, \
15
- _band_, _c_, _C_, _datum_, _D_, _distance_, \
16
- _E_, _easting_, _end_, _fi_, _gamma_, _height_, \
17
- _h_, _j_, _hemipole_, _initial_, _lam_, _lat_, \
18
- _lon_, _n_, _northing_, _number_, _outside_, \
19
- _phi_, _point_, _precision_, _points_, _radius_, \
20
- _scale_, _start_, _x_, _y_, _z_, _zone_
13
+ # from pygeodesy.dms import toDMS # _MODS
14
+ from pygeodesy.errors import _xattr, _xkwds, _xkwds_not, _ALL_LAZY, _MODS
15
+ from pygeodesy.interns import NN, _1_, _2_, _a_, _A_, _area_, _angle_, _b_, _B_, \
16
+ _band_, _c_, _C_, _D_, _datum_, _distance_, _E_, \
17
+ _easting_, _end_, _fi_, _gamma_, _h_, _height_, \
18
+ _hemipole_, _initial_, _j_, _lam_, _lat_, _lon_, \
19
+ _n_, _northing_, _number_, _outside_, _phi_, \
20
+ _point_, _precision_, _points_, _radius_, _scale_, \
21
+ _start_, _x_, _y_, _z_, _zone_
21
22
  # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .errors
22
23
  from pygeodesy.named import _NamedTuple, _Pass
23
24
  from pygeodesy.props import deprecated_property_RO, property_RO
24
- from pygeodesy.units import Band, Bearing, Degrees, Degrees2, Easting, \
25
- FIx, Height, Int, INT0, Lam, Lat, Lon, Meter, \
26
- Meter2, Northing, Number_, Phi, Precision_, \
27
- Radians, Radius, Scalar, Str
25
+ from pygeodesy.units import Band, Bearing, Degrees, Degrees2, Easting, FIx, \
26
+ Height, Int, Lam, Lat, Lon, Meter, Meter2, \
27
+ Northing, Number_, Phi, Precision_, Radians, \
28
+ Radius, Scalar, Str, INT0
28
29
 
29
30
  __all__ = _ALL_LAZY.namedTuples
30
- __version__ = '24.05.18'
31
+ __version__ = '24.06.08'
31
32
 
32
33
  # __DUNDER gets mangled in class
33
34
  _closest_ = 'closest'
@@ -324,6 +325,34 @@ class LatLonPrec5Tuple(LatLonPrec3Tuple): # .wgrs.py
324
325
  _Units_ = LatLonPrec3Tuple._Units_ + ( Height, Radius)
325
326
 
326
327
 
328
+ class _NamedTupleTo(_NamedTuple): # in .testNamedTuples
329
+ '''(INTERNAL) Base for C{-.toDegrees}, C{-.toRadians}.
330
+ '''
331
+ def _Degrees3(self, *xs, **toDMS_kwds):
332
+ '''(INTERNAL) Convert C{xs} from C{Radians} to C{Degrees} or C{toDMS}.
333
+ '''
334
+ if toDMS_kwds:
335
+ toDMS_kwds = _xkwds(toDMS_kwds, ddd=1, pos=NN)
336
+ toDMS, s = _MODS.dms.toDMS, None
337
+ else:
338
+ toDMS, s = None, self
339
+ for x in xs:
340
+ if not isinstanceof(x, Degrees):
341
+ x, s = x.toDegrees(), None
342
+ yield toDMS(x, **toDMS_kwds) if toDMS else x
343
+ yield s
344
+
345
+ def _Radians3(self, *xs, **unused):
346
+ '''(INTERNAL) Convert C{xs} from C{Degrees} to C{Radians}.
347
+ '''
348
+ s = self
349
+ for x in xs:
350
+ if not isinstanceof(x, Radians):
351
+ x, s = x.toRadians(), None
352
+ yield x
353
+ yield s
354
+
355
+
327
356
  class NearestOn2Tuple(_NamedTuple): # .ellipsoidalBaseDI
328
357
  '''2-Tuple C{(closest, fraction)} of the C{closest} point
329
358
  on and C{fraction} along a line (segment) between two
pygeodesy/nvectorBase.py CHANGED
@@ -22,8 +22,7 @@ from pygeodesy.formy import _isequalTo, n_xyz2latlon, n_xyz2philam, \
22
22
  # from pygeodesy.internals import _under # from .named
23
23
  from pygeodesy.interns import NN, _1_, _2_, _3_, _bearing_, _coincident_, \
24
24
  _COMMASPACE_, _distance_, _h_, _insufficient_, \
25
- _intersection_, _no_, _NorthPole_, _point_, \
26
- _pole_, _SPACE_, _SouthPole_
25
+ _intersection_, _no_, _point_, _pole_, _SPACE_
27
26
  from pygeodesy.latlonBase import LatLonBase, _ALL_DOCS, _ALL_LAZY, _MODS
28
27
  # from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS # from .latlonBase
29
28
  from pygeodesy.named import _xother3, _under
@@ -34,12 +33,12 @@ from pygeodesy.props import deprecated_method, Property_RO, property_doc_, \
34
33
  from pygeodesy.streprs import Fmt, hstr, unstr, _xattrs
35
34
  from pygeodesy.units import Bearing, Height, Radius_, Scalar
36
35
  from pygeodesy.utily import sincos2d, _unrollon, _unrollon3
37
- from pygeodesy.vector3d import Vector3d, _xyzhdn3
36
+ from pygeodesy.vector3d import Vector3d, _xyzhdlln4
38
37
 
39
38
  from math import fabs, sqrt
40
39
 
41
40
  __all__ = _ALL_LAZY.nvectorBase
42
- __version__ = '24.05.18'
41
+ __version__ = '24.06.06'
43
42
 
44
43
 
45
44
  class NvectorBase(Vector3d): # XXX kept private
@@ -49,32 +48,30 @@ class NvectorBase(Vector3d): # XXX kept private
49
48
  _h = Height(h=0) # height (C{meter})
50
49
  _H = NN # height prefix (C{str}), '↑' in JS version
51
50
 
52
- def __init__(self, x_xyz, y=None, z=None, h=0, ll=None, datum=None, **name):
51
+ def __init__(self, x_xyz, y=None, z=None, h=0, datum=None, **ll_name):
53
52
  '''New n-vector normal to the earth's surface.
54
53
 
55
54
  @arg x_xyz: X component of vector (C{scalar}) or (3-D) vector
56
- (C{Nvector}, L{Vector3d}, L{Vector3Tuple} or
57
- L{Vector4Tuple}).
58
- @kwarg y: Y component of vector (C{scalar}), ignored if B{C{x_xyz}}
59
- is not C{scalar}, otherwise same units as B{C{x_xyz}}.
60
- @kwarg z: Z component of vector (C{scalar}), ignored if B{C{x_xyz}}
61
- is not C{scalar}, otherwise same units as B{C{x_xyz}}.
55
+ (C{Nvector}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
56
+ @kwarg y: Y component of vector (C{scalar}), ignored if B{C{x_xyz}} is not
57
+ C{scalar}, otherwise same units as B{C{x_xyz}}.
58
+ @kwarg z: Z component of vector (C{scalar}), ignored if B{C{x_xyz}} is not
59
+ C{scalar}, otherwise same units as B{C{x_xyz}}.
62
60
  @kwarg h: Optional height above surface (C{meter}).
63
- @kwarg ll: Optional, original latlon (C{LatLon}).
64
61
  @kwarg datum: Optional, I{pass-thru} datum (L{Datum}).
65
- @kwarg name: Optional C{B{name}=NN} (C{str}).
62
+ @kwarg ll_name: Optional C{B{name}=NN} (C{str}) and optional, original
63
+ latlon C{B{ll}=None} (C{LatLon}).
66
64
 
67
- @raise TypeError: Non-scalar B{C{x}}, B{C{y}} or B{C{z}}
68
- coordinate or B{C{x}} not an C{Nvector},
69
- L{Vector3Tuple} or L{Vector4Tuple} or
70
- invalid B{C{datum}}.
65
+ @raise TypeError: Non-scalar B{C{x}}, B{C{y}} or B{C{z}} coordinate or
66
+ B{C{x_xyz}} not an C{Nvector}, L{Vector3Tuple} or
67
+ L{Vector4Tuple} or invalid B{C{datum}}.
71
68
  '''
72
- h, d, n = _xyzhdn3(x_xyz, h, datum, ll, **name)
69
+ h, d, ll, n = _xyzhdlln4(x_xyz, h, datum, **ll_name)
73
70
  Vector3d.__init__(self, x_xyz, y=y, z=z, ll=ll, name=n)
74
71
  if h:
75
72
  self.h = h
76
73
  if d is not None:
77
- self._datum = _spherical_datum(d, name=self.name) # pass-thru
74
+ self._datum = _spherical_datum(d, name=n) # pass-thru
78
75
 
79
76
  @Property_RO
80
77
  def datum(self):
@@ -326,7 +323,7 @@ class NvectorBase(Vector3d): # XXX kept private
326
323
  r = self.toCartesian(h=h, Cartesian=None, datum=d)
327
324
  else:
328
325
  kwds = _xkwds(LatLon_kwds, height=h, datum=d)
329
- r = self._xnamed(LatLon(self.lat, self.lon, **kwds))
326
+ r = LatLon(self.lat, self.lon, **self._name1__(kwds))
330
327
  return r
331
328
 
332
329
  def toStr(self, prec=5, fmt=Fmt.PAREN, sep=_COMMASPACE_): # PYCHOK expected
@@ -378,14 +375,14 @@ class NvectorBase(Vector3d): # XXX kept private
378
375
  return self.xyz.to4Tuple(self.h)
379
376
 
380
377
 
381
- NorthPole = NvectorBase(0, 0, +1, name=_NorthPole_) # North pole (C{Nvector})
382
- SouthPole = NvectorBase(0, 0, -1, name=_SouthPole_) # South pole (C{Nvector})
378
+ NorthPole = NvectorBase(0, 0, +1, name='NorthPole') # North pole (C{Nvector})
379
+ SouthPole = NvectorBase(0, 0, -1, name='SouthPole') # South pole (C{Nvector})
383
380
 
384
381
 
385
382
  class _N_vector_(NvectorBase):
386
383
  '''(INTERNAL) Minimal, low-overhead C{n-vector}.
387
384
  '''
388
- def __init__(self, x, y, z, h=0, name=NN):
385
+ def __init__(self, x, y, z, h=0, **name):
389
386
  self._x, self._y, self._z = x, y, z
390
387
  if h:
391
388
  self._h = h
pygeodesy/osgr.py CHANGED
@@ -33,14 +33,14 @@ from pygeodesy.datums import Datums, _ellipsoidal_datum, _WGS84
33
33
  # from pygeodesy.dms import parseDMS2 # _MODS
34
34
  from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB
35
35
  from pygeodesy.errors import _parseX, _TypeError, _ValueError, \
36
- _xkwds, _xkwds_get
36
+ _xkwds, _xkwds_get, _xkwds_pop2
37
37
  from pygeodesy.fmath import Fdot, fpowers
38
38
  from pygeodesy.fsums import _Fsumf_
39
39
  from pygeodesy.interns import MISSING, NN, _A_, _COLON_, _COMMA_, \
40
40
  _COMMASPACE_, _DOT_, _ellipsoidal_, \
41
41
  _latlon_, _not_, _SPACE_
42
42
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
43
- from pygeodesy.named import _NamedBase, nameof, _xnamed
43
+ from pygeodesy.named import _name2__, _NamedBase, nameof
44
44
  from pygeodesy.namedTuples import EasNor2Tuple, LatLon2Tuple, \
45
45
  LatLonDatum3Tuple
46
46
  from pygeodesy.props import Property_RO, property_RO
@@ -53,7 +53,7 @@ from pygeodesy.utily import degrees90, degrees180, sincostan3, truncate
53
53
  from math import cos, fabs, radians, sin, sqrt
54
54
 
55
55
  __all__ = _ALL_LAZY.osgr
56
- __version__ = '24.05.13'
56
+ __version__ = '24.05.31'
57
57
 
58
58
  _equivalent_ = 'equivalent'
59
59
  _OSGR_ = 'OSGR'
@@ -194,22 +194,17 @@ class Osgr(_NamedBase):
194
194
  _northing = 0 # Nothing (C{meter})
195
195
  _resolution = 0 # from L{parseOSGR} (C{meter})
196
196
 
197
- def __init__(self, easting, northing, datum=None, name=NN,
198
- resolution=0):
197
+ def __init__(self, easting, northing, datum=None, resolution=0, **name):
199
198
  '''New L{Osgr} coordinate.
200
199
 
201
- @arg easting: Easting from the OS C{National Grid}
202
- origin (C{meter}).
203
- @arg northing: Northing from the OS C{National Grid}
204
- origin (C{meter}).
200
+ @arg easting: Easting from the OS C{National Grid} origin (C{meter}).
201
+ @arg northing: Northing from the OS C{National Grid} origin (C{meter}).
205
202
  @kwarg datum: Override default datum (C{Datums.OSGB36}).
206
- @kwarg name: Optional name (C{str}).
207
- @kwarg resolution: Optional resolution (C{meter}),
208
- C{0} for default.
203
+ @kwarg resolution: Optional resolution (C{meter}), C{0} for default.
204
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
209
205
 
210
- @raise OSGRError: Invalid or negative B{C{easting}} or
211
- B{C{northing}} or B{C{datum}} not an
212
- C{Datums.OSGB36} equivalent.
206
+ @raise OSGRError: Invalid or negative B{C{easting}} or B{C{northing}}
207
+ or B{C{datum}} not an C{Datums.OSGB36} equivalent.
213
208
  '''
214
209
  if datum: # PYCHOK no cover
215
210
  try:
@@ -267,17 +262,17 @@ class Osgr(_NamedBase):
267
262
  '''
268
263
  return self._northing
269
264
 
270
- def parse(self, strOSGR, name=NN):
265
+ def parse(self, strOSGR, **name):
271
266
  '''Parse an OSGR reference to a similar L{Osgr} instance.
272
267
 
273
268
  @arg strOSGR: The OSGR reference (C{str}), see function L{parseOSGR}.
274
- @kwarg name: Optional instance name (C{str}), overriding this name.
269
+ @kwarg name: Optional C{B{name}=NN} (C{str}), overriding this name.
275
270
 
276
271
  @return: The similar instance (L{Osgr})
277
272
 
278
273
  @raise OSGRError: Invalid B{C{strOSGR}}.
279
274
  '''
280
- return parseOSGR(strOSGR, Osgr=self.classof, name=name or self.name)
275
+ return parseOSGR(strOSGR, Osgr=self.classof, name=self._name__(name))
281
276
 
282
277
  @property_RO
283
278
  def resolution(self):
@@ -496,19 +491,20 @@ def _ll2datum(ll, datum, name):
496
491
  def _ll2LatLon3(ll, LatLon, datum, LatLon_kwds):
497
492
  '''(INTERNAL) Convert C{ll} to C{LatLon}
498
493
  '''
494
+ n = nameof(ll)
499
495
  if LatLon is None:
500
496
  r = _ll2datum(ll, datum, LatLonDatum3Tuple.__name__)
501
- r = LatLonDatum3Tuple(r.lat, r.lon, r.datum)
497
+ r = LatLonDatum3Tuple(r.lat, r.lon, r.datum, name=n)
502
498
  else: # must be ellipsoidal
503
499
  _xsubclassof(_LLEB, LatLon=LatLon)
504
500
  r = _ll2datum(ll, datum, LatLon.__name__)
505
- r = LatLon(r.lat, r.lon, datum=r.datum, **LatLon_kwds)
501
+ r = LatLon(r.lat, r.lon, datum=r.datum, **_xkwds(LatLon_kwds, name=n))
506
502
  if r._iteration != ll._iteration:
507
503
  r._iteration = ll._iteration
508
- return _xnamed(r, nameof(ll))
504
+ return r
509
505
 
510
506
 
511
- def parseOSGR(strOSGR, Osgr=Osgr, name=NN, **Osgr_kwds):
507
+ def parseOSGR(strOSGR, Osgr=Osgr, **name_Osgr_kwds):
512
508
  '''Parse a string representing an OS Grid Reference, consisting
513
509
  of C{"[GD] easting northing"}.
514
510
 
@@ -520,9 +516,9 @@ def parseOSGR(strOSGR, Osgr=Osgr, name=NN, **Osgr_kwds):
520
516
  @arg strOSGR: An OSGR coordinate (C{str}).
521
517
  @kwarg Osgr: Optional class to return the OSGR coordinate
522
518
  (L{Osgr}) or C{None}.
523
- @kwarg name: Optional B{C{Osgr}} name (C{str}).
524
- @kwarg Osgr_kwds: Optional, additional B{C{Osgr}} keyword
525
- arguments, ignored if C{B{Osgr} is None}.
519
+ @kwarg name_Osgr_kwds: Optional C{B{name}=NN} (C{str}) and
520
+ optional, additional B{C{Osgr}} keyword arguments,
521
+ ignored if C{B{Osgr} is None}.
526
522
 
527
523
  @return: An (B{C{Osgr}}) instance or if B{C{Osgr}} is
528
524
  C{None} an L{EasNor2Tuple}C{(easting, northing)}.
@@ -537,7 +533,7 @@ def parseOSGR(strOSGR, Osgr=Osgr, name=NN, **Osgr_kwds):
537
533
  raise ValueError
538
534
  return g
539
535
 
540
- def _OSGR(strOSGR, Osgr, name):
536
+ def _OSGR(strOSGR, Osgr, kwds):
541
537
  s = _splituple(strOSGR.strip())
542
538
  p = len(s)
543
539
  if not p:
@@ -570,20 +566,20 @@ def parseOSGR(strOSGR, Osgr=Osgr, name=NN, **Osgr_kwds):
570
566
  e += E * _100km
571
567
  n += N * _100km
572
568
 
569
+ name, kwds = _name2__(**kwds)
573
570
  if Osgr is None:
574
571
  _ = _MODS.osgr.Osgr(e, n, resolution=m) # validate
575
572
  r = EasNor2Tuple(e, n, name=name)
576
573
  else:
577
- r = Osgr(e, n, name=name,
578
- **_xkwds(Osgr_kwds, resolution=m))
574
+ r = Osgr(e, n, name=name, **_xkwds(kwds, resolution=m))
579
575
  return r
580
576
 
581
- return _parseX(_OSGR, strOSGR, Osgr, name,
577
+ return _parseX(_OSGR, strOSGR, Osgr, name_Osgr_kwds,
582
578
  strOSGR=strOSGR, Error=OSGRError)
583
579
 
584
580
 
585
- def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, name=NN, # MCCABE 14
586
- **prec_Osgr_kwds):
581
+ def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, # MCCABE 14
582
+ **prec_name_Osgr_kwds):
587
583
  '''Convert a lat-/longitude point to an OSGR coordinate.
588
584
 
589
585
  @arg latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic
@@ -597,11 +593,10 @@ def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, name=NN, # MCC
597
593
  L{a_f2Tuple}).
598
594
  @kwarg Osgr: Optional class to return the OSGR coordinate
599
595
  (L{Osgr}) or C{None}.
600
- @kwarg name: Optional B{C{Osgr}} name (C{str}).
601
- @kwarg prec_Osgr_kwds: Optional L{truncate} precision
602
- C{B{prec}=ndigits} and/or additional
603
- B{C{Osgr}} keyword arguments, ignored
604
- if C{B{Osgr} is None}.
596
+ @kwarg prec_name_Osgr_kwds: Optional C{B{name}=NN} (C{str}),
597
+ optional L{truncate} precision C{B{prec}=ndigits}
598
+ and additional B{C{Osgr}} keyword arguments,
599
+ ignored if C{B{Osgr} is None}.
605
600
 
606
601
  @return: An (B{C{Osgr}}) instance or if B{C{Osgr}} is C{None}
607
602
  an L{EasNor2Tuple}C{(easting, northing)}.
@@ -615,9 +610,6 @@ def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, name=NN, # MCC
615
610
  B{C{datum}}, B{C{Osgr}}, B{C{Osgr_kwds}}
616
611
  or conversion to C{Datums.OSGB36} failed.
617
612
  '''
618
- def _prec_kwds2(prec=MISSING, **kwds):
619
- return prec, kwds
620
-
621
613
  if lon is not None:
622
614
  try:
623
615
  lat, lon = _MODS.dms.parseDMS2(latlon, lon)
@@ -626,8 +618,6 @@ def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, name=NN, # MCC
626
618
  raise OSGRError(latlon=latlon, lon=lon, datum=datum, cause=x)
627
619
  elif not isinstance(latlon, _LLEB):
628
620
  raise _TypeError(latlon=latlon, txt=_not_(_ellipsoidal_))
629
- elif not name: # use latlon.name
630
- name = nameof(latlon)
631
621
 
632
622
  NG = _NG
633
623
  # convert latlon to OSGB36 first
@@ -663,22 +653,24 @@ def toOsgr(latlon, lon=None, kTM=False, datum=_WGS84, Osgr=Osgr, name=NN, # MCC
663
653
  d2 / 12 * (_Fsumf_( 5, ta2, 9 * n2) +
664
654
  d2 / 30 * _Fsumf_(61, ta4, 58 * ta2)))).fsum_(m0, NG.nor0)
665
655
 
666
- p, kwds = _prec_kwds2(**prec_Osgr_kwds)
667
- if p is not MISSING:
668
- e = truncate(e, p)
669
- n = truncate(n, p)
656
+ t, kwds = _name2__(prec_name_Osgr_kwds, _or_nameof=latlon)
657
+ if kwds:
658
+ p, kwds = _xkwds_pop2(kwds, prec=MISSING)
659
+ if p is not MISSING:
660
+ e = truncate(e, p)
661
+ n = truncate(n, p)
670
662
 
671
663
  if Osgr is None:
672
664
  _ = _MODS.osgr.Osgr(e, n) # validate
673
- r = EasNor2Tuple(e, n)
665
+ r = EasNor2Tuple(e, n, name=t)
674
666
  else:
675
- r = Osgr(e, n, **kwds) # datum=NG.datum
667
+ r = Osgr(e, n, name=t, **kwds) # datum=NG.datum
676
668
  if lon is None and isinstance(latlon, _LLEB):
677
669
  if kTM:
678
670
  r._latlonTM = latlon # XXX weakref(latlon)?
679
671
  else:
680
672
  r._latlon = latlon # XXX weakref(latlon)?
681
- return _xnamed(r, name or nameof(latlon))
673
+ return r
682
674
 
683
675
 
684
676
  if __name__ == '__main__':
pygeodesy/points.py CHANGED
@@ -38,7 +38,7 @@ from pygeodesy.errors import CrossError, crosserrors, _IndexError, \
38
38
  _xattr, _xkwds, _xkwds_item2, _xkwds_pop2
39
39
  from pygeodesy.fmath import favg, fdot, hypot, Fsum, fsum
40
40
  # from pygeodesy.fsums import Fsum, fsum # from .fmath
41
- from pygeodesy.formy import _bearingTo2, equirectangular_, _spherical_datum
41
+ from pygeodesy.formy import _bearingTo2, equirectangular4, _spherical_datum
42
42
  from pygeodesy.interns import NN, _colinear_, _COMMASPACE_, _composite_, \
43
43
  _DEQUALSPACED_, _ELLIPSIS_, _EW_, _immutable_, \
44
44
  _near_, _no_, _NS_, _point_, _SPACE_, _UNDER_, \
@@ -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.05.19'
65
+ __version__ = '24.06.06'
66
66
 
67
67
  _ilat_ = 'ilat'
68
68
  _ilon_ = 'ilon'
@@ -1473,13 +1473,13 @@ def nearestOn5(point, points, closed=False, wrap=False, adjust=True,
1473
1473
  @kwarg closed: Optionally, close the path or polygon (C{bool}).
1474
1474
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll the
1475
1475
  B{C{points}} (C{bool}).
1476
- @kwarg adjust: See function L{pygeodesy.equirectangular_} (C{bool}).
1477
- @kwarg limit: See function L{pygeodesy.equirectangular_} (C{degrees}),
1476
+ @kwarg adjust: See function L{pygeodesy.equirectangular4} (C{bool}).
1477
+ @kwarg limit: See function L{pygeodesy.equirectangular4} (C{degrees}),
1478
1478
  default C{9 degrees} is about C{1,000 Kmeter} (for mean
1479
1479
  spherical earth radius L{R_KM}).
1480
1480
  @kwarg LatLon_and_kwds: Optional, C{B{LatLon}=None} class to use for
1481
1481
  the closest point and additional B{C{LatLon}} keyword
1482
- arguments, ignored if C{B{LatLon}=None} or not given.
1482
+ arguments, ignored if C{B{LatLon} is None} or not given.
1483
1483
 
1484
1484
  @return: A L{NearestOn3Tuple}C{(closest, distance, angle)} with the
1485
1485
  {closest} point (B{C{LatLon}}) or if C{B{LatLon} is None},
@@ -1490,24 +1490,24 @@ def nearestOn5(point, points, closed=False, wrap=False, adjust=True,
1490
1490
  compass C{degrees}, like function L{pygeodesy.compassAngle}.
1491
1491
 
1492
1492
  @raise LimitError: Lat- and/or longitudinal delta exceeds the B{C{limit}},
1493
- see function L{pygeodesy.equirectangular_}.
1493
+ see function L{pygeodesy.equirectangular4}.
1494
1494
 
1495
1495
  @raise PointsError: Insufficient number of B{C{points}}
1496
1496
 
1497
1497
  @raise TypeError: Some B{C{points}} are not C{LatLon}.
1498
1498
 
1499
- @note: Distances are I{approximated} by function L{pygeodesy.equirectangular_}.
1499
+ @note: Distances are I{approximated} by function L{pygeodesy.equirectangular4}.
1500
1500
  For more accuracy use one of the C{LatLon.nearestOn6} methods.
1501
1501
 
1502
1502
  @see: Function L{pygeodesy.degrees2m}.
1503
1503
  '''
1504
1504
  def _d2yx4(p2, p1, u, alw):
1505
1505
  # w = wrap if (i < (n - 1) or not closed) else False
1506
- # equirectangular_ returns a Distance4Tuple(distance
1506
+ # equirectangular4 returns a Distance4Tuple(distance
1507
1507
  # in degrees squared, delta lat, delta lon, p2.lon
1508
1508
  # unroll/wrap'd); the previous p2.lon unroll/wrap'd
1509
1509
  # is also applied to the next edge's p1.lon
1510
- return equirectangular_(p1.lat, p1.lon + u,
1510
+ return equirectangular4(p1.lat, p1.lon + u,
1511
1511
  p2.lat, p2.lon, **alw)
1512
1512
 
1513
1513
  def _h(p): # get height or default 0
@@ -1604,7 +1604,7 @@ def perimeterOf(points, closed=False, adjust=True, radius=R_M, wrap=True):
1604
1604
  @raise ValueError: Invalid B{C{radius}} or C{B{closed}=False} with
1605
1605
  C{B{points}} a composite.
1606
1606
 
1607
- @note: This perimeter is based on the L{pygeodesy.equirectangular_}
1607
+ @note: This perimeter is based on the L{pygeodesy.equirectangular4}
1608
1608
  distance approximation and is ill-suited for regions exceeding
1609
1609
  several hundred Km or Miles or with near-polar latitudes.
1610
1610
 
@@ -1618,7 +1618,7 @@ def perimeterOf(points, closed=False, adjust=True, radius=R_M, wrap=True):
1618
1618
  if w and c:
1619
1619
  w = not Ps.looped
1620
1620
  # apply previous x2's unroll/wrap'd to new x1
1621
- _, dy, dx, u = equirectangular_(p1.y, p1.x + u,
1621
+ _, dy, dx, u = equirectangular4(p1.y, p1.x + u,
1622
1622
  p2.y, p2.x,
1623
1623
  adjust=a, limit=None,
1624
1624
  wrap=w) # PYCHOK non-seq
pygeodesy/props.py CHANGED
@@ -10,9 +10,9 @@ with command line option C{-X dev} or with one of the C{-W}
10
10
  choices, see callable L{DeprecationWarnings} below.
11
11
  '''
12
12
 
13
- from pygeodesy.basics import isclass as _isclass # _MODS
13
+ from pygeodesy.basics import isclass as _isclass
14
14
  from pygeodesy.errors import _AssertionError, _AttributeError, \
15
- _xkwds, _xkwds_get
15
+ _xcallable, _xkwds, _xkwds_get
16
16
  from pygeodesy.interns import MISSING, NN, _an_, _COMMASPACE_, \
17
17
  _DEPRECATED_, _DOT_, _EQUALSPACED_, \
18
18
  _immutable_, _invalid_, _module_, _N_A_, \
@@ -25,7 +25,7 @@ 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.05.12'
28
+ __version__ = '24.05.26'
29
29
 
30
30
  _class_ = 'class'
31
31
  _dont_use_ = _DEPRECATED_ + ", don't use."
@@ -157,8 +157,7 @@ class _PropertyBase(property):
157
157
  '''
158
158
  def __init__(self, method, fget, fset, doc=NN):
159
159
 
160
- if not callable(method):
161
- self.getter(method) # PYCHOK no cover
160
+ _xcallable(getter=method, fget=fget)
162
161
 
163
162
  self.method = method
164
163
  self.name = method.__name__
@@ -288,20 +287,34 @@ class Property(Property_RO):
288
287
  @note: Setting a new property value always clears the previously I{cached}
289
288
  or I{memoized} value I{after} invoking the B{C{method}}.
290
289
  '''
291
- if not callable(method):
292
- _PropertyBase.setter(self, method) # PYCHOK no cover
290
+ def _fset(inst, val):
291
+ '''Set and I{cache}, I{memoize} the C{property} value.
292
+ '''
293
+ _ = method(inst, val)
294
+ self._update(inst) # un-cache this item
293
295
 
294
- if _FOR_DOCS: # XXX force method.__doc__ into epydoc
295
- _PropertyBase.__init__(self, self.method, self.method, method)
296
- else:
296
+ return self._setters(method, _fset)
297
297
 
298
- def _fset(inst, val):
299
- '''Set and I{cache}, I{memoize} the C{property} value.
300
- '''
301
- method(inst, val)
302
- self._update(inst) # un-cache this item
298
+ def setter_(self, method):
299
+ '''Make this C{Property} I{mutable}.
303
300
 
304
- # class Property <https://docs.Python.org/3/howto/descriptor.html>
301
+ @arg method: The callable being decorated as this C{Property}'s C{setter}
302
+ and returning the new property value to be I{cached} or
303
+ I{memoized}.
304
+ '''
305
+ def _fset(inst, val):
306
+ '''Set and I{cache}, I{memoize} the C{property} value.
307
+ '''
308
+ val = method(inst, val)
309
+ inst.__dict__[self.name] = val
310
+
311
+ return self._setters(method, _fset)
312
+
313
+ def _setters(self, method, _fset):
314
+ _xcallable(setter=method, fset=_fset)
315
+ if _FOR_DOCS: # XXX force method.__doc__ into epydoc
316
+ _PropertyBase.__init__(self, self.method, self.method, method)
317
+ else: # class Property <https://docs.Python.org/3/howto/descriptor.html>
305
318
  _PropertyBase.__init__(self, self.method, self._fget, _fset)
306
319
  return self
307
320
 
pygeodesy/rhumb/aux_.py CHANGED
@@ -32,22 +32,22 @@ from pygeodesy.auxilats.auxAngle import AuxMu, AuxPhi, hypot
32
32
  from pygeodesy.auxilats.auxDLat import AuxDLat, _DClenshaw
33
33
  # from pygeodesy.auxilats.auxDST import AuxDST # _MODS
34
34
  from pygeodesy.auxilats.auxily import _Dlam, _Dp0Dpsi, _Ufloats
35
- from pygeodesy.basics import copysign0, _reverange, _xkwds_get
35
+ from pygeodesy.basics import copysign0, _reverange, _xkwds_get1
36
36
  from pygeodesy.constants import EPS_2, MANT_DIG, PI4, isinf, \
37
37
  _0_0, _4_0, _720_0, _log2, _over
38
- from pygeodesy.datums import _WGS84, NN
39
- # from pygeodesy.errors import _xkwds_get # from .basics
38
+ # from pygeodesy.datums import _WGS84 # from .rhumb.bases
39
+ # from pygeodesy.errors import _xkwds_get1 # from .basics
40
40
  from pygeodesy.karney import Caps, _polynomial
41
41
  # from pygeodesy.fmath import hypot # from .auxilats.auxAngle
42
- # from pygeodesy.interns import NN # from .datums
43
42
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
44
- # from pygeodesy.props import Property_RO # from .rhumbBase
45
- from pygeodesy.rhumb.bases import RhumbBase, RhumbLineBase, Property_RO
43
+ # from pygeodesy.props import Property_RO # from .rhumb.bases
44
+ from pygeodesy.rhumb.bases import RhumbBase, RhumbLineBase, \
45
+ Property_RO, _WGS84
46
46
 
47
47
  from math import ceil as _ceil, fabs, radians
48
48
 
49
49
  __all__ = _ALL_LAZY.rhumb_aux_
50
- __version__ = '23.12.09'
50
+ __version__ = '24.05.29'
51
51
 
52
52
  # DIGITS = (sizeof(real) * 8) bits
53
53
  # = (ctypes.sizeof(ctypes.c_double(1.0)) * 8) bits
@@ -68,7 +68,7 @@ class RhumbAux(RhumbBase):
68
68
  installed, version 1.16 or later.
69
69
  '''
70
70
 
71
- def __init__(self, a_earth=_WGS84, f=None, exact=True, name=NN, **TMorder): # PYCHOK signature
71
+ def __init__(self, a_earth=_WGS84, f=None, exact=True, **TMorder_name): # PYCHOK signature
72
72
  '''New C{RhumbAux}.
73
73
 
74
74
  @kwarg a_earth: This rhumb's earth model (L{Datum}, L{Ellipsoid},
@@ -79,18 +79,16 @@ class RhumbAux(RhumbBase):
79
79
  @kwarg exact: If C{True}, use the exact expressions for the I{Auxiliary
80
80
  Latitudes}, otherwise use the I{Fourier} series expansion
81
81
  (C{bool}), see also property C{exact}.
82
- @kwarg name: Optional name (C{str}).
83
- @kwarg TMorder: Optional keyword argument B{C{TMorder}}, see property
84
- C{TMorder}.
82
+ @kwarg TMorder_name: Optional C{B{name}=NN} (C{str}) and optional
83
+ keyword argument C{B{TMorder}=6} for the order of
84
+ the L{KTransverseMercator}, see property C{TMorder}.
85
85
 
86
86
  @raise ImportError: Package C{numpy} not found or not installed, only
87
87
  required for area C{S12} when C{B{exact} is True}.
88
88
 
89
89
  @raise RhumbError: Invalid B{C{a_earth}}, B{C{f}} or B{C{TMorder}}.
90
90
  '''
91
- RhumbBase.__init__(self, a_earth, f, exact, name)
92
- if TMorder:
93
- self.Tmorder = _xkwds_get(TMorder, TMorder=RhumbBase._mTM)
91
+ RhumbBase.__init__(self, a_earth, f, exact, TMorder_name)
94
92
 
95
93
  def areaux(self, **exact):
96
94
  '''Get this ellipsoid's B{C{exact}} surface area (C{meter} I{squared}).
@@ -110,7 +108,7 @@ class RhumbAux(RhumbBase):
110
108
  @see: U{The area of rhumb polygons<https://ArXiv.org/pdf/2303.03219.pdf>}
111
109
  and method L{auxilats.AuxLat.AuthalicRadius2}.
112
110
  '''
113
- x = _xkwds_get(exact, exact=self.exact)
111
+ x = _xkwds_get1(exact, exact=self.exact)
114
112
  a = (self._c2 * _720_0) if bool(x) is self.exact else (
115
113
  self._auxD.AuthalicRadius2(exact=x, f_max=self.f_max) * PI4)
116
114
  return a