pygeodesy 24.10.24__py2.py3-none-any.whl → 24.12.12__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.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/METADATA +6 -6
  2. PyGeodesy-24.12.12.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +5 -5
  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 +55 -65
  19. pygeodesy/basics.py +35 -34
  20. pygeodesy/booleans.py +37 -37
  21. pygeodesy/cartesianBase.py +26 -65
  22. pygeodesy/clipy.py +1 -1
  23. pygeodesy/constants.py +7 -7
  24. pygeodesy/css.py +8 -9
  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 +10 -10
  29. pygeodesy/deprecated/consterns.py +1 -1
  30. pygeodesy/deprecated/datum.py +1 -1
  31. pygeodesy/deprecated/functions.py +23 -13
  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 +63 -69
  39. pygeodesy/elevations.py +1 -1
  40. pygeodesy/ellipsoidalBase.py +106 -121
  41. pygeodesy/ellipsoidalBaseDI.py +115 -119
  42. pygeodesy/ellipsoidalExact.py +36 -38
  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 +7 -8
  48. pygeodesy/elliptic.py +6 -6
  49. pygeodesy/epsg.py +1 -1
  50. pygeodesy/errors.py +25 -25
  51. pygeodesy/etm.py +84 -76
  52. pygeodesy/fmath.py +54 -51
  53. pygeodesy/formy.py +74 -106
  54. pygeodesy/frechet.py +1 -1
  55. pygeodesy/fstats.py +1 -1
  56. pygeodesy/fsums.py +82 -72
  57. pygeodesy/gars.py +1 -1
  58. pygeodesy/geodesici.py +4 -4
  59. pygeodesy/geodesicw.py +16 -15
  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 +3 -3
  64. pygeodesy/geodesicx/__main__.py +1 -1
  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 +8 -17
  70. pygeodesy/geohash.py +1 -1
  71. pygeodesy/geoids.py +6 -6
  72. pygeodesy/hausdorff.py +1 -1
  73. pygeodesy/heights.py +3 -3
  74. pygeodesy/internals.py +64 -80
  75. pygeodesy/interns.py +2 -3
  76. pygeodesy/iters.py +1 -1
  77. pygeodesy/karney.py +4 -4
  78. pygeodesy/ktm.py +20 -21
  79. pygeodesy/latlonBase.py +296 -346
  80. pygeodesy/lazily.py +15 -15
  81. pygeodesy/lcc.py +5 -5
  82. pygeodesy/ltp.py +55 -59
  83. pygeodesy/ltpTuples.py +208 -192
  84. pygeodesy/mgrs.py +9 -10
  85. pygeodesy/named.py +153 -3
  86. pygeodesy/namedTuples.py +58 -7
  87. pygeodesy/nvectorBase.py +122 -105
  88. pygeodesy/osgr.py +10 -13
  89. pygeodesy/points.py +1 -1
  90. pygeodesy/props.py +3 -3
  91. pygeodesy/resections.py +26 -26
  92. pygeodesy/rhumb/__init__.py +2 -2
  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 +4 -4
  97. pygeodesy/simplify.py +291 -403
  98. pygeodesy/solveBase.py +1 -1
  99. pygeodesy/sphericalBase.py +1 -1
  100. pygeodesy/sphericalNvector.py +84 -127
  101. pygeodesy/sphericalTrigonometry.py +66 -71
  102. pygeodesy/streprs.py +10 -5
  103. pygeodesy/trf.py +1 -1
  104. pygeodesy/triaxials.py +23 -16
  105. pygeodesy/units.py +17 -17
  106. pygeodesy/unitsBase.py +1 -1
  107. pygeodesy/ups.py +4 -4
  108. pygeodesy/utily.py +202 -145
  109. pygeodesy/utm.py +10 -10
  110. pygeodesy/utmups.py +1 -1
  111. pygeodesy/utmupsBase.py +1 -1
  112. pygeodesy/vector2d.py +17 -17
  113. pygeodesy/vector3d.py +32 -23
  114. pygeodesy/vector3dBase.py +22 -19
  115. pygeodesy/webmercator.py +5 -5
  116. pygeodesy/wgrs.py +5 -5
  117. PyGeodesy-24.10.24.dist-info/RECORD +0 -118
  118. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/top_level.txt +0 -0
@@ -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, \
@@ -46,15 +46,16 @@ from pygeodesy.sphericalBase import _m2radians, CartesianSphericalBase, \
46
46
  # from pygeodesy.streprs import Fmt as _Fmt # from .points XXX shadowed
47
47
  from pygeodesy.units import Bearing_, Height, _isDegrees, _isRadius, Lamd, \
48
48
  Phid, Radius_, Scalar
49
- from pygeodesy.utily import acos1, asin1, atan1d, atan2d, degrees90, degrees180, \
50
- degrees2m, m2radians, radiansPI2, sincos2_, tan_2, \
51
- unrollPI, _unrollon, _unrollon3, _Wrap, wrap180, wrapPI
49
+ from pygeodesy.utily import acos1, asin1, atan1d, atan2, atan2d, degrees90, \
50
+ degrees180, degrees2m, m2radians, radiansPI2, \
51
+ sincos2_, tan_2, unrollPI, _unrollon, _unrollon3, \
52
+ wrap180, wrapPI, _Wrap
52
53
  from pygeodesy.vector3d import sumOf, Vector3d
53
54
 
54
- from math import asin, atan2, cos, degrees, fabs, radians, sin
55
+ from math import asin, cos, degrees, fabs, radians, sin
55
56
 
56
57
  __all__ = _ALL_LAZY.sphericalTrigonometry
57
- __version__ = '24.10.12'
58
+ __version__ = '24.11.24'
58
59
 
59
60
  _PI_EPS4 = PI - EPS4
60
61
  if _PI_EPS4 >= PI:
@@ -182,8 +183,8 @@ class LatLon(LatLonSphericalBase):
182
183
  return degrees180(m - d), degrees180(m + d)
183
184
 
184
185
  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.
186
+ '''Compute the (signed) distance from this point to a great
187
+ circle from a start to an end point.
187
188
 
188
189
  @arg start: Start point of the great circle line (L{LatLon}).
189
190
  @arg end: End point of the great circle line (L{LatLon}).
@@ -205,7 +206,7 @@ class LatLon(LatLonSphericalBase):
205
206
 
206
207
  def destination(self, distance, bearing, radius=R_M, height=None):
207
208
  '''Locate the destination from this point after having
208
- travelled the given distance on the given initial bearing.
209
+ travelled the given distance on a bearing from North.
209
210
 
210
211
  @arg distance: Distance travelled (C{meter}, same units as
211
212
  B{C{radius}}).
@@ -253,7 +254,7 @@ class LatLon(LatLonSphericalBase):
253
254
 
254
255
  def greatCircle(self, bearing, Vector=Vector3d, **Vector_kwds):
255
256
  '''Compute the vector normal to great circle obtained by heading
256
- on the given initial bearing from this point.
257
+ from this point on the bearing from North.
257
258
 
258
259
  Direction of vector is such that initial bearing vector
259
260
  b = c × n, where n is an n-vector representing this point.
@@ -271,8 +272,9 @@ class LatLon(LatLonSphericalBase):
271
272
  a, b = self.philam
272
273
  sa, ca, sb, cb, st, ct = sincos2_(a, b, Bearing_(bearing))
273
274
 
274
- return Vector(sb * ct - cb * sa * st,
275
- -cb * ct - sb * sa * st,
275
+ sa *= st
276
+ return Vector(fdot_(sb, ct, -cb, sa),
277
+ -fdot_(cb, ct, sb, sa),
276
278
  ca * st, **Vector_kwds) # XXX .unit()?
277
279
 
278
280
  def initialBearingTo(self, other, wrap=False, raiser=False):
@@ -341,9 +343,9 @@ class LatLon(LatLonSphericalBase):
341
343
  a = sin(r - t) # / sr superflous
342
344
  b = sin( t) # / sr superflous
343
345
 
344
- x = a * ca1 * cb1 + b * ca2 * cb2
345
- y = a * ca1 * sb1 + b * ca2 * sb2
346
- z = a * sa1 + b * sa2
346
+ x = fdot_(a, ca1 * cb1, b, ca2 * cb2)
347
+ y = fdot_(a, ca1 * sb1, b, ca2 * sb2)
348
+ z = fdot_(a, sa1, b, sa2)
347
349
 
348
350
  a = atan1d(z, hypot(x, y))
349
351
  b = atan2d(y, x)
@@ -358,7 +360,7 @@ class LatLon(LatLonSphericalBase):
358
360
 
359
361
  def intersection(self, end1, other, end2, height=None, wrap=False):
360
362
  '''Compute the intersection point of two lines, each defined by
361
- two points or a start point and bearing from North.
363
+ two points or a start point and a bearing from North.
362
364
 
363
365
  @arg end1: End point of this line (L{LatLon}) or the initial
364
366
  bearing at this point (compass C{degrees360}).
@@ -395,7 +397,7 @@ class LatLon(LatLonSphericalBase):
395
397
  def intersections2(self, rad1, other, rad2, radius=R_M, eps=_0_0,
396
398
  height=None, wrap=True):
397
399
  '''Compute the intersection points of two circles, each defined
398
- by a center point and radius.
400
+ by a center point and a radius.
399
401
 
400
402
  @arg rad1: Radius of the this circle (C{meter} or C{radians},
401
403
  see B{C{radius}}).
@@ -536,7 +538,7 @@ class LatLon(LatLonSphericalBase):
536
538
  return r
537
539
 
538
540
  def nearestOn(self, point1, point2, radius=R_M, **wrap_adjust_limit):
539
- '''Locate the point between two points closest to this point.
541
+ '''Locate the point between two other points closest to this point.
540
542
 
541
543
  Distances are approximated by function L{pygeodesy.equirectangular4},
542
544
  subject to the supplied B{C{options}}.
@@ -679,8 +681,8 @@ class LatLon(LatLonSphericalBase):
679
681
  return self._xnamed(_t7Tuple(t, radius))
680
682
 
681
683
  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.
684
+ '''Locate a point given this, an other point and a bearing from
685
+ North at both points.
684
686
 
685
687
  @arg bearing1: Bearing at this point (compass C{degrees360}).
686
688
  @arg other: The other point (C{LatLon}).
@@ -755,8 +757,8 @@ _T00 = LatLon(0, 0, name='T00') # reference instance (L{LatLon})
755
757
 
756
758
 
757
759
  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).
760
+ '''Calculate the area of a (spherical) polygon or composite (with the
761
+ points joined by great circle arcs).
760
762
 
761
763
  @arg points: The polygon points or clips (L{LatLon}[], L{BooleanFHP}
762
764
  or L{BooleanGH}).
@@ -868,8 +870,8 @@ def _int3d2(s, end, wrap, _i_, Vector, hs):
868
870
  -(b1 + b2) * _0_5)
869
871
  cb21 *= sin(a1 - a2) # sa21
870
872
  sb21 *= sin(a1 + a2) # sa12
871
- x = Vector(sb12 * cb21 - cb12 * sb21,
872
- cb12 * cb21 + sb12 * sb21,
873
+ x = Vector(fdot_(sb12, cb21, -cb12, sb21),
874
+ fdot_(cb12, cb21, sb12, sb21),
873
875
  cos(a1) * cos(a2) * sin(db)) # ll=start
874
876
  return x.unit(), (db, (a2 - a1)) # negated d
875
877
 
@@ -882,7 +884,7 @@ def _intdot(ds, a1, b1, a, b, wrap):
882
884
 
883
885
  def intersecant2(center, circle, point, other, **radius_exact_height_wrap):
884
886
  '''Compute the intersections of a circle and a (great circle) line given as
885
- two points or as a point and bearing.
887
+ two points or as a point and a bearing from North.
886
888
 
887
889
  @arg center: Center of the circle (L{LatLon}).
888
890
  @arg circle: Radius of the circle (C{meter}, same units as the earth
@@ -916,7 +918,7 @@ def intersecant2(center, circle, point, other, **radius_exact_height_wrap):
916
918
 
917
919
 
918
920
  def _intersect(start1, end1, start2, end2, height=None, wrap=False, # in.ellipsoidalBaseDI._intersect3
919
- LatLon=None, **LatLon_kwds):
921
+ LatLon=LatLon, **LatLon_kwds):
920
922
  # (INTERNAL) Intersect two (spherical) lines, see L{intersection}
921
923
  # above, separated to allow callers to embellish any exceptions
922
924
 
@@ -984,75 +986,68 @@ def _intersect(start1, end1, start2, end2, height=None, wrap=False, # in.ellips
984
986
 
985
987
 
986
988
  def intersection(start1, end1, start2, end2, height=None, wrap=False,
987
- LatLon=LatLon, **LatLon_kwds):
988
- '''Compute the intersection point of two lines, each defined
989
- by two points or a start point and bearing from North.
989
+ **LatLon_and_kwds):
990
+ '''Compute the intersection point of two lines, each defined by
991
+ two points or by a start point and a bearing from North.
990
992
 
991
993
  @arg start1: Start point of the first line (L{LatLon}).
992
- @arg end1: End point of the first line (L{LatLon}) or
993
- the initial bearing at the first start point
994
- (compass C{degrees360}).
994
+ @arg end1: End point of the first line (L{LatLon}) or the bearing
995
+ at the first start point (compass C{degrees360}).
995
996
  @arg start2: Start point of the second line (L{LatLon}).
996
- @arg end2: End point of the second line (L{LatLon}) or
997
- the initial bearing at the second start point
998
- (compass C{degrees360}).
997
+ @arg end2: End point of the second line (L{LatLon}) or the bearing
998
+ at the second start point (compass C{degrees360}).
999
999
  @kwarg height: Optional height for the intersection point,
1000
1000
  overriding the mean height (C{meter}).
1001
- @kwarg wrap: If C{True}, wrap or I{normalize} and unroll
1002
- B{C{start2}} and both B{C{end*}} points (C{bool}).
1003
- @kwarg LatLon: Optional class to return the intersection
1004
- point (L{LatLon}) or C{None}.
1005
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1006
- arguments, ignored if C{B{LatLon} is None}.
1001
+ @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{start2}}
1002
+ and both B{C{end*}} points (C{bool}).
1003
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to use
1004
+ for the intersection point and optionally additional
1005
+ B{C{LatLon}} keyword arguments, ignored if C{B{LatLon}
1006
+ is None}.
1007
1007
 
1008
- @return: The intersection point as a (B{C{LatLon}}) or if
1009
- C{B{LatLon} is None} a L{LatLon3Tuple}C{(lat, lon,
1010
- height)}. An alternate intersection point might
1011
- be the L{antipode} to the returned result.
1008
+ @return: The intersection point as a (B{C{LatLon}}) or if C{B{LatLon}
1009
+ is None} a L{LatLon3Tuple}C{(lat, lon, height)}. An alternate
1010
+ intersection point might be the L{antipode} to the returned result.
1012
1011
 
1013
- @raise IntersectionError: Ambiguous or infinite intersection
1014
- or colinear, parallel or otherwise
1015
- non-intersecting lines.
1012
+ @raise IntersectionError: Ambiguous or infinite intersection or colinear,
1013
+ parallel or otherwise non-intersecting lines.
1016
1014
 
1017
- @raise TypeError: A B{C{start1}}, B{C{end1}}, B{C{start2}}
1018
- or B{C{end2}} point not L{LatLon}.
1015
+ @raise TypeError: A B{C{start1}}, B{C{end1}}, B{C{start2}} or B{C{end2}}
1016
+ point not L{LatLon}.
1019
1017
 
1020
1018
  @raise ValueError: Invalid B{C{height}} or C{null} line.
1021
1019
  '''
1022
1020
  s1 = _T00.others(start1=start1)
1023
1021
  s2 = _T00.others(start2=start2)
1024
1022
  try:
1025
- return _intersect(s1, end1, s2, end2, height=height, wrap=wrap,
1026
- LatLon=LatLon, **LatLon_kwds)
1023
+ return _intersect(s1, end1, s2, end2, height=height, wrap=wrap, **LatLon_and_kwds)
1027
1024
  except (TypeError, ValueError) as x:
1028
1025
  raise _xError(x, start1=start1, end1=end1, start2=start2, end2=end2)
1029
1026
 
1030
1027
 
1031
1028
  def intersections2(center1, rad1, center2, rad2, radius=R_M, eps=_0_0,
1032
1029
  height=None, wrap=False, # was=True
1033
- LatLon=LatLon, **LatLon_kwds):
1034
- '''Compute the intersection points of two circles each defined
1035
- by a center point and a radius.
1030
+ **LatLon_and_kwds):
1031
+ '''Compute the intersection points of two circles each defined by a
1032
+ center point and a radius.
1036
1033
 
1037
1034
  @arg center1: Center of the first circle (L{LatLon}).
1038
- @arg rad1: Radius of the first circle (C{meter} or C{radians},
1039
- see B{C{radius}}).
1035
+ @arg rad1: Radius of the first circle (C{meter} or C{radians}, see
1036
+ B{C{radius}}).
1040
1037
  @arg center2: Center of the second circle (L{LatLon}).
1041
- @arg rad2: Radius of the second circle (C{meter} or C{radians},
1042
- see B{C{radius}}).
1038
+ @arg rad2: Radius of the second circle (C{meter} or C{radians}, see
1039
+ B{C{radius}}).
1043
1040
  @kwarg radius: Mean earth radius (C{meter} or C{None} if B{C{rad1}},
1044
1041
  B{C{rad2}} and B{C{eps}} are given in C{radians}).
1045
- @kwarg eps: Required overlap (C{meter} or C{radians}, see
1046
- B{C{radius}}).
1042
+ @kwarg eps: Required overlap (C{meter} or C{radians}, see B{C{radius}}).
1047
1043
  @kwarg height: Optional height for the intersection points (C{meter},
1048
1044
  conventionally) or C{None} for the I{"radical height"}
1049
1045
  at the I{radical line} between both centers.
1050
1046
  @kwarg wrap: If C{True}, wrap or I{normalize} and unroll B{C{center2}}
1051
1047
  (C{bool}).
1052
- @kwarg LatLon: Optional class to return the intersection
1053
- points (L{LatLon}) or C{None}.
1054
- @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1055
- arguments, ignored if C{B{LatLon} is None}.
1048
+ @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=}L{LatLon} to use for
1049
+ the intersection points and optionally additional B{C{LatLon}}
1050
+ keyword arguments, ignored if C{B{LatLon} is None}.
1056
1051
 
1057
1052
  @return: 2-Tuple of the intersection points, each a B{C{LatLon}}
1058
1053
  instance or if C{B{LatLon} is None} a L{LatLon3Tuple}C{(lat,
@@ -1077,7 +1072,7 @@ def intersections2(center1, rad1, center2, rad2, radius=R_M, eps=_0_0,
1077
1072
  try:
1078
1073
  return _intersects2(c1, rad1, c2, rad2, radius=radius, eps=eps,
1079
1074
  height=height, wrap=wrap,
1080
- LatLon=LatLon, **LatLon_kwds)
1075
+ **LatLon_and_kwds)
1081
1076
  except (TypeError, ValueError) as x:
1082
1077
  raise _xError(x, center1=center1, rad1=rad1,
1083
1078
  center2=center2, rad2=rad2, wrap=wrap)
@@ -1226,7 +1221,7 @@ def nearestOn3(point, points, closed=False, radius=R_M, wrap=False, adjust=True,
1226
1221
  (C{degrees}), default C{9 degrees} is about C{1,000 Km} (for
1227
1222
  (mean spherical earth radius L{R_KM}).
1228
1223
  @kwarg LatLon_and_kwds: Optional class C{B{LatLon}=L{LatLon}} to return the
1229
- closest point and optional, additional C{B{LatLon}} keyword
1224
+ closest point and optionally additional C{B{LatLon}} keyword
1230
1225
  arguments or specify C{B{LatLon}=None}.
1231
1226
 
1232
1227
  @return: A L{NearestOn3Tuple}C{(closest, distance, angle)} with the
@@ -1331,9 +1326,9 @@ def triangle7(latA, lonA, latB, lonB, latC, lonC, radius=R_M,
1331
1326
  C{a}, C{b} and C{c} all in C{degrees} and C{area}
1332
1327
  in I{square} C{meter} or same units as B{C{radius}}
1333
1328
  I{squared} or if C{B{radius}=0} or C{None}, a
1334
- L{Triangle8Tuple}C{(A, a, B, b, C, c, D, E)} all in
1335
- C{radians} with the I{spherical excess} C{E} as the
1336
- C{unit area} in C{radians}.
1329
+ L{Triangle8Tuple}C{(A, a, B, b, C, c, D, E)} with
1330
+ I{spherical deficit} C{D} and I{spherical excess}
1331
+ C{E} as the C{unit area}, all in C{radians}.
1337
1332
  '''
1338
1333
  t = triangle8_(Phid(latA=latA), Lamd(lonA=lonA),
1339
1334
  Phid(latB=latB), Lamd(lonB=lonB),
@@ -1415,7 +1410,7 @@ __all__ += _ALL_OTHER(Cartesian, LatLon, # classes
1415
1410
 
1416
1411
  # **) MIT License
1417
1412
  #
1418
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1413
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1419
1414
  #
1420
1415
  # Permission is hereby granted, free of charge, to any person obtaining a
1421
1416
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/streprs.py CHANGED
@@ -14,19 +14,20 @@ 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_, \
16
16
  _STAR_, _UNDER_
17
- from pygeodesy.interns import _convergence_, _distant_, _e_, _eps_, _exceeds_, \
18
- _EQUALSPACED_, _f_, _F_, _g_, _limit_, _no_, \
19
- _tolerance_ # PYCHOK used!
17
+ from pygeodesy.interns import _convergence_, _distant_, _e_, _exceeds_, \
18
+ _EQUALSPACED_, _f_, _F_, _g_, _limit_, \
19
+ _no_, _tolerance_ # PYCHOK used!
20
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.14'
25
+ __version__ = '24.11.26'
26
26
 
27
27
  _at_ = 'at' # PYCHOK used!
28
28
  _EN_PREC = 6 # max MGRS/OSGR precision, 1 micrometer
29
29
  _EN_WIDE = 5 # number of MGRS/OSGR units, log10(_100km)
30
+ _eps_ = 'eps' # PYCHOK used!
30
31
  _OKd_ = '._-' # acceptable name characters
31
32
  _PAREN_g = '(%g)' # PYCHOK used!
32
33
  _RESIDUAL_ = 'RESIDUAL' # PYCHOK used!
@@ -191,6 +192,9 @@ _Gg = (Fmt.G, Fmt.g)
191
192
  _FfEeGg = (Fmt.F, Fmt.f, Fmt.E, Fmt.e) + _Gg # float formats
192
193
  _Fspec_ = NN('[%[<flags>][<width>]', _DOTSTAR_, ']', _BAR_.join(_FfEeGg)) # in testStreprs
193
194
 
195
+ del _convergence_, _distant_, _e_, _eps_, _exceeds_, _EQUALSPACED_,\
196
+ _f_, _F_, _g_, _limit_, _PAREN_g, _RESIDUAL_
197
+
194
198
 
195
199
  def anstr(name, OKd=_OKd_, sub=_UNDER_):
196
200
  '''Make a valid name of alphanumeric and OKd characters.
@@ -598,9 +602,10 @@ def _xzipairs(names, values, sep=_COMMASPACE_, fmt=NN, pair_fmt=Fmt.COLON):
598
602
  raise _ValueError(names=names, values=values, cause=x)
599
603
  return (fmt % (t,)) if fmt else t # enc
600
604
 
605
+
601
606
  # **) MIT License
602
607
  #
603
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
608
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
604
609
  #
605
610
  # Permission is hereby granted, free of charge, to any person obtaining a
606
611
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/trf.py CHANGED
@@ -1784,7 +1784,7 @@ if __name__ == '__main__':
1784
1784
 
1785
1785
  # **) MIT License
1786
1786
  #
1787
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1787
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1788
1788
  #
1789
1789
  # Permission is hereby granted, free of charge, to any person obtaining a
1790
1790
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/triaxials.py CHANGED
@@ -7,7 +7,7 @@ I{Charles Karney}'s C++ class U{JacobiConformal<https://GeographicLib.SourceForg
7
7
  classGeographicLib_1_1JacobiConformal.html#details>} to pure Python and miscellaneous classes
8
8
  L{BetaOmega2Tuple}, L{BetaOmega3Tuple}, L{Jacobi2Tuple} and L{TriaxialError}.
9
9
 
10
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2008-2023). For more information,
10
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2008-2024). For more information,
11
11
  see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
12
12
 
13
13
  @see: U{Geodesics on a triaxial ellipsoid<https://WikiPedia.org/wiki/Geodesics_on_an_ellipsoid#
@@ -53,13 +53,13 @@ from pygeodesy.props import Property_RO, property_ROver
53
53
  # from pygeodesy.streprs import Fmt # from .datums
54
54
  from pygeodesy.units import Degrees, Float, Height_, Meter, Meter2, Meter3, \
55
55
  Radians, Radius, Scalar_
56
- from pygeodesy.utily import asin1, atan2d, km2m, m2km, SinCos2, sincos2d_
56
+ from pygeodesy.utily import asin1, atan2, atan2d, km2m, m2km, SinCos2, sincos2d_
57
57
  from pygeodesy.vector3d import _otherV3d, Vector3d, _ALL_LAZY, _MODS
58
58
 
59
- from math import atan2, fabs, sqrt
59
+ from math import fabs, sqrt
60
60
 
61
61
  __all__ = _ALL_LAZY.triaxials
62
- __version__ = '24.10.15'
62
+ __version__ = '24.11.24'
63
63
 
64
64
  _not_ordered_ = _not_('ordered')
65
65
  _omega_ = 'omega'
@@ -213,7 +213,7 @@ class Triaxial_(_NamedEnumItem):
213
213
  C{meter}) or an other L{Triaxial} or L{Triaxial_} instance.
214
214
  @kwarg b: Middle, C{Y} semi-axis (C{meter}, same units as B{C{a}}), required
215
215
  if C{B{a_triaxial} is scalar}, ignored otherwise.
216
- @kwarg c: Small, C{Z} semi-axis (C{meter}, B{C{b}}).
216
+ @kwarg c: Small, C{Z} semi-axis (C{meter}, like B{C{b}}).
217
217
  @kwarg name: Optional C{B{name}=NN} (C{str}).
218
218
 
219
219
  @raise TriaxialError: Invalid semi-axis or -axes.
@@ -396,8 +396,10 @@ class Triaxial_(_NamedEnumItem):
396
396
  @raise TriaxialError: Non-cartesian B{C{xyz}}, invalid B{C{eps}}, no convergence in
397
397
  root finding or validation failed.
398
398
 
399
- @see: Methods L{Triaxial.normal3d} and L{Ellipsoid.height4} and I{Eberly}'s U{Distance from a
400
- Point to ...<https://www.GeometricTools.com/Documentation/DistancePointEllipseEllipsoid.pdf>}.
399
+ @see: Methods L{Triaxial.normal3d} and L{Ellipsoid.height4}, I{Eberly}'s U{Distance from a Point to ...
400
+ <https://www.GeometricTools.com/Documentation/DistancePointEllipseEllipsoid.pdf>} and I{Bektas}'
401
+ U{Shortest Distance from a Point to Triaxial Ellipsoid<https://www.ResearchGate.net/publication/
402
+ 272149005_SHORTEST_DISTANCE_FROM_A_POINT_TO_TRIAXIAL_ELLIPSOID>}.
401
403
  '''
402
404
  v, r = _otherV3d_(x_xyz, y, z), self.isSpherical
403
405
 
@@ -420,7 +422,7 @@ class Triaxial_(_NamedEnumItem):
420
422
  raise TriaxialError(x=x, y=y, z=z, cause=e)
421
423
  if h > 0 and self.sideOf(v, eps=EPS0) < 0:
422
424
  h = -h # inside
423
- n = _name__(name, name__=self.height4)
425
+ n = _name__(name, name__=self.height4) # _DUNDER_nameof
424
426
  return Vector4Tuple(x, y, z, h, iteration=i, name=n)
425
427
 
426
428
  @Property_RO
@@ -863,7 +865,8 @@ class Triaxial(Triaxial_):
863
865
  return BetaOmega3Tuple(Radians(beta=a), Radians(omega=b), h, **name)
864
866
 
865
867
  def reverseCartesian(self, x_xyz, y=None, z=None, h=0, normal=True, eps=_EPS2e4, **name):
866
- '''"Unproject" a cartesian on to a cartesion I{off} this triaxial's surface.
868
+ '''Unproject" a cartesian I{on} this triaxial's surface to a cartesion I{off}
869
+ this triaxial's surface.
867
870
 
868
871
  @arg x_xyz: X component (C{scalar}) or a cartesian (C{Cartesian},
869
872
  L{Ecef9Tuple}, L{Vector3d}, L{Vector3Tuple} or L{Vector4Tuple}).
@@ -871,7 +874,7 @@ class Triaxial(Triaxial_):
871
874
  ignored otherwise.
872
875
  @kwarg z: Z component (C{scalar}), like B{C{y}}.
873
876
  @arg h: Height above or below this triaxial's surface (C{meter}, same units
874
- as the axes).
877
+ as this triaxial's axes).
875
878
  @kwarg normal: If C{True}, the height is C{normal} to the surface, otherwise
876
879
  C{radially} to the center of this triaxial (C{bool}).
877
880
  @kwarg eps: Tolerance for on-surface test (C{scalar}), see method L{Triaxial.sideOf}.
@@ -941,7 +944,7 @@ class JacobiConformal(Triaxial):
941
944
  by C{sqrt(B{a}**2 - B{c}**2) / (2 * B{b})} so that the customary results are
942
945
  returned in the case of an ellipsoid of revolution.
943
946
 
944
- Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2023) and
947
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2024) and
945
948
  licensed under the MIT/X11 License.
946
949
 
947
950
  @note: This constructor can I{not be used to specify a sphere}, see alternate
@@ -1278,8 +1281,8 @@ def hartzell4(pov, los=False, tri_biax=_WGS84, **name):
1278
1281
  v, h, i = _hartzell3(pov, los, T)
1279
1282
  except Exception as x:
1280
1283
  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
1282
- name=_name__(name, name__=hartzell4))
1284
+ n = _name__(name, name__=hartzell4) # _DUNDER_nameof
1285
+ return Vector4Tuple(v.x, v.y, v.z, h, iteration=i, name=n)
1283
1286
 
1284
1287
 
1285
1288
  def _hypot2_1(x, y, z=0):
@@ -1319,8 +1322,8 @@ def _plumbTo3(px, py, E, eps=EPS): # in .ellipsoids.Ellipsoid.height4
1319
1322
  b2 = b - a * E.a_b
1320
1323
  tx = ty = _SQRT2_2
1321
1324
  for i in range(16): # max 5
1322
- ex = a2 * tx**3
1323
- ey = b2 * ty**3
1325
+ ex = tx**3 * a2
1326
+ ey = ty**3 * b2
1324
1327
 
1325
1328
  qx = px - ex
1326
1329
  qy = py - ey
@@ -1529,13 +1532,17 @@ if __name__ == '__main__':
1529
1532
  from pygeodesy import printf
1530
1533
  from pygeodesy.interns import _COMMA_, _NL_, _NLATvar_
1531
1534
 
1535
+ t = Triaxial_(6378388.0, 6378318.0, 6356911.9461)
1536
+ t = t.height4(3909863.9271, 3909778.123, 3170932.5016)
1537
+ printf('# Bektas: %r', t)
1538
+
1532
1539
  # __doc__ of this file, force all into registery
1533
1540
  t = [NN] + Triaxials.toRepr(all=True, asorted=True).split(_NL_)
1534
1541
  printf(_NLATvar_.join(i.strip(_COMMA_) for i in t))
1535
1542
 
1536
1543
  # **) MIT License
1537
1544
  #
1538
- # Copyright (C) 2022-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1545
+ # Copyright (C) 2022-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1539
1546
  #
1540
1547
  # Permission is hereby granted, free of charge, to any person obtaining a
1541
1548
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/units.py CHANGED
@@ -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.10.12'
30
+ __version__ = '24.11.14'
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
 
@@ -798,36 +798,36 @@ class Zone(Int):
798
798
  return Int_.__new__(cls, arg=arg, name=name, **Error_name_arg)
799
799
 
800
800
 
801
- _ScalarU = Float, Float_, Scalar, Scalar_
802
- _Degrees = (Azimuth, Bearing, Bearing_, Degrees, Degrees_) + _ScalarU
803
- _Meters = (Distance, Distance_, Meter, Meter_) + _ScalarU
804
- _Radians = (Radians, Radians_) + _ScalarU # PYCHOK unused
801
+ _Degrees = (Azimuth, Bearing, Bearing_, Degrees, Degrees_)
802
+ _Meters = (Distance, Distance_, Meter, Meter_)
803
+ _Radians = (Radians, Radians_) # PYCHOK unused
805
804
  _Radii = _Meters + (Radius, Radius_)
805
+ _ScalarU = Float, Float_, Scalar, Scalar_
806
806
 
807
807
 
808
- def _isDegrees(obj):
808
+ def _isDegrees(obj, iscalar=True):
809
809
  # Check for valid degrees types.
810
- return isinstance(obj, _Degrees) or _isScalar(obj)
810
+ return isinstance(obj, _Degrees) or (iscalar and _isScalar(obj))
811
811
 
812
812
 
813
- def _isHeight(obj):
813
+ def _isHeight(obj, iscalar=True):
814
814
  # Check for valid height types.
815
- return isinstance(obj, _Meters) or _isScalar(obj)
815
+ return isinstance(obj, _Meters) or (iscalar and _isScalar(obj))
816
816
 
817
817
 
818
- def _isMeter(obj):
818
+ def _isMeter(obj, iscalar=True):
819
819
  # Check for valid meter types.
820
- return isinstance(obj, _Meters) or _isScalar(obj)
820
+ return isinstance(obj, _Meters) or (iscalar and _isScalar(obj))
821
821
 
822
822
 
823
- def _isRadius(obj):
823
+ def _isRadius(obj, iscalar=True):
824
824
  # Check for valid earth radius types.
825
- return isinstance(obj, _Radii) or _isScalar(obj)
825
+ return isinstance(obj, _Radii) or (iscalar and _isScalar(obj))
826
826
 
827
827
 
828
- def _isScalar(obj):
828
+ def _isScalar(obj, iscalar=True):
829
829
  # Check for pure scalar types.
830
- return isscalar(obj) and not isinstance(obj, _NamedUnit)
830
+ return isinstance(obj, _ScalarU) or (iscalar and isscalar(obj) and not isinstance(obj, _NamedUnit))
831
831
 
832
832
 
833
833
  def _toUnit(Unit, arg, name=NN, **Error):
@@ -872,7 +872,7 @@ __all__ += _ALL_DOCS(_NamedUnit)
872
872
 
873
873
  # **) MIT License
874
874
  #
875
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
875
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
876
876
  #
877
877
  # Permission is hereby granted, free of charge, to any person obtaining a
878
878
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/unitsBase.py CHANGED
@@ -349,7 +349,7 @@ __all__ += _ALL_DOCS(_NamedUnit)
349
349
 
350
350
  # **) MIT License
351
351
  #
352
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
352
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
353
353
  #
354
354
  # Permission is hereby granted, free of charge, to any person obtaining a
355
355
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/ups.py CHANGED
@@ -40,16 +40,16 @@ from pygeodesy.props import deprecated_method, property_doc_, \
40
40
  Property_RO, _update_all
41
41
  # from pygeodesy.streprs import Fmt # from .utmupsBase
42
42
  from pygeodesy.units import Float, Float_, Meter, Lat
43
- from pygeodesy.utily import atan1d, degrees180, sincos2d
43
+ from pygeodesy.utily import atan1d, atan2, degrees180, sincos2d
44
44
  from pygeodesy.utmupsBase import Fmt, _LLEB, _hemi, _parseUTMUPS5, _to4lldn, \
45
45
  _to3zBhp, _to3zll, _UPS_BANDS as _Bands, \
46
46
  _UPS_LAT_MAX, _UPS_LAT_MIN, _UPS_ZONE, \
47
47
  _UPS_ZONE_STR, UtmUpsBase
48
48
 
49
- from math import atan2, fabs, radians, tan
49
+ from math import fabs, radians, tan # as _tan
50
50
 
51
51
  __all__ = _ALL_LAZY.ups
52
- __version__ = '24.10.14'
52
+ __version__ = '24.11.26'
53
53
 
54
54
  _BZ_UPS = _getPYGEODESY('UPS_POLES', _std_) == _std_
55
55
  _Falsing = Meter(2000e3) # false easting and northing (C{meter})
@@ -509,7 +509,7 @@ def upsZoneBand5(lat, lon, strict=True, **name):
509
509
 
510
510
  # **) MIT License
511
511
  #
512
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
512
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
513
513
  #
514
514
  # Permission is hereby granted, free of charge, to any person obtaining a
515
515
  # copy of this software and associated documentation files (the "Software"),