pygeodesy 24.11.11__py2.py3-none-any.whl → 25.1.5__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 (118) hide show
  1. {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/METADATA +34 -35
  2. PyGeodesy-25.1.5.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +19 -19
  5. pygeodesy/__main__.py +1 -1
  6. pygeodesy/albers.py +5 -5
  7. pygeodesy/auxilats/_CX_4.py +1 -1
  8. pygeodesy/auxilats/_CX_6.py +1 -1
  9. pygeodesy/auxilats/_CX_8.py +1 -1
  10. pygeodesy/auxilats/_CX_Rs.py +1 -1
  11. pygeodesy/auxilats/__init__.py +1 -1
  12. pygeodesy/auxilats/__main__.py +1 -1
  13. pygeodesy/auxilats/auxAngle.py +5 -5
  14. pygeodesy/auxilats/auxDLat.py +6 -6
  15. pygeodesy/auxilats/auxDST.py +2 -2
  16. pygeodesy/auxilats/auxLat.py +5 -5
  17. pygeodesy/auxilats/auxily.py +2 -2
  18. pygeodesy/azimuthal.py +5 -5
  19. pygeodesy/basics.py +60 -8
  20. pygeodesy/booleans.py +1 -1
  21. pygeodesy/cartesianBase.py +22 -61
  22. pygeodesy/clipy.py +1 -1
  23. pygeodesy/constants.py +5 -5
  24. pygeodesy/css.py +1 -1
  25. pygeodesy/datums.py +1 -1
  26. pygeodesy/deprecated/__init__.py +2 -2
  27. pygeodesy/deprecated/bases.py +1 -1
  28. pygeodesy/deprecated/classes.py +86 -2
  29. pygeodesy/deprecated/consterns.py +1 -1
  30. pygeodesy/deprecated/datum.py +5 -5
  31. pygeodesy/deprecated/functions.py +42 -8
  32. pygeodesy/deprecated/nvector.py +1 -1
  33. pygeodesy/deprecated/rhumbBase.py +1 -1
  34. pygeodesy/deprecated/rhumbaux.py +1 -1
  35. pygeodesy/deprecated/rhumbsolve.py +1 -1
  36. pygeodesy/deprecated/rhumbx.py +1 -1
  37. pygeodesy/dms.py +1 -1
  38. pygeodesy/ecef.py +53 -56
  39. pygeodesy/elevations.py +1 -1
  40. pygeodesy/ellipsoidalBase.py +3 -3
  41. pygeodesy/ellipsoidalBaseDI.py +1 -1
  42. pygeodesy/ellipsoidalExact.py +1 -1
  43. pygeodesy/ellipsoidalGeodSolve.py +1 -1
  44. pygeodesy/ellipsoidalKarney.py +1 -1
  45. pygeodesy/ellipsoidalNvector.py +1 -1
  46. pygeodesy/ellipsoidalVincenty.py +6 -5
  47. pygeodesy/ellipsoids.py +4 -5
  48. pygeodesy/elliptic.py +6 -6
  49. pygeodesy/epsg.py +1 -1
  50. pygeodesy/errors.py +1 -1
  51. pygeodesy/etm.py +5 -5
  52. pygeodesy/fmath.py +18 -17
  53. pygeodesy/formy.py +409 -555
  54. pygeodesy/frechet.py +29 -86
  55. pygeodesy/fstats.py +1 -1
  56. pygeodesy/fsums.py +32 -33
  57. pygeodesy/gars.py +1 -1
  58. pygeodesy/geodesici.py +7 -7
  59. pygeodesy/geodesicw.py +1 -1
  60. pygeodesy/geodesicx/_C4_24.py +2 -2
  61. pygeodesy/geodesicx/_C4_27.py +2 -2
  62. pygeodesy/geodesicx/_C4_30.py +2 -2
  63. pygeodesy/geodesicx/__init__.py +2 -2
  64. pygeodesy/geodesicx/__main__.py +4 -5
  65. pygeodesy/geodesicx/gx.py +6 -5
  66. pygeodesy/geodesicx/gxarea.py +2 -2
  67. pygeodesy/geodesicx/gxbases.py +2 -2
  68. pygeodesy/geodesicx/gxline.py +16 -12
  69. pygeodesy/geodsolve.py +1 -1
  70. pygeodesy/geohash.py +1 -1
  71. pygeodesy/geoids.py +277 -203
  72. pygeodesy/hausdorff.py +23 -81
  73. pygeodesy/heights.py +115 -150
  74. pygeodesy/internals.py +1 -1
  75. pygeodesy/interns.py +2 -3
  76. pygeodesy/iters.py +1 -1
  77. pygeodesy/karney.py +3 -3
  78. pygeodesy/ktm.py +16 -15
  79. pygeodesy/latlonBase.py +323 -409
  80. pygeodesy/lazily.py +53 -44
  81. pygeodesy/lcc.py +1 -1
  82. pygeodesy/ltp.py +46 -50
  83. pygeodesy/ltpTuples.py +147 -130
  84. pygeodesy/mgrs.py +1 -1
  85. pygeodesy/named.py +149 -3
  86. pygeodesy/namedTuples.py +58 -7
  87. pygeodesy/nvectorBase.py +122 -105
  88. pygeodesy/osgr.py +1 -1
  89. pygeodesy/points.py +1 -1
  90. pygeodesy/props.py +1 -1
  91. pygeodesy/resections.py +18 -17
  92. pygeodesy/rhumb/__init__.py +1 -1
  93. pygeodesy/rhumb/aux_.py +2 -2
  94. pygeodesy/rhumb/bases.py +2 -2
  95. pygeodesy/rhumb/ekx.py +4 -4
  96. pygeodesy/rhumb/solve.py +1 -1
  97. pygeodesy/simplify.py +289 -401
  98. pygeodesy/solveBase.py +1 -1
  99. pygeodesy/sphericalBase.py +1 -1
  100. pygeodesy/sphericalNvector.py +5 -5
  101. pygeodesy/sphericalTrigonometry.py +7 -6
  102. pygeodesy/streprs.py +10 -5
  103. pygeodesy/trf.py +1 -1
  104. pygeodesy/triaxials.py +23 -16
  105. pygeodesy/units.py +16 -16
  106. pygeodesy/unitsBase.py +1 -1
  107. pygeodesy/ups.py +4 -4
  108. pygeodesy/utily.py +341 -211
  109. pygeodesy/utm.py +5 -5
  110. pygeodesy/utmups.py +1 -1
  111. pygeodesy/utmupsBase.py +1 -1
  112. pygeodesy/vector2d.py +5 -5
  113. pygeodesy/vector3d.py +14 -3
  114. pygeodesy/vector3dBase.py +5 -5
  115. pygeodesy/webmercator.py +1 -1
  116. pygeodesy/wgrs.py +1 -1
  117. PyGeodesy-24.11.11.dist-info/RECORD +0 -118
  118. {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/top_level.txt +0 -0
pygeodesy/nvectorBase.py CHANGED
@@ -11,14 +11,14 @@ and published under the same MIT Licence**, see U{Vector-based geodesy
11
11
  '''
12
12
 
13
13
  # from pygeodesy.basics import map1 # from .namedTuples
14
- from pygeodesy.constants import EPS, EPS1, EPS_2, R_M, _2_0, _N_2_0
14
+ from pygeodesy.constants import EPS, EPS0, EPS1, EPS_2, R_M, \
15
+ _0_0, _1_0, _2_0, _N_2_0
15
16
  # from pygeodesy.datums import _spherical_datum # from .formy
16
17
  from pygeodesy.errors import IntersectionError, _ValueError, VectorError, \
17
18
  _xattrs, _xkwds, _xkwds_pop2
18
- from pygeodesy.fmath import fdot, fidw, hypot_ # PYCHOK fdot shared
19
+ from pygeodesy.fmath import fdot, fidw, hypot # PYCHOK fdot shared
19
20
  from pygeodesy.fsums import Fsum, fsumf_
20
- from pygeodesy.formy import _isequalTo, n_xyz2latlon, n_xyz2philam, \
21
- _spherical_datum
21
+ from pygeodesy.formy import _isequalTo, _spherical_datum
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_, \
@@ -26,23 +26,23 @@ from pygeodesy.interns import NN, _1_, _2_, _3_, _bearing_, _coincident_, \
26
26
  from pygeodesy.latlonBase import LatLonBase, _ALL_DOCS, _ALL_LAZY, _MODS
27
27
  # from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS # from .latlonBase
28
28
  from pygeodesy.named import _xother3, _under
29
- from pygeodesy.namedTuples import Trilaterate5Tuple, Vector3Tuple, \
30
- Vector4Tuple, map1
29
+ from pygeodesy.namedTuples import LatLon2Tuple, PhiLam2Tuple, Trilaterate5Tuple, \
30
+ Vector3Tuple, Vector4Tuple, map1
31
31
  from pygeodesy.props import deprecated_method, Property_RO, property_doc_, \
32
32
  property_RO, property_ROnce, _update_all
33
33
  from pygeodesy.streprs import Fmt, hstr, unstr
34
34
  from pygeodesy.units import Bearing, Height, Radius_, Scalar
35
- from pygeodesy.utily import sincos2d, _unrollon, _unrollon3
35
+ from pygeodesy.utily import atan2, sincos2d, _unrollon, _unrollon3
36
36
  from pygeodesy.vector3d import Vector3d, _xyzhdlln4
37
37
 
38
- from math import fabs, sqrt
38
+ from math import degrees, fabs, sqrt
39
39
 
40
40
  __all__ = _ALL_LAZY.nvectorBase
41
- __version__ = '24.10.12'
41
+ __version__ = '24.11.24'
42
42
 
43
43
 
44
44
  class NvectorBase(Vector3d): # XXX kept private
45
- '''Base class for ellipsoidal and spherical C{Nvector}s.
45
+ '''(INTERNAL) Base class for ellipsoidal and spherical C{Nvector}s.
46
46
  '''
47
47
  _datum = None # L{Datum}, overriden
48
48
  _h = Height(h=0) # height (C{meter})
@@ -51,8 +51,8 @@ class NvectorBase(Vector3d): # XXX kept private
51
51
  def __init__(self, x_xyz, y=None, z=None, h=0, datum=None, **ll_name):
52
52
  '''New n-vector normal to the earth's surface.
53
53
 
54
- @arg x_xyz: X component of vector (C{scalar}) or (3-D) vector
55
- (C{Nvector}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
54
+ @arg x_xyz: X component of vector (C{scalar}) or (3-D) vector (C{Nvector},
55
+ L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
56
56
  @kwarg y: Y component of vector (C{scalar}), required if B{C{x_xyz}} is
57
57
  C{scalar} and same units as B{C{x_xyz}}, ignored otherwise.
58
58
  @kwarg z: Z component of vector (C{scalar}), like B{C{y}}.
@@ -159,7 +159,7 @@ class NvectorBase(Vector3d): # XXX kept private
159
159
  def latlon(self):
160
160
  '''Get the (geodetic) lat-, longitude in C{degrees} (L{LatLon2Tuple}C{(lat, lon)}).
161
161
  '''
162
- return n_xyz2latlon(self.x, self.y, self.z, name=self.name)
162
+ return n_xyz2latlon(self, name=self.name)
163
163
 
164
164
  @Property_RO
165
165
  def latlonheight(self):
@@ -189,7 +189,7 @@ class NvectorBase(Vector3d): # XXX kept private
189
189
  def philam(self):
190
190
  '''Get the (geodetic) lat-, longitude in C{radians} (L{PhiLam2Tuple}C{(phi, lam)}).
191
191
  '''
192
- return n_xyz2philam(self.x, self.y, self.z, name=self.name)
192
+ return n_xyz2philam(self, name=self.name)
193
193
 
194
194
  @Property_RO
195
195
  def philamheight(self):
@@ -211,89 +211,71 @@ class NvectorBase(Vector3d): # XXX kept private
211
211
 
212
212
  @deprecated_method
213
213
  def to2ab(self): # PYCHOK no cover
214
- '''DEPRECATED, use property L{philam}.
215
-
216
- @return: A L{PhiLam2Tuple}C{(phi, lam)}.
217
- '''
214
+ '''DEPRECATED, use property L{philam}.'''
218
215
  return self.philam
219
216
 
220
217
  @deprecated_method
221
218
  def to3abh(self, height=None): # PYCHOK no cover
222
- '''DEPRECATED, use property L{philamheight} or C{philam.to3Tuple(B{height})}.
223
-
224
- @kwarg height: Optional height, overriding this
225
- n-vector's height (C{meter}).
226
-
227
- @return: A L{PhiLam3Tuple}C{(phi, lam, height)}.
228
-
229
- @raise ValueError: Invalid B{C{height}}.
230
- '''
219
+ '''DEPRECATED, use property L{philamheight} or C{philam.to3Tuple(B{height})}.'''
231
220
  return self.philamheight if height in (None, self.h) else \
232
221
  self.philam.to3Tuple(height)
233
222
 
234
- def toCartesian(self, h=None, Cartesian=None, datum=None, **Cartesian_kwds):
223
+ def toCartesian(self, h=None, Cartesian=None, datum=None, **name_Cartesian_kwds): # PYCHOK signature
235
224
  '''Convert this n-vector to C{Nvector}-based cartesian (ECEF) coordinates.
236
225
 
237
226
  @kwarg h: Optional height, overriding this n-vector's height (C{meter}).
238
- @kwarg Cartesian: Optional class to return the (ECEF) coordinates
239
- (C{Cartesian}).
227
+ @kwarg Cartesian: Optional class to return the (ECEF) coordinates (C{Cartesian}).
240
228
  @kwarg datum: Optional datum (C{Datum}), overriding this datum.
241
- @kwarg Cartesian_kwds: Optional, additional B{C{Cartesian}} keyword
242
- arguments, ignored if C{B{Cartesian} is None}.
229
+ @kwarg name_Cartesian_kwds: Optional C{B{name}=NN} (C{str}) and optionally, additional
230
+ B{C{Cartesian}} keyword arguments, ignored if C{B{Cartesian} is None}.
243
231
 
244
- @return: The cartesian (ECEF) coordinates (B{C{Cartesian}}) or
245
- if C{B{Cartesian} is None}, an L{Ecef9Tuple}C{(x, y, z,
246
- lat, lon, height, C, M, datum)} with C{C} and C{M} if
247
- available.
232
+ @return: The (ECEF) coordinates (B{C{Cartesian}}) or if C{B{Cartesian} is None}, an
233
+ L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with C{C} and C{M}
234
+ if available.
248
235
 
249
- @raise TypeError: Invalid B{C{Cartesian}} or B{C{Cartesian_kwds}}
250
- argument.
236
+ @raise TypeError: Invalid B{C{Cartesian}} or B{C{name_Cartesian_kwds}} argument.
251
237
 
252
238
  @raise ValueError: Invalid B{C{h}}.
253
239
  '''
254
- D = _spherical_datum(datum or self.datum, name=self.name)
255
- E = D.ellipsoid
256
- h = self.h if h is None else Height(h)
257
-
258
- x, y, z = self.x, self.y, self.z
259
- # Kenneth Gade eqn 22
260
- n = E.b / hypot_(x * E.a_b, y * E.a_b, z)
261
- r = h + n * E.a2_b2
262
-
263
- x *= r
264
- y *= r
265
- z *= h + n
240
+ if h is None:
241
+ h = self.h
242
+ elif not isinstance(h, Height):
243
+ h = Height(h=h, Error=VectorError)
244
+ _, r, v = self._toEcefDrv3(Cartesian, None, datum, h, **name_Cartesian_kwds)
245
+ if r is None:
246
+ r = v.toCartesian(Cartesian, **self._name1__(name_Cartesian_kwds)) # h=0
247
+ return r
266
248
 
267
- if Cartesian is None:
268
- r = self.Ecef(D).reverse(x, y, z, M=True)
249
+ def _toEcefDrv3(self, CC, LL, datum, h, name=NN, **unused):
250
+ '''(INTERNAL) Helper for methods C{toCartesian} and C{toLatLon}.
251
+ '''
252
+ D = self.datum if datum in (None, self.datum) else \
253
+ _spherical_datum(datum, name=self.name)
254
+ if LL is None:
255
+ v = Vector3d(self, name=name or self.name) # .toVector3d(norm=False)
256
+ E = D.ellipsoid
257
+ r = E.a_b # Kenneth Gade eqn 22
258
+ n = v.times_(r, r, _1_0).length
259
+ n = (E.b / n) if n > EPS0 else _0_0
260
+ r = E.a2_b2 * n + h # fma
261
+ v = v.times_(r, r, n + h)
262
+ r = self.Ecef(D).reverse(v, M=True) if CC is None else None
269
263
  else:
270
- kwds = _xkwds(Cartesian_kwds, datum=D) # h=0
271
- r = Cartesian(x, y, z, **kwds)
272
- return self._xnamed(r)
264
+ r = v = None
265
+ return D, r, v
273
266
 
274
267
  @deprecated_method
275
268
  def to2ll(self): # PYCHOK no cover
276
- '''DEPRECATED, use property L{latlon}.
277
-
278
- @return: A L{LatLon2Tuple}C{(lat, lon)}.
279
- '''
269
+ '''DEPRECATED, use property L{latlon}.'''
280
270
  return self.latlon
281
271
 
282
272
  @deprecated_method
283
273
  def to3llh(self, height=None): # PYCHOK no cover
284
- '''DEPRECATED, use property C{latlonheight} or C{latlon.to3Tuple(B{height})}.
285
-
286
- @kwarg height: Optional height, overriding this
287
- n-vector's height (C{meter}).
288
-
289
- @return: A L{LatLon3Tuple}C{(lat, lon, height)}.
290
-
291
- @raise ValueError: Invalid B{C{height}}.
292
- '''
274
+ '''DEPRECATED, use property C{latlonheight} or C{latlon.to3Tuple(B{height})}.'''
293
275
  return self.latlonheight if height in (None, self.h) else \
294
276
  self.latlon.to3Tuple(height)
295
277
 
296
- def toLatLon(self, height=None, LatLon=None, datum=None, **LatLon_kwds):
278
+ def toLatLon(self, height=None, LatLon=None, datum=None, **name_LatLon_kwds):
297
279
  '''Convert this n-vector to an C{Nvector}-based geodetic point.
298
280
 
299
281
  @kwarg height: Optional height, overriding this n-vector's
@@ -301,26 +283,26 @@ class NvectorBase(Vector3d): # XXX kept private
301
283
  @kwarg LatLon: Optional class to return the geodetic point
302
284
  (C{LatLon}) or C{None}.
303
285
  @kwarg datum: Optional, spherical datum (C{Datum}).
304
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
305
- arguments, ignored if C{B{LatLon} is None}.
286
+ @kwarg name_LatLon_kwds: Optional C{B{name}=NN} (C{str}) and optionally,
287
+ additional B{C{LatLon}} keyword arguments, ignored if
288
+ C{B{LatLon} is None}.
306
289
 
307
290
  @return: The geodetic point (C{LatLon}) or if C{B{LatLon} is None},
308
- an L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M,
309
- datum)} with C{C} and C{M} if available.
291
+ an L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)}
292
+ with C{C} and C{M} if available.
310
293
 
311
- @raise TypeError: Invalid B{C{LatLon}} or B{C{LatLon_kwds}}
312
- argument.
294
+ @raise TypeError: Invalid B{C{LatLon}} or B{C{name_LatLon_kwds}} argument.
313
295
 
314
296
  @raise ValueError: Invalid B{C{height}}.
315
297
  '''
316
- d = _spherical_datum(datum or self.datum, name=self.name)
317
- h = self.h if height is None else Height(height)
318
- # use self.Cartesian(Cartesian=None) for better accuracy of the height
319
- # than self.Ecef(d).forward(self.lat, self.lon, height=h, M=True)
320
- if LatLon is None:
321
- r = self.toCartesian(h=h, Cartesian=None, datum=d)
322
- else:
323
- kwds = _xkwds(LatLon_kwds, height=h, datum=d)
298
+ h = self.h if height is None else (
299
+ height if isinstance(height, Height) else
300
+ Height(height, Error=VectorError))
301
+ # use the .toCartesian() logic for better height accuracy instead of
302
+ # r = self.Ecef(D).forward(self.lat, self.lon, height=h, M=True)
303
+ D, r, _ = self._toEcefDrv3(None, LatLon, datum, h, **name_LatLon_kwds)
304
+ if r is None:
305
+ kwds = _xkwds(name_LatLon_kwds, height=h, datum=D)
324
306
  r = LatLon(self.lat, self.lon, **self._name1__(kwds))
325
307
  return r
326
308
 
@@ -349,7 +331,7 @@ class NvectorBase(Vector3d): # XXX kept private
349
331
  @return: The (normalized) vector (L{Vector3d}).
350
332
  '''
351
333
  v = Vector3d.unit(self) if norm else self
352
- return Vector3d(v.x, v.y, v.z, name=self.name)
334
+ return Vector3d(v, name=self.name)
353
335
 
354
336
  @deprecated_method
355
337
  def to4xyzh(self, h=None): # PYCHOK no cover
@@ -373,10 +355,6 @@ class NvectorBase(Vector3d): # XXX kept private
373
355
  return self.xyz.to4Tuple(self.h)
374
356
 
375
357
 
376
- NorthPole = NvectorBase(0, 0, +1, name='NorthPole') # North pole (C{Nvector})
377
- SouthPole = NvectorBase(0, 0, -1, name='SouthPole') # South pole (C{Nvector})
378
-
379
-
380
358
  class _N_vector_(NvectorBase):
381
359
  '''(INTERNAL) Minimal, low-overhead C{n-vector}.
382
360
  '''
@@ -388,16 +366,19 @@ class _N_vector_(NvectorBase):
388
366
  self.name = name
389
367
 
390
368
 
369
+ NorthPole = _N_vector_(0, 0, +1, name='NorthPole') # North pole
370
+ SouthPole = _N_vector_(0, 0, -1, name='SouthPole') # South pole
371
+
372
+
391
373
  class LatLonNvectorBase(LatLonBase):
392
- '''(INTERNAL) Base class for n-vector-based ellipsoidal and
393
- spherical C{LatLon} classes.
374
+ '''(INTERNAL) Base class for n-vector-based ellipsoidal and spherical C{LatLon}s.
394
375
  '''
395
376
 
396
377
  def _update(self, updated, *attrs, **setters): # PYCHOK _Nv=None
397
378
  '''(INTERNAL) Zap cached attributes if updated.
398
379
 
399
- @see: C{ellipsoidalNvector.LatLon} and C{sphericalNvector.LatLon}
400
- for the special case of B{C{_Nv}}.
380
+ @see: C{ellipsoidalNvector.LatLon} and C{sphericalNvector.LatLon} for
381
+ the special case of B{C{_Nv}}.
401
382
  '''
402
383
  if updated:
403
384
  _Nv, setters = _xkwds_pop2(setters, _Nv=None)
@@ -498,10 +479,10 @@ class LatLonNvectorBase(LatLonBase):
498
479
  @raise ValueError: Some B{C{points}} coincide or invalid B{C{distance1}},
499
480
  B{C{distance2}}, B{C{distance3}} or B{C{radius}}.
500
481
 
501
- @see: U{Trilateration<https://WikiPedia.org/wiki/Trilateration>},
502
- Veness' JavaScript U{Trilateration<https://www.Movable-Type.co.UK/
503
- scripts/latlong-vectors.html>} and method C{LatLon.trilaterate5}
504
- of other, non-C{Nvector LatLon} classes.
482
+ @see: U{Trilateration<https://WikiPedia.org/wiki/Trilateration>}, I{Veness}'
483
+ JavaScript U{Trilateration<https://www.Movable-Type.co.UK/scripts/
484
+ latlong-vectors.html>} and method C{LatLon.trilaterate5} of other,
485
+ non-C{Nvector LatLon} classes.
505
486
  '''
506
487
  return _trilaterate(self, distance1, self.others(point2=point2), distance2,
507
488
  self.others(point3=point3), distance3,
@@ -510,16 +491,13 @@ class LatLonNvectorBase(LatLonBase):
510
491
 
511
492
  def trilaterate5(self, distance1, point2, distance2, point3, distance3, # PYCHOK signature
512
493
  area=False, eps=EPS1, radius=R_M, wrap=False):
513
- '''B{Not implemented} for C{B{area}=True} and falls back to method
514
- C{trilaterate} otherwise.
494
+ '''B{Not implemented} for C{B{area}=True} and falls back to method C{trilaterate}.
515
495
 
516
- @return: A L{Trilaterate5Tuple}C{(min, minPoint, max, maxPoint, n)}
517
- with a single trilaterated intersection C{minPoint I{is}
518
- maxPoint}, C{min I{is} max} the nearest intersection
519
- margin and count C{n = 1}.
496
+ @return: A L{Trilaterate5Tuple}C{(min, minPoint, max, maxPoint, n)} with a
497
+ single trilaterated intersection C{minPoint I{is} maxPoint}, C{min
498
+ I{is} max} the nearest intersection margin and count C{n = 1}.
520
499
 
521
- @raise NotImplementedError: Keyword argument C{B{area}=True} not
522
- (yet) supported.
500
+ @raise NotImplementedError: Keyword argument C{B{area}=True} not (yet) supported.
523
501
 
524
502
  @see: Method L{trilaterate} for other and more details.
525
503
  '''
@@ -540,6 +518,45 @@ class LatLonNvectorBase(LatLonBase):
540
518
  raise IntersectionError(area=area, eps=eps, radius=radius, wrap=wrap, txt=t)
541
519
 
542
520
 
521
+ def n_xyz2latlon(x_xyz, y=0, z=0, **name):
522
+ '''Convert C{n-vector} to (geodetic) lat- and longitude in C{degrees}.
523
+
524
+ @arg x_xyz: X component (C{scalar}) or (3-D) vector (C{Nvector},
525
+ L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
526
+ @kwarg y: Y component of vector (C{scalar}), required if C{B{x_xyz} is
527
+ scalar} and same units as B{C{x_xyz}}, ignored otherwise.
528
+ @kwarg z: Z component of vector (C{scalar}), like B{C{y}}.
529
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
530
+
531
+ @return: A L{LatLon2Tuple}C{(lat, lon)}.
532
+
533
+ @see: Function L{n_xyz2philam}.
534
+ '''
535
+ ll = map(degrees, n_xyz2philam(x_xyz, y, z))
536
+ return LatLon2Tuple(*ll, **name)
537
+
538
+
539
+ def n_xyz2philam(x_xyz, y=0, z=0, **name):
540
+ '''Convert C{n-vector} to (geodetic) lat- and longitude in C{radians}.
541
+
542
+ @arg x_xyz: X component (C{scalar}) or (3-D) vector (C{Nvector},
543
+ L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
544
+ @kwarg y: Y component of vector (C{scalar}), required if C{B{x_xyz} is
545
+ scalar} and same units as B{C{x_xyz}}, ignored otherwise.
546
+ @kwarg z: Z component of vector (C{scalar}), like B{C{y}}.
547
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
548
+
549
+ @return: A L{PhiLam2Tuple}C{(phi, lam)}.
550
+
551
+ @see: Function L{n_xyz2latlon}.
552
+ '''
553
+ try:
554
+ x, y, z = x_xyz.xyz
555
+ except AttributeError:
556
+ x = x_xyz
557
+ return PhiLam2Tuple(atan2(z, hypot(x, y)), atan2(y, x), **name)
558
+
559
+
543
560
  def _nsumOf(nvs, h_None, Vector, Vector_kwds): # .sphericalNvector, .vector3d
544
561
  '''(INTERNAL) Separated to allow callers to embellish exceptions.
545
562
  '''
@@ -670,7 +687,7 @@ __all__ += _ALL_DOCS(LatLonNvectorBase, NvectorBase, sumOf) # classes
670
687
 
671
688
  # **) MIT License
672
689
  #
673
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
690
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
674
691
  #
675
692
  # Permission is hereby granted, free of charge, to any person obtaining a
676
693
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/osgr.py CHANGED
@@ -722,7 +722,7 @@ if __name__ == '__main__':
722
722
 
723
723
  # **) MIT License
724
724
  #
725
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
725
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
726
726
  #
727
727
  # Permission is hereby granted, free of charge, to any person obtaining a
728
728
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/points.py CHANGED
@@ -1665,7 +1665,7 @@ __all__ += _ALL_DOCS(_Array2LatLon, _Basequence)
1665
1665
 
1666
1666
  # **) MIT License
1667
1667
  #
1668
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1668
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1669
1669
  #
1670
1670
  # Permission is hereby granted, free of charge, to any person obtaining a
1671
1671
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/props.py CHANGED
@@ -701,7 +701,7 @@ _throwarning = DeprecationWarnings.throw
701
701
 
702
702
  # **) MIT License
703
703
  #
704
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
704
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
705
705
  #
706
706
  # Permission is hereby granted, free of charge, to any person obtaining a
707
707
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/resections.py CHANGED
@@ -15,26 +15,26 @@ from __future__ import division as _; del _ # PYCHOK semicolon
15
15
  from pygeodesy.basics import map1, map2, _zip, _ALL_LAZY
16
16
  from pygeodesy.constants import EPS, EPS0, EPS02, INT0, PI, PI2, PI_2, PI_4, \
17
17
  _0_0, _0_5, _1_0, _N_1_0, _2_0, _N_2_0, _4_0, \
18
- _16_0, _180_0, _360_0, _copysign_0_0, isnear0, \
19
- _over, _umod_360
18
+ _16_0, _180_0, _360_0, isnear0, _over, _umod_360
20
19
  from pygeodesy.errors import _and, _or, TriangleError, _ValueError, _xcallable, \
21
20
  _xkwds, _xkwds_pop2
22
21
  from pygeodesy.fmath import favg, Fdot, fidw, fmean, hypot, hypot2_
23
22
  from pygeodesy.fsums import _Fsumf_, fsumf_, fsum1, fsum1f_
24
23
  from pygeodesy.interns import _a_, _A_, _area_, _b_, _B_, _c_, _C_, _coincident_, \
25
- _colinear_, _d_, _eps_, _invalid_, _negative_, _not_, \
24
+ _colinear_, _d_, _invalid_, _negative_, _not_, \
26
25
  _rIn_, _SPACE_
27
26
  # from pygeodesy.lazily import _ALL_LAZY # from .basics
28
27
  from pygeodesy.named import _NamedTuple, _Pass, Fmt
29
28
  # from pygeodesy.streprs import Fmt # from .named
30
29
  from pygeodesy.units import Degrees, Distance, Radians
31
- from pygeodesy.utily import acos1, asin1, sincos2, sincos2_, sincos2d, sincos2d_
30
+ from pygeodesy.utily import acos1, asin1, atan2, sincos2, sincos2_, \
31
+ sincos2d, sincos2d_
32
32
  from pygeodesy.vector3d import _otherV3d, Vector3d
33
33
 
34
- from math import cos, atan2, degrees, fabs, radians, sin, sqrt
34
+ from math import cos, degrees, fabs, radians, sin, sqrt
35
35
 
36
36
  __all__ = _ALL_LAZY.resections
37
- __version__ = '24.11.04'
37
+ __version__ = '24.11.27'
38
38
 
39
39
  _concyclic_ = 'concyclic'
40
40
  _PA_ = 'PA'
@@ -340,7 +340,8 @@ def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
340
340
  def _cot(s, c): # -eps < I{approximate} cotangent < eps
341
341
  if eps > 0:
342
342
  return c / (min(s, -eps) if s < 0 else max(s, eps))
343
- raise ValueError(_SPACE_(_eps_, _not_, _positive_))
343
+ t = Fmt.PARENSPACED(eps=eps)
344
+ raise ValueError(_SPACE_(t, _not_, _positive_))
344
345
 
345
346
  B1, B2, B3 = _B3(useZ, point1, point2, point3)
346
347
  try:
@@ -352,7 +353,7 @@ def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
352
353
  alpha12=alpha12, alpha23=alpha23, eps=eps, cause=x)
353
354
 
354
355
 
355
- def _pierlot3(B1, B2, B3, a12, a23, useZ, cot):
356
+ def _pierlot3(B1, B2, B3, a12, a23, useZ, _cot):
356
357
  '''(INTERNAL) Shared L{pierlot} and L{pierlotx}.
357
358
  '''
358
359
  x1_, y1_, _ = B1.minus(B2).xyz3
@@ -364,14 +365,14 @@ def _pierlot3(B1, B2, B3, a12, a23, useZ, cot):
364
365
  # = (1 - (c12 * c23) / (s12 * s23)) / (c12 * s23 + s12 * c23) / (s12 * s23)
365
366
  # = (s12 * s23 - c12 * c23) / (c12 * s23 + s12 * c23)
366
367
  # = c31 / s31
367
- cot31 = cot(fsum1f_(c12 * s23, s12 * c23), # s31
368
- fsum1f_(s12 * s23, -c12 * c23)) # c31
368
+ cot31 = _cot(fsum1f_(c12 * s23, s12 * c23), # s31
369
+ fsum1f_(s12 * s23, -c12 * c23)) # c31
369
370
 
370
371
  K = _Fsumf_(x3_ * x1_, cot31 * (y3_ * x1_),
371
372
  y3_ * y1_, -cot31 * (x3_ * y1_))
372
373
  if K:
373
- cot12 = cot(s12, c12)
374
- cot23 = cot(s23, c23)
374
+ cot12 = _cot(s12, c12)
375
+ cot23 = _cot(s23, c23)
375
376
 
376
377
  # x12 = x1_ + cot12 * y1_
377
378
  # y12 = y1_ - cot12 * x1_
@@ -449,7 +450,7 @@ def pierlotx(point1, point2, point3, alpha1, alpha2, alpha3, useZ=False,
449
450
 
450
451
  def _cot(s, c): # I{exact} cotangent
451
452
  try:
452
- return (c / s) if c else _copysign_0_0(s)
453
+ return (c / s) # if c else _copysign_0_0(s)
453
454
  except ZeroDivisionError:
454
455
  raise ValueError(_or(_coincident_, _colinear_))
455
456
 
@@ -465,7 +466,7 @@ def pierlotx(point1, point2, point3, alpha1, alpha2, alpha3, useZ=False,
465
466
  alpha1=alpha1, alpha2=alpha2, alpha3=alpha3, cause=x)
466
467
 
467
468
 
468
- def _pierlotx3(a_z_Bs, useZ, cot, Cs):
469
+ def _pierlotx3(a_z_Bs, useZ, _cot, Cs):
469
470
  '''(INTERNAL) Core of L{pierlotx}.
470
471
  '''
471
472
  (a12, z12, B1), \
@@ -481,14 +482,14 @@ def _pierlotx3(a_z_Bs, useZ, cot, Cs):
481
482
  a23, B2, B3 = a12, B3, B2
482
483
  else:
483
484
  Cs(4)
484
- return _pierlot3(B1, B2, B3, a12, a23, useZ, cot)
485
+ return _pierlot3(B1, B2, B3, a12, a23, useZ, _cot)
485
486
 
486
487
  x1_, y1_, _ = B1.minus(B3).xyz3
487
488
  x2_, y2_, _ = B2.minus(B3).xyz3
488
489
 
489
490
  K = _Fsumf_(y1_ * x2_, -x1_ * y2_)
490
491
  if K:
491
- cot23 = cot(*sincos2d(a23))
492
+ cot23 = _cot(*sincos2d(a23))
492
493
 
493
494
  # x23 = x2_ + cot23 * y2_
494
495
  # y23 = y2_ - cot23 * x2_
@@ -1018,7 +1019,7 @@ def _zidw(x, y, useZ, *ABC):
1018
1019
 
1019
1020
  # **) MIT License
1020
1021
  #
1021
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1022
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1022
1023
  #
1023
1024
  # Permission is hereby granted, free of charge, to any person obtaining a
1024
1025
  # copy of this software and associated documentation files (the "Software"),
@@ -25,7 +25,7 @@ else: # lazily import modules and exported attrs
25
25
 
26
26
  # **) MIT License
27
27
  #
28
- # Copyright (C) 2018-2024 -- mrJean1 at Gmail -- All Rights Reserved.
28
+ # Copyright (C) 2018-2025 -- mrJean1 at Gmail -- All Rights Reserved.
29
29
  #
30
30
  # Permission is hereby granted, free of charge, to any person obtaining a
31
31
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/rhumb/aux_.py CHANGED
@@ -16,7 +16,7 @@ the background information on U{Rhumb lines<https://GeographicLib.SourceForge.io
16
16
  utility U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>} and U{Online rhumb
17
17
  line calculations<https://GeographicLib.SourceForge.io/cgi-bin/RhumbSolve>}.
18
18
 
19
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2022-2023) and licensed under the MIT/X11
19
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2022-2024) and licensed under the MIT/X11
20
20
  License. For more information, see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
21
21
 
22
22
  @note: C{S12} area calculations in classes L{RhumbAux} and L{RhumbLineAux} depend on class L{AuxDST} which
@@ -356,7 +356,7 @@ __all__ += _ALL_DOCS(Caps)
356
356
 
357
357
  # **) MIT License
358
358
  #
359
- # Copyright (C) 2023-2024 -- mrJean1 at Gmail -- All Rights Reserved.
359
+ # Copyright (C) 2023-2025 -- mrJean1 at Gmail -- All Rights Reserved.
360
360
  #
361
361
  # Permission is hereby granted, free of charge, to any person obtaining a
362
362
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/rhumb/bases.py CHANGED
@@ -17,7 +17,7 @@ the background information on U{Rhumb lines<https://GeographicLib.SourceForge.io
17
17
  the utily U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>} and U{Online
18
18
  rhumb line calculations<https://GeographicLib.SourceForge.io/cgi-bin/RhumbSolve>}.
19
19
 
20
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2023) and licensed under the MIT/X11
20
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2024) and licensed under the MIT/X11
21
21
  License. For more information, see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
22
22
  '''
23
23
  # make sure int/int division yields float quotient
@@ -1133,7 +1133,7 @@ if __name__ == '__main__':
1133
1133
 
1134
1134
  # **) MIT License
1135
1135
  #
1136
- # Copyright (C) 2022-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1136
+ # Copyright (C) 2022-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1137
1137
  #
1138
1138
  # Permission is hereby granted, free of charge, to any person obtaining a
1139
1139
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/rhumb/ekx.py CHANGED
@@ -16,7 +16,7 @@ the background information on U{Rhumb lines<https://GeographicLib.SourceForge.io
16
16
  the utily U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>} and U{Online
17
17
  rhumb line calculations<https://GeographicLib.SourceForge.io/cgi-bin/RhumbSolve>}.
18
18
 
19
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2022) and licensed under the MIT/X11
19
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2024) and licensed under the MIT/X11
20
20
  License. For more information, see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
21
21
  '''
22
22
  # make sure int/int division yields float quotient
@@ -40,10 +40,10 @@ from pygeodesy.rhumb.bases import RhumbBase, RhumbLineBase, \
40
40
  Caps, _update_all_rls, _WGS84
41
41
  from pygeodesy.utily import atan1, sincos2_
42
42
 
43
- from math import asinh, atan, cos, cosh, radians, sin, sinh, sqrt, tan
43
+ from math import asinh, atan, cos, cosh, radians, sin, sinh, sqrt, tan # as _tan
44
44
 
45
45
  __all__ = _ALL_LAZY.rhumb_ekx
46
- __version__ = '24.06.11'
46
+ __version__ = '24.11.26'
47
47
 
48
48
 
49
49
  class Rhumb(RhumbBase):
@@ -547,7 +547,7 @@ __all__ += _ALL_DOCS(Caps)
547
547
 
548
548
  # **) MIT License
549
549
  #
550
- # Copyright (C) 2022-2024 -- mrJean1 at Gmail -- All Rights Reserved.
550
+ # Copyright (C) 2022-2025 -- mrJean1 at Gmail -- All Rights Reserved.
551
551
  #
552
552
  # Permission is hereby granted, free of charge, to any person obtaining a
553
553
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/rhumb/solve.py CHANGED
@@ -499,7 +499,7 @@ if __name__ == '__main__':
499
499
 
500
500
  # **) MIT License
501
501
  #
502
- # Copyright (C) 2022-2024 -- mrJean1 at Gmail -- All Rights Reserved.
502
+ # Copyright (C) 2022-2025 -- mrJean1 at Gmail -- All Rights Reserved.
503
503
  #
504
504
  # Permission is hereby granted, free of charge, to any person obtaining a
505
505
  # copy of this software and associated documentation files (the "Software"),