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.
- {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
- PyGeodesy-24.11.11.dist-info/RECORD +118 -0
- {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
- pygeodesy/__init__.py +14 -14
- pygeodesy/__main__.py +5 -5
- pygeodesy/albers.py +12 -17
- pygeodesy/azimuthal.py +51 -61
- pygeodesy/basics.py +60 -62
- pygeodesy/booleans.py +87 -79
- pygeodesy/cartesianBase.py +6 -6
- pygeodesy/constants.py +23 -19
- pygeodesy/css.py +7 -8
- pygeodesy/datums.py +3 -3
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/classes.py +9 -9
- pygeodesy/deprecated/functions.py +6 -6
- pygeodesy/dms.py +250 -270
- pygeodesy/ecef.py +11 -14
- pygeodesy/ellipsoidalBase.py +106 -121
- pygeodesy/ellipsoidalBaseDI.py +114 -118
- pygeodesy/ellipsoidalExact.py +35 -37
- pygeodesy/ellipsoidalNvector.py +4 -4
- pygeodesy/ellipsoidalVincenty.py +2 -2
- pygeodesy/ellipsoids.py +10 -51
- pygeodesy/elliptic.py +14 -14
- pygeodesy/errors.py +28 -28
- pygeodesy/etm.py +92 -68
- pygeodesy/fmath.py +42 -40
- pygeodesy/formy.py +7 -6
- pygeodesy/fsums.py +72 -51
- pygeodesy/geodesici.py +43 -40
- pygeodesy/geodesicw.py +17 -16
- pygeodesy/geodesicx/__init__.py +2 -2
- pygeodesy/geodesicx/gxarea.py +3 -2
- pygeodesy/geodsolve.py +79 -39
- pygeodesy/geohash.py +2 -2
- pygeodesy/geoids.py +32 -31
- pygeodesy/heights.py +2 -2
- pygeodesy/internals.py +201 -147
- pygeodesy/interns.py +23 -20
- pygeodesy/karney.py +62 -13
- pygeodesy/ktm.py +11 -13
- pygeodesy/latlonBase.py +18 -20
- pygeodesy/lazily.py +210 -218
- pygeodesy/lcc.py +4 -4
- pygeodesy/ltp.py +10 -10
- pygeodesy/ltpTuples.py +74 -75
- pygeodesy/mgrs.py +20 -21
- pygeodesy/named.py +15 -10
- pygeodesy/nvectorBase.py +1 -1
- pygeodesy/osgr.py +9 -12
- pygeodesy/points.py +2 -2
- pygeodesy/props.py +35 -14
- pygeodesy/resections.py +9 -10
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/bases.py +5 -5
- pygeodesy/rhumb/solve.py +9 -10
- pygeodesy/simplify.py +5 -5
- pygeodesy/solveBase.py +7 -25
- pygeodesy/sphericalBase.py +20 -23
- pygeodesy/sphericalNvector.py +103 -145
- pygeodesy/sphericalTrigonometry.py +68 -73
- pygeodesy/streprs.py +5 -5
- pygeodesy/trf.py +6 -4
- pygeodesy/triaxials.py +46 -9
- pygeodesy/units.py +5 -4
- pygeodesy/ups.py +6 -6
- pygeodesy/utily.py +2 -2
- pygeodesy/utm.py +7 -7
- pygeodesy/vector2d.py +13 -13
- pygeodesy/vector3d.py +19 -21
- pygeodesy/vector3dBase.py +21 -19
- pygeodesy/webmercator.py +4 -4
- pygeodesy/wgrs.py +4 -4
- PyGeodesy-24.10.10.dist-info/RECORD +0 -118
- {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-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
275
|
-
|
|
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
|
|
345
|
-
y = a
|
|
346
|
-
z = a
|
|
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
|
|
683
|
-
|
|
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
|
-
|
|
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
|
|
872
|
-
cb12
|
|
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
|
|
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
|
-
|
|
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}}
|
|
903
|
-
|
|
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=
|
|
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
|
-
|
|
987
|
-
'''Compute the intersection point of two lines, each defined
|
|
988
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1002
|
-
@kwarg
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
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
|
-
|
|
1009
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1033
|
-
'''Compute the intersection points of two circles each defined
|
|
1034
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1052
|
-
|
|
1053
|
-
|
|
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
|
-
|
|
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
|
|
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)}
|
|
1334
|
-
C{
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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_(
|
|
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-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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) #
|
|
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, #
|
|
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{
|
|
1315
|
-
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
36
|
-
from pygeodesy.named import nameof,
|
|
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.
|
|
52
|
+
__version__ = '24.10.14'
|
|
53
53
|
|
|
54
|
-
_BZ_UPS =
|
|
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(
|
|
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-
|
|
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.
|
|
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-
|
|
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.
|
|
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
|
|
569
|
+
T = tan(a)
|
|
570
570
|
T12 = hypot1(T)
|
|
571
|
-
S
|
|
571
|
+
S = sinh(E.e * atanh(E.e * T / T12))
|
|
572
572
|
|
|
573
|
-
T_ = T
|
|
574
|
-
H
|
|
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
|