pygeodesy 24.3.24__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PyGeodesy-24.3.24.dist-info/METADATA +272 -0
- PyGeodesy-24.3.24.dist-info/RECORD +115 -0
- PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
- PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
- pygeodesy/LICENSE +21 -0
- pygeodesy/__init__.py +615 -0
- pygeodesy/__main__.py +103 -0
- pygeodesy/albers.py +867 -0
- pygeodesy/auxilats/_CX_4.py +218 -0
- pygeodesy/auxilats/_CX_6.py +314 -0
- pygeodesy/auxilats/_CX_8.py +475 -0
- pygeodesy/auxilats/__init__.py +54 -0
- pygeodesy/auxilats/__main__.py +86 -0
- pygeodesy/auxilats/auxAngle.py +548 -0
- pygeodesy/auxilats/auxDLat.py +302 -0
- pygeodesy/auxilats/auxDST.py +296 -0
- pygeodesy/auxilats/auxLat.py +848 -0
- pygeodesy/auxilats/auxily.py +272 -0
- pygeodesy/azimuthal.py +1150 -0
- pygeodesy/basics.py +892 -0
- pygeodesy/booleans.py +2031 -0
- pygeodesy/cartesianBase.py +1062 -0
- pygeodesy/clipy.py +704 -0
- pygeodesy/constants.py +516 -0
- pygeodesy/css.py +660 -0
- pygeodesy/datums.py +752 -0
- pygeodesy/deprecated/__init__.py +61 -0
- pygeodesy/deprecated/bases.py +40 -0
- pygeodesy/deprecated/classes.py +262 -0
- pygeodesy/deprecated/consterns.py +54 -0
- pygeodesy/deprecated/datum.py +40 -0
- pygeodesy/deprecated/functions.py +375 -0
- pygeodesy/deprecated/nvector.py +48 -0
- pygeodesy/deprecated/rhumbBase.py +32 -0
- pygeodesy/deprecated/rhumbaux.py +33 -0
- pygeodesy/deprecated/rhumbsolve.py +33 -0
- pygeodesy/deprecated/rhumbx.py +33 -0
- pygeodesy/dms.py +986 -0
- pygeodesy/ecef.py +1348 -0
- pygeodesy/elevations.py +279 -0
- pygeodesy/ellipsoidalBase.py +1224 -0
- pygeodesy/ellipsoidalBaseDI.py +913 -0
- pygeodesy/ellipsoidalExact.py +343 -0
- pygeodesy/ellipsoidalGeodSolve.py +343 -0
- pygeodesy/ellipsoidalKarney.py +403 -0
- pygeodesy/ellipsoidalNvector.py +685 -0
- pygeodesy/ellipsoidalVincenty.py +590 -0
- pygeodesy/ellipsoids.py +2476 -0
- pygeodesy/elliptic.py +1198 -0
- pygeodesy/epsg.py +243 -0
- pygeodesy/errors.py +804 -0
- pygeodesy/etm.py +1190 -0
- pygeodesy/fmath.py +1013 -0
- pygeodesy/formy.py +1818 -0
- pygeodesy/frechet.py +865 -0
- pygeodesy/fstats.py +760 -0
- pygeodesy/fsums.py +1898 -0
- pygeodesy/gars.py +358 -0
- pygeodesy/geodesicw.py +581 -0
- pygeodesy/geodesicx/_C4_24.py +1699 -0
- pygeodesy/geodesicx/_C4_27.py +2395 -0
- pygeodesy/geodesicx/_C4_30.py +3301 -0
- pygeodesy/geodesicx/__init__.py +48 -0
- pygeodesy/geodesicx/__main__.py +91 -0
- pygeodesy/geodesicx/gx.py +1382 -0
- pygeodesy/geodesicx/gxarea.py +535 -0
- pygeodesy/geodesicx/gxbases.py +154 -0
- pygeodesy/geodesicx/gxline.py +669 -0
- pygeodesy/geodsolve.py +426 -0
- pygeodesy/geohash.py +914 -0
- pygeodesy/geoids.py +1884 -0
- pygeodesy/hausdorff.py +892 -0
- pygeodesy/heights.py +1155 -0
- pygeodesy/interns.py +687 -0
- pygeodesy/iters.py +545 -0
- pygeodesy/karney.py +919 -0
- pygeodesy/ktm.py +633 -0
- pygeodesy/latlonBase.py +1766 -0
- pygeodesy/lazily.py +960 -0
- pygeodesy/lcc.py +684 -0
- pygeodesy/ltp.py +1107 -0
- pygeodesy/ltpTuples.py +1563 -0
- pygeodesy/mgrs.py +721 -0
- pygeodesy/named.py +1324 -0
- pygeodesy/namedTuples.py +683 -0
- pygeodesy/nvectorBase.py +695 -0
- pygeodesy/osgr.py +781 -0
- pygeodesy/points.py +1686 -0
- pygeodesy/props.py +628 -0
- pygeodesy/resections.py +1048 -0
- pygeodesy/rhumb/__init__.py +46 -0
- pygeodesy/rhumb/aux_.py +397 -0
- pygeodesy/rhumb/bases.py +1148 -0
- pygeodesy/rhumb/ekx.py +563 -0
- pygeodesy/rhumb/solve.py +572 -0
- pygeodesy/simplify.py +647 -0
- pygeodesy/solveBase.py +472 -0
- pygeodesy/sphericalBase.py +724 -0
- pygeodesy/sphericalNvector.py +1264 -0
- pygeodesy/sphericalTrigonometry.py +1447 -0
- pygeodesy/streprs.py +627 -0
- pygeodesy/trf.py +2079 -0
- pygeodesy/triaxials.py +1484 -0
- pygeodesy/units.py +969 -0
- pygeodesy/unitsBase.py +349 -0
- pygeodesy/ups.py +538 -0
- pygeodesy/utily.py +1231 -0
- pygeodesy/utm.py +762 -0
- pygeodesy/utmups.py +318 -0
- pygeodesy/utmupsBase.py +517 -0
- pygeodesy/vector2d.py +785 -0
- pygeodesy/vector3d.py +968 -0
- pygeodesy/vector3dBase.py +1049 -0
- pygeodesy/webmercator.py +383 -0
- pygeodesy/wgrs.py +439 -0
pygeodesy/rhumb/ekx.py
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
u'''A pure Python version of I{Karney}'s I{elliptic functions}, I{Krüger series expansion}, C++
|
|
5
|
+
classes U{Rhumb<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Rhumb.html>} and
|
|
6
|
+
and U{RhumbLine<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1RhumbLine.html>}
|
|
7
|
+
from I{GeographicLib version 2.0}, kept for backward compatibility.
|
|
8
|
+
|
|
9
|
+
Class L{RhumbLine} has been enhanced with methods C{Intersecant2}, C{Intersection} and C{PlumbTo} to
|
|
10
|
+
iteratively find the intersection of a rhumb line and a circle or an other rhumb line, respectively
|
|
11
|
+
a perpendicular geodesic or other rhumb line.
|
|
12
|
+
|
|
13
|
+
For more details, see the C++ U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/index.html>}
|
|
14
|
+
documentation, especially the U{Class List<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>},
|
|
15
|
+
the background information on U{Rhumb lines<https://GeographicLib.SourceForge.io/C++/doc/rhumb.html>},
|
|
16
|
+
the utily U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>} and U{Online
|
|
17
|
+
rhumb line calculations<https://GeographicLib.SourceForge.io/cgi-bin/RhumbSolve>}.
|
|
18
|
+
|
|
19
|
+
Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2014-2022) and licensed under the MIT/X11
|
|
20
|
+
License. For more information, see the U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
|
|
21
|
+
'''
|
|
22
|
+
# make sure int/int division yields float quotient
|
|
23
|
+
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
24
|
+
|
|
25
|
+
from pygeodesy.basics import copysign0, neg
|
|
26
|
+
from pygeodesy.constants import PI_2, _0_0s, _0_0, _0_5, _1_0, \
|
|
27
|
+
_2_0, _4_0, _720_0, _over, _1_over
|
|
28
|
+
from pygeodesy.datums import _WGS84
|
|
29
|
+
# from pygeodesy.deprecated import RhumbOrder2Tuple # _MODS
|
|
30
|
+
from pygeodesy.errors import RhumbError, _Xorder
|
|
31
|
+
from pygeodesy.fmath import hypot, hypot1
|
|
32
|
+
# from pygeodesy.fsums import fsum1f_ # _MODS
|
|
33
|
+
# from pygeodesy.interns import NN # from .farney
|
|
34
|
+
from pygeodesy.karney import Caps, NN
|
|
35
|
+
from pygeodesy.ktm import KTransverseMercator, _Xs, \
|
|
36
|
+
_AlpCoeffs, _BetCoeffs # PYCHOK used!
|
|
37
|
+
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
38
|
+
from pygeodesy.props import deprecated_method, Property, Property_RO, property_RO
|
|
39
|
+
from pygeodesy.rhumb.bases import RhumbBase, RhumbLineBase, _update_all_rls
|
|
40
|
+
from pygeodesy.utily import atan1, sincos2_
|
|
41
|
+
|
|
42
|
+
from math import asinh, atan, cos, cosh, radians, sin, sinh, sqrt, tan
|
|
43
|
+
|
|
44
|
+
__all__ = _ALL_LAZY.rhumb_ekx
|
|
45
|
+
__version__ = '23.12.03'
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Rhumb(RhumbBase):
|
|
49
|
+
'''Class to solve the I{direct} and I{inverse rhumb} problems, based on
|
|
50
|
+
I{elliptic functions} or I{Krüger series expansion}
|
|
51
|
+
|
|
52
|
+
@see: The U{Detailed Description<https://GeographicLib.SourceForge.io/C++/doc/
|
|
53
|
+
classGeographicLib_1_1Rhumb.html>} of I{Karney}'s C++ C{Rhumb Class}.
|
|
54
|
+
'''
|
|
55
|
+
_mRA = 6 # see .RAorder
|
|
56
|
+
|
|
57
|
+
def __init__(self, a_earth=_WGS84, f=None, exact=True, name=NN, **RA_TMorder):
|
|
58
|
+
'''New C{Rhumb}.
|
|
59
|
+
|
|
60
|
+
@kwarg a_earth: This rhumb's earth model (L{Datum}, L{Ellipsoid},
|
|
61
|
+
L{Ellipsoid2}, L{a_f2Tuple}, 2-tuple C{(a, f)}) or
|
|
62
|
+
the (equatorial) radius (C{meter}, conventionally).
|
|
63
|
+
@kwarg f: The ellipsoid's flattening (C{scalar}), iff B{C{a_earth}} is
|
|
64
|
+
C{scalar}, ignored otherwise.
|
|
65
|
+
@kwarg exact: If C{True}, use an addition theorem for elliptic integrals
|
|
66
|
+
to compute I{Divided differences}, otherwise use the I{Krüger}
|
|
67
|
+
series expansion (C{bool} or C{None}), see also properties
|
|
68
|
+
C{exact} and C{TMorder}.
|
|
69
|
+
@kwarg name: Optional name (C{str}).
|
|
70
|
+
@kwarg RA_TMorder: Optional keyword arguments B{C{RAorder}} and B{C{TMorder}}
|
|
71
|
+
to set the respective C{order}, see properties C{RAorder}
|
|
72
|
+
and C{TMorder} and method C{orders}.
|
|
73
|
+
|
|
74
|
+
@raise RhumbError: Invalid B{C{a_earth}}, B{C{f}} or B{C{RA_TMorder}}.
|
|
75
|
+
'''
|
|
76
|
+
RhumbBase.__init__(self, a_earth, f, exact, name)
|
|
77
|
+
if RA_TMorder:
|
|
78
|
+
self.orders(**RA_TMorder)
|
|
79
|
+
|
|
80
|
+
@Property_RO
|
|
81
|
+
def _A2(self): # Conformal2RectifyingCoeffs
|
|
82
|
+
m = self.TMorder
|
|
83
|
+
return _Xs(_AlpCoeffs, m, self.ellipsoid), m
|
|
84
|
+
|
|
85
|
+
@Property_RO
|
|
86
|
+
def _B2(self): # Rectifying2ConformalCoeffs
|
|
87
|
+
m = self.TMorder
|
|
88
|
+
return _Xs(_BetCoeffs, m, self.ellipsoid), m
|
|
89
|
+
|
|
90
|
+
def _DConformal2Rectifying(self, x, y): # radians
|
|
91
|
+
return _1_0 + (_sincosSeries(True, x, y, *self._A2) if self.f else _0_0)
|
|
92
|
+
|
|
93
|
+
@deprecated_method
|
|
94
|
+
def Direct7(self, lat1, lon1, azi12, s12, outmask=Caps.LATITUDE_LONGITUDE_AREA): # PYCHOK no cover
|
|
95
|
+
'''DEPRECATED, use method L{Rhumb.Direct8}.
|
|
96
|
+
|
|
97
|
+
@return: A I{DEPRECATED} L{Rhumb7Tuple}.
|
|
98
|
+
'''
|
|
99
|
+
return self.Direct8(lat1, lon1, azi12, s12, outmask=outmask)._to7Tuple()
|
|
100
|
+
|
|
101
|
+
def _DIsometrict(self, phix, phiy, tphix, tphiy, _Dtan_phix_phiy):
|
|
102
|
+
E = self.ellipsoid
|
|
103
|
+
return _Dtan_phix_phiy * _Dasinh(tphix, tphiy) - \
|
|
104
|
+
_Dsin(phix, phiy) * _DeatanhE(sin(phix), sin(phiy), E)
|
|
105
|
+
|
|
106
|
+
def _DIsometric2Rectifyingd(self, psix, psiy): # degrees
|
|
107
|
+
if self.exact:
|
|
108
|
+
E = self.ellipsoid
|
|
109
|
+
phix, phiy, tphix, tphiy = _Eaux4(E.auxIsometric, psix, psiy)
|
|
110
|
+
t = _Dtant(phix - phiy, tphix, tphiy)
|
|
111
|
+
r = _over(self._DRectifyingt( tphix, tphiy, t),
|
|
112
|
+
self._DIsometrict(phix, phiy, tphix, tphiy, t))
|
|
113
|
+
else:
|
|
114
|
+
x, y = radians(psix), radians(psiy)
|
|
115
|
+
r = self._DConformal2Rectifying(_gd(x), _gd(y)) * _Dgd(x, y)
|
|
116
|
+
return r
|
|
117
|
+
|
|
118
|
+
def _DRectifyingt(self, tphix, tphiy, _Dtan_phix_phiy):
|
|
119
|
+
E = self.ellipsoid
|
|
120
|
+
tbetx = E.f1 * tphix
|
|
121
|
+
tbety = E.f1 * tphiy
|
|
122
|
+
return (E.f1 * _Dtan_phix_phiy * E.b * PI_2
|
|
123
|
+
* _DfEt( tbetx, tbety, self._eF)
|
|
124
|
+
* _Datan(tbetx, tbety)) / E.L
|
|
125
|
+
|
|
126
|
+
def _DRectifying2Conformal(self, x, y): # radians
|
|
127
|
+
return _1_0 - (_sincosSeries(True, x, y, *self._B2) if self.f else _0_0)
|
|
128
|
+
|
|
129
|
+
def _DRectifying2Isometricd(self, mux, muy): # degrees
|
|
130
|
+
E = self.ellipsoid
|
|
131
|
+
phix, phiy, tphix, tphiy = _Eaux4(E.auxRectifying, mux, muy)
|
|
132
|
+
if self.exact:
|
|
133
|
+
t = _Dtant(phix - phiy, tphix, tphiy)
|
|
134
|
+
r = _over(self._DIsometrict(phix, phiy, tphix, tphiy, t),
|
|
135
|
+
self._DRectifyingt( tphix, tphiy, t))
|
|
136
|
+
else:
|
|
137
|
+
r = self._DRectifying2Conformal(radians(mux), radians(muy)) * \
|
|
138
|
+
_Dgdinv(E.es_taupf(tphix), E.es_taupf(tphiy))
|
|
139
|
+
return r
|
|
140
|
+
|
|
141
|
+
@Property_RO
|
|
142
|
+
def _eF(self):
|
|
143
|
+
'''(INTERNAL) Get the ellipsoid's elliptic function.
|
|
144
|
+
'''
|
|
145
|
+
# .k2 = 0.006739496742276434
|
|
146
|
+
return self.ellipsoid._elliptic_e12 # _MODS.elliptic.Elliptic(-self.ellipsoid._e12)
|
|
147
|
+
|
|
148
|
+
def _Inverse4(self, lon12, r, outmask):
|
|
149
|
+
'''(INTERNAL) See method C{RhumbBase.Inverse}.
|
|
150
|
+
'''
|
|
151
|
+
E, Cs = self.ellipsoid, Caps
|
|
152
|
+
psi1 = E.auxIsometric(r.lat1)
|
|
153
|
+
psi2 = E.auxIsometric(r.lat2)
|
|
154
|
+
psi12 = psi2 - psi1 # degrees
|
|
155
|
+
if (outmask & Cs.DISTANCE):
|
|
156
|
+
a = s = hypot(lon12, psi12)
|
|
157
|
+
if a:
|
|
158
|
+
a *= self._DIsometric2Rectifyingd(psi2, psi1)
|
|
159
|
+
s = self._mpd * a # == E._Lpd
|
|
160
|
+
a = copysign0(a, s)
|
|
161
|
+
r.set_(a12=a, s12=s)
|
|
162
|
+
|
|
163
|
+
if ((outmask | self._debug) & Cs._DEBUG_INVERSE): # PYCHOK no cover
|
|
164
|
+
r.set_(a=E.a, f=E.f, f1=E.f1, L=E.L,
|
|
165
|
+
b=E.b, e=E.e, e2=E.e2, k2=self._eF.k2,
|
|
166
|
+
lon12=lon12, psi1=psi1, exact=self.exact,
|
|
167
|
+
psi12=psi12, psi2=psi2)
|
|
168
|
+
return lon12, psi12, psi1, psi2
|
|
169
|
+
|
|
170
|
+
@deprecated_method
|
|
171
|
+
def Inverse7(self, lat1, lon1, azi12, s12, outmask=Caps.AZIMUTH_DISTANCE_AREA): # PYCHOK no cover
|
|
172
|
+
'''DEPRECATED, use method L{Rhumb.Inverse8}.
|
|
173
|
+
|
|
174
|
+
@return: A I{DEPRECATED} L{Rhumb7Tuple}.
|
|
175
|
+
'''
|
|
176
|
+
return self.Inverse8(lat1, lon1, azi12, s12, outmask=outmask)._to7Tuple()
|
|
177
|
+
|
|
178
|
+
@Property_RO
|
|
179
|
+
def _mpd(self): # meter per degree
|
|
180
|
+
return self.ellipsoid._Lpd
|
|
181
|
+
|
|
182
|
+
@Property_RO
|
|
183
|
+
def _mpr(self): # meter per radian
|
|
184
|
+
return self.ellipsoid._Lpr # degrees(._Lpd)
|
|
185
|
+
|
|
186
|
+
@deprecated_method
|
|
187
|
+
def orders(self, RAorder=None, TMorder=None): # PYCHOK no cover
|
|
188
|
+
'''DEPRECATED, use properties C{RAorder} and/or C{TMorder}.
|
|
189
|
+
|
|
190
|
+
Get and set the I{RAorder} and/or I{TMorder}.
|
|
191
|
+
|
|
192
|
+
@kwarg RAorder: I{Rhumb Area} order (C{int}, 4, 5, 6, 7
|
|
193
|
+
or 8).
|
|
194
|
+
@kwarg TMorder: I{Transverse Mercator} order (C{int}, 4,
|
|
195
|
+
5, 6, 7 or 8).
|
|
196
|
+
|
|
197
|
+
@return: DEPRECATED L{RhumbOrder2Tuple}C{(RAorder, TMorder)}
|
|
198
|
+
with the previous C{RAorder} and C{TMorder} setting.
|
|
199
|
+
'''
|
|
200
|
+
t = _MODS.deprecated.classes.RhumbOrder2Tuple(self.RAorder, self.TMorder)
|
|
201
|
+
if RAorder not in (None, t.RAorder): # PYCHOK attr
|
|
202
|
+
self.RAorder = RAorder
|
|
203
|
+
if TMorder not in (None, t.TMorder): # PYCHOK attr
|
|
204
|
+
self.TMorder = TMorder
|
|
205
|
+
return t
|
|
206
|
+
|
|
207
|
+
@Property_RO
|
|
208
|
+
def _RA2(self):
|
|
209
|
+
# for WGS84: (0, -0.0005583633519275459, -3.743803759172812e-07, -4.633682270824446e-10,
|
|
210
|
+
# RAorder 6: -7.709197397676237e-13, -1.5323287106694307e-15, -3.462875359099873e-18)
|
|
211
|
+
m = self.RAorder
|
|
212
|
+
return _Xs(_RACoeffs, m, self.ellipsoid, RA=True), m
|
|
213
|
+
|
|
214
|
+
@Property
|
|
215
|
+
def RAorder(self):
|
|
216
|
+
'''Get the I{Rhumb Area} order (C{int}, 4, 5, 6, 7 or 8).
|
|
217
|
+
'''
|
|
218
|
+
return self._mRA
|
|
219
|
+
|
|
220
|
+
@RAorder.setter # PYCHOK setter!
|
|
221
|
+
def RAorder(self, order):
|
|
222
|
+
'''Set the I{Rhumb Area} order (C{int}, 4, 5, 6, 7 or 8).
|
|
223
|
+
'''
|
|
224
|
+
m = _Xorder(_RACoeffs, RhumbError, RAorder=order)
|
|
225
|
+
if self._mRA != m:
|
|
226
|
+
_update_all_rls(self)
|
|
227
|
+
self._mRA = m
|
|
228
|
+
|
|
229
|
+
# _RhumbLine = RhumbLine # see further below
|
|
230
|
+
|
|
231
|
+
def _S12d(self, psi1, psi2, lon12): # degrees
|
|
232
|
+
'''(INTERNAL) Compute the area C{S12}.
|
|
233
|
+
'''
|
|
234
|
+
S = (self.ellipsoid.areax if self.exact else
|
|
235
|
+
self.ellipsoid.area) * lon12 / _720_0
|
|
236
|
+
if S:
|
|
237
|
+
x, y = radians(psi1), radians(psi2) # _meanSinXi(x, y)
|
|
238
|
+
s = _Dlog(cosh(x), cosh(y)) * _Dcosh(x, y)
|
|
239
|
+
if self.f:
|
|
240
|
+
s += _sincosSeries(False, _gd(x), _gd(y), *self._RA2) * _Dgd(x, y)
|
|
241
|
+
S *= s
|
|
242
|
+
return S
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class RhumbLine(RhumbLineBase):
|
|
246
|
+
'''Compute one or several points on a single rhumb line.
|
|
247
|
+
|
|
248
|
+
Class C{RhumbLine} facilitates the determination of points on
|
|
249
|
+
a single rhumb line. The starting point (C{lat1}, C{lon1})
|
|
250
|
+
and the azimuth C{azi12} are specified once.
|
|
251
|
+
'''
|
|
252
|
+
_Rhumb = Rhumb # rhumb.ekx.Rhumb
|
|
253
|
+
|
|
254
|
+
def __init__(self, rhumb, lat1=0, lon1=0, azi12=None, **caps_name): # PYCHOK signature
|
|
255
|
+
'''New C{RhumbLine}.
|
|
256
|
+
|
|
257
|
+
@arg rhumb: The rhumb reference (L{Rhumb}).
|
|
258
|
+
@kwarg lat1: Latitude of the start point (C{degrees90}).
|
|
259
|
+
@kwarg lon1: Longitude of the start point (C{degrees180}).
|
|
260
|
+
@kwarg azi12: Azimuth of this rhumb line (compass C{degrees}).
|
|
261
|
+
@kwarg caps_name: Optional keyword arguments C{B{name}=NN} and
|
|
262
|
+
C{B{caps}=0}, a bit-or'ed combination of L{Caps}
|
|
263
|
+
values specifying the required capabilities. Include
|
|
264
|
+
C{Caps.LINE_OFF} if updates to the B{C{rhumb}} should
|
|
265
|
+
I{not} be reflected in this rhumb line.
|
|
266
|
+
'''
|
|
267
|
+
RhumbLineBase.__init__(self, rhumb, lat1, lon1, azi12, **caps_name)
|
|
268
|
+
|
|
269
|
+
@Property_RO
|
|
270
|
+
def _dpm12(self): # PYCHOK no cover
|
|
271
|
+
'''(INTERNAL) Get this rhumb line's parallel I{circle radius} (C{degree per meter}).
|
|
272
|
+
'''
|
|
273
|
+
r = self._salp
|
|
274
|
+
if r:
|
|
275
|
+
r = _over(r, self.ellipsoid.circle4(self.lat1).radius)
|
|
276
|
+
return r
|
|
277
|
+
|
|
278
|
+
@Property_RO
|
|
279
|
+
def _mu1(self):
|
|
280
|
+
'''(INTERNAL) Get the I{rectifying auxiliary} latitude (C{degrees}).
|
|
281
|
+
'''
|
|
282
|
+
return self.ellipsoid.auxRectifying(self.lat1)
|
|
283
|
+
|
|
284
|
+
def _mu2lat(self, mu):
|
|
285
|
+
'''(INTERNAL) Get the inverse I{rectifying auxiliary} latitude (C{degrees}).
|
|
286
|
+
'''
|
|
287
|
+
return self.ellipsoid.auxRectifying(mu, inverse=True)
|
|
288
|
+
|
|
289
|
+
def _Position4(self, unused, mu2, s12, mu12):
|
|
290
|
+
'''(INTERNAL) See method C{RhumbLineBase._Position}.
|
|
291
|
+
'''
|
|
292
|
+
psi1 = psi2 = self._psi1
|
|
293
|
+
if mu12: # self._calp != 0
|
|
294
|
+
lat2 = self._mu2lat(mu2)
|
|
295
|
+
psi12 = self.rhumb._DRectifying2Isometricd(mu2, self._mu1) * mu12
|
|
296
|
+
lon2 = self._talp * psi12
|
|
297
|
+
psi2 += psi12
|
|
298
|
+
else: # meridional
|
|
299
|
+
lat2 = self.lat1
|
|
300
|
+
lon2 = self._dpm12 * s12
|
|
301
|
+
return lat2, lon2, psi1, psi2
|
|
302
|
+
|
|
303
|
+
@Property_RO
|
|
304
|
+
def _psi1(self):
|
|
305
|
+
'''(INTERNAL) Get the I{isometric auxiliary} latitude C{psi} (C{degrees}).
|
|
306
|
+
'''
|
|
307
|
+
return self.ellipsoid.auxIsometric(self.lat1)
|
|
308
|
+
|
|
309
|
+
@property_RO
|
|
310
|
+
def RAorder(self):
|
|
311
|
+
'''Get this rhumb line's I{Rhumb Area} order (C{int}, 4, 5, 6, 7 or 8).
|
|
312
|
+
'''
|
|
313
|
+
return self.rhumb.RAorder
|
|
314
|
+
|
|
315
|
+
Rhumb._RhumbLine = RhumbLine # PYCHOK see RhumbBase._RhumbLine
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# Use I{Divided Differences} to determine (mu2 - mu1) / (psi2 - psi1) accurately.
|
|
319
|
+
# Definition: _Df(x,y,d) = (f(x) - f(y)) / (x - y), @see W. M. Kahan & R. J.
|
|
320
|
+
# Fateman, "Symbolic computation of Divided Differences", SIGSAM Bull. 33(3),
|
|
321
|
+
# 7-28 (1999). U{ACM<https://DL.ACM.org/doi/pdf/10.1145/334714.334716> and @see
|
|
322
|
+
# U{UCB<https://www.CS.Berkeley.edu/~fateman/papers/divdiff.pdf>}, Dec 8, 1999.
|
|
323
|
+
|
|
324
|
+
def _Dasinh(x, y):
|
|
325
|
+
hx = hypot1(x)
|
|
326
|
+
d = x - y
|
|
327
|
+
if d:
|
|
328
|
+
hx *= y
|
|
329
|
+
hy = x * hypot1(y)
|
|
330
|
+
t = (d * (x + y) / (hy + hx)) if (x * y) > 0 else (hy - hx)
|
|
331
|
+
r = asinh(t) / d
|
|
332
|
+
else:
|
|
333
|
+
r = _1_0 / hx
|
|
334
|
+
return r
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _Datan(x, y):
|
|
338
|
+
xy = x * y
|
|
339
|
+
r = xy + _1_0
|
|
340
|
+
d = x - y
|
|
341
|
+
if d: # 2 * xy > -1 == 2 * xy + 1 > 0 == xy + r > 0 == xy > -r
|
|
342
|
+
r = (atan1(d, r) if xy > -r else (atan1(x) - atan1(y))) / d
|
|
343
|
+
else:
|
|
344
|
+
r = _1_over(r)
|
|
345
|
+
return r
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _Dcosh(x, y):
|
|
349
|
+
return _Dsincos(x, y, sinh, sinh)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _DeatanhE(x, y, E): # see .albers._Datanhee
|
|
353
|
+
# Deatanhe(x, y) = eatanhe((x - y) / (1 - e^2 * x * y)) / (x - y)
|
|
354
|
+
e = _1_0 - E.e2 * x * y
|
|
355
|
+
if e: # assert not isnear0(e)
|
|
356
|
+
d = x - y
|
|
357
|
+
e = (E._es_atanh(d / e) / d) if d else (E.e2 / e)
|
|
358
|
+
return e
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _DfEt(tx, ty, eF): # tangents
|
|
362
|
+
# eF = Elliptic(-E.e12) # -E.e2 / (1 - E.e2)
|
|
363
|
+
r, x, y, = _1_0, atan(tx), atan(ty)
|
|
364
|
+
d = x - y
|
|
365
|
+
if (x * y) > 0:
|
|
366
|
+
# See U{DLMF<https://DLMF.NIST.gov/19.11>}: 19.11.2 and 19.11.4
|
|
367
|
+
# letting theta -> x, phi -> -y, psi -> z
|
|
368
|
+
# (E(x) - E(y)) / d = E(z)/d - k2 * sin(x) * sin(y) * sin(z)/d
|
|
369
|
+
# tan(z/2) = (sin(x)*Delta(y) - sin(y)*Delta(x)) / (cos(x) + cos(y))
|
|
370
|
+
# = d * Dsin(x,y) * (sin(x) + sin(y))/(cos(x) + cos(y)) /
|
|
371
|
+
# (sin(x)*Delta(y) + sin(y)*Delta(x))
|
|
372
|
+
# = t = d * Dt
|
|
373
|
+
# sin(z) = 2*t/(1+t^2); cos(z) = (1-t^2)/(1+t^2)
|
|
374
|
+
# Alt (this only works for |z| <= pi/2 -- however, this conditions
|
|
375
|
+
# holds if x*y > 0):
|
|
376
|
+
# sin(z) = d * Dsin(x,y) * (sin(x) + sin(y)) /
|
|
377
|
+
# (sin(x)*cos(y)*Delta(y) + sin(y)*cos(x)*Delta(x))
|
|
378
|
+
# cos(z) = sqrt((1-sin(z))*(1+sin(z)))
|
|
379
|
+
sx, cx, sy, cy = sincos2_(x, y)
|
|
380
|
+
D = (cx + cy) * (eF.fDelta(sy, cy) * sx +
|
|
381
|
+
eF.fDelta(sx, cx) * sy)
|
|
382
|
+
D = (sx + sy) * _Dsin(x, y) / D
|
|
383
|
+
t = D * d
|
|
384
|
+
t2 = _1_0 + t**2
|
|
385
|
+
D *= _2_0 / t2
|
|
386
|
+
s = D * d
|
|
387
|
+
if s:
|
|
388
|
+
c = (t + _1_0) * (_1_0 - t) / t2
|
|
389
|
+
r = eF.fE(s, c, eF.fDelta(s, c)) / s
|
|
390
|
+
r = D * (r - eF.k2 * sx * sy)
|
|
391
|
+
elif d:
|
|
392
|
+
r = (eF.fE(x) - eF.fE(y)) / d
|
|
393
|
+
return r
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _Dgd(x, y):
|
|
397
|
+
return _Datan(sinh(x), sinh(y)) * _Dsinh(x, y)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _Dgdinv(x, y): # x, y are tangents
|
|
401
|
+
return _Dasinh(x, y) / _Datan(x, y)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _Dlog(x, y):
|
|
405
|
+
d = (x - y) * _0_5
|
|
406
|
+
# Changed atanh(t / (x + y)) to asinh(t / (2 * sqrt(x*y))) to
|
|
407
|
+
# avoid taking atanh(1) when x is large and y is 1. This also
|
|
408
|
+
# fixes bogus results being returned for the area when an endpoint
|
|
409
|
+
# is at a pole. N.B. this routine is invoked with positive x
|
|
410
|
+
# and y, so the sqrt is always taken of a positive quantity.
|
|
411
|
+
return (asinh(d / sqrt(x * y)) / d) if d else _1_over(x)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _Dsin(x, y):
|
|
415
|
+
return _Dsincos(x, y, sin, cos)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _Dsincos(x, y, sin_, cos_):
|
|
419
|
+
r = cos_((x + y) * _0_5)
|
|
420
|
+
d = (x - y) * _0_5
|
|
421
|
+
if d:
|
|
422
|
+
r *= sin_(d) / d
|
|
423
|
+
return r
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _Dsinh(x, y):
|
|
427
|
+
return _Dsincos(x, y, sinh, cosh)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def _Dtan(x, y): # PYCHOK no cover
|
|
431
|
+
return _Dtant(x - y, tan(x), tan(y))
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _Dtant(dxy, tx, ty):
|
|
435
|
+
txy = tx * ty
|
|
436
|
+
r = txy + _1_0
|
|
437
|
+
if dxy: # 2 * txy > -1 == 2 * txy + 1 > 0 == txy + r > 0 == txy > -r
|
|
438
|
+
r = ((tan(dxy) * r) if txy > -r else (tx - ty)) / dxy
|
|
439
|
+
return r
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def _Eaux4(E_aux, mu_psi_x, mu_psi_y): # degrees
|
|
443
|
+
# get inverse auxiliary lats in radians and tangents
|
|
444
|
+
phix = radians(E_aux(mu_psi_x, inverse=True))
|
|
445
|
+
phiy = radians(E_aux(mu_psi_y, inverse=True))
|
|
446
|
+
return phix, phiy, tan(phix), tan(phiy)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def _gd(x):
|
|
450
|
+
return atan(sinh(x))
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _sincosSeries(sinp, x, y, C, n):
|
|
454
|
+
# N.B. C[] has n+1 elements of which
|
|
455
|
+
# C[0] is ignored and n >= 0
|
|
456
|
+
# Use Clenshaw summation to evaluate
|
|
457
|
+
# m = (g(x) + g(y)) / 2 -- mean value
|
|
458
|
+
# s = (g(x) - g(y)) / (x - y) -- average slope
|
|
459
|
+
# where
|
|
460
|
+
# g(x) = sum(C[j] * SC(2 * j * x), j = 1..n)
|
|
461
|
+
# SC = sinp ? sin : cos
|
|
462
|
+
# CS = sinp ? cos : sin
|
|
463
|
+
# ...
|
|
464
|
+
d, _neg = (x - y), neg
|
|
465
|
+
sp, cp, sd, cd = sincos2_(x + y, d)
|
|
466
|
+
sd = (sd / d) if d else _1_0
|
|
467
|
+
s = _neg(sp * sd) # negative
|
|
468
|
+
# 2x2 matrices in row-major order
|
|
469
|
+
a1 = s * d**2
|
|
470
|
+
a2 = s * _4_0
|
|
471
|
+
a0 = a3 = _2_0 * cp * cd # m
|
|
472
|
+
b2 = b1 = _0_0s(4)
|
|
473
|
+
if n > 0:
|
|
474
|
+
b1 = C[n], _0_0, _0_0, C[n]
|
|
475
|
+
|
|
476
|
+
_fsum = _MODS.fsums.fsum1f_
|
|
477
|
+
for j in range(n - 1, 0, -1): # C[0] unused
|
|
478
|
+
b1, b2, Cj = b2, b1, C[j]
|
|
479
|
+
# b1 = a * b2 - b1 + C[j] * I
|
|
480
|
+
m0, m1, m2, m3 = b2
|
|
481
|
+
n0, n1, n2, n3 = map(_neg, b1)
|
|
482
|
+
b1 = (_fsum(a0 * m0, a1 * m2, n0, Cj),
|
|
483
|
+
_fsum(a0 * m1, a1 * m3, n1),
|
|
484
|
+
_fsum(a2 * m0, a3 * m2, n2),
|
|
485
|
+
_fsum(a2 * m1, a3 * m3, n3, Cj))
|
|
486
|
+
# Here are the full expressions for m and s
|
|
487
|
+
# f01, f02, f11, f12 = (0, 0, cd * sp, 2 * sd * cp) if sinp else \
|
|
488
|
+
# (1, 0, cd * cp, -2 * sd * sp)
|
|
489
|
+
# m = -b2[1] * f02 + (C[0] - b2[0]) * f01 + b1[0] * f11 + b1[1] * f12
|
|
490
|
+
# s = -b2[2] * f01 + (C[0] - b2[3]) * f02 + b1[2] * f11 + b1[3] * f12
|
|
491
|
+
cd *= b1[2]
|
|
492
|
+
sd *= b1[3] * _2_0
|
|
493
|
+
s = _fsum(cd * sp, sd * cp) if sinp else \
|
|
494
|
+
_fsum(cd * cp, _neg(sd * sp), _neg(b2[2]))
|
|
495
|
+
return s
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
_RACoeffs = { # Generated by Maxima on 2015-05-15 08:24:04-04:00
|
|
499
|
+
4: ( # GEOGRAPHICLIB_RHUMBAREA_ORDER == 4
|
|
500
|
+
691, 7860, -20160, 18900, 0, 56700, # R[0]/n^0, polynomial(n), order 4
|
|
501
|
+
1772, -5340, 6930, -4725, 14175, # R[1]/n^1, polynomial(n), order 3
|
|
502
|
+
-1747, 1590, -630, 4725, # PYCHOK R[2]/n^2, polynomial(n), order 2
|
|
503
|
+
104, -31, 315, # R[3]/n^3, polynomial(n), order 1
|
|
504
|
+
-41, 420), # PYCHOK R[4]/n^4, polynomial(n), order 0, count = 20
|
|
505
|
+
5: ( # GEOGRAPHICLIB_RHUMBAREA_ORDER == 5
|
|
506
|
+
-79036, 22803, 259380, -665280, 623700, 0, 1871100, # PYCHOK R[0]/n^0, polynomial(n), order 5
|
|
507
|
+
41662, 58476, -176220, 228690, -155925, 467775, # PYCHOK R[1]/n^1, polynomial(n), order 4
|
|
508
|
+
18118, -57651, 52470, -20790, 155925, # PYCHOK R[2]/n^2, polynomial(n), order 3
|
|
509
|
+
-23011, 17160, -5115, 51975, # PYCHOK R[3]/n^3, polynomial(n), order 2
|
|
510
|
+
5480, -1353, 13860, # PYCHOK R[4]/n^4, polynomial(n), order 1
|
|
511
|
+
-668, 5775), # PYCHOK R[5]/n^5, polynomial(n), order 0, count = 27
|
|
512
|
+
6: ( # GEOGRAPHICLIB_RHUMBAREA_ORDER == 6
|
|
513
|
+
128346268, -107884140, 31126095, 354053700, -908107200, 851350500, 0, 2554051500, # R[0]/n^0, polynomial(n), order 6
|
|
514
|
+
-114456994, 56868630, 79819740, -240540300, 312161850, -212837625, 638512875, # PYCHOK R[1]/n^1, polynomial(n), order 5
|
|
515
|
+
51304574, 24731070, -78693615, 71621550, -28378350, 212837625, # R[2]/n^2, polynomial(n), order 4
|
|
516
|
+
1554472, -6282003, 4684680, -1396395, 14189175, # R[3]/n^3, polynomial(n), order 3
|
|
517
|
+
-4913956, 3205800, -791505, 8108100, # PYCHOK R[4]/n^4, polynomial(n), order 2
|
|
518
|
+
1092376, -234468, 2027025, # R[5]/n^5, polynomial(n), order 1
|
|
519
|
+
-313076, 2027025), # PYCHOK R[6]/n^6, polynomial(n), order 0, count = 35
|
|
520
|
+
7: ( # GEOGRAPHICLIB_RHUMBAREA_ORDER == 7
|
|
521
|
+
-317195588, 385038804, -323652420, 93378285, 1062161100, -2724321600, 2554051500, 0, 7662154500, # PYCHOK R[0]/n^0, polynomial(n), order 7
|
|
522
|
+
258618446, -343370982, 170605890, 239459220, -721620900, 936485550, -638512875, 1915538625, # PYCHOK R[1]/n^1, polynomial(n), order 6
|
|
523
|
+
-248174686, 153913722, 74193210, -236080845, 214864650, -85135050, 638512875, # PYCHOK R[2]/n^2, polynomial(n), order 5
|
|
524
|
+
114450437, 23317080, -94230045, 70270200, -20945925, 212837625, # PYCHOK R[3]/n^3, polynomial(n), order 4
|
|
525
|
+
15445736, -103193076, 67321800, -16621605, 170270100, # PYCHOK R[4]/n^4, polynomial(n), order 3
|
|
526
|
+
-27766753, 16385640, -3517020, 30405375, # PYCHOK R[4]/n^4, polynomial(n), order 3
|
|
527
|
+
4892722, -939228, 6081075, # PYCHOK R[4]/n^4, polynomial(n), order 3
|
|
528
|
+
-3189007, 14189175), # PYCHOK R[7]/n^7, polynomial(n), order 0, count = 44
|
|
529
|
+
8: ( # GEOGRAPHICLIB_RHUMBAREA_ORDER == 8
|
|
530
|
+
71374704821, -161769749880, 196369790040, -165062734200, 47622925350, 541702161000, -1389404016000, 1302566265000, 0, 3907698795000, # R[0]/n^0, polynomial(n), order 8
|
|
531
|
+
-13691187484, 65947703730, -87559600410, 43504501950, 61062101100, -184013329500, 238803815250, -162820783125, 488462349375, # PYCHOK R[1]/n^1, polynomial(n), order 7
|
|
532
|
+
30802104839, -63284544930, 39247999110, 18919268550, -60200615475, 54790485750, -21709437750, 162820783125, # R[2]/n^2, polynomial(n), order 6
|
|
533
|
+
-8934064508, 5836972287, 1189171080, -4805732295, 3583780200, -1068242175, 10854718875, # PYCHOK R[3]/n^3, polynomial(n), order 5
|
|
534
|
+
50072287748, 3938662680, -26314234380, 17167059000, -4238509275, 43418875500, # R[4]/n^4, polynomial(n), order 4
|
|
535
|
+
359094172, -9912730821, 5849673480, -1255576140, 10854718875, # R[5]/n^5, polynomial(n), order 3
|
|
536
|
+
-16053944387, 8733508770, -1676521980, 10854718875, # PYCHOK R[6]/n^6, polynomial(n), order 2
|
|
537
|
+
930092876, -162639357, 723647925, # R[7]/n^7, polynomial(n), order 1
|
|
538
|
+
-673429061, 1929727800) # PYCHOK R[8]/n^8, polynomial(n), order 0, count = 54
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
__all__ += _ALL_DOCS(Caps)
|
|
542
|
+
|
|
543
|
+
# **) MIT License
|
|
544
|
+
#
|
|
545
|
+
# Copyright (C) 2022-2024 -- mrJean1 at Gmail -- All Rights Reserved.
|
|
546
|
+
#
|
|
547
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
548
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
549
|
+
# to deal in the Software without restriction, including without limitation
|
|
550
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
551
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
552
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
553
|
+
#
|
|
554
|
+
# The above copyright notice and this permission notice shall be included
|
|
555
|
+
# in all copies or substantial portions of the Software.
|
|
556
|
+
#
|
|
557
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
558
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
559
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
560
|
+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
561
|
+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
562
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
563
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|