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.
Files changed (115) hide show
  1. PyGeodesy-24.3.24.dist-info/METADATA +272 -0
  2. PyGeodesy-24.3.24.dist-info/RECORD +115 -0
  3. PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
  4. PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
  5. pygeodesy/LICENSE +21 -0
  6. pygeodesy/__init__.py +615 -0
  7. pygeodesy/__main__.py +103 -0
  8. pygeodesy/albers.py +867 -0
  9. pygeodesy/auxilats/_CX_4.py +218 -0
  10. pygeodesy/auxilats/_CX_6.py +314 -0
  11. pygeodesy/auxilats/_CX_8.py +475 -0
  12. pygeodesy/auxilats/__init__.py +54 -0
  13. pygeodesy/auxilats/__main__.py +86 -0
  14. pygeodesy/auxilats/auxAngle.py +548 -0
  15. pygeodesy/auxilats/auxDLat.py +302 -0
  16. pygeodesy/auxilats/auxDST.py +296 -0
  17. pygeodesy/auxilats/auxLat.py +848 -0
  18. pygeodesy/auxilats/auxily.py +272 -0
  19. pygeodesy/azimuthal.py +1150 -0
  20. pygeodesy/basics.py +892 -0
  21. pygeodesy/booleans.py +2031 -0
  22. pygeodesy/cartesianBase.py +1062 -0
  23. pygeodesy/clipy.py +704 -0
  24. pygeodesy/constants.py +516 -0
  25. pygeodesy/css.py +660 -0
  26. pygeodesy/datums.py +752 -0
  27. pygeodesy/deprecated/__init__.py +61 -0
  28. pygeodesy/deprecated/bases.py +40 -0
  29. pygeodesy/deprecated/classes.py +262 -0
  30. pygeodesy/deprecated/consterns.py +54 -0
  31. pygeodesy/deprecated/datum.py +40 -0
  32. pygeodesy/deprecated/functions.py +375 -0
  33. pygeodesy/deprecated/nvector.py +48 -0
  34. pygeodesy/deprecated/rhumbBase.py +32 -0
  35. pygeodesy/deprecated/rhumbaux.py +33 -0
  36. pygeodesy/deprecated/rhumbsolve.py +33 -0
  37. pygeodesy/deprecated/rhumbx.py +33 -0
  38. pygeodesy/dms.py +986 -0
  39. pygeodesy/ecef.py +1348 -0
  40. pygeodesy/elevations.py +279 -0
  41. pygeodesy/ellipsoidalBase.py +1224 -0
  42. pygeodesy/ellipsoidalBaseDI.py +913 -0
  43. pygeodesy/ellipsoidalExact.py +343 -0
  44. pygeodesy/ellipsoidalGeodSolve.py +343 -0
  45. pygeodesy/ellipsoidalKarney.py +403 -0
  46. pygeodesy/ellipsoidalNvector.py +685 -0
  47. pygeodesy/ellipsoidalVincenty.py +590 -0
  48. pygeodesy/ellipsoids.py +2476 -0
  49. pygeodesy/elliptic.py +1198 -0
  50. pygeodesy/epsg.py +243 -0
  51. pygeodesy/errors.py +804 -0
  52. pygeodesy/etm.py +1190 -0
  53. pygeodesy/fmath.py +1013 -0
  54. pygeodesy/formy.py +1818 -0
  55. pygeodesy/frechet.py +865 -0
  56. pygeodesy/fstats.py +760 -0
  57. pygeodesy/fsums.py +1898 -0
  58. pygeodesy/gars.py +358 -0
  59. pygeodesy/geodesicw.py +581 -0
  60. pygeodesy/geodesicx/_C4_24.py +1699 -0
  61. pygeodesy/geodesicx/_C4_27.py +2395 -0
  62. pygeodesy/geodesicx/_C4_30.py +3301 -0
  63. pygeodesy/geodesicx/__init__.py +48 -0
  64. pygeodesy/geodesicx/__main__.py +91 -0
  65. pygeodesy/geodesicx/gx.py +1382 -0
  66. pygeodesy/geodesicx/gxarea.py +535 -0
  67. pygeodesy/geodesicx/gxbases.py +154 -0
  68. pygeodesy/geodesicx/gxline.py +669 -0
  69. pygeodesy/geodsolve.py +426 -0
  70. pygeodesy/geohash.py +914 -0
  71. pygeodesy/geoids.py +1884 -0
  72. pygeodesy/hausdorff.py +892 -0
  73. pygeodesy/heights.py +1155 -0
  74. pygeodesy/interns.py +687 -0
  75. pygeodesy/iters.py +545 -0
  76. pygeodesy/karney.py +919 -0
  77. pygeodesy/ktm.py +633 -0
  78. pygeodesy/latlonBase.py +1766 -0
  79. pygeodesy/lazily.py +960 -0
  80. pygeodesy/lcc.py +684 -0
  81. pygeodesy/ltp.py +1107 -0
  82. pygeodesy/ltpTuples.py +1563 -0
  83. pygeodesy/mgrs.py +721 -0
  84. pygeodesy/named.py +1324 -0
  85. pygeodesy/namedTuples.py +683 -0
  86. pygeodesy/nvectorBase.py +695 -0
  87. pygeodesy/osgr.py +781 -0
  88. pygeodesy/points.py +1686 -0
  89. pygeodesy/props.py +628 -0
  90. pygeodesy/resections.py +1048 -0
  91. pygeodesy/rhumb/__init__.py +46 -0
  92. pygeodesy/rhumb/aux_.py +397 -0
  93. pygeodesy/rhumb/bases.py +1148 -0
  94. pygeodesy/rhumb/ekx.py +563 -0
  95. pygeodesy/rhumb/solve.py +572 -0
  96. pygeodesy/simplify.py +647 -0
  97. pygeodesy/solveBase.py +472 -0
  98. pygeodesy/sphericalBase.py +724 -0
  99. pygeodesy/sphericalNvector.py +1264 -0
  100. pygeodesy/sphericalTrigonometry.py +1447 -0
  101. pygeodesy/streprs.py +627 -0
  102. pygeodesy/trf.py +2079 -0
  103. pygeodesy/triaxials.py +1484 -0
  104. pygeodesy/units.py +969 -0
  105. pygeodesy/unitsBase.py +349 -0
  106. pygeodesy/ups.py +538 -0
  107. pygeodesy/utily.py +1231 -0
  108. pygeodesy/utm.py +762 -0
  109. pygeodesy/utmups.py +318 -0
  110. pygeodesy/utmupsBase.py +517 -0
  111. pygeodesy/vector2d.py +785 -0
  112. pygeodesy/vector3d.py +968 -0
  113. pygeodesy/vector3dBase.py +1049 -0
  114. pygeodesy/webmercator.py +383 -0
  115. 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.