pygeodesy 25.11.5__py2.py3-none-any.whl → 25.12.31__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 (125) hide show
  1. pygeodesy/__init__.py +46 -25
  2. pygeodesy/__main__.py +1 -1
  3. pygeodesy/albers.py +1 -1
  4. pygeodesy/angles.py +960 -0
  5. pygeodesy/auxilats/_CX_4.py +1 -1
  6. pygeodesy/auxilats/_CX_6.py +1 -1
  7. pygeodesy/auxilats/_CX_8.py +1 -1
  8. pygeodesy/auxilats/_CX_Rs.py +1 -1
  9. pygeodesy/auxilats/__init__.py +2 -2
  10. pygeodesy/auxilats/__main__.py +1 -1
  11. pygeodesy/auxilats/auxAngle.py +7 -8
  12. pygeodesy/auxilats/auxDLat.py +1 -1
  13. pygeodesy/auxilats/auxDST.py +1 -1
  14. pygeodesy/auxilats/auxLat.py +1 -1
  15. pygeodesy/auxilats/auxily.py +1 -1
  16. pygeodesy/azimuthal.py +6 -5
  17. pygeodesy/basics.py +14 -10
  18. pygeodesy/booleans.py +1 -1
  19. pygeodesy/cartesianBase.py +7 -7
  20. pygeodesy/clipy.py +1 -1
  21. pygeodesy/constants.py +29 -24
  22. pygeodesy/css.py +1 -1
  23. pygeodesy/datums.py +1 -1
  24. pygeodesy/deprecated/__init__.py +1 -1
  25. pygeodesy/deprecated/bases.py +1 -1
  26. pygeodesy/deprecated/classes.py +14 -7
  27. pygeodesy/deprecated/consterns.py +1 -1
  28. pygeodesy/deprecated/datum.py +1 -1
  29. pygeodesy/deprecated/functions.py +1 -1
  30. pygeodesy/deprecated/nvector.py +1 -1
  31. pygeodesy/deprecated/rhumbBase.py +1 -1
  32. pygeodesy/deprecated/rhumbaux.py +1 -1
  33. pygeodesy/deprecated/rhumbsolve.py +1 -1
  34. pygeodesy/deprecated/rhumbx.py +1 -1
  35. pygeodesy/dms.py +1 -1
  36. pygeodesy/ecef.py +1 -1
  37. pygeodesy/ecefLocals.py +1 -1
  38. pygeodesy/elevations.py +1 -1
  39. pygeodesy/ellipsoidalBase.py +1 -1
  40. pygeodesy/ellipsoidalBaseDI.py +1 -1
  41. pygeodesy/ellipsoidalExact.py +1 -1
  42. pygeodesy/ellipsoidalGeodSolve.py +1 -1
  43. pygeodesy/ellipsoidalKarney.py +1 -1
  44. pygeodesy/ellipsoidalNvector.py +1 -1
  45. pygeodesy/ellipsoidalVincenty.py +1 -1
  46. pygeodesy/ellipsoids.py +30 -17
  47. pygeodesy/elliptic.py +1 -1
  48. pygeodesy/epsg.py +1 -1
  49. pygeodesy/errors.py +8 -4
  50. pygeodesy/etm.py +1 -1
  51. pygeodesy/fmath.py +19 -14
  52. pygeodesy/formy.py +251 -10
  53. pygeodesy/frechet.py +1 -1
  54. pygeodesy/fstats.py +1 -1
  55. pygeodesy/fsums.py +41 -29
  56. pygeodesy/gars.py +1 -1
  57. pygeodesy/geod3solve.py +489 -0
  58. pygeodesy/geodesici.py +9 -8
  59. pygeodesy/geodesicw.py +1 -1
  60. pygeodesy/geodesicx/_C4_24.py +1 -1
  61. pygeodesy/geodesicx/_C4_27.py +1 -1
  62. pygeodesy/geodesicx/_C4_30.py +1 -1
  63. pygeodesy/geodesicx/__init__.py +2 -2
  64. pygeodesy/geodesicx/__main__.py +1 -1
  65. pygeodesy/geodesicx/gx.py +1 -1
  66. pygeodesy/geodesicx/gxarea.py +54 -24
  67. pygeodesy/geodesicx/gxbases.py +1 -1
  68. pygeodesy/geodesicx/gxline.py +1 -1
  69. pygeodesy/geodsolve.py +73 -104
  70. pygeodesy/geohash.py +1 -1
  71. pygeodesy/geoids.py +1 -1
  72. pygeodesy/hausdorff.py +1 -1
  73. pygeodesy/heights.py +1 -1
  74. pygeodesy/internals.py +1 -1
  75. pygeodesy/interns.py +3 -3
  76. pygeodesy/iters.py +1 -1
  77. pygeodesy/karney.py +152 -151
  78. pygeodesy/ktm.py +1 -1
  79. pygeodesy/latlonBase.py +1 -1
  80. pygeodesy/lazily.py +24 -13
  81. pygeodesy/lcc.py +1 -1
  82. pygeodesy/ltp.py +1 -1
  83. pygeodesy/ltpTuples.py +1 -1
  84. pygeodesy/mgrs.py +3 -3
  85. pygeodesy/named.py +15 -10
  86. pygeodesy/namedTuples.py +1 -1
  87. pygeodesy/nvectorBase.py +1 -1
  88. pygeodesy/osgr.py +1 -1
  89. pygeodesy/points.py +1 -1
  90. pygeodesy/props.py +6 -4
  91. pygeodesy/resections.py +1 -1
  92. pygeodesy/rhumb/__init__.py +8 -6
  93. pygeodesy/rhumb/aux_.py +1 -1
  94. pygeodesy/rhumb/bases.py +1 -1
  95. pygeodesy/rhumb/ekx.py +1 -1
  96. pygeodesy/rhumb/solve.py +91 -84
  97. pygeodesy/simplify.py +1 -1
  98. pygeodesy/solveBase.py +72 -49
  99. pygeodesy/sphericalBase.py +1 -1
  100. pygeodesy/sphericalNvector.py +1 -1
  101. pygeodesy/sphericalTrigonometry.py +1 -1
  102. pygeodesy/streprs.py +6 -4
  103. pygeodesy/trf.py +2 -4
  104. pygeodesy/triaxials/__init__.py +70 -0
  105. pygeodesy/triaxials/bases.py +966 -0
  106. pygeodesy/triaxials/conformal3.py +617 -0
  107. pygeodesy/triaxials/triaxial3.py +968 -0
  108. pygeodesy/{triaxials.py → triaxials/triaxial5.py} +353 -781
  109. pygeodesy/units.py +1 -1
  110. pygeodesy/unitsBase.py +1 -1
  111. pygeodesy/ups.py +2 -3
  112. pygeodesy/utily.py +17 -14
  113. pygeodesy/utm.py +1 -1
  114. pygeodesy/utmups.py +1 -1
  115. pygeodesy/utmupsBase.py +1 -1
  116. pygeodesy/vector2d.py +1 -1
  117. pygeodesy/vector3d.py +1 -1
  118. pygeodesy/vector3dBase.py +1 -1
  119. pygeodesy/webmercator.py +1 -1
  120. pygeodesy/wgrs.py +1 -1
  121. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/METADATA +28 -21
  122. pygeodesy-25.12.31.dist-info/RECORD +125 -0
  123. pygeodesy-25.11.5.dist-info/RECORD +0 -119
  124. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/WHEEL +0 -0
  125. {pygeodesy-25.11.5.dist-info → pygeodesy-25.12.31.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,489 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''Wrapper to invoke I{Karney}'s U{Geod3Solve
5
+ <https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>} utility
6
+ as a C{triaxial} geodesic, but intended I{mainly for testing purposes}.
7
+
8
+ Set env variable C{PYGEODESY_GEOD3SOLVE} to the (fully qualified) path of
9
+ the C{Geod3Solve} executable or use property L{Geodesic3Solve.Geod3Solve
10
+ <geod3solve._Geodesic3SolveBase.Geod3Solve>}.
11
+ '''
12
+
13
+ from pygeodesy.angles import Ang, Deg, isAng, hypot
14
+ from pygeodesy.basics import _xinstanceof # typename
15
+ from pygeodesy.constants import _0_0, _0_5, _360_0, _over
16
+ from pygeodesy.errors import GeodesicError, _xkwds_get
17
+ # from pygeodesy.fmath import hypot # from .angles
18
+ # from pygeodesy.geodesicx import GeodesicAreaExact # _MODS
19
+ from pygeodesy.interns import NN, _a12_, _DMAIN_, _s12_, _UNDER_, _UNUSED_
20
+ from pygeodesy.karney import Caps, _GTuple, _Xables, sincos2d
21
+ # from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY # from .solveBase
22
+ from pygeodesy.props import Property, Property_RO, property_RO
23
+ from pygeodesy.solveBase import _Solve3Base, _ALL_DOCS, _ALL_LAZY
24
+ from pygeodesy.triaxials.triaxial3 import Triaxial3, Triaxial3s
25
+ from pygeodesy.units import Degrees, Meter
26
+ # from pygeodesy.utily import sincos2d # from .karney
27
+
28
+ __all__ = _ALL_LAZY.geod3solve
29
+ __version__ = '25.12.31'
30
+
31
+ _Triaxial3_WGS84 = Triaxial3s.WGS84_3r # a=6378172, b=6378102, c=6356752
32
+
33
+
34
+ class Geodesic3Error(GeodesicError):
35
+ '''Error raised for issues in L{geod3solve<pygeodesy.geod3solve>}.
36
+ '''
37
+ pass
38
+
39
+
40
+ class Geod3Solve8Tuple(_GTuple):
41
+ '''8-Tuple C{(bet1, omg1, alp1, bet2, omg2, alp2, s12, a12)} with C{ellipsoidal}
42
+ latitudes C{bet1} and C{bet2}, C{ellipsoidal} longitudes C{omg1} and C{omg2},
43
+ forward azimuths C{alp1} and C{alp2} in bearings from North, distance C{s12} in
44
+ C{meter}, conventionally and I{approximate} arc length C{a12} in degrees, see
45
+ U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}.
46
+ '''
47
+ # from Geod3Solve --help option -f ... bet1 omg1 alp1 bet2 omg2 alp2 s12
48
+ _Names_ = ('bet1', 'omg1', 'alp1', 'bet2', 'omg2', 'alp2', _s12_, _a12_)
49
+ _Units_ = ( Deg, Deg, Deg, Deg, Deg, Deg, Meter, Deg)
50
+
51
+
52
+ class _Geodesic3SolveBase(_Solve3Base):
53
+ '''(INTERNAL) Base class for L{Geodesic3Solve} and L{GeodesicLine3Solve}.
54
+ '''
55
+ _Error = Geodesic3Error
56
+ _Names_Direct = _Names_Distance = \
57
+ _Names_Inverse = Geod3Solve8Tuple._Names_[:7] # 7 only, always
58
+ _triaxial3 = _Triaxial3_WGS84
59
+ _Xable_name = _Xables.Geod3Solve.__name__ # typename
60
+ _Xable_path = _Xables.Geod3Solve()
61
+
62
+ @Property_RO
63
+ def a(self):
64
+ '''Get the triaxial's I{major} radius, semi-axis (C{meter}).
65
+ '''
66
+ return self._triaxial3.a
67
+
68
+ @Property_RO
69
+ def b(self):
70
+ '''Get the triaxial's I{middle} radius, semi-axis (C{meter}).
71
+ '''
72
+ return self._triaxial3.b
73
+
74
+ @Property_RO
75
+ def c(self):
76
+ '''Get the triaxial's I{minor} radius, semi-axis (C{meter}).
77
+ '''
78
+ return self._triaxial3.c
79
+
80
+ @Property_RO
81
+ def _cmdBasic(self):
82
+ '''(INTERNAL) Get the basic C{GeodSolve} cmd (C{tuple}).
83
+ '''
84
+ return (self.Geod3Solve, '-f') + (self._t_option +
85
+ self._p_option +
86
+ self._u_option)
87
+
88
+ @property_RO
89
+ def _e_option(self):
90
+ return ()
91
+
92
+ _mpd = _E_option = _e_option
93
+ flattening = f = ellipsoid = datum = None
94
+
95
+ @Property
96
+ def Geod3Solve(self):
97
+ '''Get the U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}
98
+ executable (C{filename}).
99
+ '''
100
+ return self._Xable_path
101
+
102
+ @Geod3Solve.setter # PYCHOK setter!
103
+ def Geod3Solve(self, path):
104
+ '''Set the U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}
105
+ executable (C{filename}), the (fully qualified) path to the C{Geod3Solve} executable.
106
+
107
+ @raise GeodesicError: Invalid B{C{path}}, B{C{path}} doesn't exist or
108
+ isn't the C{Geod3Solve} executable.
109
+ '''
110
+ self._setXable(path)
111
+
112
+ @property_RO
113
+ def _t_option(self):
114
+ return ('-t',) + self._toStdin(self._triaxial3._abc3)
115
+
116
+ def toStr(self, **prec_sep): # PYCHOK signature
117
+ '''Return this C{Geodesic3Solve} as string.
118
+
119
+ @kwarg prec_sep: See L{toStr<pygeodesy.solveBase._SolveBase.toStr>}.
120
+
121
+ @return: Geodesic3Solve items (C{str}).
122
+ '''
123
+ return _Solve3Base.toStr(self, Geod3Solve=self.Geod3Solve, **prec_sep)
124
+
125
+ @Property_RO
126
+ def _u_option(self):
127
+ return ('-u',) if self.unroll else ()
128
+
129
+
130
+ class Geodesic3Solve(_Geodesic3SolveBase):
131
+ '''Wrapper to invoke I{Karney}'s U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>}
132
+ as a C{triaxial} version of I{Karney}'s Python class U{Geodesic<https://GeographicLib.SourceForge.io/C++/doc/
133
+ python/code.html#geographiclib.geodesic.Geodesic>}.
134
+
135
+ @note: Use property C{GeodSolve} or env variable C{PYGEODESY_GEOD3SOLVE} to specify the (fully
136
+ qualified) path to the C{Geod3Solve} executable.
137
+
138
+ @note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve}
139
+ executable for I{every} method call.
140
+ '''
141
+
142
+ def __init__(self, triaxial3=_Triaxial3_WGS84, path=NN, **name):
143
+ '''New C{Solve} instance.
144
+
145
+ @arg triaxial3: A triaxial (L{Triaxial3}), default C{Triaxial3s.WGS84_3r}.
146
+ @kwarg path: Optionally, the (fully qualified) path to the C{GeodSolve}
147
+ or C{RhumbSolve} executable (C{filename}).
148
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
149
+
150
+ @raise TypeError: Invalid B{C{a_ellipsoid}} or B{C{f}}.
151
+ '''
152
+ _xinstanceof(Triaxial3, triaxial3=triaxial3)
153
+ if self._triaxial3 != triaxial3:
154
+ self._triaxial3 = triaxial3
155
+ if name:
156
+ self.name = name
157
+ if path:
158
+ self._setXable(path)
159
+
160
+ def _a12d(self, r):
161
+ '''(INTERNAL) Add arc C{a12} in degrees to C{GDict}.
162
+ '''
163
+ a = r.s12 or _0_0
164
+ if a:
165
+ t = self.triaxial3
166
+ z = _toAzi(r.alp1) + _toAzi(r.alp2)
167
+ s, c = sincos2d(z * _0_5)
168
+ a *= hypot(_over(s, t.perimeter4ab), # azimuth!
169
+ _over(c, t.perimeter4bc)) * _360_0
170
+ r[_a12_] = a
171
+ return r
172
+
173
+ def Direct(self, bet1, omg1, alp1, s12, outmask=_UNUSED_, **unit): # PYCHOK unused
174
+ '''Return the C{Direct} result at distance C{s12}.
175
+ '''
176
+ bet1, omg1, alp1 = _toDegrees(bet1, omg1, alp1, **unit)
177
+ r = self._GDictDirect(bet1, omg1, alp1, False, s12)
178
+ return self._a12d(r)
179
+
180
+ def DirectLine(self, bet1, omg1, alp1, caps=Caps.ALL, **unit_name):
181
+ '''Set up a L{GeodesicLine3Solve} to compute several points
182
+ on a single geodesic.
183
+
184
+ @arg bet1: Ellipsoidal Latitude of the first point (C{Ang} or B{C{unit}}).
185
+ @arg omg1: Ellipsoidal Longitude of the first point (C{Ang} or B{C{unit}}).
186
+ @arg alp1: Azimuth at the first point (compass C{degrees}, C{Ang} or C{unit}).
187
+ @kwarg caps: Desired capabilities for the L{GeodesicLine3Solve} instance.
188
+ @kwarg unit_name: Optional C{B{name}=NN} (C{str}) and scalar C{B{unit}=}L{Degrees}
189
+ (or L{Degrees}).
190
+
191
+ @return: A L{GeodesicLine3Solve} instance.
192
+
193
+ @see: C++ U{GeodesicExact.Line
194
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
195
+ and Python U{Geodesic.Line<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
196
+ '''
197
+ return GeodesicLine3Solve(self, bet1, omg1, alp1, caps=caps, **unit_name)
198
+
199
+ Line = DirectLine # ArcDirectLine
200
+
201
+ def Inverse(self, bet1, omg1, bet2, omg2, outmask=_UNUSED_, **unit): # PYCHOK unused
202
+ '''Return the C{Inverse} result.
203
+ '''
204
+ r = self._GDictInverse(*_toDegrees(bet1, omg1, bet2, omg2, **unit))
205
+ return self._a12d(r)
206
+
207
+ def InverseLine(self, bet1, omg1, bet2, omg2, caps=Caps.ALL, **unit_name):
208
+ '''Set up a L{GeodesicLine3Solve} to compute several points
209
+ on a single geodesic.
210
+
211
+ @arg bet1: Latitude of the first point (C{Ang} or B{C{unit}}).
212
+ @arg omg1: Longitude of the first point (C{Ang} or B{C{unit}}).
213
+ @arg bet2: Latitude of the second point (C{Ang} or B{C{unit}}).
214
+ @arg omg2: Longitude of the second point (C{Ang} or B{C{unit}}).
215
+ @kwarg caps: Desired capabilities for the L{GeodesicLine3Solve} instance.
216
+ @kwarg unit_name: Optional C{B{name}=NN} (C{str}) and scalar C{B{unit}=}L{Degrees}
217
+ (or L{Degrees}).
218
+
219
+ @return: A L{GeodesicLine3Solve} instance.
220
+
221
+ @note: Both B{C{bet1}} and B{C{bet2}} should in the range C{[-90, +90]}.
222
+
223
+ @see: C++ U{GeodesicExact.InverseLine
224
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
225
+ Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
226
+ '''
227
+ r = self.Inverse(bet1, omg1, bet2, omg2, **unit_name)
228
+ gl = GeodesicLine3Solve(self, r.bet1, r.omg1, r.alp1, caps=caps, **unit_name)
229
+ # gl._a13 = r.a12 # gl.SetArc(r.a12)
230
+ # gl._s13 = r.s12 # gl.SetDistance(r.s12)
231
+ return gl
232
+
233
+ def toStr(self, **prec_sep_other): # PYCHOK signature
234
+ '''Return this C{Geodesic3Solve} as string.
235
+
236
+ @kwarg prec_sep: See L{toStr<pygeodesy.solveBase._Solve3Base.toStr>}.
237
+
238
+ @return: Geodesic3Solve items (C{str}).
239
+ '''
240
+ return _Solve3Base.toStr(self, Geod3Solve=self.Geod3Solve, **prec_sep_other)
241
+
242
+ @property_RO
243
+ def triaxial3(self):
244
+ '''Get the triaxial (C{Triaxial3}).
245
+ '''
246
+ return self._triaxial3
247
+
248
+
249
+ class GeodesicLine3Solve(_Geodesic3SolveBase): # _SolveGDictLineBase):
250
+ '''Wrapper to invoke I{Karney}'s U{Geod3Solve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.3.html>}
251
+ as a C{triaxial} version of I{Karney}'s Python class U{GeodesicLine<https://GeographicLib.SourceForge.io/
252
+ C++/doc/python/code.html#geographiclib.geodesicline.GeodesicLine>}.
253
+
254
+ @note: Use property C{GeodSolve} or env variable C{PYGEODESY_GEODSOLVE} to specify the (fully
255
+ qualified) path to the C{GeodSolve} executable.
256
+
257
+ @note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve}
258
+ executable for I{every} method call.
259
+ '''
260
+ # _a13 = \
261
+ # _s13 = NAN # see GeodesicSolve._InverseLine
262
+ _solve = None # L{Geodesic3Solve} instance
263
+
264
+ def __init__(self, geodesic3, bet1, omg1, alp1, caps=Caps.ALL, **unit_name):
265
+ '''New L{GeodesicLine3Solve} instance, allowing points to be found along
266
+ a geodesic starting at C{(B{bet1}, B{omg1})} with azimuth B{C{alp1}}.
267
+
268
+ @arg geodesic3: The geodesic to use (L{Geodesic3Solve}).
269
+ @arg bet1: Ellipsoidal latitude of the first point (C{Ang} or B{C{unit}}).
270
+ @arg omg1: Ellipsoidal longitude of the first point (C{Ang} or B{C{unit}}).
271
+ @arg alp1: Azimuth at the first point (compass C{degrees}, C{Ang} or C{unit}).
272
+ @kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
273
+ specifying the capabilities the L{GeodesicLine3Solve} instance
274
+ should possess, C{B{caps}=Caps.ALL} always. Include C{Caps.LINE_OFF}
275
+ if updates to the B{C{geodesic3}} should I{not be reflected} in this
276
+ L{GeodesicLine3Solve} instance.
277
+ @kwarg unit_name: Optional C{B{name}=NN} (C{str}) and scalar C{B{unit}=}L{Degrees}
278
+ (or L{Degrees}).
279
+
280
+ @raise Geodesic3Error: Invalid path for the C{Geod3Solve} executable or isn't the
281
+ C{Geod3Solve} executable, see property C{geodesic3.Geod3Solve}.
282
+
283
+ @raise TypeError: Invalid B{C{geodesic3}}.
284
+ '''
285
+ _xinstanceof(Geodesic3Solve, geodesic3=geodesic3)
286
+ if (caps & Caps.LINE_OFF): # copy to avoid updates
287
+ geodesic3 = geodesic3.copy(deep=False, name=_UNDER_(NN, geodesic3.name)) # NOT _under!
288
+ self._bet1, \
289
+ self._omg1, \
290
+ self._alp1 = _toDegrees(bet1, omg1, alp1, **unit_name)
291
+ self._caps = caps | Caps._AZIMUTH_LATITUDE_LONG_UNROLL
292
+ self._debug = geodesic3._debug & Caps._DEBUG_ALL
293
+ self._solve = geodesic3
294
+ try:
295
+ self.Geod3Solve = geodesic3.Geod3Solve # geodesic or copy of geodesic
296
+ except GeodesicError:
297
+ pass
298
+ if unit_name:
299
+ name = _xkwds_get(unit_name, name=None)
300
+ if name:
301
+ self.name = name
302
+
303
+ @Property_RO
304
+ def alp1(self):
305
+ '''Get the azimuth at the first point (compass C{degrees}).
306
+ '''
307
+ return self._alp1
308
+
309
+ # azi12 = alp1 # like RhumbLineSolve
310
+
311
+ # @Property_RO
312
+ # def azi1_sincos2(self):
313
+ # '''Get the sine and cosine of the first point's azimuth (2-tuple C{(sin, cos)}).
314
+ # '''
315
+ # return _sincos2d(self.alp1)
316
+ #
317
+ # azi12_sincos2 = azi1_sincos2
318
+
319
+ @Property_RO
320
+ def bet1(self):
321
+ '''Get the I{ellipsoidal} latitude of the first point (C{degrees}).
322
+ '''
323
+ return self._bet1
324
+
325
+ @Property_RO
326
+ def _cmdDistance(self):
327
+ '''(INTERNAL) Get the C{Geod3Solve} I{-L} cmd (C{tuple}).
328
+ '''
329
+ t = self.bet1, self.omg1, self.alp1
330
+ return self._cmdBasic + ('-L',) + self._toStdin(t)
331
+
332
+ @property_RO
333
+ def geodesic3(self):
334
+ '''Get the C{triaxial} geodesic (L{Geodesic3Solve}).
335
+ '''
336
+ return self._solve # see .solveBase._SolveLineBase
337
+
338
+ def Intersecant2(self, bet0, omg0, radius, **kwds): # PYCHOK no cover
339
+ '''B{Not implemented}, throws a C{NotImplementedError} always.'''
340
+ self._notImplemented(bet0, omg0, radius, **kwds)
341
+
342
+ @Property_RO
343
+ def omg1(self):
344
+ '''Get the I{ellipsoidal} longitude of the first point (C{degrees}).
345
+ '''
346
+ return self._omg1
347
+
348
+ def PlumbTo(self, bet0, omg0, **kwds): # PYCHOK no cover
349
+ '''B{Not implemented}, throws a C{NotImplementedError} always.'''
350
+ self._notImplemented(bet0, omg0, **kwds)
351
+
352
+ def Position(self, s12, outmask=Caps.ALL): # PYCHOK usused
353
+ '''Find the position on the line given B{C{s12}}.
354
+
355
+ @arg s12: Distance from the first point to the second (C{meter}).
356
+
357
+ @return: A C{GDict} with 7 items C{bet1, omg1, alp1, bet2, omg2, alp2, s12}.
358
+ '''
359
+ r = self._GDictInvoke(self._cmdDistance, self._Names_Distance, s12) # ._unCaps(outmask)
360
+ return self.geodesic3._a12d(r)
361
+
362
+ def toStr(self, **prec_sep_other): # PYCHOK signature
363
+ '''Return this C{GeodesicLine3Solve} as string.
364
+
365
+ @kwarg prec_sep: See L{toStr<pygeodesy.solveBase._Solve3Base.toStr>}.
366
+
367
+ @return: GeodesicLine3Solve items (C{str}).
368
+ '''
369
+ return _Solve3Base.toStr(self, bet1=self.bet1, omg1=self.omg1, alp1=self.alp1,
370
+ geodesic3=self.geodesic3, **prec_sep_other)
371
+
372
+ @property_RO
373
+ def triaxial3(self):
374
+ '''Get the triaxial (C{Triaxial3}).
375
+ '''
376
+ return self.geodesic3.triaxial3
377
+
378
+
379
+ def _toAzi(alp): # as degrees
380
+ return alp.degrees0 if isAng(alp) else alp
381
+
382
+
383
+ def _toDegrees(*angs, **unit_name):
384
+ unit = _xkwds_get(unit_name, unit=Degrees)
385
+ for ang in angs:
386
+ if not isAng(ang):
387
+ ang = Ang.fromScalar(ang, unit=unit)
388
+ yield ang.degrees
389
+
390
+
391
+ __all__ += _ALL_DOCS(_Geodesic3SolveBase)
392
+
393
+ if __name__ == _DMAIN_:
394
+
395
+ def _main():
396
+ from pygeodesy import printf
397
+ from sys import argv
398
+
399
+ gS = Geodesic3Solve(name='Test')
400
+ gS.verbose = v = '--verbose' in argv # or '-v' in argv
401
+
402
+ if not _Xables.X_OK(gS.Geod3Solve): # not set
403
+ gS.Geod3Solve = _Xables.Geod3Solve(_Xables.bin_)
404
+ printf('version: %s', gS.version, nt=v)
405
+
406
+ r = gS.Direct(40.6, -73.8, 51, 5.5e6)
407
+ printf('Direct: %r', r, nt=v)
408
+
409
+ printf('Inverse: %r', gS.Inverse( 40.6, -73.8, 51.6, -0.5), nt=v)
410
+
411
+ glS = GeodesicLine3Solve(gS, 40.6, -73.8, 51, name='LineTest')
412
+ printf('Line: %r', glS)
413
+ p = glS.Position(5.5e6)
414
+ printf('Position: %r %s', p, p == r)
415
+
416
+ _main()
417
+
418
+ # % python3 -m pygeodesy.geod3solve
419
+
420
+ # version: /opt/local/bin/Geod3Solve: GeographicLib version 2.7
421
+ # Direct: GDict(a12=49.410276, alp1=51.0, alp2=107.340251, bet1=40.6, bet2=51.895816, omg1=-73.8, omg2=-1.038308, s12=5500000.0)
422
+ # Inverse: GDict(a12=49.816802, alp1=51.235527, alp2=107.918138, bet1=40.6, bet2=51.6, omg1=-73.8, omg2=-0.5, s12=5545275.651379)
423
+ # Line: GeodesicLine3Solve(alp1=51.0, bet1=40.6, geodesic3=Geodesic3Solve(Geod3Solve='/opt/local/bin/Geod3Solve', invokation=3, status=0), invokation=1, omg1=-73.8, status=0)
424
+ # Position: GDict(a12=49.410276, alp1=51.0, alp2=107.340251, bet1=40.6, bet2=51.895816, omg1=-73.8, omg2=-1.038308, s12=5500000.0) True
425
+
426
+
427
+ # % python3 -m pygeodesy.geod3solve --verbose
428
+
429
+ # Geodesic3Solve 'Test'@1: /opt/local/bin/Geod3Solve --version (invoke)
430
+ # Geodesic3Solve 'Test'@1: '/opt/local/bin/Geod3Solve: GeographicLib version 2.7' (0, stdout/-err)
431
+ # Geodesic3Solve 'Test'@1: /opt/local/bin/Geod3Solve: GeographicLib version 2.7 (0)
432
+ # version: /opt/local/bin/Geod3Solve: GeographicLib version 2.7
433
+ #
434
+ # Geodesic3Solve 'Test'@2: /opt/local/bin/Geod3Solve -f -t 6378172.0 6378102.0 6356752.0 -p 10 \ 40.6 -73.8 51.0 5500000.0 (Direct)
435
+ # Geodesic3Solve 'Test'@2: '40.600000000000001 -73.799999999999997 51.000000000000007 51.895816223972680 -1.038308043217667 107.340251322641734 5500000.0000000000' (0, stdout/-err)
436
+ # Geodesic3Solve 'Test'@2: bet1=40.600000000000001, omg1=-73.799999999999997, alp1=51.000000000000007, bet2=51.89581622397268, omg2=-1.038308043217667, alp2=107.340251322641734, s12=5500000.0 (0)
437
+ # Direct: GDict(a12=49.410276, alp1=51.0, alp2=107.340251, bet1=40.6, bet2=51.895816, omg1=-73.8, omg2=-1.038308, s12=5500000.0)
438
+ #
439
+ # Geodesic3Solve 'Test'@3: /opt/local/bin/Geod3Solve -f -t 6378172.0 6378102.0 6356752.0 -p 10 -i \ 40.6 -73.8 51.6 -0.5 (Inverse)
440
+ # Geodesic3Solve 'Test'@3: '40.600000000000001 -73.799999999999997 51.235527494379824 51.600000000000001 -0.500000000000000 107.918137616344865 5545275.6513788253' (0, stdout/-err)
441
+ # Geodesic3Solve 'Test'@3: bet1=40.600000000000001, omg1=-73.799999999999997, alp1=51.235527494379824, bet2=51.600000000000001, omg2=-0.5, alp2=107.918137616344865, s12=5545275.6513788253 (0)
442
+ # Inverse: GDict(a12=49.816802, alp1=51.235527, alp2=107.918138, bet1=40.6, bet2=51.6, omg1=-73.8, omg2=-0.5, s12=5545275.651379)
443
+ #
444
+ # Line: GeodesicLine3Solve(alp1=51.0, bet1=40.6, geodesic3=Geodesic3Solve(Geod3Solve='/opt/local/bin/Geod3Solve', invokation=3, status=0), invokation=1, omg1=-73.8, status=0)
445
+ # Position: GDict(a12=49.410276, alp1=51.0, alp2=107.340251, bet1=40.6, bet2=51.895816, omg1=-73.8, omg2=-1.038308, s12=5500000.0) True
446
+
447
+
448
+ # Examples <https://GeographicLib.SourceForge.io/C++/doc/Geod3Solve.1.html>
449
+
450
+ # % echo 40:38:23N 073:46:44W-19.43W X 01:21:33N 103:59:22E-19.43W | tr X '\n' | Cart3Convert -G | Cart3Convert -E -r | tr '\n' ' ' | Geod3Solve -i -p 0 -f
451
+ # 40.57193 -54.38111 3.20824 1.35529 123.41971 177.48319 15347602
452
+ # % echo 40:38:23N 073:46:44W-19.43W X 01:21:33N 103:59:22E-19.43W | tr X '\n' | Cart3Convert -G | Cart3Convert -E -r | tr '\n' ' ' | Geod3Solve -i -p 0
453
+ # 3.20824 177.48319 15347602
454
+ # % echo 40:38:23N 073:46:44W-19.43W X 01:21:33N 103:59:22E-19.43W | tr X '\n' | Cart3Convert -G | Cart3Convert -E -r | tr '\n' ' ' | Geod3Solve -i -p 9
455
+ # 3.20824419242752 177.48319457984906 15347602.214888915
456
+
457
+ # % Geod3Solve -L 40.57193 -54.38111 3.20824
458
+ # 15347602
459
+ # 1.35529159 123.41971119 177.48319768
460
+ # 15347602
461
+ # 1.35529159 123.41971119 177.48319768
462
+ # % Geod3Solve -L 40.57193 -54.38111 3.20824 -f
463
+ # 15347602
464
+ # 40.57193000 -54.38111000 3.20824000 1.35529159 123.41971119 177.48319768 15347602.000
465
+ # % Geod3Solve -L 40.57193 -54.38111 3.20824 -f -p 9
466
+ # 15347602
467
+ # 40.57193000000000 -54.38111000000000 3.20824000000000 1.35529159010289 123.41971119123770 177.48319768195134 15347602.000000000
468
+
469
+ # **) MIT License
470
+ #
471
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
472
+ #
473
+ # Permission is hereby granted, free of charge, to any person obtaining a
474
+ # copy of this software and associated documentation files (the "Software"),
475
+ # to deal in the Software without restriction, including without limitation
476
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
477
+ # and/or sell copies of the Software, and to permit persons to whom the
478
+ # Software is furnished to do so, subject to the following conditions:
479
+ #
480
+ # The above copyright notice and this permission notice shall be included
481
+ # in all copies or substantial portions of the Software.
482
+ #
483
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
484
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
485
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
486
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
487
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
488
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
489
+ # OTHER DEALINGS IN THE SOFTWARE.
pygeodesy/geodesici.py CHANGED
@@ -7,10 +7,11 @@ Class L{Intersector} is a pure Python version of I{Karney}'s C++ class U{Interse
7
7
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Intersect.html>}.
8
8
 
9
9
  Class L{Intersectool} is a wrapper to invoke I{Karney}'s U{IntersectTool
10
- <https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} utility, but intended I{for testing purposes only}.
10
+ <https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} utility, mainly intended I{for testing purposes}.
11
11
 
12
- Set env variable C{PYGEODESY_INTERSECTTOOL} to the (fully qualified) path of the C{IntersectTool} executable. For usage
13
- and some examples run C{"env PYGEODESY_INTERSECTTOOL=<IntersectTool-path> python3 -m pygeodesy.geodesici --help"}.
12
+ Set env variable C{PYGEODESY_INTERSECTTOOL} to the (fully qualified) path of the C{IntersectTool} executable or use
13
+ property L{Intersectool.IntersectTool}. For usage and some examples run C{"env PYGEODESY_INTERSECTTOOL=<IntersectTool-path>
14
+ python3 -m pygeodesy.geodesici --help"}.
14
15
 
15
16
  Both L{Intersectool} and L{Intersector} provide methods C{All}, C{Closest}, C{Next} and C{Segment} and produce
16
17
  L{XDict} instances with 4 or more items. Adjacent methods C{All5}, C{Closest5}, C{Next5} and C{Segment} return
@@ -57,7 +58,7 @@ from pygeodesy.utily import atan2, sincos2, fabs, radians
57
58
  # from math import ceil as _ceil, fabs, radians # .fsums, .utily
58
59
 
59
60
  __all__ = _ALL_LAZY.geodesici
60
- __version__ = '25.06.02'
61
+ __version__ = '25.12.31'
61
62
 
62
63
  _0t = 0, # int
63
64
  _1_1t = -1, +1
@@ -487,7 +488,7 @@ class Intersectool(_IntersectBase, _SolveCapsBase):
487
488
  @raise GeodesicError: The eccentricity of the B{C{geodesic}}'s ellipsoid is too
488
489
  large or no initial convergence.
489
490
 
490
- @see: The B{Note} at I{Karney}'s C++ U{Intersect<https://GeographicLib.sourceforge.io/
491
+ @see: The B{Note} at I{Karney}'s C++ U{Intersect<https://GeographicLib.SourceForge.io/
491
492
  C++/doc/classGeographicLib_1_1Intersect.html#ae41f54c9a44836f6c8f140f6994930cf>}.
492
493
  '''
493
494
  g = self._GeodesicExact() if a_geodesic is None else (a_geodesic if f is None else
@@ -777,7 +778,7 @@ class Intersector(_IntersectBase):
777
778
  wrapped L{GeodesicLine<pygeodesy.geodesicw.GeodesicLine>} or
778
779
  L{GeodesicLineSolve<pygeodesy.geodsolve.GeodesicLineSolve>}.
779
780
 
780
- @see: I{Karney}'s C++ class U{Intersect<https://GeographicLib.sourceforge.io/
781
+ @see: I{Karney}'s C++ class U{Intersect<https://GeographicLib.SourceForge.io/
781
782
  C++/doc/classGeographicLib_1_1Intersect.html#details>} for more details.
782
783
  '''
783
784
 
@@ -792,7 +793,7 @@ class Intersector(_IntersectBase):
792
793
  @raise GeodesicError: The eccentricity of the B{C{geodesic}}'s ellipsoid is too
793
794
  large or no initial convergence.
794
795
 
795
- @see: The B{Note} at I{Karney}'s C++ U{Intersect<https://GeographicLib.sourceforge.io/
796
+ @see: The B{Note} at I{Karney}'s C++ U{Intersect<https://GeographicLib.SourceForge.io/
796
797
  C++/doc/classGeographicLib_1_1Intersect.html#ae41f54c9a44836f6c8f140f6994930cf>}.
797
798
  '''
798
799
  _IntersectBase.__init__(self, geodesic, **name)
@@ -1775,7 +1776,7 @@ if __name__ == _DMAIN_: # MCCABE 14
1775
1776
 
1776
1777
  # **) MIT License
1777
1778
  #
1778
- # Copyright (C) 2024-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1779
+ # Copyright (C) 2024-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1779
1780
  #
1780
1781
  # Permission is hereby granted, free of charge, to any person obtaining a
1781
1782
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/geodesicw.py CHANGED
@@ -609,7 +609,7 @@ def _PlumbTo(gl, lat0, lon0, est=None, tol=_TOL):
609
609
 
610
610
  # **) MIT License
611
611
  #
612
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
612
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
613
613
  #
614
614
  # Permission is hereby granted, free of charge, to any person obtaining a
615
615
  # copy of this software and associated documentation files (the "Software"),
@@ -1676,7 +1676,7 @@ del _g, _Gfloats, _f, _f2
1676
1676
 
1677
1677
  # **) MIT License
1678
1678
  #
1679
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1679
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1680
1680
  #
1681
1681
  # Permission is hereby granted, free of charge, to any person obtaining a
1682
1682
  # copy of this software and associated documentation files (the "Software"),
@@ -2372,7 +2372,7 @@ del _g, _Gfloats, _f, _f2
2372
2372
 
2373
2373
  # **) MIT License
2374
2374
  #
2375
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
2375
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
2376
2376
  #
2377
2377
  # Permission is hereby granted, free of charge, to any person obtaining a
2378
2378
  # copy of this software and associated documentation files (the "Software"),
@@ -3278,7 +3278,7 @@ del _g, _Gfloats, _f, _f2
3278
3278
 
3279
3279
  # **) MIT License
3280
3280
  #
3281
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
3281
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
3282
3282
  #
3283
3283
  # Permission is hereby granted, free of charge, to any person obtaining a
3284
3284
  # copy of this software and associated documentation files (the "Software"),
@@ -23,11 +23,11 @@ from pygeodesy.karney import Caps, GeodesicError
23
23
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
24
24
 
25
25
  __all__ = _ALL_LAZY.geodesicx + _ALL_DOCS(Caps, GeodesicError)
26
- __version__ = '25.09.02'
26
+ __version__ = '25.12.23'
27
27
 
28
28
  # **) MIT License
29
29
  #
30
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
30
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
31
31
  #
32
32
  # Permission is hereby granted, free of charge, to any person obtaining a
33
33
  # copy of this software and associated documentation files (the "Software"),
@@ -67,7 +67,7 @@ _main(C4order=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
67
67
 
68
68
  # **) MIT License
69
69
  #
70
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
70
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
71
71
  #
72
72
  # Permission is hereby granted, free of charge, to any person obtaining a
73
73
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/geodesicx/gx.py CHANGED
@@ -1343,7 +1343,7 @@ __all__ += _ALL_DOCS(GeodesicExact, GeodesicLineExact)
1343
1343
 
1344
1344
  # **) MIT License
1345
1345
  #
1346
- # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1346
+ # Copyright (C) 2016-2026 -- mrJean1 at Gmail -- All Rights Reserved.
1347
1347
  #
1348
1348
  # Permission is hereby granted, free of charge, to any person obtaining a
1349
1349
  # copy of this software and associated documentation files (the "Software"),