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/solveBase.py ADDED
@@ -0,0 +1,472 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''(INTERNAL) Private base classes for L{pygeodesy.geodsolve} and L{pygeodesy.rhumb.solve}.
5
+ '''
6
+
7
+ from pygeodesy.basics import map2, ub2str, _zip
8
+ from pygeodesy.constants import DIG
9
+ from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
10
+ # from pygeodesy.ellipsoids import _EWGS84 # from .datums
11
+ from pygeodesy.errors import _AssertionError, _xkwds_get, _xkwds_item2
12
+ from pygeodesy.interns import NN, _0_, _BACKSLASH_, _COMMASPACE_, _enquote, \
13
+ _EQUAL_, _Error_, _not_, _SPACE_, _UNUSED_
14
+ from pygeodesy.karney import Caps, _CapsBase, GDict
15
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, printf, _unlazy
16
+ from pygeodesy.named import callername, notOverloaded
17
+ from pygeodesy.props import Property, Property_RO, property_RO, _update_all
18
+ from pygeodesy.streprs import Fmt, fstr, fstrzs, pairs, strs
19
+ from pygeodesy.units import Precision_
20
+ from pygeodesy.utily import unroll180, wrap360 # PYCHOK shared
21
+
22
+ from subprocess import PIPE as _PIPE, Popen as _Popen, STDOUT as _STDOUT
23
+
24
+ __all__ = _ALL_LAZY.solveBase
25
+ __version__ = '24.03.15'
26
+
27
+ _ERROR_ = 'ERROR'
28
+ _text_True = dict() if _unlazy else dict(text=True)
29
+
30
+
31
+ def _cmd_stdin_(cmd, stdin): # PYCHOK no cover
32
+ '''(INTERNAL) Cmd line, stdin and caller as sC{str}.
33
+ '''
34
+ c = Fmt.PAREN(callername(up=3))
35
+ t = (c,) if stdin is None else (_BACKSLASH_, str(stdin), c)
36
+ return _SPACE_.join(cmd + t)
37
+
38
+
39
+ def _popen2(cmd, stdin=None): # in .mgrs, .test.base, .test.testMgrs
40
+ '''(INTERNAL) Invoke C{B{cmd} tuple} and return C{exitcode}
41
+ and all output to C{stdout/-err}.
42
+ '''
43
+ p = _Popen(cmd, creationflags=0,
44
+ # executable=sys.executable, shell=True,
45
+ stdin=_PIPE, stdout=_PIPE, stderr=_STDOUT,
46
+ **_text_True) # PYCHOK kwArgs
47
+ r = p.communicate(stdin)[0]
48
+ return p.returncode, ub2str(r).strip()
49
+
50
+
51
+ class _SolveLineSolveBase(_CapsBase):
52
+ '''(NTERNAL) Base class for C{_Solve} and C{_LineSolve}.
53
+ '''
54
+ _Error = None
55
+ _Exact = True
56
+ _invokation = 0
57
+ _Names_Direct = \
58
+ _Names_Inverse = ()
59
+ _prec = Precision_(prec=DIG)
60
+ _reverse2 = False
61
+ _Solve_name = NN # executable basename
62
+ _Solve_path = NN # executable path
63
+ _status = None
64
+ _unroll = False
65
+ _verbose = False
66
+
67
+ @property_RO
68
+ def _cmdBasic(self): # PYCHOK no cover
69
+ '''(INTERNAL) I{Must be overloaded}.'''
70
+ notOverloaded(self, underOK=True)
71
+
72
+ @property
73
+ def Exact(self):
74
+ '''Get the Solve's C{exact} setting (C{bool}).
75
+ '''
76
+ return self._Exact
77
+
78
+ @Exact.setter # PYCHOK setter!
79
+ def Exact(self, Exact):
80
+ '''Set the Solve's C{exact} setting (C{bool}),
81
+ if C{True} use I{exact} version.
82
+ '''
83
+ Exact = bool(Exact)
84
+ if self._Exact != Exact:
85
+ _update_all(self)
86
+ self._Exact = Exact
87
+
88
+ def _GDictInvoke(self, cmd, floats, Names, *args):
89
+ '''(INTERNAL) Invoke C{Solve}, return results as C{GDict}.
90
+ '''
91
+ N = len(Names)
92
+ if N < 1:
93
+ raise _AssertionError(cmd=cmd, Names=Names)
94
+ i = fstr(args, prec=DIG, fmt=Fmt.F, sep=_SPACE_) if args else None # not Fmt.G!
95
+ t = self._invoke(cmd, stdin=i).lstrip().split() # 12-/+ tuple
96
+ if len(t) > N: # PYCHOK no cover
97
+ # unzip instrumented name=value pairs to names and values
98
+ n, v = _zip(*(p.split(_EQUAL_) for p in t[:-N])) # strict=True
99
+ v += tuple(t[-N:])
100
+ n += Names
101
+ else:
102
+ n, v = Names, t
103
+ if self.verbose: # PYCHOK no cover
104
+ self._print(_COMMASPACE_.join(map(Fmt.EQUAL, n, map(fstrzs, v))))
105
+ if floats:
106
+ v = map(float, v)
107
+ r = GDict(_zip(n, v)) # strict=True
108
+ return self._iter2tion(r, r)
109
+
110
+ @property_RO
111
+ def invokation(self):
112
+ '''Get the most recent C{Solve} invokation number (C{int}).
113
+ '''
114
+ return self._invokation
115
+
116
+ def invoke(self, *options, **stdin):
117
+ '''Invoke the C{Solve} executable and return the result.
118
+
119
+ @arg options: No, one or several C{Solve} command line
120
+ options (C{str}s).
121
+ @kwarg stdin: Optional input to pass to C{Solve.stdin} (C{str}).
122
+
123
+ @return: The C{Solve.stdout} and C{.stderr} output (C{str}).
124
+
125
+ @raise GeodesicError: On any error, including a non-zero return
126
+ code from C{GeodSolve}.
127
+
128
+ @raise RhumbError: On any error, including a non-zero return code
129
+ from C{RhumbSolve}.
130
+
131
+ @note: The C{Solve} return code is in property L{status}.
132
+ '''
133
+ c = (self._Solve_path,) + map2(str, options)
134
+ i = _xkwds_get(stdin, stdin=None)
135
+ r = self._invoke(c, stdin=i)
136
+ s = self.status
137
+ if s:
138
+ raise self._Error(cmd=_cmd_stdin_(c, i), status=s,
139
+ txt=_not_(_0_))
140
+ if self.verbose: # PYCHOK no cover
141
+ self._print(r)
142
+ return r
143
+
144
+ def _invoke(self, cmd, stdin=None):
145
+ '''(INTERNAL) Invoke the C{Solve} executable, with the
146
+ given B{C{cmd}} line and optional input to B{C{stdin}}.
147
+ '''
148
+ self._invokation += 1
149
+ self._status = t = None
150
+ if self.verbose: # PYCHOK no cover
151
+ t = _cmd_stdin_(cmd, stdin)
152
+ self._print(t)
153
+ try: # invoke and write to stdin
154
+ s, r = _popen2(cmd, stdin)
155
+ if len(r) < 6 or r[:5] in (_Error_, _ERROR_):
156
+ raise ValueError(r)
157
+ except (IOError, OSError, TypeError, ValueError) as x:
158
+ raise self._Error(cmd=t or _cmd_stdin_(cmd, stdin), cause=x)
159
+ self._status = s
160
+ return r
161
+
162
+ @Property_RO
163
+ def _mpd(self): # meter per degree
164
+ return self.ellipsoid._Lpd
165
+
166
+ @property_RO
167
+ def _p_option(self):
168
+ return '-p', str(self.prec - 5) # -p is distance prec
169
+
170
+ @Property
171
+ def prec(self):
172
+ '''Get the precision, number of (decimal) digits (C{int}).
173
+ '''
174
+ return self._prec
175
+
176
+ @prec.setter # PYCHOK setter!
177
+ def prec(self, prec):
178
+ '''Set the precision for C{angles} in C{degrees}, like C{lat}, C{lon},
179
+ C{azimuth} and C{arc} in number of decimal digits (C{int}, C{0}..L{DIG}).
180
+
181
+ @note: The precision for C{distance = B{prec} - 5} or up to
182
+ 10 decimal digits for C{nanometer} and for C{area =
183
+ B{prec} - 12} or at most C{millimeter} I{squared}.
184
+ '''
185
+ prec = Precision_(prec=prec, high=DIG)
186
+ if self._prec != prec:
187
+ _update_all(self)
188
+ self._prec = prec
189
+
190
+ def _print(self, line): # PYCHOK no cover
191
+ '''(INTERNAL) Print a status line.
192
+ '''
193
+ if self.status is not None:
194
+ line = _SPACE_(line, Fmt.PAREN(self.status))
195
+ printf('%s %d: %s', self.named2, self.invokation, line)
196
+
197
+ @Property
198
+ def reverse2(self):
199
+ '''Get the C{azi2} direction (C{bool}).
200
+ '''
201
+ return self._reverse2
202
+
203
+ @reverse2.setter # PYCHOK setter!
204
+ def reverse2(self, reverse2):
205
+ '''Set the direction for C{azi2} (C{bool}), if C{True} reverse C{azi2}.
206
+ '''
207
+ reverse2 = bool(reverse2)
208
+ if self._reverse2 != reverse2:
209
+ _update_all(self)
210
+ self._reverse2 = reverse2
211
+
212
+ def _setSolve(self, path, **Solve_path):
213
+ '''(INTERNAL) Set the executable C{path}.
214
+ '''
215
+ hold = self._Solve_path
216
+ if hold != path:
217
+ _update_all(self)
218
+ self._Solve_path = path
219
+ try:
220
+ _ = self.version # test path and ...
221
+ if self.status: # ... return code
222
+ S_p = Solve_path or {self._Solve_name: _enquote(path)}
223
+ raise self._Error(status=self.status, txt=_not_(_0_), **S_p)
224
+ hold = path
225
+ finally: # restore in case of error
226
+ if self._Solve_path != hold:
227
+ _update_all(self)
228
+ self._Solve_path = hold
229
+
230
+ @property_RO
231
+ def status(self):
232
+ '''Get the most recent C{Solve} return code (C{int}, C{str})
233
+ or C{None}.
234
+ '''
235
+ return self._status
236
+
237
+ @Property
238
+ def unroll(self):
239
+ '''Get the C{lon2} unroll'ing (C{bool}).
240
+ '''
241
+ return self._unroll
242
+
243
+ @unroll.setter # PYCHOK setter!
244
+ def unroll(self, unroll):
245
+ '''Set unroll'ing for C{lon2} (C{bool}), if C{True} unroll C{lon2}, otherwise don't.
246
+ '''
247
+ unroll = bool(unroll)
248
+ if self._unroll != unroll:
249
+ _update_all(self)
250
+ self._unroll = unroll
251
+
252
+ @property
253
+ def verbose(self):
254
+ '''Get the C{verbose} option (C{bool}).
255
+ '''
256
+ return self._verbose
257
+
258
+ @verbose.setter # PYCHOK setter!
259
+ def verbose(self, verbose):
260
+ '''Set the C{verbose} option (C{bool}), C{True} prints
261
+ a message around each C{RhumbSolve} invokation.
262
+ '''
263
+ self._verbose = bool(verbose)
264
+
265
+ @Property_RO
266
+ def version(self):
267
+ '''Get the result of C{"GeodSolve --version"} or C{"RhumbSolve --version"}.
268
+ '''
269
+ return self.invoke('--version')
270
+
271
+
272
+ class _SolveBase(_SolveLineSolveBase):
273
+ '''(NTERNAL) Base class for C{_GeodesicSolveBase} and C{_RhumbSolveBase}.
274
+ '''
275
+ _datum = _WGS84
276
+
277
+ def __init__(self, a_ellipsoid=_EWGS84, f=None, path=NN, name=NN):
278
+ '''New C{Solve} instance.
279
+
280
+ @arg a_ellipsoid: An ellipsoid (L{Ellipsoid}) or datum (L{Datum}) or
281
+ the equatorial radius of the ellipsoid (C{scalar},
282
+ conventionally in C{meter}), see B{C{f}}.
283
+ @arg f: The flattening of the ellipsoid (C{scalar}) if B{C{a_ellipsoid}}
284
+ is specified as C{scalar}.
285
+ @kwarg path: Optionally, the (fully qualified) path to the C{GeodSolve}
286
+ or C{RhumbSolve} executable (C{filename}).
287
+ @kwarg name: Optional name (C{str}).
288
+
289
+ @raise TypeError: Invalid B{C{a_ellipsoid}} or B{C{f}}.
290
+ '''
291
+ _earth_datum(self, a_ellipsoid, f=f, name=name)
292
+ if name:
293
+ self.name = name
294
+ if path:
295
+ self._setSolve(path)
296
+
297
+ @Property_RO
298
+ def a(self):
299
+ '''Get the I{equatorial} radius, semi-axis (C{meter}).
300
+ '''
301
+ return self.ellipsoid.a
302
+
303
+ @Property_RO
304
+ def _cmdDirect(self):
305
+ '''(INTERNAL) Get the C{Solve} I{Direct} cmd (C{tuple}).
306
+ '''
307
+ return self._cmdBasic
308
+
309
+ @Property_RO
310
+ def _cmdInverse(self):
311
+ '''(INTERNAL) Get the C{Solve} I{Inverse} cmd (C{tuple}).
312
+ '''
313
+ return self._cmdBasic + ('-i',)
314
+
315
+ @property_RO
316
+ def datum(self):
317
+ '''Get the datum (C{Datum}).
318
+ '''
319
+ return self._datum
320
+
321
+ def Direct(self, lat1, lon1, azi1, s12, outmask=_UNUSED_): # PYCHOK unused
322
+ '''Return the C{Direct} result.
323
+ '''
324
+ return self._GDictDirect(lat1, lon1, azi1, False, s12)
325
+
326
+ @Property_RO
327
+ def ellipsoid(self):
328
+ '''Get the ellipsoid (C{Ellipsoid}).
329
+ '''
330
+ return self.datum.ellipsoid
331
+
332
+ @Property_RO
333
+ def _e_option(self):
334
+ E = self.ellipsoid
335
+ if E is _EWGS84:
336
+ return () # default
337
+ a, f = strs(E.a_f, fmt=Fmt.F, prec=DIG + 3) # not .G!
338
+ return ('-e', a, f)
339
+
340
+ @Property_RO
341
+ def flattening(self):
342
+ '''Get the C{ellipsoid}'s I{flattening} (C{scalar}), M{(a - b) / a},
343
+ C{0} for spherical, negative for prolate.
344
+ '''
345
+ return self.ellipsoid.f
346
+
347
+ f = flattening
348
+
349
+ def _GDictDirect(self, lat, lon, azi, arcmode, s12_a12, outmask=_UNUSED_, **floats): # PYCHOK for .geodesicx.gxarea
350
+ '''(INTERNAL) Get C{_GenDirect}-like result as C{GDict}.
351
+ '''
352
+ if arcmode:
353
+ raise self._Error(arcmode=arcmode, txt=str(NotImplemented))
354
+ floats = _xkwds_get(floats, floats=True)
355
+ return self._GDictInvoke(self._cmdDirect, floats, self._Names_Direct,
356
+ lat, lon, azi, s12_a12)
357
+
358
+ def _GDictInverse(self, lat1, lon1, lat2, lon2, outmask=_UNUSED_, **floats): # PYCHOK for .geodesicx.gxarea
359
+ '''(INTERNAL) Get C{_GenInverse}-like result as C{GDict}, but
360
+ I{without} C{_SALPs_CALPs_}.
361
+ '''
362
+ floats = _xkwds_get(floats, floats=True)
363
+ return self._GDictInvoke(self._cmdInverse, floats, self._Names_Inverse,
364
+ lat1, lon1, lat2, lon2)
365
+
366
+ def Inverse(self, lat1, lon1, lat2, lon2, outmask=_UNUSED_): # PYCHOK unused
367
+ '''Return the C{Inverse} result.
368
+ '''
369
+ return self._GDictInverse(lat1, lon1, lat2, lon2)
370
+
371
+ def Inverse1(self, lat1, lon1, lat2, lon2, wrap=False):
372
+ '''Return the non-negative, I{angular} distance in C{degrees}.
373
+ '''
374
+ # see .FrechetKarney.distance, .HausdorffKarney._distance
375
+ # and .HeightIDWkarney._distances
376
+ _, lon2 = unroll180(lon1, lon2, wrap=wrap) # self.LONG_UNROLL
377
+ r = self._GDictInverse(lat1, lon1, lat2, lon2, floats=False)
378
+ # XXX self.DISTANCE needed for 'a12'?
379
+ return abs(float(r.a12))
380
+
381
+ def _toStr(self, prec=6, sep=_COMMASPACE_, **Solve): # PYCHOK signature
382
+ '''(INTERNAL) Return this C{_Solve} as string..
383
+ '''
384
+ d = dict(ellipsoid=self.ellipsoid, invokation=self.invokation,
385
+ status=self.status, **Solve)
386
+ return sep.join(pairs(d, prec=prec))
387
+
388
+
389
+ class _SolveLineBase(_SolveLineSolveBase):
390
+ '''(NTERNAL) Base class for C{GeodesicLineSolve} and C{RhumbLineSolve}.
391
+ '''
392
+ # _caps = 0
393
+ # _lla1 = {}
394
+ _solve = None # L{GeodesicSolve} or L{RhumbSolve} instance
395
+
396
+ def __init__(self, solve, lat1, lon1, caps, name, **azi):
397
+ self._caps = caps | Caps._LINE
398
+ self._debug = solve._debug & Caps._DEBUG_ALL
399
+ self._lla1 = GDict(lat1=lat1, lon1=lon1, **azi)
400
+ self._solve = solve
401
+
402
+ n = name or solve.name
403
+ if n:
404
+ self.name = n
405
+
406
+ @Property_RO
407
+ def _cmdDistance(self):
408
+ '''(INTERNAL) Get the C{GeodSolve} I{-L} cmd (C{tuple}).
409
+ '''
410
+ def _lla3(lat1=0, lon1=0, **azi):
411
+ _, azi = _xkwds_item2(azi)
412
+ return lat1, lon1, azi
413
+
414
+ t = strs(_lla3(**self._lla1), prec=DIG, fmt=Fmt.F) # self._solve.prec
415
+ return self._cmdBasic + ('-L',) + t
416
+
417
+ @property_RO
418
+ def datum(self):
419
+ '''Get the datum (C{Datum}).
420
+ '''
421
+ return self._solve.datum
422
+
423
+ @property_RO
424
+ def ellipsoid(self):
425
+ '''Get the ellipsoid (C{Ellipsoid}).
426
+ '''
427
+ return self._solve.ellipsoid
428
+
429
+ @Property_RO
430
+ def lat1(self):
431
+ '''Get the latitude of the first point (C{degrees}).
432
+ '''
433
+ return self._lla1.lat1
434
+
435
+ @Property_RO
436
+ def lon1(self):
437
+ '''Get the longitude of the first point (C{degrees}).
438
+ '''
439
+ return self._lla1.lon1
440
+
441
+ def _toStr(self, prec=6, sep=_COMMASPACE_, **solve): # PYCHOK signature
442
+ '''(INTERNAL) Return this C{_LineSolve} as string..
443
+ '''
444
+ d = dict(ellipsoid=self.ellipsoid, invokation=self._solve.invokation,
445
+ lat1=self.lat1, lon1=self.lon1,
446
+ status=self._solve.status, **solve)
447
+ return sep.join(pairs(d, prec=prec))
448
+
449
+
450
+ __all__ += _ALL_DOCS(_SolveBase, _SolveLineBase, _SolveLineSolveBase)
451
+
452
+ # **) MIT License
453
+ #
454
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
455
+ #
456
+ # Permission is hereby granted, free of charge, to any person obtaining a
457
+ # copy of this software and associated documentation files (the "Software"),
458
+ # to deal in the Software without restriction, including without limitation
459
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
460
+ # and/or sell copies of the Software, and to permit persons to whom the
461
+ # Software is furnished to do so, subject to the following conditions:
462
+ #
463
+ # The above copyright notice and this permission notice shall be included
464
+ # in all copies or substantial portions of the Software.
465
+ #
466
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
467
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
468
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
469
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
470
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
471
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
472
+ # OTHER DEALINGS IN THE SOFTWARE.