pygeodesy 24.6.24__py2.py3-none-any.whl → 24.7.24__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pygeodesy/solveBase.py CHANGED
@@ -4,14 +4,16 @@
4
4
  u'''(INTERNAL) Private base classes for L{pygeodesy.geodsolve} and L{pygeodesy.rhumb.solve}.
5
5
  '''
6
6
 
7
- from pygeodesy.basics import map2, ub2str, _zip
7
+ from pygeodesy.basics import clips, map2, ub2str, _zip
8
8
  from pygeodesy.constants import DIG
9
9
  from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
10
10
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
11
- from pygeodesy.errors import _AssertionError, _xkwds_get1, _xkwds_item2
11
+ from pygeodesy.errors import _AssertionError, _xkwds_get, _xkwds_get1, \
12
+ _xkwds_item2
12
13
  from pygeodesy.internals import _enquote, printf
13
- from pygeodesy.interns import NN, _0_, _BACKSLASH_, _COMMASPACE_, \
14
- _EQUAL_, _Error_, _SPACE_, _UNUSED_
14
+ from pygeodesy.interns import NN, _0_, _AT_,_BACKSLASH_, _COLONSPACE_, \
15
+ _COMMASPACE_, _EQUAL_, _Error_, _SPACE_, \
16
+ _UNUSED_
15
17
  from pygeodesy.karney import Caps, _CapsBase, GDict
16
18
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _sys_version_info2
17
19
  from pygeodesy.named import callername, _name2__, notOverloaded
@@ -23,7 +25,7 @@ from pygeodesy.utily import unroll180, wrap360 # PYCHOK shared
23
25
  from subprocess import PIPE as _PIPE, Popen as _Popen, STDOUT as _STDOUT
24
26
 
25
27
  __all__ = _ALL_LAZY.solveBase
26
- __version__ = '24.06.05'
28
+ __version__ = '24.07.11'
27
29
 
28
30
  _ERROR_ = 'ERROR'
29
31
  _Popen_kwds = dict(creationflags=0,
@@ -43,36 +45,96 @@ def _cmd_stdin_(cmd, stdin): # PYCHOK no cover
43
45
  return _SPACE_.join(cmd)
44
46
 
45
47
 
48
+ # def _float_int(r):
49
+ # '''(INTERNAL) Convert result into C{float} or C{int}.
50
+ # '''
51
+ # f = float(r)
52
+ # i = int(f)
53
+ # return i if float(i) == f else f # PYCHOK inconsistent
54
+
55
+
46
56
  def _popen2(cmd, stdin=None): # in .mgrs, test.bases, .testMgrs
47
57
  '''(INTERNAL) Invoke C{B{cmd} tuple} and return C{exitcode}
48
- and all output to C{stdout/-err}.
58
+ and all output from C{stdout/-err}, I{stripped}.
49
59
  '''
50
60
  p = _Popen(cmd, **_Popen_kwds) # PYCHOK kwArgs
51
- r = p.communicate(stdin)[0]
61
+ r = p.communicate(stdin)[0] # stdout + NL + stderr
52
62
  return p.returncode, ub2str(r).strip()
53
63
 
54
64
 
55
65
  class _SolveCapsBase(_CapsBase):
56
66
  '''(NTERNAL) Base class for C{_SolveBase} and C{_LineSolveBase}.
57
67
  '''
58
- _Error = None
59
- _Exact = True
60
- _invokation = 0
61
- _Names_Direct = \
62
- _Names_Inverse = ()
63
- _prec = Precision_(prec=DIG)
64
- _reverse2 = False
65
- _Solve_name = NN # executable basename
66
- _Solve_path = NN # executable path
67
- _status = None
68
- _unroll = False
69
- _verbose = False
68
+ _datum = _WGS84
69
+ _Error = None
70
+ _Exact = True
71
+ _invokat = _AT_
72
+ _invokation = 0
73
+ _linelimit = 0
74
+ _prec = Precision_(prec=DIG)
75
+ _prec2stdin = DIG
76
+ _Xable_name = NN # executable basename
77
+ _Xable_path = NN # executable path
78
+ _status = None
79
+ _verbose = False
80
+
81
+ @Property_RO
82
+ def a(self):
83
+ '''Get the I{equatorial} radius, semi-axis (C{meter}).
84
+ '''
85
+ return self.ellipsoid.a
70
86
 
71
87
  @property_RO
72
88
  def _cmdBasic(self): # PYCHOK no cover
73
89
  '''(INTERNAL) I{Must be overloaded}.'''
74
90
  notOverloaded(self, underOK=True)
75
91
 
92
+ @property_RO
93
+ def datum(self):
94
+ '''Get the datum (C{Datum}).
95
+ '''
96
+ return self._datum
97
+
98
+ def _Dict(self, Dict, n, v, floats=True, **unused):
99
+ if self.verbose: # PYCHOK no cover
100
+ self._print(_COMMASPACE_.join(map(Fmt.EQUAL, n, map(fstrzs, v))))
101
+ if floats:
102
+ v = map(float, v) # _float_int, see Intersectool._XDistInvoke
103
+ return Dict(_zip(n, v)) # strict=True
104
+
105
+ def _DictInvoke2(self, cmd, args, Names, Dict, **floats_R):
106
+ '''(INTERNAL) Invoke C{Solve}, return results as C{Dict}.
107
+ '''
108
+ N = len(Names)
109
+ if N < 1:
110
+ raise _AssertionError(cmd=cmd, Names=Names)
111
+ i = fstr(args, prec=self._prec2stdin, fmt=Fmt.F, sep=_SPACE_) if args else None # NOT Fmt.G!
112
+ t = self._invoke(cmd, stdin=i, **floats_R).lstrip().split() # 12-/++ tuple
113
+ if _xkwds_get(floats_R, _R=None): # == '-R' in cmd
114
+ return self._Dicts(Dict, Names, t, **floats_R), True
115
+ elif len(t) > N: # PYCHOK no cover
116
+ # unzip instrumented name=value pairs to names and values
117
+ n, v = _zip(*(p.split(_EQUAL_) for p in t[:-N])) # strict=True
118
+ v += tuple(t[-N:])
119
+ n += Names
120
+ else:
121
+ n, v = Names, t
122
+ r = self._Dict(Dict, n, t, **floats_R)
123
+ return self._iter2tion(r, **r), None
124
+
125
+ def _Dicts(self, Dict, Names, t, **floats_R):
126
+ i, N = 0, len(Names)
127
+ for x in range(0, len(t), N):
128
+ if t[x] == 'nan':
129
+ break
130
+ X = self._Dict(Dict, Names, t[x:x + N], **floats_R)
131
+ yield X.set_(iteration=i)
132
+ i += 1
133
+
134
+ @Property_RO
135
+ def _E_option(self):
136
+ return ('-E',) if self.Exact else ()
137
+
76
138
  @property
77
139
  def Exact(self):
78
140
  '''Get the Solve's C{exact} setting (C{bool}).
@@ -89,27 +151,38 @@ class _SolveCapsBase(_CapsBase):
89
151
  _update_all(self)
90
152
  self._Exact = Exact
91
153
 
92
- def _GDictInvoke(self, cmd, floats, Names, *args):
93
- '''(INTERNAL) Invoke C{Solve}, return results as C{GDict}.
154
+ @Property_RO
155
+ def ellipsoid(self):
156
+ '''Get the ellipsoid (C{Ellipsoid}).
94
157
  '''
95
- N = len(Names)
96
- if N < 1:
97
- raise _AssertionError(cmd=cmd, Names=Names)
98
- i = fstr(args, prec=DIG, fmt=Fmt.F, sep=_SPACE_) if args else None # not Fmt.G!
99
- t = self._invoke(cmd, stdin=i).lstrip().split() # 12-/+ tuple
100
- if len(t) > N: # PYCHOK no cover
101
- # unzip instrumented name=value pairs to names and values
102
- n, v = _zip(*(p.split(_EQUAL_) for p in t[:-N])) # strict=True
103
- v += tuple(t[-N:])
104
- n += Names
105
- else:
106
- n, v = Names, t
107
- if self.verbose: # PYCHOK no cover
108
- self._print(_COMMASPACE_.join(map(Fmt.EQUAL, n, map(fstrzs, v))))
109
- if floats:
110
- v = map(float, v)
111
- r = GDict(_zip(n, v)) # strict=True
112
- return self._iter2tion(r, **r)
158
+ return self.datum.ellipsoid
159
+
160
+ @Property_RO
161
+ def _e_option(self):
162
+ E = self.ellipsoid
163
+ if E is _EWGS84:
164
+ return () # default
165
+ a, f = strs(E.a_f, fmt=Fmt.F, prec=DIG + 3) # not .G!
166
+ return ('-e', a, f)
167
+
168
+ @Property_RO
169
+ def flattening(self):
170
+ '''Get the C{ellipsoid}'s I{flattening} (C{scalar}), M{(a - b) / a},
171
+ C{0} for spherical, negative for prolate.
172
+ '''
173
+ return self.ellipsoid.f
174
+
175
+ f = flattening
176
+
177
+ def invokat(self, *prefix):
178
+ '''Get and set the invokation number C{"@"} prefix (C{str}).
179
+
180
+ @return: Previous prefix (C{str}).
181
+ '''
182
+ p = self._invokat
183
+ if prefix:
184
+ set._invokat = str(prefix[0])
185
+ return p
113
186
 
114
187
  @property_RO
115
188
  def invokation(self):
@@ -134,7 +207,7 @@ class _SolveCapsBase(_CapsBase):
134
207
 
135
208
  @note: The C{Solve} return code is in property L{status}.
136
209
  '''
137
- c = (self._Solve_path,) + map2(str, options) # map2(_enquote, options)
210
+ c = (self._Xable_path,) + map2(str, options) # map2(_enquote, options)
138
211
  i = _xkwds_get1(stdin, stdin=None)
139
212
  r = self._invoke(c, stdin=i)
140
213
  s = self.status
@@ -145,7 +218,7 @@ class _SolveCapsBase(_CapsBase):
145
218
  self._print(r)
146
219
  return r
147
220
 
148
- def _invoke(self, cmd, stdin=None):
221
+ def _invoke(self, cmd, stdin=None, **unused): # _R=None
149
222
  '''(INTERNAL) Invoke the C{Solve} executable, with the
150
223
  given B{C{cmd}} line and optional input to B{C{stdin}}.
151
224
  '''
@@ -161,8 +234,24 @@ class _SolveCapsBase(_CapsBase):
161
234
  except (IOError, OSError, TypeError, ValueError) as x:
162
235
  raise self._Error(cmd=t or _cmd_stdin_(cmd, stdin), cause=x)
163
236
  self._status = s
237
+ if self.verbose: # and _R is None: # PYCHOK no cover
238
+ self._print(repr(r), 'stdout/-err')
164
239
  return r
165
240
 
241
+ def linelimit(self, *limit):
242
+ '''Set and get the print line length limit.
243
+
244
+ @arg limit: New line limit (C{int}) or C{0}
245
+ or C{None} for unlimited.
246
+
247
+ @return: Teh previous limit (C{int}).
248
+ '''
249
+ n = self._linelimit
250
+ if limit:
251
+ m = int(limit[0] or 0)
252
+ self._linelimit = max(80, m) if m > 0 else (n if m < 0 else 0)
253
+ return n
254
+
166
255
  @Property_RO
167
256
  def _mpd(self): # meter per degree
168
257
  return self.ellipsoid._Lpd
@@ -191,45 +280,34 @@ class _SolveCapsBase(_CapsBase):
191
280
  _update_all(self)
192
281
  self._prec = prec
193
282
 
194
- def _print(self, line): # PYCHOK no cover
283
+ def _print(self, line, *suffix): # PYCHOK no cover
195
284
  '''(INTERNAL) Print a status line.
196
285
  '''
286
+ if self._linelimit:
287
+ line = clips(line, limit=self._linelimit, length=True)
197
288
  if self.status is not None:
198
- line = _SPACE_(line, Fmt.PAREN(self.status))
199
- printf('%s %d: %s', self.named2, self.invokation, line)
200
-
201
- @Property
202
- def reverse2(self):
203
- '''Get the C{azi2} direction (C{bool}).
204
- '''
205
- return self._reverse2
206
-
207
- @reverse2.setter # PYCHOK setter!
208
- def reverse2(self, reverse2):
209
- '''Set the direction for C{azi2} (C{bool}), if C{True} reverse C{azi2}.
210
- '''
211
- reverse2 = bool(reverse2)
212
- if self._reverse2 != reverse2:
213
- _update_all(self)
214
- self._reverse2 = reverse2
289
+ s = _COMMASPACE_(self.status, *suffix)
290
+ line = _SPACE_(line, Fmt.PAREN(s))
291
+ p = NN(self.named2, self._invokat, self.invokation)
292
+ printf(_COLONSPACE_(p, line))
215
293
 
216
- def _setSolve(self, path, **Solve_path):
294
+ def _setXable(self, path, **Xable_path):
217
295
  '''(INTERNAL) Set the executable C{path}.
218
296
  '''
219
- hold = self._Solve_path
297
+ hold = self._Xable_path
220
298
  if hold != path:
221
299
  _update_all(self)
222
- self._Solve_path = path
300
+ self._Xable_path = path
223
301
  try:
224
302
  _ = self.version # test path and ...
225
303
  if self.status: # ... return code
226
- S_p = Solve_path or {self._Solve_name: _enquote(path)}
304
+ S_p = Xable_path or {self._Xable_name: _enquote(path)}
227
305
  raise self._Error(status=self.status, txt_not_=_0_, **S_p)
228
306
  hold = path
229
307
  finally: # restore in case of error
230
- if self._Solve_path != hold:
308
+ if self._Xable_path != hold:
231
309
  _update_all(self)
232
- self._Solve_path = hold
310
+ self._Xable_path = hold
233
311
 
234
312
  @property_RO
235
313
  def status(self):
@@ -238,21 +316,6 @@ class _SolveCapsBase(_CapsBase):
238
316
  '''
239
317
  return self._status
240
318
 
241
- @Property
242
- def unroll(self):
243
- '''Get the C{lon2} unroll'ing (C{bool}).
244
- '''
245
- return self._unroll
246
-
247
- @unroll.setter # PYCHOK setter!
248
- def unroll(self, unroll):
249
- '''Set unroll'ing for C{lon2} (C{bool}), if C{True} unroll C{lon2}, otherwise don't.
250
- '''
251
- unroll = bool(unroll)
252
- if self._unroll != unroll:
253
- _update_all(self)
254
- self._unroll = unroll
255
-
256
319
  @property
257
320
  def verbose(self):
258
321
  '''Get the C{verbose} option (C{bool}).
@@ -274,9 +337,47 @@ class _SolveCapsBase(_CapsBase):
274
337
 
275
338
 
276
339
  class _SolveBase(_SolveCapsBase):
340
+ '''(INTERNAL) Base class for C{_SolveBase} and C{_SolveLineBase}.
341
+ '''
342
+ _Names_Direct = \
343
+ _Names_Inverse = ()
344
+ _reverse2 = False
345
+ _unroll = False
346
+
347
+ @Property
348
+ def reverse2(self):
349
+ '''Get the C{azi2} direction (C{bool}).
350
+ '''
351
+ return self._reverse2
352
+
353
+ @reverse2.setter # PYCHOK setter!
354
+ def reverse2(self, reverse2):
355
+ '''Set the direction for C{azi2} (C{bool}), if C{True} reverse C{azi2}.
356
+ '''
357
+ reverse2 = bool(reverse2)
358
+ if self._reverse2 != reverse2:
359
+ _update_all(self)
360
+ self._reverse2 = reverse2
361
+
362
+ @Property
363
+ def unroll(self):
364
+ '''Get the C{lon2} unroll'ing (C{bool}).
365
+ '''
366
+ return self._unroll
367
+
368
+ @unroll.setter # PYCHOK setter!
369
+ def unroll(self, unroll):
370
+ '''Set unroll'ing for C{lon2} (C{bool}), if C{True} unroll C{lon2}, otherwise don't.
371
+ '''
372
+ unroll = bool(unroll)
373
+ if self._unroll != unroll:
374
+ _update_all(self)
375
+ self._unroll = unroll
376
+
377
+
378
+ class _SolveGDictBase(_SolveBase):
277
379
  '''(NTERNAL) Base class for C{_GeodesicSolveBase} and C{_RhumbSolveBase}.
278
380
  '''
279
- _datum = _WGS84
280
381
 
281
382
  def __init__(self, a_ellipsoid=_EWGS84, f=None, path=NN, **name):
282
383
  '''New C{Solve} instance.
@@ -296,13 +397,7 @@ class _SolveBase(_SolveCapsBase):
296
397
  if name:
297
398
  self.name = name
298
399
  if path:
299
- self._setSolve(path)
300
-
301
- @Property_RO
302
- def a(self):
303
- '''Get the I{equatorial} radius, semi-axis (C{meter}).
304
- '''
305
- return self.ellipsoid.a
400
+ self._setXable(path)
306
401
 
307
402
  @Property_RO
308
403
  def _cmdDirect(self):
@@ -316,56 +411,29 @@ class _SolveBase(_SolveCapsBase):
316
411
  '''
317
412
  return self._cmdBasic + ('-i',)
318
413
 
319
- @property_RO
320
- def datum(self):
321
- '''Get the datum (C{Datum}).
322
- '''
323
- return self._datum
324
-
325
414
  def Direct(self, lat1, lon1, azi1, s12, outmask=_UNUSED_): # PYCHOK unused
326
415
  '''Return the C{Direct} result.
327
416
  '''
328
417
  return self._GDictDirect(lat1, lon1, azi1, False, s12)
329
418
 
330
- @Property_RO
331
- def ellipsoid(self):
332
- '''Get the ellipsoid (C{Ellipsoid}).
333
- '''
334
- return self.datum.ellipsoid
335
-
336
- @Property_RO
337
- def _e_option(self):
338
- E = self.ellipsoid
339
- if E is _EWGS84:
340
- return () # default
341
- a, f = strs(E.a_f, fmt=Fmt.F, prec=DIG + 3) # not .G!
342
- return ('-e', a, f)
343
-
344
- @Property_RO
345
- def flattening(self):
346
- '''Get the C{ellipsoid}'s I{flattening} (C{scalar}), M{(a - b) / a},
347
- C{0} for spherical, negative for prolate.
348
- '''
349
- return self.ellipsoid.f
350
-
351
- f = flattening
352
-
353
419
  def _GDictDirect(self, lat, lon, azi, arcmode, s12_a12, outmask=_UNUSED_, **floats): # PYCHOK for .geodesicx.gxarea
354
420
  '''(INTERNAL) Get C{_GenDirect}-like result as C{GDict}.
355
421
  '''
356
422
  if arcmode:
357
423
  raise self._Error(arcmode=arcmode, txt=str(NotImplemented))
358
- floats = _xkwds_get1(floats, floats=True)
359
- return self._GDictInvoke(self._cmdDirect, floats, self._Names_Direct,
360
- lat, lon, azi, s12_a12)
424
+ return self._GDictInvoke(self._cmdDirect, self._Names_Direct,
425
+ lat, lon, azi, s12_a12, **floats)
361
426
 
362
427
  def _GDictInverse(self, lat1, lon1, lat2, lon2, outmask=_UNUSED_, **floats): # PYCHOK for .geodesicx.gxarea
363
- '''(INTERNAL) Get C{_GenInverse}-like result as C{GDict}, but
364
- I{without} C{_SALPs_CALPs_}.
428
+ '''(INTERNAL) Get C{_GenInverse}-like result as C{GDict}, but I{without} C{_SALP_CALPs_}.
429
+ '''
430
+ return self._GDictInvoke(self._cmdInverse, self._Names_Inverse,
431
+ lat1, lon1, lat2, lon2, **floats)
432
+
433
+ def _GDictInvoke(self, cmd, Names, *args, **floats):
434
+ '''(INTERNAL) Invoke C{Solve}, return results as C{Dict}.
365
435
  '''
366
- floats = _xkwds_get1(floats, floats=True)
367
- return self._GDictInvoke(self._cmdInverse, floats, self._Names_Inverse,
368
- lat1, lon1, lat2, lon2)
436
+ return self._DictInvoke2(cmd, args, Names, GDict, **floats)[0] # _R
369
437
 
370
438
  def Inverse(self, lat1, lon1, lat2, lon2, outmask=_UNUSED_): # PYCHOK unused
371
439
  '''Return the C{Inverse} result.
@@ -390,7 +458,7 @@ class _SolveBase(_SolveCapsBase):
390
458
  return sep.join(pairs(d, prec=prec))
391
459
 
392
460
 
393
- class _SolveLineBase(_SolveCapsBase):
461
+ class _SolveGDictLineBase(_SolveGDictBase):
394
462
  '''(NTERNAL) Base class for C{GeodesicLineSolve} and C{RhumbLineSolve}.
395
463
  '''
396
464
  # _caps = 0
@@ -402,7 +470,7 @@ class _SolveLineBase(_SolveCapsBase):
402
470
  if name:
403
471
  self.name = name
404
472
 
405
- self._caps = caps | Caps._LINE
473
+ self._caps = caps | Caps._AZIMUTH_LATITUDE_LONG_UNROLL
406
474
  self._debug = solve._debug & Caps._DEBUG_ALL
407
475
  self._lla1 = GDict(lat1=lat1, lon1=lon1, **azi)
408
476
  self._solve = solve
@@ -451,7 +519,7 @@ class _SolveLineBase(_SolveCapsBase):
451
519
  return sep.join(pairs(d, prec=prec))
452
520
 
453
521
 
454
- __all__ += _ALL_DOCS(_SolveBase, _SolveLineBase, _SolveCapsBase)
522
+ __all__ += _ALL_DOCS(_SolveBase, _SolveCapsBase, _SolveGDictBase, _SolveGDictLineBase)
455
523
 
456
524
  # **) MIT License
457
525
  #
pygeodesy/triaxials.py CHANGED
@@ -49,7 +49,7 @@ from pygeodesy.named import _lazyNamedEnumItem as _lazy, _name__, _NamedEnum, \
49
49
  _NamedEnumItem, _Pass
50
50
  from pygeodesy.namedTuples import LatLon3Tuple, _NamedTupleTo, Vector3Tuple, \
51
51
  Vector4Tuple
52
- from pygeodesy.props import Property_RO, property_RO
52
+ from pygeodesy.props import Property_RO, property_ROver
53
53
  # from pygeodesy.streprs import Fmt # from .datums
54
54
  from pygeodesy.units import Degrees, Float, Height_, Meter, Meter2, Meter3, \
55
55
  Radians, Radius, Scalar_
@@ -59,7 +59,7 @@ from pygeodesy.vector3d import _otherV3d, Vector3d, _ALL_LAZY, _MODS
59
59
  from math import atan2, fabs, sqrt
60
60
 
61
61
  __all__ = _ALL_LAZY.triaxials
62
- __version__ = '24.06.24'
62
+ __version__ = '24.07.12'
63
63
 
64
64
  _not_ordered_ = _not_('ordered')
65
65
  _omega_ = 'omega'
@@ -360,12 +360,11 @@ class Triaxial_(_NamedEnumItem):
360
360
 
361
361
  _1e2bc = _c2_b2 # C{1 - e2bc} == C{(c/b)**2}
362
362
 
363
- @property_RO
363
+ @property_ROver
364
364
  def _Elliptic(self):
365
365
  '''(INTERNAL) Get class L{Elliptic}, I{once}.
366
366
  '''
367
- Triaxial_._Elliptic = E = _MODS.elliptic.Elliptic # overwrite property_RO
368
- return E
367
+ return _MODS.elliptic.Elliptic # overwrite propertyROver
369
368
 
370
369
  def hartzell4(self, pov, los=False, **name):
371
370
  '''Compute the intersection of this triaxial's surface with a Line-Of-Sight
pygeodesy/units.py CHANGED
@@ -27,7 +27,7 @@ from pygeodesy.unitsBase import Float, Int, _NamedUnit, Radius, Str, Fmt, fstr
27
27
  from math import degrees, radians
28
28
 
29
29
  __all__ = _ALL_LAZY.units
30
- __version__ = '24.06.15'
30
+ __version__ = '24.06.29'
31
31
 
32
32
 
33
33
  class Float_(Float):
@@ -781,10 +781,10 @@ class Zone(Int):
781
781
  return Int_.__new__(cls, arg=arg, name=name, **Error_name_arg)
782
782
 
783
783
 
784
- _Scalars = Float, Float_, Scalar, Scalar_
785
- _Degrees = (Bearing, Bearing_, Degrees, Degrees_) + _Scalars
786
- _Meters = (Distance, Distance_, Meter, Meter_) + _Scalars
787
- _Radians = (Radians, Radians_) + _Scalars # PYCHOK unused
784
+ _ScalarU = Float, Float_, Scalar, Scalar_
785
+ _Degrees = (Bearing, Bearing_, Degrees, Degrees_) + _ScalarU
786
+ _Meters = (Distance, Distance_, Meter, Meter_) + _ScalarU
787
+ _Radians = (Radians, Radians_) + _ScalarU # PYCHOK unused
788
788
  _Radii = _Meters + (Radius, Radius_)
789
789
 
790
790