pygeodesy 24.10.10__py2.py3-none-any.whl → 24.11.11__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 (76) hide show
  1. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
  2. PyGeodesy-24.11.11.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +14 -14
  5. pygeodesy/__main__.py +5 -5
  6. pygeodesy/albers.py +12 -17
  7. pygeodesy/azimuthal.py +51 -61
  8. pygeodesy/basics.py +60 -62
  9. pygeodesy/booleans.py +87 -79
  10. pygeodesy/cartesianBase.py +6 -6
  11. pygeodesy/constants.py +23 -19
  12. pygeodesy/css.py +7 -8
  13. pygeodesy/datums.py +3 -3
  14. pygeodesy/deprecated/__init__.py +1 -1
  15. pygeodesy/deprecated/classes.py +9 -9
  16. pygeodesy/deprecated/functions.py +6 -6
  17. pygeodesy/dms.py +250 -270
  18. pygeodesy/ecef.py +11 -14
  19. pygeodesy/ellipsoidalBase.py +106 -121
  20. pygeodesy/ellipsoidalBaseDI.py +114 -118
  21. pygeodesy/ellipsoidalExact.py +35 -37
  22. pygeodesy/ellipsoidalNvector.py +4 -4
  23. pygeodesy/ellipsoidalVincenty.py +2 -2
  24. pygeodesy/ellipsoids.py +10 -51
  25. pygeodesy/elliptic.py +14 -14
  26. pygeodesy/errors.py +28 -28
  27. pygeodesy/etm.py +92 -68
  28. pygeodesy/fmath.py +42 -40
  29. pygeodesy/formy.py +7 -6
  30. pygeodesy/fsums.py +72 -51
  31. pygeodesy/geodesici.py +43 -40
  32. pygeodesy/geodesicw.py +17 -16
  33. pygeodesy/geodesicx/__init__.py +2 -2
  34. pygeodesy/geodesicx/gxarea.py +3 -2
  35. pygeodesy/geodsolve.py +79 -39
  36. pygeodesy/geohash.py +2 -2
  37. pygeodesy/geoids.py +32 -31
  38. pygeodesy/heights.py +2 -2
  39. pygeodesy/internals.py +201 -147
  40. pygeodesy/interns.py +23 -20
  41. pygeodesy/karney.py +62 -13
  42. pygeodesy/ktm.py +11 -13
  43. pygeodesy/latlonBase.py +18 -20
  44. pygeodesy/lazily.py +210 -218
  45. pygeodesy/lcc.py +4 -4
  46. pygeodesy/ltp.py +10 -10
  47. pygeodesy/ltpTuples.py +74 -75
  48. pygeodesy/mgrs.py +20 -21
  49. pygeodesy/named.py +15 -10
  50. pygeodesy/nvectorBase.py +1 -1
  51. pygeodesy/osgr.py +9 -12
  52. pygeodesy/points.py +2 -2
  53. pygeodesy/props.py +35 -14
  54. pygeodesy/resections.py +9 -10
  55. pygeodesy/rhumb/__init__.py +1 -1
  56. pygeodesy/rhumb/bases.py +5 -5
  57. pygeodesy/rhumb/solve.py +9 -10
  58. pygeodesy/simplify.py +5 -5
  59. pygeodesy/solveBase.py +7 -25
  60. pygeodesy/sphericalBase.py +20 -23
  61. pygeodesy/sphericalNvector.py +103 -145
  62. pygeodesy/sphericalTrigonometry.py +68 -73
  63. pygeodesy/streprs.py +5 -5
  64. pygeodesy/trf.py +6 -4
  65. pygeodesy/triaxials.py +46 -9
  66. pygeodesy/units.py +5 -4
  67. pygeodesy/ups.py +6 -6
  68. pygeodesy/utily.py +2 -2
  69. pygeodesy/utm.py +7 -7
  70. pygeodesy/vector2d.py +13 -13
  71. pygeodesy/vector3d.py +19 -21
  72. pygeodesy/vector3dBase.py +21 -19
  73. pygeodesy/webmercator.py +4 -4
  74. pygeodesy/wgrs.py +4 -4
  75. PyGeodesy-24.10.10.dist-info/RECORD +0 -118
  76. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ L{perimeterOf}, I{all spherical}.
10
10
 
11
11
  Pure Python implementation of geodetic (lat-/longitude) methods using
12
12
  spherical trigonometry, transcoded from JavaScript originals by
13
- I{(C) Chris Veness 2011-2016} published under the same MIT Licence**, see
13
+ I{(C) Chris Veness 2011-2024} published under the same MIT Licence**, see
14
14
  U{Latitude/Longitude<https://www.Movable-Type.co.UK/scripts/latlong.html>}.
15
15
  '''
16
16
  # make sure int/int division yields float quotient, see .basics
@@ -24,7 +24,7 @@ from pygeodesy.datums import _ellipsoidal_datum, _mean_radius
24
24
  from pygeodesy.errors import _AssertionError, CrossError, crosserrors, \
25
25
  _TypeError, _ValueError, IntersectionError, \
26
26
  _xError, _xkwds, _xkwds_get, _xkwds_pop2
27
- from pygeodesy.fmath import favg, fdot, fmean, hypot
27
+ from pygeodesy.fmath import favg, fdot, fdot_, fmean, hypot
28
28
  from pygeodesy.fsums import Fsum, fsum, fsumf_
29
29
  from pygeodesy.formy import antipode_, bearing_, _bearingTo2, excessAbc_, \
30
30
  excessGirard_, excessLHuilier_, opposing_, _radical2, \
@@ -54,7 +54,7 @@ from pygeodesy.vector3d import sumOf, Vector3d
54
54
  from math import asin, atan2, cos, degrees, fabs, radians, sin
55
55
 
56
56
  __all__ = _ALL_LAZY.sphericalTrigonometry
57
- __version__ = '24.09.23'
57
+ __version__ = '24.11.07'
58
58
 
59
59
  _PI_EPS4 = PI - EPS4
60
60
  if _PI_EPS4 >= PI:
@@ -182,8 +182,8 @@ class LatLon(LatLonSphericalBase):
182
182
  return degrees180(m - d), degrees180(m + d)
183
183
 
184
184
  def crossTrackDistanceTo(self, start, end, radius=R_M, wrap=False):
185
- '''Compute the (signed) distance from this point to
186
- the great circle defined by a start and an end point.
185
+ '''Compute the (signed) distance from this point to a great
186
+ circle from a start to an end point.
187
187
 
188
188
  @arg start: Start point of the great circle line (L{LatLon}).
189
189
  @arg end: End point of the great circle line (L{LatLon}).
@@ -205,7 +205,7 @@ class LatLon(LatLonSphericalBase):
205
205
 
206
206
  def destination(self, distance, bearing, radius=R_M, height=None):
207
207
  '''Locate the destination from this point after having
208
- travelled the given distance on the given initial bearing.
208
+ travelled the given distance on a bearing from North.
209
209
 
210
210
  @arg distance: Distance travelled (C{meter}, same units as
211
211
  B{C{radius}}).
@@ -253,7 +253,7 @@ class LatLon(LatLonSphericalBase):
253
253
 
254
254
  def greatCircle(self, bearing, Vector=Vector3d, **Vector_kwds):
255
255
  '''Compute the vector normal to great circle obtained by heading
256
- on the given initial bearing from this point.
256
+ from this point on the bearing from North.
257
257
 
258
258
  Direction of vector is such that initial bearing vector
259
259
  b = c × n, where n is an n-vector representing this point.
@@ -271,8 +271,9 @@ class LatLon(LatLonSphericalBase):
271
271
  a, b = self.philam
272
272
  sa, ca, sb, cb, st, ct = sincos2_(a, b, Bearing_(bearing))
273
273
 
274
- return Vector(sb * ct - cb * sa * st,
275
- -cb * ct - sb * sa * st,
274
+ sa *= st
275
+ return Vector(fdot_(sb, ct, -cb, sa),
276
+ -fdot_(cb, ct, sb, sa),
276
277
  ca * st, **Vector_kwds) # XXX .unit()?
277
278
 
278
279
  def initialBearingTo(self, other, wrap=False, raiser=False):
@@ -341,9 +342,9 @@ class LatLon(LatLonSphericalBase):
341
342
  a = sin(r - t) # / sr superflous
342
343
  b = sin( t) # / sr superflous
343
344
 
344
- x = a * ca1 * cb1 + b * ca2 * cb2
345
- y = a * ca1 * sb1 + b * ca2 * sb2
346
- z = a * sa1 + b * sa2
345
+ x = fdot_(a, ca1 * cb1, b, ca2 * cb2)
346
+ y = fdot_(a, ca1 * sb1, b, ca2 * sb2)
347
+ z = fdot_(a, sa1, b, sa2)
347
348
 
348
349
  a = atan1d(z, hypot(x, y))
349
350
  b = atan2d(y, x)
@@ -358,7 +359,7 @@ class LatLon(LatLonSphericalBase):
358
359
 
359
360
  def intersection(self, end1, other, end2, height=None, wrap=False):
360
361
  '''Compute the intersection point of two lines, each defined by
361
- two points or a start point and bearing from North.
362
+ two points or a start point and a bearing from North.
362
363
 
363
364
  @arg end1: End point of this line (L{LatLon}) or the initial
364
365
  bearing at this point (compass C{degrees360}).
@@ -395,7 +396,7 @@ class LatLon(LatLonSphericalBase):
395
396
  def intersections2(self, rad1, other, rad2, radius=R_M, eps=_0_0,
396
397
  height=None, wrap=True):
397
398
  '''Compute the intersection points of two circles, each defined
398
- by a center point and radius.
399
+ by a center point and a radius.
399
400
 
400
401
  @arg rad1: Radius of the this circle (C{meter} or C{radians},
401
402
  see B{C{radius}}).
@@ -536,7 +537,7 @@ class LatLon(LatLonSphericalBase):
536
537
  return r
537
538
 
538
539
  def nearestOn(self, point1, point2, radius=R_M, **wrap_adjust_limit):
539
- '''Locate the point between two points closest to this point.
540
+ '''Locate the point between two other points closest to this point.
540
541
 
541
542
  Distances are approximated by function L{pygeodesy.equirectangular4},
542
543
  subject to the supplied B{C{options}}.
@@ -679,8 +680,8 @@ class LatLon(LatLonSphericalBase):
679
680
  return self._xnamed(_t7Tuple(t, radius))
680
681
 
681
682
  def triangulate(self, bearing1, other, bearing2, **height_wrap):
682
- '''Locate a point given this, an other point and the (initial) bearing
683
- at this and at the other point.
683
+ '''Locate a point given this, an other point and a bearing from
684
+ North at both points.
684
685
 
685
686
  @arg bearing1: Bearing at this point (compass C{degrees360}).
686
687
  @arg other: The other point (C{LatLon}).
@@ -755,8 +756,8 @@ _T00 = LatLon(0, 0, name='T00') # reference instance (L{LatLon})
755
756
 
756
757
 
757
758
  def areaOf(points, radius=R_M, wrap=False): # was=True
758
- '''Calculate the area of a (spherical) polygon or composite
759
- (with the pointsjoined by great circle arcs).
759
+ '''Calculate the area of a (spherical) polygon or composite (with the
760
+ points joined by great circle arcs).
760
761
 
761
762
  @arg points: The polygon points or clips (L{LatLon}[], L{BooleanFHP}
762
763
  or L{BooleanGH}).
@@ -868,8 +869,8 @@ def _int3d2(s, end, wrap, _i_, Vector, hs):
868
869
  -(b1 + b2) * _0_5)
869
870
  cb21 *= sin(a1 - a2) # sa21
870
871
  sb21 *= sin(a1 + a2) # sa12
871
- x = Vector(sb12 * cb21 - cb12 * sb21,
872
- cb12 * cb21 + sb12 * sb21,
872
+ x = Vector(fdot_(sb12, cb21, -cb12, sb21),
873
+ fdot_(cb12, cb21, sb12, sb21),
873
874
  cos(a1) * cos(a2) * sin(db)) # ll=start
874
875
  return x.unit(), (db, (a2 - a1)) # negated d
875
876
 
@@ -882,16 +883,17 @@ def _intdot(ds, a1, b1, a, b, wrap):
882
883
 
883
884
  def intersecant2(center, circle, point, other, **radius_exact_height_wrap):
884
885
  '''Compute the intersections of a circle and a (great circle) line given as
885
- two points or as a point and bearing.
886
+ two points or as a point and a bearing from North.
886
887
 
887
888
  @arg center: Center of the circle (L{LatLon}).
888
- @arg circle: Radius of the circle (C{meter}, same units as B{C{radius}})
889
- or a point on the circle (L{LatLon}).
889
+ @arg circle: Radius of the circle (C{meter}, same units as the earth
890
+ B{C{radius}}) or a point on the circle (L{LatLon}).
890
891
  @arg point: A point on the (great circle) line (L{LatLon}).
891
892
  @arg other: An other point on the (great circle) line (L{LatLon}) or
892
893
  the bearing at the B{C{point}} (compass C{degrees360}).
893
- @kwarg radius_exact_height_wrap: Optional keyword arguments, see
894
- method L{LatLon.intersecant2} for further details.
894
+ @kwarg radius_exact_height_wrap: Optional keyword arguments, see method
895
+ L{intersecant2<pygeodesy.sphericalBase.LatLonSphericalBase.
896
+ intersecant2>} for further details.
895
897
 
896
898
  @return: 2-Tuple of the intersection points (representing a chord), each
897
899
  an instance of the B{C{point}} class. Both points are the same
@@ -899,8 +901,8 @@ def intersecant2(center, circle, point, other, **radius_exact_height_wrap):
899
901
 
900
902
  @raise IntersectionError: The circle and line do not intersect.
901
903
 
902
- @raise TypeError: If B{C{center}} or B{C{point}} not L{LatLon} or
903
- B{C{circle}} or B{C{other}} invalid.
904
+ @raise TypeError: If B{C{center}}, B{C{point}}, B{C{circle}} or B{C{other}}
905
+ not L{LatLon}.
904
906
 
905
907
  @raise UnitError: Invalid B{C{circle}}, B{C{other}}, B{C{radius}},
906
908
  B{C{exact}}, B{C{height}} or B{C{napieradius}}.
@@ -915,7 +917,7 @@ def intersecant2(center, circle, point, other, **radius_exact_height_wrap):
915
917
 
916
918
 
917
919
  def _intersect(start1, end1, start2, end2, height=None, wrap=False, # in.ellipsoidalBaseDI._intersect3
918
- LatLon=None, **LatLon_kwds):
920
+ LatLon=LatLon, **LatLon_kwds):
919
921
  # (INTERNAL) Intersect two (spherical) lines, see L{intersection}
920
922
  # above, separated to allow callers to embellish any exceptions
921
923
 
@@ -983,75 +985,68 @@ def _intersect(start1, end1, start2, end2, height=None, wrap=False, # in.ellips
983
985
 
984
986
 
985
987
  def intersection(start1, end1, start2, end2, height=None, wrap=False,
986
- LatLon=LatLon, **LatLon_kwds):
987
- '''Compute the intersection point of two lines, each defined
988
- by two points or a start point and bearing from North.
988
+ **LatLon_and_kwds):
989
+ '''Compute the intersection point of two lines, each defined by
990
+ two points or by a start point and a bearing from North.
989
991
 
990
992
  @arg start1: Start point of the first line (L{LatLon}).
991
- @arg end1: End point of the first line (L{LatLon}) or
992
- the initial bearing at the first start point
993
- (compass C{degrees360}).
993
+ @arg end1: End point of the first line (L{LatLon}) or the bearing
994
+ at the first start point (compass C{degrees360}).
994
995
  @arg start2: Start point of the second line (L{LatLon}).
995
- @arg end2: End point of the second line (L{LatLon}) or
996
- the initial bearing at the second start point
997
- (compass C{degrees360}).
996
+ @arg end2: End point of the second line (L{LatLon}) or the bearing
997
+ at the second start point (compass C{degrees360}).
998
998
  @kwarg height: Optional height for the intersection point,
999
999
  overriding the mean height (C{meter}).
1000
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
1001
- B{C{start2}} and both B{C{end*}} points (C{bool}).
1002
- @kwarg LatLon: Optional class to return the intersection
1003
- point (L{LatLon}) or C{None}.
1004
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1005
- arguments, ignored if C{B{LatLon} is None}.
1000
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{start2}}
1001
+ and both B{C{end*}} points (C{bool}).
1002
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to use
1003
+ for the intersection point and optionally additional
1004
+ B{C{LatLon}} keyword arguments, ignored if C{B{LatLon}
1005
+ is None}.
1006
1006
 
1007
- @return: The intersection point as a (B{C{LatLon}}) or if
1008
- C{B{LatLon} is None} a L{LatLon3Tuple}C{(lat, lon,
1009
- height)}. An alternate intersection point might
1010
- be the L{antipode} to the returned result.
1007
+ @return: The intersection point as a (B{C{LatLon}}) or if C{B{LatLon}
1008
+ is None} a L{LatLon3Tuple}C{(lat, lon, height)}. An alternate
1009
+ intersection point might be the L{antipode} to the returned result.
1011
1010
 
1012
- @raise IntersectionError: Ambiguous or infinite intersection
1013
- or colinear, parallel or otherwise
1014
- non-intersecting lines.
1011
+ @raise IntersectionError: Ambiguous or infinite intersection or colinear,
1012
+ parallel or otherwise non-intersecting lines.
1015
1013
 
1016
- @raise TypeError: A B{C{start1}}, B{C{end1}}, B{C{start2}}
1017
- or B{C{end2}} point not L{LatLon}.
1014
+ @raise TypeError: A B{C{start1}}, B{C{end1}}, B{C{start2}} or B{C{end2}}
1015
+ point not L{LatLon}.
1018
1016
 
1019
1017
  @raise ValueError: Invalid B{C{height}} or C{null} line.
1020
1018
  '''
1021
1019
  s1 = _T00.others(start1=start1)
1022
1020
  s2 = _T00.others(start2=start2)
1023
1021
  try:
1024
- return _intersect(s1, end1, s2, end2, height=height, wrap=wrap,
1025
- LatLon=LatLon, **LatLon_kwds)
1022
+ return _intersect(s1, end1, s2, end2, height=height, wrap=wrap, **LatLon_and_kwds)
1026
1023
  except (TypeError, ValueError) as x:
1027
1024
  raise _xError(x, start1=start1, end1=end1, start2=start2, end2=end2)
1028
1025
 
1029
1026
 
1030
1027
  def intersections2(center1, rad1, center2, rad2, radius=R_M, eps=_0_0,
1031
1028
  height=None, wrap=False, # was=True
1032
- LatLon=LatLon, **LatLon_kwds):
1033
- '''Compute the intersection points of two circles each defined
1034
- by a center point and a radius.
1029
+ **LatLon_and_kwds):
1030
+ '''Compute the intersection points of two circles each defined by a
1031
+ center point and a radius.
1035
1032
 
1036
1033
  @arg center1: Center of the first circle (L{LatLon}).
1037
- @arg rad1: Radius of the first circle (C{meter} or C{radians},
1038
- see B{C{radius}}).
1034
+ @arg rad1: Radius of the first circle (C{meter} or C{radians}, see
1035
+ B{C{radius}}).
1039
1036
  @arg center2: Center of the second circle (L{LatLon}).
1040
- @arg rad2: Radius of the second circle (C{meter} or C{radians},
1041
- see B{C{radius}}).
1037
+ @arg rad2: Radius of the second circle (C{meter} or C{radians}, see
1038
+ B{C{radius}}).
1042
1039
  @kwarg radius: Mean earth radius (C{meter} or C{None} if B{C{rad1}},
1043
1040
  B{C{rad2}} and B{C{eps}} are given in C{radians}).
1044
- @kwarg eps: Required overlap (C{meter} or C{radians}, see
1045
- B{C{radius}}).
1041
+ @kwarg eps: Required overlap (C{meter} or C{radians}, see B{C{radius}}).
1046
1042
  @kwarg height: Optional height for the intersection points (C{meter},
1047
1043
  conventionally) or C{None} for the I{"radical height"}
1048
1044
  at the I{radical line} between both centers.
1049
1045
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{center2}}
1050
1046
  (C{bool}).
1051
- @kwarg LatLon: Optional class to return the intersection
1052
- points (L{LatLon}) or C{None}.
1053
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1054
- arguments, ignored if C{B{LatLon} is None}.
1047
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to use for
1048
+ the intersection points and optionally additional B{C{LatLon}}
1049
+ keyword arguments, ignored if C{B{LatLon} is None}.
1055
1050
 
1056
1051
  @return: 2-Tuple of the intersection points, each a B{C{LatLon}}
1057
1052
  instance or if C{B{LatLon} is None} a L{LatLon3Tuple}C{(lat,
@@ -1076,7 +1071,7 @@ def intersections2(center1, rad1, center2, rad2, radius=R_M, eps=_0_0,
1076
1071
  try:
1077
1072
  return _intersects2(c1, rad1, c2, rad2, radius=radius, eps=eps,
1078
1073
  height=height, wrap=wrap,
1079
- LatLon=LatLon, **LatLon_kwds)
1074
+ **LatLon_and_kwds)
1080
1075
  except (TypeError, ValueError) as x:
1081
1076
  raise _xError(x, center1=center1, rad1=rad1,
1082
1077
  center2=center2, rad2=rad2, wrap=wrap)
@@ -1225,7 +1220,7 @@ def nearestOn3(point, points, closed=False, radius=R_M, wrap=False, adjust=True,
1225
1220
  (C{degrees}), default C{9 degrees} is about C{1,000 Km} (for
1226
1221
  (mean spherical earth radius L{R_KM}).
1227
1222
  @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=L{LatLon}} to return the
1228
- closest point and optional, additional C{B{LatLon}} keyword
1223
+ closest point and optionally additional C{B{LatLon}} keyword
1229
1224
  arguments or specify C{B{LatLon}=None}.
1230
1225
 
1231
1226
  @return: A L{NearestOn3Tuple}C{(closest, distance, angle)} with the
@@ -1330,9 +1325,9 @@ def triangle7(latA, lonA, latB, lonB, latC, lonC, radius=R_M,
1330
1325
  C{a}, C{b} and C{c} all in C{degrees} and C{area}
1331
1326
  in I{square} C{meter} or same units as B{C{radius}}
1332
1327
  I{squared} or if C{B{radius}=0} or C{None}, a
1333
- L{Triangle8Tuple}C{(A, a, B, b, C, c, D, E)} all in
1334
- C{radians} with the I{spherical excess} C{E} as the
1335
- C{unit area} in C{radians}.
1328
+ L{Triangle8Tuple}C{(A, a, B, b, C, c, D, E)} with
1329
+ I{spherical deficit} C{D} and I{spherical excess}
1330
+ C{E} as the C{unit area}, all in C{radians}.
1336
1331
  '''
1337
1332
  t = triangle8_(Phid(latA=latA), Lamd(lonA=lonA),
1338
1333
  Phid(latB=latB), Lamd(lonB=lonB),
pygeodesy/streprs.py CHANGED
@@ -9,7 +9,7 @@ from pygeodesy.basics import isint, islistuple, isscalar, isstr, itemsorted, \
9
9
  # from pygeodesy.constants import _0_0
10
10
  from pygeodesy.errors import _or, _IsnotError, _TypeError, _ValueError, \
11
11
  _xkwds_get, _xkwds_item2
12
- # from pygeodesy.internals import _dunder_nameof # from .lazily
12
+ from pygeodesy.internals import _DUNDER_nameof
13
13
  from pygeodesy.interns import NN, _0_, _0to9_, MISSING, _BAR_, _COMMASPACE_, \
14
14
  _DOT_, _E_, _ELLIPSIS_, _EQUAL_, _H_, _LR_PAIRS, \
15
15
  _N_, _name_, _not_scalar_, _PERCENT_, _SPACE_, \
@@ -17,12 +17,12 @@ from pygeodesy.interns import NN, _0_, _0to9_, MISSING, _BAR_, _COMMASPACE_, \
17
17
  from pygeodesy.interns import _convergence_, _distant_, _e_, _eps_, _exceeds_, \
18
18
  _EQUALSPACED_, _f_, _F_, _g_, _limit_, _no_, \
19
19
  _tolerance_ # PYCHOK used!
20
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _dunder_nameof
20
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
21
21
 
22
22
  from math import fabs, log10 as _log10
23
23
 
24
24
  __all__ = _ALL_LAZY.streprs
25
- __version__ = '24.10.04'
25
+ __version__ = '24.10.14'
26
26
 
27
27
  _at_ = 'at' # PYCHOK used!
28
28
  _EN_PREC = 6 # max MGRS/OSGR precision, 1 micrometer
@@ -557,14 +557,14 @@ def unstr(where, *args, **kwds_):
557
557
  t = reprs(args, fmt=g) if args else ()
558
558
  if kwds:
559
559
  t += pairs(itemsorted(kwds), fmt=g)
560
- n = where if isstr(where) else _dunder_nameof(where) # _NN_
560
+ n = where if isstr(where) else _DUNDER_nameof(where) # _NN_
561
561
  if C and hasattr(C, n):
562
562
  try: # bound method of class C?
563
563
  where = where.__func__
564
564
  except AttributeError:
565
565
  pass # method of C?
566
566
  if getattr(C, n, None) is where:
567
- n = _DOT_(_dunder_nameof(C), n)
567
+ n = _DOT_(_DUNDER_nameof(C), n)
568
568
  return Fmt.PAREN(n, _COMMASPACE_.join(t))
569
569
 
570
570
 
pygeodesy/trf.py CHANGED
@@ -5,7 +5,7 @@ u'''I{Veness}' Terrestrial Reference Frames (TRF).
5
5
 
6
6
  Classes L{RefFrame}, registry L{RefFrames} and L{TRFError}.
7
7
 
8
- Transcoded from I{Chris Veness'} (C) 2006-2022 JavaScript originals U{latlon-ellipsoidal-referenceframe.js
8
+ Transcoded from I{Chris Veness'} (C) 2006-2024 JavaScript originals U{latlon-ellipsoidal-referenceframe.js
9
9
  <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js>} and
10
10
  U{latlon-ellipsoidal-referenceframe-txparams.js
11
11
  <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe-txparams.js>}.
@@ -91,7 +91,7 @@ from math import ceil as _ceil, fabs
91
91
  # import operator as _operator # from .datums
92
92
 
93
93
  __all__ = _ALL_LAZY.trf
94
- __version__ = '24.06.09'
94
+ __version__ = '24.10.14'
95
95
 
96
96
  _EP0CH = Epoch(0, low=0)
97
97
  _Es = {_EP0CH: _EP0CH} # L{Epoch}s, deleted below
@@ -391,7 +391,9 @@ class TransformXform(Transform):
391
391
  @return: Inverse (L{TransformXform}), unregistered.
392
392
  '''
393
393
  r = Transform.inverse(self, **name)
394
- r._Xform = r.Xform.inverse()
394
+ X = self.Xform
395
+ if X: # unregistered
396
+ r._Xform = X.inverse()
395
397
  return r
396
398
 
397
399
  def rename(self, name=NN):
@@ -1778,7 +1780,7 @@ if __name__ == '__main__':
1778
1780
  raise AssertionError(_SPACE_(n, _vs_, t))
1779
1781
 
1780
1782
  _main()
1781
- del _main
1783
+ # del _main
1782
1784
 
1783
1785
  # **) MIT License
1784
1786
  #
pygeodesy/triaxials.py CHANGED
@@ -30,14 +30,14 @@ see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
30
30
  # make sure int/int division yields float quotient, see .basics
31
31
  from __future__ import division as _; del _ # PYCHOK semicolon
32
32
 
33
- from pygeodesy.basics import isLatLon, isscalar, _ValueError
33
+ from pygeodesy.basics import isLatLon, isscalar
34
34
  from pygeodesy.constants import EPS, EPS0, EPS02, EPS4, INT0, PI2, PI_3, PI4, \
35
- _EPS2e4, float0_, isfinite, isnear1, _over, \
35
+ _EPS2e4, _SQRT2_2, float0_, isfinite, isnear1, _over, \
36
36
  _0_0, _0_5, _1_0, _N_1_0, _64_0, _4_0 # PYCHOK used!
37
37
  from pygeodesy.datums import Datum, _spherical_datum, _WGS84, Ellipsoid, _EWGS84, Fmt
38
38
  # from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
39
39
  # from pygeodesy.elliptic import Elliptic # _MODS
40
- # from pygeodesy.errors import _ValueError # from .basics
40
+ from pygeodesy.errors import _AssertionError, _ValueError
41
41
  from pygeodesy.fmath import Fdot, fdot, fmean_, hypot, hypot_, norm2, sqrt0
42
42
  from pygeodesy.fsums import _Fsumf_, fsumf_, fsum1f_
43
43
  from pygeodesy.interns import NN, _a_, _b_, _beta_, _c_, _distant_, _finite_, \
@@ -59,7 +59,7 @@ from pygeodesy.vector3d import _otherV3d, Vector3d, _ALL_LAZY, _MODS
59
59
  from math import atan2, fabs, sqrt
60
60
 
61
61
  __all__ = _ALL_LAZY.triaxials
62
- __version__ = '24.08.26'
62
+ __version__ = '24.10.15'
63
63
 
64
64
  _not_ordered_ = _not_('ordered')
65
65
  _omega_ = 'omega'
@@ -1272,13 +1272,13 @@ def hartzell4(pov, los=False, tri_biax=_WGS84, **name):
1272
1272
  T = tri_biax
1273
1273
  else:
1274
1274
  D = tri_biax if isinstance(tri_biax, Datum) else \
1275
- _spherical_datum(tri_biax, name__=hartzell4) # _dunder_nameof
1275
+ _spherical_datum(tri_biax, name__=hartzell4) # _DUNDER_nameof
1276
1276
  T = D.ellipsoid._triaxial
1277
1277
  try:
1278
1278
  v, h, i = _hartzell3(pov, los, T)
1279
1279
  except Exception as x:
1280
1280
  raise TriaxialError(pov=pov, los=los, tri_biax=tri_biax, cause=x)
1281
- return Vector4Tuple(v.x, v.y, v.z, h, iteration=i, # _dunder_nameof
1281
+ return Vector4Tuple(v.x, v.y, v.z, h, iteration=i, # _DUNDER_nameof
1282
1282
  name=_name__(name, name__=hartzell4))
1283
1283
 
1284
1284
 
@@ -1308,12 +1308,49 @@ def _over02(p, q):
1308
1308
  return (p / q)**2 if p and q else _0_0
1309
1309
 
1310
1310
 
1311
+ def _plumbTo3(px, py, E, eps=EPS): # in .ellipsoids.Ellipsoid.height4
1312
+ '''(INTERNAL) Nearest point on a 2-D ellipse in 1st quadrant.
1313
+ '''
1314
+ a, b = E.a, E.b
1315
+ if min(px, py, a, b) < EPS0:
1316
+ raise _AssertionError(px=px, py=py, a=a, b=b, E=E)
1317
+
1318
+ a2 = a - b * E.b_a
1319
+ b2 = b - a * E.a_b
1320
+ tx = ty = _SQRT2_2
1321
+ for i in range(16): # max 5
1322
+ ex = a2 * tx**3
1323
+ ey = b2 * ty**3
1324
+
1325
+ qx = px - ex
1326
+ qy = py - ey
1327
+ q = hypot(qx, qy)
1328
+ if q < EPS0: # PYCHOK no cover
1329
+ break
1330
+ r = hypot(ex - tx * a,
1331
+ ey - ty * b) / q
1332
+
1333
+ sx, tx = tx, min(_1_0, max(0, (ex + qx * r) / a))
1334
+ sy, ty = ty, min(_1_0, max(0, (ey + qy * r) / b))
1335
+ t = hypot(ty, tx)
1336
+ if t < EPS0: # PYCHOK no cover
1337
+ break
1338
+ tx = tx / t # /= chokes PyChecker
1339
+ ty = ty / t
1340
+ if fabs(sx - tx) < eps and \
1341
+ fabs(sy - ty) < eps:
1342
+ break
1343
+
1344
+ tx *= a / px
1345
+ ty *= b / py
1346
+ return tx, ty, i # x and y as fractions
1347
+
1348
+
1311
1349
  def _plumbTo4(x, y, a, b, eps=EPS):
1312
1350
  '''(INTERNAL) Nearest point on and distance to a 2-D ellipse, I{unordered}.
1313
1351
 
1314
- @see: Function C{pygeodesy.ellipsoids._plumbTo3} and I{Eberly}'s U{Distance
1315
- from a Point to ... an Ellipse ...<https://www.GeometricTools.com/
1316
- Documentation/DistancePointEllipseEllipsoid.pdf>}.
1352
+ @see: Function C{_plumbTo3} and I{Eberly}'s U{Distance from a Point to ... an Ellipse ...
1353
+ <https://www.GeometricTools.com/Documentation/DistancePointEllipseEllipsoid.pdf>}.
1317
1354
  '''
1318
1355
  if b > a:
1319
1356
  b, a, d, i = _plumbTo4(y, x, b, a, eps=eps)
pygeodesy/units.py CHANGED
@@ -18,7 +18,7 @@ from pygeodesy.interns import NN, _azimuth_, _band_, _bearing_, _COMMASPACE_, \
18
18
  _NS_, _NSEW_, _number_, _PERCENT_, _phi_, _precision_, \
19
19
  _radians_, _radians2_, _radius_, _S_, _scalar_, \
20
20
  _units_, _W_, _zone_, _std_ # PYCHOK used!
21
- from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
21
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
22
22
  # from pygeodesy.named import _name__ # _MODS
23
23
  from pygeodesy.props import Property_RO
24
24
  # from pygeodesy.streprs import Fmt, fstr # from .unitsBase
@@ -27,7 +27,7 @@ from pygeodesy.unitsBase import Float, Int, _NamedUnit, Radius, Str, Fmt, fstr
27
27
  from math import degrees, isnan, radians
28
28
 
29
29
  __all__ = _ALL_LAZY.units
30
- __version__ = '24.08.13'
30
+ __version__ = '24.11.06'
31
31
 
32
32
 
33
33
  class Float_(Float):
@@ -527,7 +527,7 @@ class FIx(Float_):
527
527
  (C{bool}) or C{None} for backward compatible L{LatLon2Tuple} or
528
528
  B{C{LatLon}} with I{averaged} lat- and longitudes.
529
529
  @kwarg LatLon_or_Vector_and_kwds: Optional C{B{LatLon}=None} I{or} C{B{Vector}=None}
530
- to return the I{intermediate}, I{fractional} point and optional,
530
+ to return the I{intermediate}, I{fractional} point and optionally,
531
531
  additional B{C{LatLon}} I{or} B{C{Vector}} keyword arguments, see
532
532
  function L{fractional<pygeodesy.points.fractional>}.
533
533
 
@@ -858,13 +858,14 @@ def _xlimits(arg, low, high, g=False):
858
858
  def _std_repr(*Classes):
859
859
  '''(INTERNAL) Use standard C{repr} or named C{toRepr}.
860
860
  '''
861
+ from pygeodesy.internals import _getenv
861
862
  for C in Classes:
862
863
  if hasattr(C, _std_repr.__name__): # PYCHOK del _std_repr
863
864
  env = 'PYGEODESY_%s_STD_REPR' % (C.__name__.upper(),)
864
865
  if _getenv(env, _std_).lower() != _std_:
865
866
  C._std_repr = False
866
867
 
867
- _std_repr(Azimuth, Bearing, Bool, Degrees, Float, Int, Meter, Radians, Str) # PYCHOK expected
868
+ _std_repr(Azimuth, Bearing, Bool, Degrees, Epoch, Float, Int, Meter, Radians, Str) # PYCHOK expected
868
869
  del _std_repr
869
870
 
870
871
  __all__ += _ALL_DOCS(_NamedUnit)
pygeodesy/ups.py CHANGED
@@ -28,12 +28,12 @@ from pygeodesy.datums import _ellipsoidal_datum, _WGS84
28
28
  from pygeodesy.dms import degDMS, _neg, parseDMS2
29
29
  from pygeodesy.errors import RangeError, _ValueError, _xkwds_pop2
30
30
  from pygeodesy.fmath import hypot, hypot1, sqrt0
31
- # from pygeodesy.internals import _under # from .named
31
+ from pygeodesy.internals import _getPYGEODESY, _under
32
32
  from pygeodesy.interns import NN, _COMMASPACE_, _inside_, _N_, \
33
33
  _pole_, _range_, _S_, _scale0_, \
34
34
  _SPACE_, _std_, _to_, _UTM_
35
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv
36
- from pygeodesy.named import nameof, _under
35
+ # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
36
+ from pygeodesy.named import nameof, _ALL_LAZY, _MODS
37
37
  from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple, \
38
38
  UtmUps8Tuple, UtmUpsLatLon5Tuple
39
39
  from pygeodesy.props import deprecated_method, property_doc_, \
@@ -49,9 +49,9 @@ from pygeodesy.utmupsBase import Fmt, _LLEB, _hemi, _parseUTMUPS5, _to4lldn, \
49
49
  from math import atan2, fabs, radians, tan
50
50
 
51
51
  __all__ = _ALL_LAZY.ups
52
- __version__ = '24.06.11'
52
+ __version__ = '24.10.14'
53
53
 
54
- _BZ_UPS = _getenv('PYGEODESY_UPS_POLES', _std_) == _std_
54
+ _BZ_UPS = _getPYGEODESY('UPS_POLES', _std_) == _std_
55
55
  _Falsing = Meter(2000e3) # false easting and northing (C{meter})
56
56
  _K0_UPS = Float(_K0_UPS= 0.994) # scale factor at central meridian
57
57
  _K1_UPS = Float(_K1_UPS=_1_0) # rescale point scale factor
@@ -229,7 +229,7 @@ class Ups(UtmUpsBase):
229
229
 
230
230
  r = hypot(x, y)
231
231
  t = (r * E.es_c / (self.scale0 * E.a * _2_0)) if r > 0 else EPS0
232
- t = E.es_tauf((_1_0 / t - t) * _0_5)
232
+ t = E.es_tauf(_0_5 / t - _0_5 * t)
233
233
  a = atan1d(t)
234
234
  if self._pole == _N_:
235
235
  b, g = atan2(x, -y), 1
pygeodesy/utily.py CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  u'''Various utility functions.
5
5
 
6
- After I{(C) Chris Veness 2011-2015} published under the same MIT Licence**, see
6
+ After I{(C) Chris Veness 2011-2024} published under the same MIT Licence**, see
7
7
  U{Latitude/Longitude<https://www.Movable-Type.co.UK/scripts/latlong.html>} and
8
8
  U{Vector-based geodesy<https://www.Movable-Type.co.UK/scripts/latlong-vectors.html>}.
9
9
  '''
@@ -27,7 +27,7 @@ from pygeodesy.units import Degrees, Degrees_, Feet, Float, Lam, Lamd, \
27
27
  from math import acos, asin, atan2, cos, degrees, fabs, radians, sin, tan # pow
28
28
 
29
29
  __all__ = _ALL_LAZY.utily
30
- __version__ = '24.06.15'
30
+ __version__ = '24.10.12'
31
31
 
32
32
  # read constant name "_M_Unit" as "meter per Unit"
33
33
  _M_CHAIN = _F( 20.1168) # yard2m(1) * 22
pygeodesy/utm.py CHANGED
@@ -8,7 +8,7 @@ L{utmZoneBand5}.
8
8
 
9
9
  Pure Python implementation of UTM / WGS-84 conversion functions using
10
10
  an ellipsoidal earth model, transcoded from JavaScript originals by
11
- I{(C) Chris Veness 2011-2016} published under the same MIT Licence**, see
11
+ I{(C) Chris Veness 2011-2024} published under the same MIT Licence**, see
12
12
  U{UTM<https://www.Movable-Type.co.UK/scripts/latlong-utm-mgrs.html>} and
13
13
  U{Module utm<https://www.Movable-Type.co.UK/scripts/geodesy/docs/module-utm.html>}.
14
14
 
@@ -39,7 +39,7 @@ from pygeodesy.datums import _ellipsoidal_datum, _WGS84, _under
39
39
  from pygeodesy.dms import degDMS, parseDMS2
40
40
  from pygeodesy.errors import MGRSError, RangeError, _ValueError, \
41
41
  _xkwds_get, _xkwds_pop2
42
- from pygeodesy.fmath import fdot3, hypot, hypot1, _operator
42
+ from pygeodesy.fmath import fdot_, fdot3, hypot, hypot1, _operator
43
43
  # from pygeodesy.internals import _under # from .datums
44
44
  from pygeodesy.interns import MISSING, NN, _by_, _COMMASPACE_, _N_, \
45
45
  _NS_, _outside_, _range_, _S_, _scale0_, \
@@ -63,7 +63,7 @@ from math import asinh, atanh, atan2, cos, cosh, degrees, fabs, \
63
63
  # import operator as _operator # from .fmath
64
64
 
65
65
  __all__ = _ALL_LAZY.utm
66
- __version__ = '24.06.11'
66
+ __version__ = '24.11.07'
67
67
 
68
68
  _Bands = 'CDEFGHJKLMNPQRSTUVWXX' # UTM latitude bands C..X (no
69
69
  # I|O) 8° each, covering 80°S to 84°N and X repeated for 80-84°N
@@ -566,12 +566,12 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
566
566
  # easting, northing: Karney 2011 Eq 7-14, 29, 35
567
567
  sb, cb = sincos2(b)
568
568
 
569
- T = tan(a)
569
+ T = tan(a)
570
570
  T12 = hypot1(T)
571
- S = sinh(E.e * atanh(E.e * T / T12))
571
+ S = sinh(E.e * atanh(E.e * T / T12))
572
572
 
573
- T_ = T * hypot1(S) - S * T12
574
- H = hypot(T_, cb)
573
+ T_ = fdot_(T, hypot1(S), -S, T12)
574
+ H = hypot(T_, cb)
575
575
 
576
576
  y = atan2(T_, cb) # ξ' ksi
577
577
  x = asinh(sb / H) # η' eta