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/karney.py ADDED
@@ -0,0 +1,919 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''Wrapper around several C{geomath.Math} functions from I{Karney}'s Python package U{geographiclib
5
+ <https://PyPI.org/project/geographiclib>}, provided that package is installed.
6
+
7
+ The I{wrapped} class methods return a L{GDict} instance offering access to the C{dict} items
8
+ either by C{key} or by C{attribute} name.
9
+ All methods of the I{wrapped} L{Geodesic<geodesicw.Geodesic>} and L{GeodesicLine<geodesicw.GeodesicLine>}
10
+ classes return a L{GDict} instance offering access to the C{dict} items either by C{key} or by
11
+ C{attribute} name.
12
+
13
+ With env variable C{PYGEODESY_GEOGRAPHICLIB} left undefined or set to C{"2"}, modules L{geodesicx},
14
+ L{geodesicw} and this module will use U{GeographicLib 2.0<https://GeographicLib.SourceForge.io/C++/doc/>}
15
+ and newer transcoding, otherwise C{1.52} or older.
16
+
17
+ Karney-based functionality
18
+ ==========================
19
+
20
+ 1. The following classes and functions in C{pygeodesy}
21
+
22
+ - L{AlbersEqualArea}, L{AlbersEqualArea2}, L{AlbersEqualArea4},
23
+ L{AlbersEqualAreaCylindrical}, L{AlbersEqualAreaNorth}, L{AlbersEqualAreaSouth} --
24
+ U{AlbersEqualArea<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AlbersEqualArea.html>}
25
+
26
+ - L{AuxAngle}, L{AuxDST}, L{AuxDLat}, L{AuxLat} -- U{AuxAngle
27
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxAngle.html>},
28
+ U{DST<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1DST.html>},
29
+ U{DAuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1DAuxLatitude.html>},
30
+ U{AuxLatitude<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AuxLatitude.html>} in I{GeographicLib 2.2+}
31
+
32
+ - L{CassiniSoldner} -- U{CassiniSoldner<https://GeographicLib.SourceForge.io/C++/doc/
33
+ classGeographicLib_1_1CassiniSoldner.html>}
34
+
35
+ - L{EcefKarney} -- U{Geocentric<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Geocentric.html>}
36
+
37
+ - L{Elliptic} -- U{EllipticFunction<https://GeographicLib.SourceForge.io/C++/doc/
38
+ classGeographicLib_1_1EllipticFunction.html>}
39
+
40
+ - L{EquidistantExact}, L{EquidistantGeodSolve}, L{EquidistantKarney} -- U{AzimuthalEquidistant
41
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1AzimuthalEquidistant.html>}
42
+
43
+ - L{Etm}, L{ExactTransverseMercator} -- U{TransverseMercatorExact
44
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercatorExact.html>}
45
+
46
+ - L{Geodesic}, L{GeodesicLine} -- I{wrapped} U{geodesic.Geodesic<https://PyPI.org/project/geographiclib>},
47
+ I{wrapped} U{geodesicline.GeodesicLine<https://PyPI.org/project/geographiclib>}
48
+
49
+ - L{GeodesicAreaExact}, L{PolygonArea} -- U{PolygonArea<https://GeographicLib.SourceForge.io/C++/doc/
50
+ classGeographicLib_1_1PolygonAreaT.html>}
51
+
52
+ - L{GeodesicExact}, L{GeodesicLineExact} -- U{GeodesicExact<https://GeographicLib.SourceForge.io/C++/doc/
53
+ classGeographicLib_1_1GeodesicExact.html>}, U{GeodesicLineExact<https://GeographicLib.SourceForge.io/C++/doc/
54
+ classGeographicLib_1_1GeodesicLineExact.html>}
55
+
56
+ - L{GeoidKarney} -- U{Geoid<https://GeographicLib.SourceForge.io/C++/doc/geoid.html>}
57
+
58
+ - L{Georef} -- U{Georef<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Georef.html>}
59
+
60
+ - L{GnomonicExact}, L{GnomonicGeodSolve}, L{GnomonicKarney} -- U{Gnomonic
61
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Gnomonic.html>}
62
+
63
+ - L{JacobiConformal} -- U{JacobiConformal
64
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1JacobiConformal.html#details>}
65
+
66
+ - L{KTransverseMercator} - U{TransverseMercator
67
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
68
+
69
+ - L{LocalCartesian}, L{Ltp} -- U{LocalCartesian<https://GeographicLib.SourceForge.io/C++/doc/
70
+ classGeographicLib_1_1LocalCartesian.html>}
71
+
72
+ - L{Osgr} -- U{OSGB<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1OSGB.html>}
73
+
74
+ - L{rhumb.aux_}, L{RhumbAux}, L{RhumbLineAux} -- U{Rhumb
75
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Rhumb.html>} and U{RhumbLine
76
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1RhumbLine.html>} from I{GeographicLib 2.2+}
77
+
78
+ - L{rhumb.ekx}, L{Rhumb}, L{RhumbLine} -- U{Rhumb
79
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Rhumb.html>},
80
+ U{RhumbLine<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1RhumbLine.html>},
81
+ U{TransverseMercator<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
82
+ from I{GeographicLib 2.0}
83
+
84
+ - L{Ups} -- U{PolarStereographic<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1PolarStereographic.html>}
85
+
86
+ - L{Utm} -- U{TransverseMercator<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
87
+
88
+ - L{UtmUps}, L{Epsg} -- U{UTMUPS<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1UTMUPS.html>}
89
+
90
+ - L{atan1d}, L{atan2d}, L{sincos2}, L{sincos2d}, L{tand} -- U{geomath.Math
91
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Math.html>}
92
+
93
+ are I{transcoded} from C++ classes in I{Karney}'s U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>}.
94
+
95
+ 2. These C{pygeodesy} modules and classes
96
+
97
+ - L{ellipsoidalGeodSolve}, L{ellipsoidalKarney}, L{geodsolve}, L{karney}, L{rhumb.solve}
98
+ - L{EquidistantKarney}, L{FrechetKarney}, L{GeodesicSolve}, L{GeodesicLineSolve}, L{GnomonicGeodSolve},
99
+ L{GnomonicKarney}, L{HeightIDWkarney}
100
+
101
+ are or use I{wrappers} around I{Karney}'s Python U{geographiclib<https://PyPI.org/project/geographiclib>}
102
+ C{geodesic}, C++ utility U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>} or
103
+ C++ utility U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>}.
104
+
105
+ 3. All C{pygeodesy} functions and methods to compute I{ellipsoidal} intersections, nearest points and trilaterations
106
+
107
+ - L{ellipsoidalExact.intersection3}, L{ellipsoidalExact.intersections2}, L{ellipsoidalExact.nearestOn},
108
+ L{ellipsoidalExact.LatLon.intersection3}, L{ellipsoidalExact.LatLon.intersections2},
109
+ L{ellipsoidalExact.LatLon.nearestOn}, L{ellipsoidalExact.LatLon.trilaterate5}
110
+
111
+ - L{ellipsoidalKarney.intersection3}, L{ellipsoidalKarney.intersections2}, L{ellipsoidalKarney.nearestOn},
112
+ L{ellipsoidalKarney.LatLon.intersection3}, L{ellipsoidalKarney.LatLon.intersections2},
113
+ L{ellipsoidalKarney.LatLon.nearestOn}, L{ellipsoidalKarney.LatLon.trilaterate5}
114
+
115
+ - L{ellipsoidalVincenty.intersection3}, L{ellipsoidalVincenty.intersections2}, L{ellipsoidalVincenty.nearestOn},
116
+ L{ellipsoidalVincenty.LatLon.intersection3}, L{ellipsoidalVincenty.LatLon.intersections2},
117
+ L{ellipsoidalVincenty.LatLon.nearestOn}, L{ellipsoidalVincenty.LatLon.trilaterate5}
118
+
119
+ - L{RhumbLineAux.Intersection} and L{RhumbLine.Intersection}
120
+
121
+ are implementations of I{Karney}'s iterative solution posted under U{The B{ellipsoidal} case
122
+ <https://GIS.StackExchange.com/questions/48937/calculating-intersection-of-two-circles>} and in paper U{Geodesics
123
+ on an ellipsoid of revolution<https://ArXiv.org/pdf/1102.1215.pdf>} (pp 20-21, section B{14. MARITIME BOUNDARIES}).
124
+
125
+ 4. The C{pygeodesy} methods to compute I{ellipsoidal} intersections and nearest points
126
+
127
+ - L{RhumbLineAux.Intersecant2}, L{RhumbLineAux.PlumbTo}, L{RhumbLine.Intersecant2} and L{RhumbLine.PlumbTo}
128
+
129
+ are I{transcoded} of I{Karney}'s iterative C++ function U{rhumb-intercept
130
+ <https://SourceForge.net/p/geographiclib/discussion/1026620/thread/2ddc295e/>}.
131
+
132
+ 5. Spherical functions
133
+
134
+ - L{pygeodesy.excessKarney_}, L{sphericalTrigonometry.areaOf}
135
+
136
+ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
137
+ <https://MathOverflow.net/questions/97711/the-area-of-spherical-polygons>}, 3rd Answer.
138
+ '''
139
+ # make sure int/int division yields float quotient, see .basics
140
+ from __future__ import division as _; del _ # PYCHOK semicolon
141
+
142
+ from pygeodesy.basics import _copysign, int1s, isint, itemsorted, neg, unsigned0, \
143
+ _xgeographiclib, _zip
144
+ from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
145
+ _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
146
+ from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get
147
+ from pygeodesy.fmath import cbrt, fremainder, norm2
148
+ from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi2_, _azi12_, _composite_, \
149
+ _lat1_, _lat2_, _lon1_, _lon2_, _m12_, _M12_, _M21_, \
150
+ _number_, _s12_, _S12_, _UNDER_, _version_info, \
151
+ _BAR_ # PYCHOK used!
152
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
153
+ from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
154
+ from pygeodesy.props import deprecated_method, Property_RO
155
+ from pygeodesy.units import Bearing as _Azi, Degrees as _Deg, Lat, Lon, \
156
+ Meter as _M, Meter2 as _M2, Number_
157
+ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
158
+
159
+ # from math import fabs # from .utily
160
+
161
+ __all__ = _ALL_LAZY.karney
162
+ __version__ = '24.03.22'
163
+
164
+ _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_) == _2_
165
+ _perimeter_ = 'perimeter'
166
+
167
+
168
+ class _GTuple(_NamedTuple): # in .testNamedTuples
169
+ '''(INTERNAL) Helper.
170
+ '''
171
+ def toGDict(self, **updates):
172
+ '''Convert this C{*Tuple} to a L{GDict}.
173
+
174
+ @kwarg updates: Optional items to apply (C{nam=value} pairs)
175
+ '''
176
+ r = GDict(_zip(self._Names_, self)) # strict=True
177
+ if updates:
178
+ r.update(updates)
179
+ if self._iteration is not None:
180
+ r._iteration = self._iteration
181
+ return r
182
+
183
+
184
+ class _Lat(Lat):
185
+ '''(INTERNAL) Latitude B{C{lat}}.
186
+ '''
187
+ def __init__(self, *lat, **Error_name):
188
+ kwds = _xkwds(Error_name, clip=0, Error=GeodesicError)
189
+ Lat.__new__(_Lat, *lat, **kwds)
190
+
191
+
192
+ class _Lon(Lon):
193
+ '''(INTERNAL) Longitude B{C{lon}}.
194
+ '''
195
+ def __init__(self, *lon, **Error_name):
196
+ kwds = _xkwds(Error_name, clip=0, Error=GeodesicError)
197
+ Lon.__new__(_Lon, *lon, **kwds)
198
+
199
+
200
+ class Area3Tuple(_NamedTuple): # in .geodesicx.gxarea
201
+ '''3-Tuple C{(number, perimeter, area)} with the C{number}
202
+ of points of the polygon or polyline, the C{perimeter} in
203
+ C{meter} and the C{area} in C{meter} I{squared}.
204
+ '''
205
+ _Names_ = (_number_, _perimeter_, _area_)
206
+ _Units_ = ( Number_, _M, _M2)
207
+
208
+
209
+ class Caps(object): # PYCHOK
210
+ '''(INTERNAL) Overriden by C{Caps} below.
211
+ '''
212
+ EMPTY = 0 # formerly aka NONE
213
+ _CAP_1 = 1 << 0 # for goedesicw only
214
+ _CAP_1p = 1 << 1 # for goedesicw only
215
+ # _CAP_2 = 1 << 2
216
+ _CAP_3 = 1 << 3 # for goedesicw only
217
+ # _CAP_4 = 1 << 4
218
+ # _CAP_ALL = 0x1F
219
+ # _CAP_MASK = _CAP_ALL
220
+ LATITUDE = 1 << 7 # compute latitude C{lat2}
221
+ LONGITUDE = 1 << 8 # compute longitude C{lon2} _CAP_3
222
+ AZIMUTH = 1 << 9 # azimuths C{azi1} and C{azi2}
223
+ DISTANCE = 1 << 10 # compute distance C{s12} _CAP_1
224
+ DISTANCE_IN = 1 << 11 # allow distance C{s12} in Direct _CAP_1 | _CAP_1p
225
+ REDUCEDLENGTH = 1 << 12 # compute reduced length C{m12} _CAP_1 | _CAP_2
226
+ GEODESICSCALE = 1 << 13 # compute geodesic scales C{M12} and C{M21} _CAP_1 | _CAP_2
227
+ AREA = 1 << 14 # compute area C{S12} _CAP_4
228
+
229
+ STANDARD = AZIMUTH | DISTANCE | DISTANCE_IN | LATITUDE | LONGITUDE
230
+ ALL = 0x7F80 # without LONG_UNROLL, LINE_OFF, REVERSE2 and _DEBUG_*
231
+
232
+ _DIRECT3 = AZIMUTH | LATITUDE | LONGITUDE | _CAP_3 # for goedesicw only
233
+ _INVERSE3 = AZIMUTH | DISTANCE | _CAP_1 # for goedesicw only
234
+ _STD = STANDARD | _CAP_3 | _CAP_1 # for goedesicw only
235
+ _STD_LINE = _STD | _CAP_1p # for goedesicw only
236
+
237
+ LINE_OFF = 1 << 15 # Line without updates from parent geodesic or rhumb
238
+ LONG_UNROLL = 1 << 16 # unroll C{lon2} in .Direct and .Position
239
+ REVERSE2 = 1 << 17 # reverse C{azi2}
240
+
241
+ LATITUDE_LONGITUDE = LATITUDE | LONGITUDE
242
+ LATITUDE_LONGITUDE_AREA = LATITUDE | LONGITUDE | AREA
243
+
244
+ AZIMUTH_DISTANCE = AZIMUTH | DISTANCE
245
+ AZIMUTH_DISTANCE_AREA = AZIMUTH | DISTANCE | AREA
246
+
247
+ _ANGLE_ONLY = 1 << 18 # angular distance C{a12} only
248
+ _SALPs_CALPs = 1 << 19 # (INTERNAL) GeodesicExact._GenInverse
249
+
250
+ _DEBUG_AREA = 1 << 20 # (INTERNAL) include Line details
251
+ _DEBUG_DIRECT = 1 << 21 # (INTERNAL) include Direct details
252
+ _DEBUG_INVERSE = 1 << 22 # (INTERNAL) include Inverse details
253
+ _DEBUG_LINE = 1 << 23 # (INTERNAL) include Line details
254
+ _DEBUG_ALL = _DEBUG_AREA | _DEBUG_DIRECT | _DEBUG_INVERSE | \
255
+ _DEBUG_LINE | _ANGLE_ONLY | _SALPs_CALPs
256
+
257
+ _OUT_ALL = ALL
258
+ _OUT_MASK = ALL | LONG_UNROLL | REVERSE2 | _DEBUG_ALL
259
+
260
+ _AZIMUTH_LATITUDE_LONGITUDE = AZIMUTH | LATITUDE | LONGITUDE
261
+ _DEBUG_DIRECT_LINE = _DEBUG_DIRECT | _DEBUG_LINE
262
+ # _DISTANCE_IN_OUT = DISTANCE_IN & _OUT_MASK # == DISTANCE_IN in .gx, .gxline
263
+ _LINE = AZIMUTH | LATITUDE | LONG_UNROLL
264
+ _REDUCEDLENGTH_GEODESICSCALE = REDUCEDLENGTH | GEODESICSCALE
265
+ # _REDUCEDLENGTH_GEODESICSCALE_DISTANCE = REDUCEDLENGTH | GEODESICSCALE | DISTANCE
266
+
267
+ def toStr(self, Csk, sep=_BAR_):
268
+ '''Return a C{Caps} or C{outmask} as C{str} or tuple of C{str}s.
269
+ '''
270
+ s = []
271
+ for c, C in itemsorted(self.__class__.__dict__):
272
+ if isint(C) and (Csk & C) and int1s(C) == 1 \
273
+ and (C in (Caps.REVERSE2, Caps._SALPs_CALPs)
274
+ or c.replace(_UNDER_, NN).isupper()):
275
+ s.append(c)
276
+ return sep.join(s) if sep else tuple(s)
277
+
278
+ Caps = Caps() # PYCHOK singleton
279
+ '''I{Enum}-style masks to be bit-C{or}'ed to specify geodesic or
280
+ rhumb capabilities (C{caps}) and expected results (C{outmask}).
281
+
282
+ C{AREA} - compute area C{S12},
283
+
284
+ C{AZIMUTH} - include azimuths C{azi1} and C{azi2},
285
+
286
+ C{DISTANCE} - compute distance C{s12},
287
+
288
+ C{DISTANCE_IN} - allow distance C{s12} in C{.Direct},
289
+
290
+ C{EMPTY} - nothing, formerly aka C{NONE},
291
+
292
+ C{GEODESICSCALE} - compute geodesic scales C{M12} and C{M21},
293
+
294
+ C{LATITUDE} - compute latitude C{lat2},
295
+
296
+ C{LINE_OFF} - Line without updates from parent geodesic or rhumb.
297
+
298
+ C{LONGITUDE} - compute longitude C{lon2},
299
+
300
+ C{LONG_UNROLL} - unroll C{lon2} in C{.Direct},
301
+
302
+ C{REDUCEDLENGTH} - compute reduced length C{m12},
303
+
304
+ C{REVERSE2} - reverse C{azi2},
305
+
306
+ and C{ALL} - all of the above.
307
+
308
+ C{STANDARD} = C{AZIMUTH | DISTANCE | DISTANCE_IN | LATITUDE | LONGITUDE}'''
309
+
310
+
311
+ class _CapsBase(_NamedBase): # in .auxilats, .geodesicx.gxbases
312
+ '''(INTERNAL) Base class for C{[_]Geodesic*Exact}.
313
+ '''
314
+ ALL = Caps.ALL
315
+ AREA = Caps.AREA
316
+ AZIMUTH = Caps.AZIMUTH
317
+ DISTANCE = Caps.DISTANCE
318
+ DISTANCE_IN = Caps.DISTANCE_IN
319
+ EMPTY = Caps.EMPTY # aka NONE
320
+ GEODESICSCALE = Caps.GEODESICSCALE
321
+ LATITUDE = Caps.LATITUDE
322
+ LINE_OFF = Caps.LINE_OFF
323
+ LONGITUDE = Caps.LONGITUDE
324
+ LONG_UNROLL = Caps.LONG_UNROLL
325
+ REDUCEDLENGTH = Caps.REDUCEDLENGTH
326
+ STANDARD = Caps.STANDARD
327
+
328
+ _caps = 0 # None
329
+ _debug = 0 # or Caps._DEBUG_...
330
+
331
+ @Property_RO
332
+ def caps(self):
333
+ '''Get the capabilities (bit-or'ed C{Caps}).
334
+ '''
335
+ return self._caps
336
+
337
+ def caps_(self, caps):
338
+ '''Check the available capabilities.
339
+
340
+ @arg caps: Bit-or'ed combination of L{Caps} values
341
+ for all capabilities to be checked.
342
+
343
+ @return: C{True} if I{all} B{C{caps}} are available,
344
+ C{False} otherwise (C{bool}).
345
+ '''
346
+ caps &= Caps._OUT_ALL
347
+ return (self.caps & caps) == caps
348
+
349
+ @property
350
+ def debug(self):
351
+ '''Get the C{debug} option (C{bool}).
352
+ '''
353
+ return bool(self._debug)
354
+
355
+ @debug.setter # PYCHOK setter!
356
+ def debug(self, debug):
357
+ '''Set the C{debug} option (C{bool}) to include
358
+ more details in L{GDict} results.
359
+ '''
360
+ self._debug = Caps._DEBUG_ALL if debug else 0
361
+
362
+ def _iter2tion(self, r, s):
363
+ '''(INTERNAL) Copy C{C{s}.iter} into C{B{r}._iteration}.
364
+ '''
365
+ i = _xkwds_get(s, iter=None)
366
+ if i is not None:
367
+ self._iteration = r._iteration = i
368
+ return r
369
+
370
+
371
+ class Direct9Tuple(_GTuple):
372
+ '''9-Tuple C{(a12, lat2, lon2, azi2, s12, m12, M12, M21, S12)} with arc
373
+ length C{a12}, angles C{lat2}, C{lon2} and azimuth C{azi2} in C{degrees},
374
+ distance C{s12} and reduced length C{m12} in C{meter} and area C{S12} in
375
+ C{meter} I{squared}.
376
+ '''
377
+ _Names_ = (_a12_, _lat2_, _lon2_, _azi2_, _s12_, _m12_, _M12_, _M21_, _S12_)
378
+ _Units_ = (_Azi, _Lat, _Lon, _Azi, _M, _Pass, _Pass, _Pass, _M2)
379
+
380
+
381
+ class GDict(ADict): # XXX _NamedDict
382
+ '''A C{dict} with both C{key} I{and} C{attribute} access to the C{dict} items.
383
+
384
+ Results of all C{geodesic} and C{rhumb} methods (with capitalized named) are
385
+ returned as L{GDict} instances, see for example L{GeodesicExact} and L{RhumbAux}.
386
+ '''
387
+ def toDirect9Tuple(self, dflt=NAN):
388
+ '''Convert this L{GDict} result to a 9-tuple, like I{Karney}'s method
389
+ C{geographiclib.geodesic.Geodesic._GenDirect}.
390
+
391
+ @kwarg dflt: Default value for missing items (C{any}).
392
+
393
+ @return: L{Direct9Tuple}C{(a12, lat2, lon2, azi2,
394
+ s12, m12, M12, M21, S12)}
395
+ '''
396
+ return self._toTuple(Direct9Tuple, dflt)
397
+
398
+ def toGeodSolve12Tuple(self, dflt=NAN): # PYCHOK 12 args
399
+ '''Convert this L{GDict} result to a 12-Tuple, compatible with I{Karney}'s
400
+ U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}
401
+ result.
402
+
403
+ @kwarg dflt: Default value for missing items (C{any}).
404
+
405
+ @return: L{GeodSolve12Tuple}C{(lat1, lon1, azi1, lat2, lon2, azi2,
406
+ s12, a12, m12, M12, M21, S12)}.
407
+ '''
408
+ return self._toTuple(_MODS.geodsolve.GeodSolve12Tuple, dflt)
409
+
410
+ def toInverse10Tuple(self, dflt=NAN):
411
+ '''Convert this L{GDict} result to a 10-tuple, like I{Karney}'s
412
+ method C{geographiclib.geodesic.Geodesic._GenInverse}.
413
+
414
+ @kwarg dflt: Default value for missing items (C{any}).
415
+
416
+ @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1,
417
+ salp2, calp2, m12, M12, M21, S12)}.
418
+ '''
419
+ return self._toTuple(Inverse10Tuple, dflt)
420
+
421
+ @deprecated_method
422
+ def toRhumb7Tuple(self, dflt=NAN): # PYCHOK no cover
423
+ '''DEPRECATED on 23.12.07, use method C{toRhumb8Tuple}.
424
+
425
+ @return: A I{DEPRECATED} L{Rhumb7Tuple}.
426
+ '''
427
+ return self._toTuple(_MODS.deprecated.classes.Rhumb7Tuple, dflt)
428
+
429
+ def toRhumb8Tuple(self, dflt=NAN):
430
+ '''Convert this L{GDict} result to a 8-tuple.
431
+
432
+ @kwarg dflt: Default value for missing items (C{any}).
433
+
434
+ @return: L{Rhumb8Tuple}C{(lat1, lon1, lat2, lon2,
435
+ azi12, s12, S12, a12)}.
436
+ '''
437
+ return self._toTuple(Rhumb8Tuple, dflt)
438
+
439
+ def toRhumbSolve7Tuple(self, dflt=NAN):
440
+ '''Convert this L{GDict} result to a 8-tuple.
441
+
442
+ @kwarg dflt: Default value for missing items (C{any}).
443
+
444
+ @return: L{RhumbSolve7Tuple}C{(lat1, lon1, lat2, lon2,
445
+ azi12, s12, S12)}.
446
+ '''
447
+ return self._toTuple(_MODS.rhumb.solve.RhumbSolve7Tuple, dflt)
448
+
449
+ def _toTuple(self, nTuple, dflt):
450
+ '''(INTERNAL) Convert this C{GDict} to an B{C{nTuple}}.
451
+ '''
452
+ _g = getattr
453
+ t = tuple(_g(self, n, dflt) for n in nTuple._Names_)
454
+ return nTuple(t, iteration=self._iteration)
455
+
456
+
457
+ class Inverse10Tuple(_GTuple):
458
+ '''10-Tuple C{(a12, s12, salp1, calp1, salp2, calp2, m12, M12, M21, S12)} with arc length
459
+ C{a12} in C{degrees}, distance C{s12} and reduced length C{m12} in C{meter}, area
460
+ C{S12} in C{meter} I{squared} and the sines C{salp1}, C{salp2} and cosines C{calp1},
461
+ C{calp2} of the initial C{1} and final C{2} (forward) azimuths.
462
+ '''
463
+ _Names_ = (_a12_, _s12_, 'salp1', 'calp1', 'salp2', 'calp2', _m12_, _M12_, _M21_, _S12_)
464
+ _Units_ = (_Azi, _M, _Pass, _Pass, _Pass, _Pass, _Pass, _Pass, _Pass, _M2)
465
+
466
+ def toGDict(self, **updates):
467
+ '''Convert this C{Inverse10Tuple} to a L{GDict}.
468
+
469
+ @kwarg updates: Optional items to apply (C{nam=value} pairs)
470
+ '''
471
+ return _GTuple.toGDict(self, azi1=atan2d(self.salp1, self.calp1), # PYCHOK indent, namedTuple
472
+ azi2=atan2d(self.salp2, self.calp2), # PYCHOK namedTuple
473
+ **updates) # PYCHOK indent
474
+
475
+
476
+ class _kWrapped(object): # in .geodesicw
477
+ ''''(INTERNAL) Wrapper for some of I{Karney}'s U{geographiclib
478
+ <https://PyPI.org/project/geographiclib>} classes.
479
+ '''
480
+
481
+ @Property_RO
482
+ def geographiclib(self):
483
+ '''Lazily import C{geographiclib}, provided the U{geographiclib
484
+ <https://PyPI.org/project/geographiclib>} package is installed,
485
+ otherwise raise a C{LazyImportError}.
486
+ '''
487
+ g = _xgeographiclib(self.__class__, 1, 49)
488
+ from geographiclib.geodesic import Geodesic
489
+ g.Geodesic = Geodesic
490
+ from geographiclib.geodesicline import GeodesicLine
491
+ g.GeodesicLine = GeodesicLine
492
+ from geographiclib.geomath import Math
493
+ g.Math = Math
494
+ return g
495
+
496
+ @Property_RO
497
+ def Math(self):
498
+ '''Wrap the C{geomath.Math} class, provided the U{geographiclib
499
+ <https://PyPI.org/project/geographiclib>} package is installed,
500
+ otherwise C{None}.
501
+ '''
502
+ try:
503
+ g = self.geographiclib
504
+ M = g.Math
505
+ if _version_info(g) < (2,):
506
+ if _K_2_0:
507
+ M = None
508
+ # elif not _K_2_0: # XXX set 2.0?
509
+ # _K_2_0 = True
510
+ except (AttributeError, ImportError):
511
+ M = None
512
+ return M
513
+
514
+ _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
515
+
516
+
517
+ class Rhumb8Tuple(_GTuple):
518
+ '''8-Tuple C{(lat1, lon1, lat2, lon2, azi12, s12, S12, a12)} with lat- C{lat1},
519
+ C{lat2} and longitudes C{lon1}, C{lon2} of both points, the azimuth of the
520
+ rhumb line C{azi12}, the distance C{s12}, the area C{S12} under the rhumb
521
+ line and the angular distance C{a12} between both points.
522
+ '''
523
+ _Names_ = (_lat1_, _lon1_, _lat2_, _lon2_, _azi12_, _s12_, _S12_, _a12_)
524
+ _Units_ = ( Lat, Lon, Lat, Lon, _Azi, _M, _M2, _Deg)
525
+
526
+ def toDirect9Tuple(self, dflt=NAN, **a12_azi1_azi2_m12_M12_M21):
527
+ '''Convert this L{Rhumb8Tuple} result to a 9-tuple, like I{Karney}'s
528
+ method C{geographiclib.geodesic.Geodesic._GenDirect}.
529
+
530
+ @kwarg dflt: Default value for missing items (C{any}).
531
+ @kwarg a12_azi1_azi2_m12_M12_M21: Optional keyword arguments
532
+ to specify or override L{Inverse10Tuple} items.
533
+
534
+ @return: L{Direct9Tuple}C{(a12, lat2, lon2, azi2, s12,
535
+ m12, M12, M21, S12)}
536
+ '''
537
+ d = dict(azi1=self.azi12, M12=_1_0, m12=self.s12, # PYCHOK attr
538
+ azi2=self.azi12, M21=_1_0) # PYCHOK attr
539
+ if a12_azi1_azi2_m12_M12_M21:
540
+ d.update(a12_azi1_azi2_m12_M12_M21)
541
+ return self._toTuple(Direct9Tuple, dflt, d)
542
+
543
+ def toInverse10Tuple(self, dflt=NAN, **a12_m12_M12_M21_salp1_calp1_salp2_calp2):
544
+ '''Convert this L{Rhumb8Tuple} to a 10-tuple, like I{Karney}'s
545
+ method C{geographiclib.geodesic.Geodesic._GenInverse}.
546
+
547
+ @kwarg dflt: Default value for missing items (C{any}).
548
+ @kwarg a12_m12_M12_M21_salp1_calp1_salp2_calp2: Optional keyword
549
+ arguments to specify or override L{Inverse10Tuple} items.
550
+
551
+ @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
552
+ m12, M12, M21, S12)}.
553
+ '''
554
+ s, c = sincos2d(self.azi12) # PYCHOK attr
555
+ d = dict(salp1=s, calp1=c, M12=_1_0, m12=self.s12, # PYCHOK attr
556
+ salp2=s, calp2=c, M21=_1_0)
557
+ if a12_m12_M12_M21_salp1_calp1_salp2_calp2:
558
+ d.update(a12_m12_M12_M21_salp1_calp1_salp2_calp2)
559
+ return self._toTuple(Inverse10Tuple, dflt, d)
560
+
561
+ def _toTuple(self, nTuple, dflt, updates={}):
562
+ '''(INTERNAL) Convert this C{Rhumb8Tuple} to an B{C{nTuple}}.
563
+ '''
564
+ _g = self.toGDict(**updates).get
565
+ t = tuple(_g(n, dflt) for n in nTuple._Names_)
566
+ return nTuple(t, name=self.name)
567
+
568
+ @deprecated_method
569
+ def _to7Tuple(self):
570
+ '''DEPRECATED, do not use!'''
571
+ return _MODS.deprecated.classes.Rhumb7Tuple(self[:-1])
572
+
573
+
574
+ def _around(x): # in .utily.sincos2d
575
+ '''I{Coarsen} a scalar by rounding small values to underflow to C{0.0}.
576
+
577
+ @return: Coarsened value (C{float}).
578
+
579
+ @see: I{Karney}'s U{geomath.Math.AngRound<https://SourceForge.net/p/
580
+ geographiclib/code/ci/release/tree/python/geographiclib/geomath.py>}
581
+ '''
582
+ try:
583
+ return _wrapped.Math.AngRound(x)
584
+ except AttributeError:
585
+ if x:
586
+ y = _1_16th - fabs(x)
587
+ if y > 0: # fabs(x) < _1_16th
588
+ x = _copysign(_1_16th - y, x)
589
+ else:
590
+ x = _0_0 # -0 to 0
591
+ return x
592
+
593
+
594
+ def _atan2d(y, x):
595
+ '''Return C{atan2(B{y}, B{x})} in C{degrees}.
596
+ '''
597
+ try:
598
+ return _wrapped.Math.atan2d(y, x)
599
+ except AttributeError:
600
+ return atan2d(y, x)
601
+
602
+
603
+ def _cbrt(x):
604
+ '''Return C{cubic root(B{x})}.
605
+ '''
606
+ try:
607
+ return _wrapped.Math.cbrt(x)
608
+ except AttributeError:
609
+ return cbrt(x)
610
+
611
+
612
+ def _copyBit(x, y):
613
+ '''Like C{copysign0(B{x}, B{y})}, with C{B{x} > 0}.
614
+ '''
615
+ return (-x) if _signBit(y) else x
616
+
617
+
618
+ def _2cos2x(cx, sx): # in .auxDST, .auxLat, .gxbases
619
+ '''Return M{2 * cos(2 * x)} from cos(x) and sin(x).
620
+ '''
621
+ r = cx - sx
622
+ if r:
623
+ r *= (cx + sx) * _2_0
624
+ return r
625
+
626
+
627
+ def _diff182(deg0, deg, K_2_0=False):
628
+ '''Compute C{deg - deg0}, reduced to C{[-180,180]} accurately.
629
+
630
+ @return: 2-Tuple C{(delta_angle, residual)} in C{degrees}.
631
+ '''
632
+ try:
633
+ return _wrapped.Math.AngDiff(deg0, deg)
634
+ except AttributeError:
635
+ if K_2_0 or _K_2_0: # geographiclib 2.0
636
+ _r, _360 = fremainder, _360_0
637
+ d, t = _sum2(_r(-deg0, _360),
638
+ _r( deg, _360))
639
+ d, t = _sum2(_r( d, _360), t)
640
+ if d in (_0_0, _180_0, _N_180_0):
641
+ d = _copysign(d, -t if t else (deg - deg0))
642
+ else:
643
+ _n = _norm180
644
+ d, t = _sum2(_n(-deg0), _n(deg))
645
+ d = _n(d)
646
+ if t > 0 and d == _180_0:
647
+ d = _N_180_0
648
+ d, t = _sum2(d, t)
649
+ return d, t
650
+
651
+
652
+ def _fix90(deg): # mimick Math.LatFix
653
+ '''Replace angle in C{degrees} outside [-90,90] by NAN.
654
+
655
+ @return: Angle C{degrees} or NAN.
656
+ '''
657
+ try:
658
+ return _wrapped.Math.LatFix(deg)
659
+ except AttributeError:
660
+ return NAN if fabs(deg) > 90 else deg
661
+
662
+
663
+ def _isfinite(x): # mimick geomath.Math.isfinite
664
+ '''Check finiteness of C{x}.
665
+
666
+ @return: C{True} if finite.
667
+ '''
668
+ try:
669
+ return _wrapped.Math.isfinite(x)
670
+ except AttributeError:
671
+ return _math_isfinite(x) # and fabs(x) <= _MAX
672
+
673
+
674
+ def _norm2(x, y): # mimick geomath.Math.norm
675
+ '''Normalize C{B{x}} and C{B{y}}.
676
+
677
+ @return: 2-Tuple of C{(B{x}, B{y})}, normalized.
678
+ '''
679
+ try:
680
+ return _wrapped.Math.norm(x, y)
681
+ except AttributeError:
682
+ return norm2(x, y)
683
+
684
+
685
+ def _norm180(deg): # mimick geomath.Math.AngNormalize
686
+ '''Reduce angle in C{degrees} to (-180,180].
687
+
688
+ @return: Reduced angle C{degrees}.
689
+ '''
690
+ try:
691
+ return _wrapped.Math.AngNormalize(deg)
692
+ except AttributeError:
693
+ d = fremainder(deg, _360_0)
694
+ if d in (_180_0, _N_180_0):
695
+ d = _copysign(_180_0, deg) if _K_2_0 else _180_0
696
+ return d
697
+
698
+
699
+ def _polygon(geodesic, points, closed, line, wrap):
700
+ '''(INTERNAL) Compute the area or perimeter of a polygon,
701
+ using a L{GeodesicExact}, L{GeodesicSolve} or (if the
702
+ C{geographiclib} package is installed) a C{Geodesic}
703
+ or C{geodesicw.Geodesic} instance.
704
+ '''
705
+ if not wrap: # capability LONG_UNROLL can't be off
706
+ notImplemented(None, wrap=wrap, up=3)
707
+
708
+ if _MODS.booleans.isBoolean(points):
709
+ # recursive call for each boolean clip
710
+
711
+ def _a_p(clip, *args, **unused):
712
+ return _polygon(geodesic, clip, *args)
713
+
714
+ if not closed: # closed only
715
+ raise _ValueError(closed=closed, points=_composite_)
716
+
717
+ return points._sum1(_a_p, closed, line, wrap)
718
+
719
+ gP = geodesic.Polygon(line)
720
+ _A = gP.AddPoint
721
+
722
+ Ps = _MODS.iters.PointsIter(points, loop=1, wrap=wrap) # base=LatLonEllipsoidalBase(0, 0)
723
+ p1 = p0 = Ps[0]
724
+
725
+ # note, lon deltas are unrolled, by default
726
+ _A(p1.lat, p1.lon)
727
+ for p2 in Ps.iterate(closed=closed):
728
+ if wrap and not Ps.looped:
729
+ p2 = _unrollon(p1, p2)
730
+ _A(p2.lat, p2.lon)
731
+ p1 = p2
732
+ if closed and line and p1 != p0:
733
+ _A(p0.lat, p0.lon)
734
+
735
+ # gP.Compute returns (number_of_points, perimeter, signed area)
736
+ return gP.Compute(False, True)[1 if line else 2]
737
+
738
+
739
+ def _polynomial(x, cs, i, j): # PYCHOK shared
740
+ '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but with a
741
+ different signature and cascaded summation as C{karney._sum2_}.
742
+
743
+ @return: M{sum(cs[k] * x**(j - k - 1) for k in range(i, j)}
744
+ '''
745
+ # assert 0 <= i <= j <= len(cs)
746
+ # try:
747
+ # return _wrapped.Math.polyval(j - i - 1, cs, i, x)
748
+ # except AttributeError:
749
+ # s, t = cs[i], _0_0
750
+ # for c in cs[i+1:j]:
751
+ # s, t = _sum2_(s * x, t * x, c)
752
+ # return s # + t
753
+ s, _ = _sum2_(cs[i], _0_0, x=x, *cs[i+1:j])
754
+ return s # + t
755
+
756
+
757
+ def _remainder(x, y):
758
+ '''Remainder of C{x / y}.
759
+
760
+ @return: Remainder in the range M{[-y / 2, y / 2]}, preserving signed 0.0.
761
+ '''
762
+ try:
763
+ return _wrapped.Math.remainder(x, y)
764
+ except AttributeError:
765
+ return fremainder(x, y)
766
+
767
+
768
+ if _K_2_0:
769
+ from math import cos as _cos, sin as _sin
770
+
771
+ def _sincos2(rad):
772
+ return _sin(rad), _cos(rad)
773
+
774
+ _signBit = _MODS.basics.signBit
775
+ else:
776
+ _sincos2 = _MODS.utily.sincos2 # PYCHOK shared
777
+
778
+ def _signBit(x):
779
+ '''(INTERNAL) GeographicLib 1.52-.
780
+ '''
781
+ return x < 0
782
+
783
+
784
+ def _sincos2d(deg):
785
+ '''Return sine and cosine of an angle in C{degrees}.
786
+
787
+ @return: 2-Tuple C{(sin(B{deg}), cos(B{deg}))}.
788
+ '''
789
+ try:
790
+ return _wrapped.Math.sincosd(deg)
791
+ except AttributeError:
792
+ return sincos2d(deg)
793
+
794
+
795
+ def _sincos2de(deg, t):
796
+ '''Return sine and cosine of a corrected angle in C{degrees}.
797
+
798
+ @return: 2-Tuple C{(sin(B{deg}), cos(B{deg}))}.
799
+ '''
800
+ try:
801
+ return _wrapped.Math.sincosde(deg, t)
802
+ except AttributeError:
803
+ return sincos2d(deg, adeg=t)
804
+
805
+
806
+ def _sum2(u, v): # mimick geomath.Math.sum, actually sum2
807
+ '''Error-free summation like C{geomath.Math.sum}.
808
+
809
+ @return: 2-Tuple C{(B{u} + B{v}, residual)}.
810
+
811
+ @note: The C{residual} can be the same as B{C{u}} or B{C{v}}.
812
+
813
+ @see: U{Algorithm 3.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
814
+ '''
815
+ try:
816
+ return _wrapped.Math.sum(u, v)
817
+ except AttributeError:
818
+ s = u + v
819
+ r = s - v
820
+ t = s - r
821
+ # if Algorithm_3_1:
822
+ # t = (u - t) + (v + r)
823
+ # elif C_CPP: # Math::sum C/C++
824
+ # r -= u
825
+ # t -= v
826
+ # t += r
827
+ # t = -t
828
+ # else:
829
+ t = (u - r) + (v - t)
830
+ return s, t
831
+
832
+
833
+ def _sum2_(s, t, *vs, **x):
834
+ '''Accumulate any B{C{vs}} into a previous C{_sum2(s, t)}.
835
+
836
+ @kwarg x: Optional polynomial C{B{x}=1} (C{scalar}).
837
+
838
+ @return: 2-Tuple C{(B{s} + B{t} + sum(B{vs}), residual)}.
839
+
840
+ @see: I{Karney's} C++ U{Accumulator<https://GeographicLib.SourceForge.io/
841
+ C++/doc/Accumulator_8hpp_source.html>} comments for more details and
842
+ function C{_sum2} above.
843
+
844
+ @note: NOT "error-free", see C{pygeodesy.test/testKarney.py}.
845
+ '''
846
+ x = _xkwds_get(x, x=0)
847
+
848
+ _s2, _u0 = _sum2, unsigned0
849
+ for v in vs:
850
+ if x:
851
+ s *= x
852
+ t *= x
853
+ if v:
854
+ t, u = _s2(t, v) # start at the least-
855
+ if s:
856
+ s, t = _s2(s, t) # significant end
857
+ if s:
858
+ t += u # accumulate u into t
859
+ # elif t: # s == 0 implies t == 0
860
+ # raise _AssertionError(t=t, txt=_not_(_0_))
861
+ else:
862
+ s = _u0(u) # result is u, t = 0
863
+ else:
864
+ s, t = _u0(t), u
865
+ return s, t
866
+
867
+
868
+ def _tand(x):
869
+ '''Return C{tan(B{x})} in C{degrees}.
870
+ '''
871
+ try:
872
+ return _wrapped.Math.tand(x)
873
+ except AttributeError:
874
+ return tand(x)
875
+
876
+
877
+ def _unroll2(lon1, lon2, wrap=False): # see .ellipsoidalBaseDI._intersects2
878
+ '''Unroll B{C{lon2 - lon1}} like C{geodesic.Geodesic.Inverse}.
879
+
880
+ @return: 2-Tuple C{(B{lon2} - B{lon1}, B{lon2})} with B{C{lon2}}
881
+ unrolled if B{C{wrap}} is C{True}, normalized otherwise.
882
+ '''
883
+ if wrap:
884
+ d, t = _diff182(lon1, lon2)
885
+ lon2, _ = _sum2_(d, t, lon1) # (lon1 + d) + t
886
+ else:
887
+ lon2 = _norm180(lon2)
888
+ return (lon2 - lon1), lon2
889
+
890
+
891
+ def _unsigned2(x):
892
+ '''(INTERNAL) Unsign B{C{x}}.
893
+ '''
894
+ return (neg(x), True) if _signBit(x) else (x, False)
895
+
896
+
897
+ __all__ += _ALL_DOCS(_CapsBase)
898
+
899
+ # **) MIT License
900
+ #
901
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
902
+ #
903
+ # Permission is hereby granted, free of charge, to any person obtaining a
904
+ # copy of this software and associated documentation files (the "Software"),
905
+ # to deal in the Software without restriction, including without limitation
906
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
907
+ # and/or sell copies of the Software, and to permit persons to whom the
908
+ # Software is furnished to do so, subject to the following conditions:
909
+ #
910
+ # The above copyright notice and this permission notice shall be included
911
+ # in all copies or substantial portions of the Software.
912
+ #
913
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
914
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
915
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
916
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
917
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
918
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
919
+ # OTHER DEALINGS IN THE SOFTWARE.