pygeodesy 24.6.1__py2.py3-none-any.whl → 24.6.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 (89) hide show
  1. {PyGeodesy-24.6.1.dist-info → PyGeodesy-24.6.24.dist-info}/METADATA +2 -2
  2. PyGeodesy-24.6.24.dist-info/RECORD +117 -0
  3. pygeodesy/__init__.py +33 -32
  4. pygeodesy/albers.py +2 -2
  5. pygeodesy/auxilats/__init__.py +1 -1
  6. pygeodesy/auxilats/auxAngle.py +40 -39
  7. pygeodesy/auxilats/auxDLat.py +3 -2
  8. pygeodesy/auxilats/auxLat.py +16 -18
  9. pygeodesy/auxilats/auxily.py +1 -1
  10. pygeodesy/azimuthal.py +10 -10
  11. pygeodesy/basics.py +9 -1
  12. pygeodesy/booleans.py +53 -66
  13. pygeodesy/cartesianBase.py +143 -155
  14. pygeodesy/css.py +14 -18
  15. pygeodesy/datums.py +6 -6
  16. pygeodesy/deprecated/__init__.py +1 -1
  17. pygeodesy/deprecated/classes.py +16 -2
  18. pygeodesy/deprecated/datum.py +3 -3
  19. pygeodesy/deprecated/functions.py +6 -8
  20. pygeodesy/dms.py +23 -27
  21. pygeodesy/ecef.py +49 -55
  22. pygeodesy/elevations.py +4 -4
  23. pygeodesy/ellipsoidalBase.py +28 -70
  24. pygeodesy/ellipsoidalBaseDI.py +19 -23
  25. pygeodesy/ellipsoidalExact.py +3 -3
  26. pygeodesy/ellipsoidalGeodSolve.py +15 -23
  27. pygeodesy/ellipsoidalKarney.py +37 -60
  28. pygeodesy/ellipsoidalNvector.py +44 -50
  29. pygeodesy/ellipsoidalVincenty.py +11 -14
  30. pygeodesy/ellipsoids.py +107 -101
  31. pygeodesy/errors.py +101 -49
  32. pygeodesy/etm.py +32 -44
  33. pygeodesy/formy.py +55 -58
  34. pygeodesy/frechet.py +20 -23
  35. pygeodesy/fsums.py +4 -4
  36. pygeodesy/gars.py +3 -4
  37. pygeodesy/geodesici.py +909 -0
  38. pygeodesy/geodesicw.py +11 -13
  39. pygeodesy/geodesicx/__init__.py +4 -4
  40. pygeodesy/geodesicx/gx.py +18 -28
  41. pygeodesy/geodesicx/gxbases.py +20 -8
  42. pygeodesy/geodesicx/gxline.py +16 -22
  43. pygeodesy/geodsolve.py +102 -34
  44. pygeodesy/geohash.py +39 -60
  45. pygeodesy/geoids.py +28 -37
  46. pygeodesy/hausdorff.py +21 -23
  47. pygeodesy/heights.py +15 -28
  48. pygeodesy/internals.py +19 -12
  49. pygeodesy/interns.py +4 -10
  50. pygeodesy/iters.py +2 -2
  51. pygeodesy/karney.py +20 -4
  52. pygeodesy/ktm.py +13 -16
  53. pygeodesy/latlonBase.py +202 -191
  54. pygeodesy/lazily.py +96 -59
  55. pygeodesy/lcc.py +29 -32
  56. pygeodesy/ltp.py +43 -24
  57. pygeodesy/ltpTuples.py +190 -183
  58. pygeodesy/mgrs.py +35 -9
  59. pygeodesy/named.py +106 -72
  60. pygeodesy/namedTuples.py +43 -14
  61. pygeodesy/nvectorBase.py +23 -27
  62. pygeodesy/osgr.py +9 -9
  63. pygeodesy/points.py +7 -7
  64. pygeodesy/rhumb/__init__.py +1 -1
  65. pygeodesy/rhumb/aux_.py +5 -5
  66. pygeodesy/rhumb/bases.py +30 -31
  67. pygeodesy/rhumb/ekx.py +3 -4
  68. pygeodesy/rhumb/solve.py +8 -61
  69. pygeodesy/solveBase.py +22 -19
  70. pygeodesy/sphericalBase.py +26 -21
  71. pygeodesy/sphericalNvector.py +13 -13
  72. pygeodesy/sphericalTrigonometry.py +86 -97
  73. pygeodesy/streprs.py +8 -36
  74. pygeodesy/trf.py +3 -3
  75. pygeodesy/triaxials.py +117 -91
  76. pygeodesy/units.py +229 -321
  77. pygeodesy/unitsBase.py +116 -108
  78. pygeodesy/ups.py +26 -31
  79. pygeodesy/utily.py +12 -11
  80. pygeodesy/utm.py +35 -40
  81. pygeodesy/utmups.py +43 -46
  82. pygeodesy/utmupsBase.py +9 -10
  83. pygeodesy/vector3d.py +59 -62
  84. pygeodesy/vector3dBase.py +17 -15
  85. pygeodesy/webmercator.py +19 -21
  86. pygeodesy/wgrs.py +18 -20
  87. PyGeodesy-24.6.1.dist-info/RECORD +0 -116
  88. {PyGeodesy-24.6.1.dist-info → PyGeodesy-24.6.24.dist-info}/WHEEL +0 -0
  89. {PyGeodesy-24.6.1.dist-info → PyGeodesy-24.6.24.dist-info}/top_level.txt +0 -0
pygeodesy/utmups.py CHANGED
@@ -31,7 +31,7 @@ from pygeodesy.utmupsBase import Fmt, _to4lldn, _to3zBhp, _UPS_ZONE, \
31
31
  _UTMUPS_ZONE_MAX, _WGS84
32
32
 
33
33
  __all__ = _ALL_LAZY.utmups
34
- __version__ = '24.05.30'
34
+ __version__ = '24.06.11'
35
35
 
36
36
  _MGRS_TILE = _100km # in .mgrs.Mgrs.tile
37
37
 
@@ -111,32 +111,31 @@ def toUtmUps8(latlon, lon=None, datum=None, falsed=True, Utm=Utm, Ups=Ups,
111
111
 
112
112
  @arg latlon: Latitude (C{degrees}) or an (ellipsoidal)
113
113
  geodetic C{LatLon} point.
114
- @kwarg lon: Optional longitude (C{degrees}) or C{None}.
115
- @kwarg datum: Optional datum to use this UTM coordinate,
116
- overriding B{C{latlon}}'s datum (C{Datum}).
117
- @kwarg falsed: False both easting and northing (C{bool}).
118
- @kwarg Utm: Optional class to return the UTM coordinate (L{Utm})
119
- or C{None}.
120
- @kwarg Ups: Optional class to return the UPS coordinate (L{Ups})
121
- or C{None}.
122
- @kwarg pole: Optional top/center of UPS (stereographic)
123
- projection (C{str}, C{'N[orth]'} or C{'S[outh]'}).
124
- @kwarg name_cmoff: Optional B{C{Utm}} or B{C{Ups}} C{B{name}=NN}
125
- (C{str}) and DEPRECATED keyword argument C{B{cmoff}=True}
126
- to offset the longitude from the zone's central meridian
127
- (C{bool}), use B{C{falsed}} instead and I{for UTM only}.
128
-
129
- @return: The UTM or UPS coordinate (B{C{Utm}} respectively B{C{Ups}})
130
- or a L{UtmUps8Tuple}C{(zone, hemipole, easting, northing,
131
- band, datum, gamma, scale)} if B{C{Utm}} respectively
132
- B{C{Ups}} is C{None} or B{C{cmoff}} is C{False}.
133
-
134
- @raise RangeError: If B{C{lat}} outside the valid UTM or UPS bands
135
- or if B{C{lat}} or B{C{lon}} outside the valid
136
- range and L{pygeodesy.rangerrors} set to C{True}.
137
-
138
- @raise TypeError: If B{C{latlon}} is not ellipsoidal or B{C{lon}}
139
- value is missing of B{C{datum}} is invalid.
114
+ @kwarg lon: Longitude (C{degrees}), required if B{C{latlon}} is C{degrees},
115
+ ignored otherwise.
116
+ @kwarg datum: Optional datum to use this UTM coordinate, overriding the
117
+ B{C{latlon}}'s datum (C{Datum}).
118
+ @kwarg falsed: If C{True}, false both easting and northing (C{bool}).
119
+ @kwarg Utm: Optional class to return the UTM coordinate (L{Utm}) or C{None}.
120
+ @kwarg Ups: Optional class to return the UPS coordinate (L{Ups}) or C{None}.
121
+ @kwarg pole: Optional top/center of UPS (stereographic) projection (C{str},
122
+ C{'N[orth]'} or C{'S[outh]'}).
123
+ @kwarg name_cmoff: Optional C{B{name}=NN} (C{str}) and DEPRECATED keyword
124
+ argument C{B{cmoff}=True} to offset the longitude from the zone's
125
+ central meridian (C{bool}), use B{C{falsed}} instead and I{for
126
+ UTM only}.
127
+
128
+ @return: The UTM or UPS coordinate (B{C{Utm}} respectively B{C{Ups}}) or a
129
+ L{UtmUps8Tuple}C{(zone, hemipole, easting, northing, band, datum,
130
+ gamma, scale)} if B{C{Utm}} respectively C{B{Ups} is None} or if
131
+ C{B{falsed} is False}.
132
+
133
+ @raise RangeError: If B{C{lat}} outside the valid UTM or UPS bands or if
134
+ B{C{lat}} or B{C{lon}} outside the valid range and
135
+ L{rangerrors<pygeodesy.rangerrors>} is C{True}.
136
+
137
+ @raise TypeError: If B{C{latlon}} is not ellipsoidal or B{C{lon}} is missing
138
+ or B{C{datum}} is invalid.
140
139
 
141
140
  @raise UTMUPSError: UTM or UPS validation failed.
142
141
 
@@ -154,21 +153,20 @@ def toUtmUps8(latlon, lon=None, datum=None, falsed=True, Utm=Utm, Ups=Ups,
154
153
  return u
155
154
 
156
155
 
157
- def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84,
158
- falsed=True, **name):
156
+ def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84, falsed=True, **name):
159
157
  '''Class-like function to create a UTM/UPS coordinate.
160
158
 
161
159
  @kwarg zone: The UTM zone with/-out I{longitudinal} Band or UPS zone C{0}
162
160
  or C{"00"} with/-out I{polar} Band (C{str} or C{int}).
163
- @kwarg hemipole: UTM hemisphere or UPS top/center of projection
164
- (C{str}, C{'N[orth]'} or C{'S[outh]'}).
161
+ @kwarg hemipole: UTM hemisphere or UPS top/center of projection (C{str},
162
+ C{'N[orth]'} or C{'S[outh]'}).
165
163
  @arg easting: Easting, see B{C{falsed}} (C{meter}).
166
164
  @arg northing: Northing, see B{C{falsed}} (C{meter}).
167
165
  @kwarg band: Optional, UTM I{latitudinal} C{'C'|'D'|..|'W'|'X'} or UPS
168
166
  I{polar} Band letter C{'A'|'B'|'Y'|'Z'} Band letter (C{str}).
169
167
  @kwarg datum: The coordinate's datum (L{Datum}).
170
- @kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are
171
- falsed (C{bool}).
168
+ @kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are falsed
169
+ (C{bool}).
172
170
  @kwarg name: Optional L{Utm} or L{Ups} C{B{name}=NN} (C{str}).
173
171
 
174
172
  @return: New UTM or UPS instance (L{Utm} or L{Ups}).
@@ -182,17 +180,16 @@ def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84,
182
180
  '''
183
181
  z, B, hp = _to3zBhp(zone, band, hemipole=hemipole)
184
182
  U = Ups if z in (_UPS_ZONE, _UPS_ZONE_STR) else Utm
185
- return U(z, hp, easting, northing, band=B, datum=datum,
186
- falsed=falsed, **name)
183
+ return U(z, hp, easting, northing, band=B, datum=datum, falsed=falsed, **name)
187
184
 
188
185
 
189
186
  def utmupsValidate(coord, falsed=False, MGRS=False, Error=UTMUPSError):
190
187
  '''Check a UTM or UPS coordinate.
191
188
 
192
- @arg coord: The UTM or UPS coordinate (L{Utm}, L{Etm}, L{Ups}
193
- or C{5+Tuple}).
194
- @kwarg falsed: C{5+Tuple} easting and northing are falsed
195
- (C{bool}), ignored otherwise.
189
+ @arg coord: The UTM or UPS coordinate (L{Utm}, L{Etm}, L{Ups} or
190
+ C{5+Tuple}).
191
+ @kwarg falsed: If C{True}, easting and northing are falsed in the
192
+ C{B{coord} 5+Tuple} (C{bool}), ignored otherwise.
196
193
  @kwarg MGRS: Increase easting and northing ranges (C{bool}).
197
194
  @kwarg Error: Optional error to raise, overriding the default
198
195
  (L{UTMUPSError}).
@@ -253,8 +250,8 @@ def utmupsValidateOK(coord, falsed=False, ok=True):
253
250
  '''Check a UTM or UPS coordinate.
254
251
 
255
252
  @arg coord: The UTM or UPS coordinate (L{Utm}, L{Ups} or C{5+Tuple}).
256
- @kwarg falsed: Use C{B{falsed}=True} if the C{5+Tuple} easting and
257
- northing are falsed (C{bool}).
253
+ @kwarg falsed: If C{True}, easting and northing are falsed in the
254
+ C{B{coord} 5+Tuple} (C{bool}), ignored otherwise.
258
255
  @kwarg ok: Result to return if validation passed (B{C{ok}}).
259
256
 
260
257
  @return: B{C{ok}} if validation passed, otherwise the L{UTMUPSError}.
@@ -263,9 +260,9 @@ def utmupsValidateOK(coord, falsed=False, ok=True):
263
260
  '''
264
261
  try:
265
262
  utmupsValidate(coord, falsed=falsed)
266
- return ok
267
263
  except UTMUPSError as x:
268
264
  return x
265
+ return ok
269
266
 
270
267
 
271
268
  def utmupsZoneBand5(lat, lon, cmoff=False, **name):
@@ -280,11 +277,11 @@ def utmupsZoneBand5(lat, lon, cmoff=False, **name):
280
277
 
281
278
  @return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat, lon)}
282
279
  where C{hemipole} is C{'N'|'S'}, the UTM hemisphere or UPS
283
- pole, the UPS projection top/center.
280
+ pole, projection top/center.
284
281
 
285
- @raise RangeError: If B{C{lat}} outside the valid UTM or UPS bands
286
- or if B{C{lat}} or B{C{lon}} outside the valid
287
- range and L{pygeodesy.rangerrors} set to C{True}.
282
+ @raise RangeError: If B{C{lat}} outside the valid UTM or UPS bands or
283
+ if B{C{lat}} or B{C{lon}} outside the valid range
284
+ and L{rangerrors<pygeodesy.rangerrors>} is C{True}.
288
285
 
289
286
  @raise ValueError: Invalid B{C{lat}} or B{C{lon}}.
290
287
 
pygeodesy/utmupsBase.py CHANGED
@@ -12,22 +12,22 @@ from pygeodesy.datums import _ellipsoidal_datum, _WGS84
12
12
  from pygeodesy.dms import degDMS, parseDMS2
13
13
  from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB
14
14
  from pygeodesy.errors import _or, ParseError, _parseX, _ValueError, \
15
- _xkwds, _xkwds_not
15
+ _xattrs, _xkwds, _xkwds_not
16
16
  # from pygeodesy.internals import _name__, _under # from .named
17
17
  from pygeodesy.interns import NN, _A_, _B_, _COMMA_, _Error_, \
18
18
  _gamma_, _n_a_, _not_, _N_, _NS_, _PLUS_, \
19
19
  _S_, _scale_, _SPACE_, _Y_, _Z_
20
20
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
21
- from pygeodesy.named import _NamedBase, _xnamed, _name__, _under
21
+ from pygeodesy.named import _name__, _NamedBase, _under
22
22
  from pygeodesy.namedTuples import EasNor2Tuple, LatLonDatum5Tuple
23
23
  from pygeodesy.props import deprecated_method, property_doc_, _update_all, \
24
24
  deprecated_property_RO, Property_RO, property_RO
25
- from pygeodesy.streprs import Fmt, fstr, _fstrENH2, _xattrs, _xzipairs
25
+ from pygeodesy.streprs import Fmt, fstr, _fstrENH2, _xzipairs
26
26
  from pygeodesy.units import Band, Easting, Northing, Scalar, Zone
27
27
  from pygeodesy.utily import _Wrap, wrap360
28
28
 
29
29
  __all__ = _ALL_LAZY.utmupsBase
30
- __version__ = '24.05.30'
30
+ __version__ = '24.06.12'
31
31
 
32
32
  _UPS_BANDS = _A_, _B_, _Y_, _Z_ # UPS polar bands SE, SW, NE, NW
33
33
  # _UTM_BANDS = _MODS.utm._Bands
@@ -210,13 +210,12 @@ class UtmUpsBase(_NamedBase):
210
210
  ll = self._latlon
211
211
  if LatLon is None:
212
212
  r = LatLonDatum5Tuple(ll.lat, ll.lon, ll.datum,
213
- ll.gamma, ll.scale)
213
+ ll.gamma, ll.scale, name=ll.name)
214
214
  else:
215
215
  _xsubclassof(_LLEB, LatLon=LatLon)
216
- kwds = _xkwds(LatLon_kwds, datum=ll.datum)
217
- r = _xattrs(LatLon(ll.lat, ll.lon, **kwds),
218
- ll, _under(_gamma_), _under(_scale_))
219
- return _xnamed(r, ll.name)
216
+ r = LatLon(ll.lat, ll.lon, **_xkwds(LatLon_kwds, datum=ll.datum, name=ll.name))
217
+ r = _xattrs(r, ll, _under(_gamma_), _under(_scale_))
218
+ return r
220
219
 
221
220
  def _latlon5args(self, ll, g, k, _toBand, unfalse, *other):
222
221
  '''(INTERNAL) See C{._toLLEB} methods, functions C{ups.toUps8} and C{utm._toXtm8}
@@ -472,7 +471,7 @@ def _to3zBhp(zone, band, hemipole=NN, Error=_ValueError): # in .epsg, .ups, .ut
472
471
  elif not B:
473
472
  return z, B, hp
474
473
 
475
- raise ValueError # _invalid_
474
+ raise ValueError() # _invalid_
476
475
  except (AttributeError, IndexError, TypeError, ValueError) as x:
477
476
  raise Error(zone=zone, band=B, hemipole=hemipole, cause=x)
478
477
 
pygeodesy/vector3d.py CHANGED
@@ -25,13 +25,15 @@ from pygeodesy.namedTuples import Intersection3Tuple, NearestOn2Tuple, \
25
25
  # from pygeodesy.streprs import Fmt # from .iters
26
26
  from pygeodesy.units import _fi_j2, _isDegrees, Radius, Radius_
27
27
  from pygeodesy.utily import atan2b, sincos2d
28
- # from pygeodesy.vector2d import .... # in .... below
28
+ # import pygeodesy.vector2d as _vector2d # _MODS.into
29
29
  from pygeodesy.vector3dBase import Vector3dBase
30
30
 
31
31
  # from math import fabs, sqrt # from .fmath
32
32
 
33
33
  __all__ = _ALL_LAZY.vector3d
34
- __version__ = '24.05.21'
34
+ __version__ = '24.06.18'
35
+
36
+ _vector2d = _MODS.into(vector2d=__name__)
35
37
 
36
38
 
37
39
  class Vector3d(Vector3dBase):
@@ -87,7 +89,7 @@ class Vector3d(Vector3dBase):
87
89
  Triangle<https://MathWorld.Wolfram.com/ContactTriangle.html>}.
88
90
  '''
89
91
  try:
90
- return _MODS.vector2d._circin6(self, point2, point3, eps=eps, useZ=True)
92
+ return _vector2d._circin6(self, point2, point3, eps=eps, useZ=True)
91
93
  except (AssertionError, TypeError, ValueError) as x:
92
94
  raise _xError(x, point=self, point2=point2, point3=point3)
93
95
 
@@ -118,8 +120,8 @@ class Vector3d(Vector3dBase):
118
120
  @see: Function L{pygeodesy.circum3} and methods L{circum4_} and L{meeus2}.
119
121
  '''
120
122
  try:
121
- return _MODS.vector2d._circum3(self, point2, point3, circum=circum,
122
- eps=eps, useZ=True, clas=self.classof)
123
+ return _vector2d._circum3(self, point2, point3, circum=circum,
124
+ eps=eps, useZ=True, clas=self.classof)
123
125
  except (AssertionError, TypeError, ValueError) as x:
124
126
  raise _xError(x, point=self, point2=point2, point3=point3, circum=circum)
125
127
 
@@ -143,7 +145,7 @@ class Vector3d(Vector3dBase):
143
145
 
144
146
  @see: Function L{pygeodesy.circum4_} and methods L{circum3} and L{meeus2}.
145
147
  '''
146
- return _MODS.vector2d.circum4_(self, *points, useZ=True, Vector=self.classof)
148
+ return _vector2d.circum4_(self, *points, useZ=True, Vector=self.classof)
147
149
 
148
150
  def iscolinearWith(self, point1, point2, eps=EPS):
149
151
  '''Check whether this and two other (3-D) points are colinear.
@@ -163,7 +165,7 @@ class Vector3d(Vector3dBase):
163
165
  @see: Method L{nearestOn}.
164
166
  '''
165
167
  v = self if self.name else _otherV3d(NN_OK=False, this=self)
166
- return _MODS.vector2d._iscolinearWith(v, point1, point2, eps=eps)
168
+ return _vector2d._iscolinearWith(v, point1, point2, eps=eps)
167
169
 
168
170
  def meeus2(self, point2, point3, circum=False):
169
171
  '''Return the radius and I{Meeus}' Type of the smallest circle I{through}
@@ -186,7 +188,7 @@ class Vector3d(Vector3dBase):
186
188
  @see: Function L{pygeodesy.meeus2} and methods L{circum3} and L{circum4_}.
187
189
  '''
188
190
  try:
189
- return _MODS.vector2d._meeus2(self, point2, point3, circum, clas=self.classof)
191
+ return _vector2d._meeus2(self, point2, point3, circum, clas=self.classof)
190
192
  except (TypeError, ValueError) as x:
191
193
  raise _xError(x, point=self, point2=point2, point3=point3, circum=circum)
192
194
 
@@ -270,7 +272,7 @@ class Vector3d(Vector3dBase):
270
272
  Circles<https://MathWorld.Wolfram.com/TangentCircles.html>}.
271
273
  '''
272
274
  try:
273
- return _MODS.vector2d._radii11ABC(self, point2, point3, useZ=True)[0]
275
+ return _vector2d._radii11ABC(self, point2, point3, useZ=True)[0]
274
276
  except (TypeError, ValueError) as x:
275
277
  raise _xError(x, point=self, point2=point2, point3=point3)
276
278
 
@@ -299,7 +301,7 @@ class Vector3d(Vector3dBase):
299
301
 
300
302
  @see: Function L{pygeodesy.soddy4}.
301
303
  '''
302
- return _MODS.vector2d.soddy4(self, point2, point3, eps=eps, useZ=True)
304
+ return _vector2d.soddy4(self, point2, point3, eps=eps, useZ=True)
303
305
 
304
306
  def trilaterate2d2(self, radius, center2, radius2, center3, radius3, eps=EPS4, z=INT0):
305
307
  '''Trilaterate this and two other circles, each given as a (2-D) center
@@ -335,10 +337,10 @@ class Vector3d(Vector3dBase):
335
337
  return v.x, v.y, r
336
338
 
337
339
  try:
338
- return _MODS.vector2d._trilaterate2d2(*(_xyr3(radius, center=self) +
339
- _xyr3(radius2, center2=center2) +
340
- _xyr3(radius3, center3=center3)),
341
- eps=eps, Vector=self.classof, z=z)
340
+ return _vector2d._trilaterate2d2(*(_xyr3(radius, center=self) +
341
+ _xyr3(radius2, center2=center2) +
342
+ _xyr3(radius3, center3=center3)),
343
+ eps=eps, Vector=self.classof, z=z)
342
344
  except (AssertionError, TypeError, ValueError) as x:
343
345
  raise _xError(x, center=self, radius=radius,
344
346
  center2=center2, radius2=radius2,
@@ -386,10 +388,10 @@ class Vector3d(Vector3dBase):
386
388
  '''
387
389
  try:
388
390
  c1 = _otherV3d(center=self, NN_OK=False)
389
- return _MODS.vector2d._trilaterate3d2(c1, Radius_(radius, low=eps),
390
- center2, radius2,
391
- center3, radius3,
392
- eps=eps, clas=self.classof)
391
+ return _vector2d._trilaterate3d2(c1, Radius_(radius, low=eps),
392
+ center2, radius2,
393
+ center3, radius3,
394
+ eps=eps, clas=self.classof)
393
395
  except (AssertionError, TypeError, ValueError) as x:
394
396
  raise _xError(x, center=self, radius=radius,
395
397
  center2=center2, radius2=radius2,
@@ -473,7 +475,8 @@ def _intersect3d3(start1, end1, start2, end2, eps=EPS, useZ=False): # MCCABE 16
473
475
  t = cb.dot(ab)
474
476
  o1 = 0 if b1 else _outside(t, ab2, 1)
475
477
  v = s1.plus(a.times(t / ab2))
476
- o2 = 0 if b2 else _outside(v.minus(s2).dot(b), b.length2, 2)
478
+ t = v.minus(s2).dot(b)
479
+ o2 = 0 if b2 else _outside(t, b.length2, 2)
477
480
  return v, o1, o2
478
481
 
479
482
 
@@ -539,16 +542,15 @@ def intersections2(center1, radius1, center2, radius2, sphere=True, **Vector_and
539
542
  intersection points and optional, additional B{C{Vector}}
540
543
  keyword arguments, otherwise B{C{center1}}'s (sub-)class.
541
544
 
542
- @return: If B{C{sphere}} is C{True}, a 2-tuple of the C{center} and C{radius}
543
- of the intersection of the I{spheres}. The C{radius} is C{0.0} for
544
- abutting spheres (and the C{center} is aka the I{radical center}).
545
+ @return: If C{B{sphere} is True}, a 2-tuple of the C{center} and C{radius} of the
546
+ intersection of the I{spheres}. For abutting circles, C{radius} is C{0.0}
547
+ and C{center} is the I{radical center}.
545
548
 
546
- If B{C{sphere}} is C{False}, a 2-tuple with the two intersection
547
- points of the I{circles}. For abutting circles, both points are
548
- the same instance, aka the I{radical center}.
549
+ If C{B{sphere} is False}, a 2-tuple with the two intersection points of the
550
+ I{circles}. For abutting circles, both points are the same instance, aka
551
+ the I{radical center}.
549
552
 
550
- @raise IntersectionError: Concentric, invalid or non-intersecting spheres
551
- or circles.
553
+ @raise IntersectionError: Concentric, invalid or non-intersecting spheres or circles.
552
554
 
553
555
  @raise TypeError: Invalid B{C{center1}} or B{C{center2}}.
554
556
 
@@ -635,15 +637,15 @@ def iscolinearWith(point, point1, point2, eps=EPS, useZ=True):
635
637
  @kwarg eps: Tolerance (C{scalar}), same units as C{x}, C{y} and C{z}.
636
638
  @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
637
639
 
638
- @return: C{True} if B{C{point}} is colinear B{C{point1}} and B{C{point2}},
639
- C{False} otherwise.
640
+ @return: C{True} if B{C{point}} is colinear B{C{point1}} and B{C{point2}}, C{False}
641
+ otherwise.
640
642
 
641
643
  @raise TypeError: Invalid B{C{point}}, B{C{point1}} or B{C{point2}}.
642
644
 
643
645
  @see: Function L{nearestOn}.
644
646
  '''
645
647
  p = _otherV3d(useZ=useZ, point=point)
646
- return _MODS.vector2d._iscolinearWith(p, point1, point2, eps=eps, useZ=useZ)
648
+ return _vector2d._iscolinearWith(p, point1, point2, eps=eps, useZ=useZ)
647
649
 
648
650
 
649
651
  def nearestOn(point, point1, point2, within=True, useZ=True, Vector=None, **Vector_kwds):
@@ -659,8 +661,8 @@ def nearestOn(point, point1, point2, within=True, useZ=True, Vector=None, **Vect
659
661
  points, otherwise the closest point on the extended line
660
662
  through both points (C{bool}).
661
663
  @kwarg useZ: If C{True}, use the Z components, otherwise force C{z=INT0} (C{bool}).
662
- @kwarg Vector: Class to return closest point (C{Cartesian}, L{Vector3d}
663
- or C{Vector3Tuple}) or C{None}.
664
+ @kwarg Vector: Class to return closest point (C{Cartesian}, L{Vector3d} or
665
+ C{Vector3Tuple}) or C{None}.
664
666
  @kwarg Vector_kwds: Optional, additional B{C{Vector}} keyword arguments,
665
667
  ignored if C{B{Vector} is None}.
666
668
 
@@ -764,23 +766,22 @@ def nearestOn6(point, points, closed=False, useZ=True, **Vector_and_kwds): # ep
764
766
  return NearestOn6Tuple(v, sqrt(c2), f, j, s, e)
765
767
 
766
768
 
767
- def _nVc(v, clas=None, Vector=None, **Vector_kwds_name): # in .vector2d
769
+ def _nVc(v, clas=None, Vector=None, **name_Vector_kwds): # in .vector2d
768
770
  # return a named C{Vector} or C{clas} instance
769
- name, Vector_kwds = _name2__(**Vector_kwds_name)
771
+ name, kwds = _name2__(**name_Vector_kwds)
770
772
  if Vector is not None:
771
- v = Vector(v.x, v.y, v.z, **Vector_kwds)
773
+ v = Vector(v.x, v.y, v.z, **kwds)
772
774
  elif clas is not None:
773
775
  v = clas(v.x, v.y, v.z) # ignore Vector_kwds
774
776
  return _xnamed(v, name) if name else v
775
777
 
776
778
 
777
- def _otherV3d(useZ=True, NN_OK=True, i=None, **name_v):
779
+ def _otherV3d(useZ=True, NN_OK=True, i=None, **name_vector):
778
780
  # check named vector instance, return Vector3d
779
- n, v = _xkwds_item2(name_v)
781
+ n, v = _xkwds_item2(name_vector)
782
+ n = Fmt.INDEX(n, i)
780
783
  if useZ and isinstance(v, Vector3dBase):
781
- return v if NN_OK or v.name else v.copy(name=Fmt.INDEX(n, i))
782
-
783
- n = Fmt.INDEX(n, i)
784
+ return v if NN_OK or v.name else v.copy(name=n)
784
785
  try:
785
786
  return Vector3d(v.x, v.y, (v.z if useZ else INT0), name=n)
786
787
  except AttributeError: # no .x, .y or .z attr
@@ -797,7 +798,7 @@ def parse3d(str3d, sep=_COMMA_, Vector=Vector3d, **Vector_kwds):
797
798
  @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments,
798
799
  ignored if C{B{Vector} is None}.
799
800
 
800
- @return: A B{C{Vector}} instance or if B{C{Vector}} is C{None},
801
+ @return: A B{C{Vector}} instance or if C{B{Vector} is None},
801
802
  a named L{Vector3Tuple}C{(x, y, z)}.
802
803
 
803
804
  @raise VectorError: Invalid B{C{str3d}}.
@@ -818,11 +819,11 @@ def sumOf(vectors, Vector=Vector3d, **Vector_kwds):
818
819
 
819
820
  @arg vectors: Vectors to be added (L{Vector3d}[]).
820
821
  @kwarg Vector: Optional class for the vectorial sum (L{Vector3d}).
821
- @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments,
822
- ignored if C{B{Vector} is None}.
822
+ @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments, ignored
823
+ if C{B{Vector} is None}.
823
824
 
824
- @return: Vectorial sum as B{C{Vector}} or if B{C{Vector}} is
825
- C{None}, a named L{Vector3Tuple}C{(x, y, z)}.
825
+ @return: Vectorial sum as B{C{Vector}} or if B{C{Vector} is None},
826
+ a named L{Vector3Tuple}C{(x, y, z)}.
826
827
 
827
828
  @raise VectorError: No B{C{vectors}}.
828
829
  '''
@@ -869,9 +870,9 @@ def trilaterate2d2(x1, y1, radius1, x2, y2, radius2, x3, y3, radius3,
869
870
  <https://math.StackExchange.com/questions/884807>} and function
870
871
  L{pygeodesy.trilaterate3d2}.
871
872
  '''
872
- return _MODS.vector2d._trilaterate2d2(x1, y1, radius1,
873
- x2, y2, radius2,
874
- x3, y3, radius3, eps=eps, **Vector_and_kwds)
873
+ return _vector2d._trilaterate2d2(x1, y1, radius1,
874
+ x2, y2, radius2,
875
+ x3, y3, radius3, eps=eps, **Vector_and_kwds)
875
876
 
876
877
 
877
878
  def trilaterate3d2(center1, radius1, center2, radius2, center3, radius3,
@@ -919,27 +920,23 @@ def trilaterate3d2(center1, radius1, center2, radius2, center3, radius3,
919
920
  288825016>} and function L{pygeodesy.trilaterate2d2}.
920
921
  '''
921
922
  try:
922
- return _MODS.vector2d._trilaterate3d2(_otherV3d(center1=center1, NN_OK=False),
923
- Radius_(radius1=radius1, low=eps),
924
- center2, radius2, center3, radius3, eps=eps,
925
- clas=center1.classof, **Vector_and_kwds)
923
+ return _vector2d._trilaterate3d2(_otherV3d(center1=center1, NN_OK=False),
924
+ Radius_(radius1=radius1, low=eps),
925
+ center2, radius2, center3, radius3, eps=eps,
926
+ clas=center1.classof, **Vector_and_kwds)
926
927
  except (AssertionError, TypeError, ValueError) as x:
927
928
  raise _xError(x, center1=center1, radius1=radius1,
928
929
  center2=center2, radius2=radius2,
929
930
  center3=center3, radius3=radius3)
930
931
 
931
932
 
932
- def _xyzhdn3(xyz, height, datum, ll, **name): # in .cartesianBase, .nvectorBase
933
- '''(INTERNAL) Get a C{(h, d, name)} 3-tuple.
933
+ def _xyzhdlln4(xyz, height, datum, ll=None, **name): # in .cartesianBase, .nvectorBase
934
+ '''(INTERNAL) Get a C{(h, d, ll, name)} 4-tuple.
934
935
  '''
935
- h = height or _xattr(xyz, height=None) \
936
- or _xattr(xyz, h=None) \
937
- or _xattr(ll, height=None)
938
-
939
- d = datum or _xattr(xyz, datum=None) \
940
- or _xattr(ll, datum=None)
941
-
942
- return h, d, _name__(name, _or_nameof=xyz)
936
+ _x = _xattr
937
+ h = height or _x(xyz, height=None) or _x(xyz, h=None) or _x(ll, height=None)
938
+ d = datum or _x(xyz, datum=None) or _x(ll, datum=None)
939
+ return h, d, ll, _name__(name, _or_nameof=ll)
943
940
 
944
941
 
945
942
  __all__ += _ALL_DOCS(intersections2, sumOf, Vector3dBase)
pygeodesy/vector3dBase.py CHANGED
@@ -9,7 +9,7 @@ A pure Python implementation of vector-based functions by I{(C) Chris Veness
9
9
  '''
10
10
 
11
11
  from pygeodesy.basics import _copysign, islistuple, isscalar, map1, \
12
- map2, _zip
12
+ map2, _signOf, _zip
13
13
  from pygeodesy.constants import EPS, EPS0, INT0, PI, PI2, _copysignINF, \
14
14
  _float0, isnear0, isnear1, isneg0, \
15
15
  _pos_self, _0_0, _1_0
@@ -30,7 +30,7 @@ from pygeodesy.units import Float, Scalar
30
30
  from math import atan2, ceil, fabs, floor, trunc
31
31
 
32
32
  __all__ = _ALL_LAZY.vector3dBase
33
- __version__ = '24.05.19'
33
+ __version__ = '24.06.11'
34
34
 
35
35
 
36
36
  class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
@@ -107,9 +107,7 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
107
107
 
108
108
  @raise TypeError: Incompatible B{C{other}} C{type}.
109
109
  '''
110
- n = self.others(other).length
111
- return -1 if self.length < n else (
112
- +1 if self.length > n else 0)
110
+ return _signOf(self.length, self._other_cmp(other))
113
111
 
114
112
  cmp = __cmp__
115
113
 
@@ -156,7 +154,7 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
156
154
 
157
155
  @raise TypeError: Incompatible B{C{other}} C{type}.
158
156
  '''
159
- return self.length >= self.others(other).length
157
+ return self.length >= self._other_cmp(other)
160
158
 
161
159
  # def __getitem__(self, key):
162
160
  # '''Return C{item} at index or slice C{[B{key}]}.
@@ -172,7 +170,7 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
172
170
 
173
171
  @raise TypeError: Incompatible B{C{other}} C{type}.
174
172
  '''
175
- return self.length > self.others(other).length
173
+ return self.length > self._other_cmp(other)
176
174
 
177
175
  def __hash__(self): # PYCHOK no cover
178
176
  '''Return this instance' C{hash}.
@@ -261,7 +259,7 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
261
259
 
262
260
  @raise TypeError: Incompatible B{C{other}} C{type}.
263
261
  '''
264
- return self.length <= self.others(other).length
262
+ return self.length <= self._other_cmp(other)
265
263
 
266
264
  # def __len__(self):
267
265
  # '''Return C{3}, always.
@@ -277,7 +275,7 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
277
275
 
278
276
  @raise TypeError: Incompatible B{C{other}} C{type}.
279
277
  '''
280
- return self.length < self.others(other).length
278
+ return self.length < self._other_cmp(other)
281
279
 
282
280
  def __matmul__(self, other): # PYCHOK Python 3.5+
283
281
  '''Compute the cross product of this and an other vector, C{this @ B{other}}.
@@ -493,15 +491,14 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
493
491
  '''Compute the cross product of this and an other vector.
494
492
 
495
493
  @arg other: The other vector (L{Vector3d}).
496
- @kwarg raiser: Optional, L{CrossError} label if raised (C{str},
497
- non-L{NN}).
498
- @kwarg eps0: Near-zero tolerance (C{scalar}), same units as
499
- C{x}, C{y}, and C{z}.
494
+ @kwarg raiser: Optional, L{CrossError} label if raised (C{str}, non-L{NN}).
495
+ @kwarg eps0: Near-zero tolerance (C{scalar}), same units as C{x}, C{y} and
496
+ C{z}.
500
497
 
501
498
  @return: Cross product (L{Vector3d}).
502
499
 
503
- @raise CrossError: Zero or near-zero cross product and both
504
- B{C{raiser}} and L{pygeodesy.crosserrors} set.
500
+ @raise CrossError: Zero or near-zero cross product and if B{C{raiser}} and
501
+ L{crosserrors<pygeodesy.crosserrors>} are both C{True}.
505
502
 
506
503
  @raise TypeError: Incompatible B{C{other}} C{type}.
507
504
  '''
@@ -759,6 +756,11 @@ class Vector3dBase(_NamedBase): # sync __methods__ with .fsums.Fsum
759
756
  '''
760
757
  return _MODS.nvectorBase._N_vector_(*self.xyz, name=self.name)
761
758
 
759
+ def _other_cmp(self, other):
760
+ '''(INTERNAL) Return the value for comparison.
761
+ '''
762
+ return other if isscalar(other) else self.others(other).length
763
+
762
764
  def others(self, *other, **name_other_up):
763
765
  '''Refined class comparison.
764
766
 
pygeodesy/webmercator.py CHANGED
@@ -36,7 +36,7 @@ from pygeodesy.utily import degrees90, degrees180
36
36
  from math import atan, atanh, exp, radians, sin, tanh
37
37
 
38
38
  __all__ = _ALL_LAZY.webmercator
39
- __version__ = '24.05.31'
39
+ __version__ = '24.06.11'
40
40
 
41
41
  # _FalseEasting = 0 # false Easting (C{meter})
42
42
  # _FalseNorthing = 0 # false Northing (C{meter})
@@ -283,8 +283,8 @@ def parseWM(strWM, radius=R_MA, Wm=Wm, **name):
283
283
  or C{None}.
284
284
  @kwarg name: Optional C{B{name}=NN} (C{str}).
285
285
 
286
- @return: The WM coordinate (B{C{Wm}}) or if B{C{Wm}} is C{None}
287
- an L{EasNorRadius3Tuple}C{(easting, northing, radius)}.
286
+ @return: The WM coordinate (B{C{Wm}}) or if C{B{Wm} is None}, an
287
+ L{EasNorRadius3Tuple}C{(easting, northing, radius)}.
288
288
 
289
289
  @raise WebMercatorError: Invalid B{C{strWM}}.
290
290
  '''
@@ -307,27 +307,25 @@ def parseWM(strWM, radius=R_MA, Wm=Wm, **name):
307
307
  def toWm(latlon, lon=None, earth=R_MA, Wm=Wm, **name_Wm_kwds_radius):
308
308
  '''Convert a lat-/longitude point to a WM coordinate.
309
309
 
310
- @arg latlon: Latitude (C{degrees}) or an (ellipsoidal or
311
- spherical) geodetic C{LatLon} point.
310
+ @arg latlon: Latitude (C{degrees}) or an (ellipsoidal or spherical)
311
+ geodetic C{LatLon} point.
312
312
  @kwarg lon: Optional longitude (C{degrees} or C{None}).
313
- @kwarg earth: Earth radius (C{meter}), datum or ellipsoid
314
- (L{Datum}, L{a_f2Tuple}, L{Ellipsoid} or
315
- L{Ellipsoid2}), overridden by B{C{latlon}}'s
316
- datum if present.
317
- @kwarg Wm: Optional class to return the WM coordinate (L{Wm})
318
- or C{None}.
319
- @kwarg name_Wm_kwds_radius: Optional C{B{name}=NN} (C{str}),
320
- optional, additional B{C{Wm}} keyword arguments,
321
- ignored if C{B{Wm} is None} and DEPRECATED keyword
322
- argument C{B{radius}=earth}, use B{C{earth}}.
323
-
324
- @return: The WM coordinate (B{C{Wm}}) or if B{C{Wm}} is C{None} an
313
+ @kwarg earth: Earth radius (C{meter}), datum or ellipsoid (L{Datum},
314
+ L{a_f2Tuple}, L{Ellipsoid} or L{Ellipsoid2}), overridden
315
+ by B{C{latlon}}'s datum if present.
316
+ @kwarg Wm: Optional class to return the WM coordinate (L{Wm}) or C{None}.
317
+ @kwarg name_Wm_kwds_radius: Optional C{B{name}=NN} (C{str}), optional,
318
+ additional B{C{Wm}} keyword arguments, ignored if C{B{Wm} is
319
+ None} and DEPRECATED keyword argument C{B{radius}=earth},
320
+ use B{C{earth}}.
321
+
322
+ @return: The WM coordinate (B{C{Wm}}) or if C{B{Wm} is None}, an
325
323
  L{EasNorRadius3Tuple}C{(easting, northing, radius)}.
326
324
 
327
- @raise ValueError: If B{C{lon}} value is missing, if B{C{latlon}} is not
328
- scalar, if B{C{latlon}} is beyond the valid WM range
329
- and L{pygeodesy.rangerrors} is set to C{True} or if
330
- B{C{earth}} is invalid.
325
+ @raise ValueError: If B{C{earth}} is invalid, if B{C{lon}} value is missing,
326
+ if B{C{latlon}} is not scalar, or if B{C{latlon}} is beyond
327
+ the valid WM range and L{rangerrrors<pygeodesy.rangerrors>}
328
+ is C{True}.
331
329
  '''
332
330
  name, kwds = _name2__(name_Wm_kwds_radius)
333
331
  R, kwds = _xkwds_pop2(kwds, radius=earth)