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/ltpTuples.py ADDED
@@ -0,0 +1,1563 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''Named, I{Local Tangent Plane} (LTP) tuples.
5
+
6
+ Local coordinate classes L{XyzLocal}, L{Enu}, L{Ned} and L{Aer}
7
+ and local coordinate tuples L{Local9Tuple}, L{Xyz4Tuple}, L{Enu4Tuple},
8
+ L{Ned4Tuple}, L{Aer4Tuple}, L{ChLV9Tuple}, L{ChLVEN2Tuple},
9
+ L{ChLVYX2Tuple}, L{ChLVyx2Tuple} and L{Footprint5Tuple}.
10
+
11
+ @see: References in module L{ltp}.
12
+ '''
13
+
14
+ # from pygeodesy.basics import issubclassof # from .units
15
+ from pygeodesy.constants import _0_0, _1_0, _90_0, _N_90_0
16
+ from pygeodesy.dms import F_D, toDMS
17
+ from pygeodesy.errors import _TypeError, _TypesError, _xattr, \
18
+ _xkwds, _xkwds_item2
19
+ from pygeodesy.fmath import hypot, hypot_
20
+ from pygeodesy.interns import NN, _4_, _azimuth_, _center_, _COMMASPACE_, \
21
+ _down_, _east_, _ecef_, _elevation_, _height_, \
22
+ _lat_, _lon_, _ltp_, _M_, _north_, _not_, _up_, \
23
+ _X_, _x_, _xyz_, _Y_, _y_, _z_
24
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
25
+ from pygeodesy.named import _NamedBase, _NamedTuple, notOverloaded, \
26
+ _Pass, _xnamed
27
+ from pygeodesy.namedTuples import LatLon2Tuple, PhiLam2Tuple, Vector3Tuple
28
+ from pygeodesy.props import deprecated_method, deprecated_Property_RO, \
29
+ Property_RO, property_RO
30
+ from pygeodesy.streprs import Fmt, fstr, strs, _xzipairs
31
+ from pygeodesy.units import Bearing, Degrees, Degrees_, Height, _isDegrees, \
32
+ _isMeter, Lat, Lon, Meter, Meter_, issubclassof
33
+ from pygeodesy.utily import atan2d, atan2b, sincos2_, sincos2d_
34
+ from pygeodesy.vector3d import Vector3d
35
+
36
+ from math import cos, radians
37
+
38
+ __all__ = _ALL_LAZY.ltpTuples
39
+ __version__ = '24.03.15'
40
+
41
+ _aer_ = 'aer'
42
+ _alt_ = 'alt'
43
+ _enu_ = 'enu'
44
+ _h__ = 'h_'
45
+ _ned_ = 'ned'
46
+ _local_ = 'local'
47
+ _roll_ = 'roll'
48
+ _slantrange_ = 'slantrange'
49
+ _tilt_ = 'tilt'
50
+ _uvw_ = 'uvw'
51
+ _yaw_ = 'yaw'
52
+
53
+
54
+ def _er2gr(e, r):
55
+ '''(INTERNAL) Elevation and slant range to ground range.
56
+ '''
57
+ c = cos(radians(e))
58
+ return Meter_(groundrange=r * c)
59
+
60
+
61
+ def _toStr2(inst, prec=None, fmt=Fmt.SQUARE, sep=_COMMASPACE_):
62
+ '''(INTERNAL) Get attribute name and value strings, joined and bracketed.
63
+ '''
64
+ a = inst._toStr # 'aer', 'enu', 'ned', 'xyz'
65
+ t = getattr(inst, a + _4_, ())[:len(a)] or getattr(inst, a)
66
+ t = strs(t, prec=3 if prec is None else prec)
67
+ if sep:
68
+ t = sep.join(t)
69
+ if fmt:
70
+ t = fmt(t)
71
+ return a, t
72
+
73
+
74
+ def _4Tuple2Cls(inst, Cls, Cls_kwds):
75
+ '''(INTERNAL) Convert 4-Tuple to C{Cls} instance.
76
+ '''
77
+ if Cls is None:
78
+ return inst
79
+ elif issubclassof(Cls, Aer):
80
+ return inst.xyzLocal.toAer(Aer=Cls, **Cls_kwds)
81
+ elif issubclassof(Cls, Enu): # PYCHOK no cover
82
+ return inst.xyzLocal.toEnu(Enu=Cls, **Cls_kwds)
83
+ elif issubclassof(Cls, Ned):
84
+ return inst.xyzLocal.toNed(Ned=Cls, **Cls_kwds)
85
+ elif issubclassof(Cls, XyzLocal): # PYCHOK no cover
86
+ return inst.xyzLocal.toXyz(Xyz=Cls, **Cls_kwds)
87
+ elif Cls is Local9Tuple: # PYCHOK no cover
88
+ return inst.xyzLocal.toLocal9Tuple(**Cls_kwds)
89
+ n = inst.__class__.__name__[:3] # PYCHOK no cover
90
+ raise _TypesError(n, Cls, Aer, Enu, Ned, XyzLocal)
91
+
92
+
93
+ def _xyz2aer4(inst):
94
+ '''(INTERNAL) Convert C{(x, y, z}) to C{(A, E, R)}.
95
+ '''
96
+ x, y, z, _ = inst.xyz4
97
+ A = Bearing(azimuth=atan2b(x, y))
98
+ E = Degrees(elevation=atan2d(z, hypot(x, y)))
99
+ R = Meter(slantrange=hypot_(x, y, z))
100
+ return Aer4Tuple(A, E, R, inst.ltp, name=inst.name)
101
+
102
+
103
+ def _xyzLocal(*Types, **name_inst):
104
+ '''(INTERNAL) Get C{inst} or C{inst.xyzLocal}.
105
+ '''
106
+ n, inst = _xkwds_item2(name_inst)
107
+ if isinstance(inst, Types):
108
+ return None
109
+ try:
110
+ return inst.xyzLocal
111
+ except (AttributeError, TypeError):
112
+ raise _TypeError(n, inst, txt=_not_(_local_))
113
+
114
+
115
+ class _NamedAerNed(_NamedBase):
116
+ '''(INTERNAL) Base class for classes C{Aer} and C{Ned}.
117
+ '''
118
+ _ltp = None # local tangent plane (C{Ltp}), origin
119
+
120
+ @Property_RO
121
+ def ltp(self):
122
+ '''Get the I{local tangent plane} (L{Ltp}).
123
+ '''
124
+ return self._ltp
125
+
126
+ def toAer(self, Aer=None, **Aer_kwds):
127
+ '''Get the I{local} I{Azimuth, Elevation, slant Range} (AER) components.
128
+
129
+ @kwarg Aer: Class to return AER (L{Aer}) or C{None}.
130
+ @kwarg Aer_kwds: Optional, additional B{L{Aer}} keyword
131
+ arguments, ignored if B{C{Aer}} is C{None}.
132
+
133
+ @return: AER as an L{Aer} instance or if C{B{Aer} is None},
134
+ an L{Aer4Tuple}C{(azimuth, elevation, slantrange, ltp)}.
135
+ '''
136
+ return self.xyz4._toXyz(Aer, Aer_kwds)
137
+
138
+ def toEnu(self, Enu=None, **Enu_kwds):
139
+ '''Get the I{local} I{East, North, Up} (ENU) components.
140
+
141
+ @kwarg Enu: Class to return ENU (L{Enu}) or C{None}.
142
+ @kwarg Enu_kwds: Optional, additional B{L{Enu}} keyword
143
+ arguments, ignored if C{B{Enu} is None}.
144
+
145
+ @return: ENU as an L{Enu} instance or if C{B{Enu} is None},
146
+ an L{Enu4Tuple}C{(east, north, up, ltp)}.
147
+ '''
148
+ return self.xyz4._toXyz(Enu, Enu_kwds)
149
+
150
+ def toNed(self, Ned=None, **Ned_kwds):
151
+ '''Get the I{local} I{North, East, Down} (NED) components.
152
+
153
+ @kwarg Ned: Class to return NED (L{Ned}) or C{None}.
154
+ @kwarg Ned_kwds: Optional, additional B{L{Ned}} keyword
155
+ arguments, ignored if B{C{Ned}} is C{None}.
156
+
157
+ @return: NED as an L{Ned} instance or if C{B{Ned} is None},
158
+ an L{Ned4Tuple}C{(north, east, down, ltp)}.
159
+ '''
160
+ return self.xyz4._toXyz(Ned, Ned_kwds)
161
+
162
+ def toXyz(self, Xyz=None, **Xyz_kwds):
163
+ '''Get the local I{X, Y, Z} (XYZ) components.
164
+
165
+ @kwarg Xyz: Class to return XYZ (L{XyzLocal}, L{Enu},
166
+ L{Ned}, L{Aer}) or C{None}.
167
+ @kwarg Xyz_kwds: Optional, additional B{C{Xyz}} keyword
168
+ arguments, ignored if C{B{Xyz} is None}.
169
+
170
+ @return: XYZ as an B{C{Xyz}} instance or if C{B{Xyz} is None},
171
+ an L{Xyz4Tuple}C{(x, y, z, ltp)}.
172
+
173
+ @raise TypeError: Invalid B{C{Xyz}}.
174
+ '''
175
+ return self.xyz4._toXyz(Xyz, Xyz_kwds)
176
+
177
+ @Property_RO
178
+ def xyz(self):
179
+ '''Get the I{local} C{(X, Y, Z)} coordinates (L{Vector3Tuple}C{(x, y, z)}).
180
+ '''
181
+ return Vector3Tuple(self.x, self.y, self.z, name=self.name) # like Ecef9Tuple.xyz, Local6tuple.xyz
182
+
183
+ @property_RO
184
+ def xyz4(self): # PYCHOK no cover
185
+ '''I{Must be overloaded}.'''
186
+ notOverloaded(self)
187
+
188
+ @Property_RO
189
+ def xyzLocal(self):
190
+ '''Get this AER or NED as an L{XyzLocal}.
191
+ '''
192
+ return XyzLocal(self.xyz4, name=self.name)
193
+
194
+
195
+ class Aer(_NamedAerNed):
196
+ '''Local C{Azimuth-Elevation-Range} (AER) in a I{local tangent plane}.
197
+ '''
198
+ _azimuth = _0_0 # bearing from North (C{degrees360})
199
+ _elevation = _0_0 # tilt, pitch from horizon (C{degrees}).
200
+ # _ltp = None # local tangent plane (C{Ltp}), origin
201
+ _slantrange = _0_0 # distance (C{Meter})
202
+ _toStr = _aer_
203
+
204
+ def __init__(self, azimuth_aer, elevation=0, slantrange=0, ltp=None, name=NN):
205
+ '''New L{Aer}.
206
+
207
+ @arg azimuth_aer: Scalar azimuth, bearing from North (compass C{degrees})
208
+ or a previous I{local} instance (L{Aer}, L{Aer4Tuple},
209
+ L{Enu}, L{Enu4Tuple}, L{Local9Tuple}, L{Ned},
210
+ L{Ned4Tuple}, L{XyzLocal} or L{Xyz4Tuple}).
211
+ @kwarg elevation: Scalar angle I{above} the horizon, I{above} B{C{ltp}}
212
+ (C{degrees}, horizon is 0, zenith +90 and nadir -90),
213
+ only used with scalar B{C{azimuth_aer}}.
214
+ @kwarg slantrange: Scalar distance (C{meter}), only used with scalar
215
+ B{C{azimuth_aer}}.
216
+ @kwarg ltp: The I{local tangent plane}, (geodetic) origin (L{Ltp},
217
+ L{LocalCartesian}).
218
+ @kwarg name: Optional name (C{str}).
219
+
220
+ @raise TypeError: Invalid B{C{azimuth_aer}} or B{C{ltp}}.
221
+
222
+ @raise UnitError: Invalid B{C{azimuth_aer}}, B{C{elevation}} or
223
+ or B{C{slantrange}}.
224
+ '''
225
+ if _isDegrees(azimuth_aer):
226
+ self._azimuth = Bearing(azimuth=azimuth_aer)
227
+ self._elevation = Degrees_(elevation=elevation, low=_N_90_0, high=_90_0)
228
+ self._slantrange = Meter_(slantrange=slantrange)
229
+ p, n = ltp, name
230
+ else: # PYCHOK no cover
231
+ p = _xyzLocal(Aer, Aer4Tuple, Ned, azimuth_aer=azimuth_aer)
232
+ aer = p.toAer() if p else azimuth_aer
233
+ self._azimuth, self._elevation, self._slantrange = \
234
+ aer.azimuth, aer.elevation, aer.slantrange
235
+ p = _xattr(aer, ltp=ltp)
236
+ n = name or _xattr(aer, name=name)
237
+
238
+ if p:
239
+ self._ltp = _MODS.ltp._xLtp(p)
240
+ if name:
241
+ self.name = n
242
+
243
+ @Property_RO
244
+ def aer4(self):
245
+ '''Get the C{(azimuth, elevation, slantrange, ltp)} components (L{Aer4Tuple}).
246
+ '''
247
+ return Aer4Tuple(self.azimuth, self.elevation, self.slantrange, self.ltp, name=self.name)
248
+
249
+ @Property_RO
250
+ def azimuth(self):
251
+ '''Get the Azimuth, bearing from North (C{degrees360}).
252
+ '''
253
+ return self._azimuth
254
+
255
+ @Property_RO
256
+ def down(self):
257
+ '''Get the Down component (C{meter}).
258
+ '''
259
+ return self.xyzLocal.down
260
+
261
+ @Property_RO
262
+ def east(self):
263
+ '''Get the East component (C{meter}).
264
+ '''
265
+ return self.xyzLocal.east
266
+
267
+ @Property_RO
268
+ def elevation(self):
269
+ '''Get the Elevation, tilt above horizon (C{degrees90}).
270
+ '''
271
+ return self._elevation
272
+
273
+ @Property_RO
274
+ def groundrange(self):
275
+ '''Get the I{ground range}, distance (C{meter}).
276
+ '''
277
+ return _er2gr(self._elevation, self._slantrange)
278
+
279
+ @Property_RO
280
+ def north(self):
281
+ '''Get the North component (C{meter}).
282
+ '''
283
+ return self.xyzLocal.north
284
+
285
+ @Property_RO
286
+ def slantrange(self):
287
+ '''Get the I{slant Range}, distance (C{meter}).
288
+ '''
289
+ return self._slantrange
290
+
291
+ def toRepr(self, prec=None, fmt=Fmt.SQUARE, sep=_COMMASPACE_, **unused): # PYCHOK expected
292
+ '''Return a string representation of this AER as azimuth
293
+ (bearing), elevation and slant range.
294
+
295
+ @kwarg prec: Number of (decimal) digits, unstripped (C{int}).
296
+ @kwarg fmt: Enclosing backets format (C{str}).
297
+ @kwarg sep: Optional separator between AERs (C{str}).
298
+
299
+ @return: This AER as "[A:degrees360, E:degrees90, R:meter]" (C{str}).
300
+ '''
301
+ t = (toDMS(self.azimuth, form=F_D, prec=prec, ddd=0),
302
+ toDMS(self.elevation, form=F_D, prec=prec, ddd=0),
303
+ fstr( self.slantrange, prec=3 if prec is None else prec))
304
+ return _xzipairs(self._toStr.upper(), t, sep=sep, fmt=fmt)
305
+
306
+ def toStr(self, **prec_fmt_sep): # PYCHOK expected
307
+ '''Return a string representation of this AER.
308
+
309
+ @kwarg prec_fmt_sep: Keyword arguments C{B{prec}=3} for the
310
+ number of (decimal) digits, unstripped
311
+ (C{int}), C{B{fmt}='[]'} the enclosing
312
+ backets format (C{str}) and separator
313
+ C{B{sep}=', '} to join (C{str}).
314
+
315
+ @return: This AER as "[degrees360, degrees90, meter]" (C{str}).
316
+ '''
317
+ _, t = _toStr2(self, **prec_fmt_sep)
318
+ return t
319
+
320
+ @Property_RO
321
+ def up(self):
322
+ '''Get the Up component (C{meter}).
323
+ '''
324
+ return self.xyzLocal.up
325
+
326
+ @Property_RO
327
+ def x(self):
328
+ '''Get the X component (C{meter}).
329
+ '''
330
+ return self.xyz4.x
331
+
332
+ @Property_RO
333
+ def xyz4(self):
334
+ '''Get the C{(x, y, z, ltp)} components (L{Xyz4Tuple}).
335
+ '''
336
+ sA, cA, sE, cE = sincos2d_(self._azimuth, self._elevation)
337
+ R = self._slantrange
338
+ r = cE * R # ground range
339
+ return Xyz4Tuple(sA * r, cA * r, sE * R, self.ltp, name=self.name)
340
+
341
+ @Property_RO
342
+ def y(self):
343
+ '''Get the Y component (C{meter}).
344
+ '''
345
+ return self.xyz4.y
346
+
347
+ @Property_RO
348
+ def z(self):
349
+ '''Get the Z component (C{meter}).
350
+ '''
351
+ return self.xyz4.z
352
+
353
+
354
+ class Aer4Tuple(_NamedTuple):
355
+ '''4-Tuple C{(azimuth, elevation, slantrange, ltp)},
356
+ all in C{meter} except C{ltp}.
357
+ '''
358
+ _Names_ = (_azimuth_, _elevation_, _slantrange_, _ltp_)
359
+ _Units_ = ( Meter, Meter, Meter, _Pass)
360
+
361
+ def _toAer(self, Cls, Cls_kwds):
362
+ '''(INTERNAL) Return C{Cls(..., **Cls_kwds)} instance.
363
+ '''
364
+ if issubclassof(Cls, Aer):
365
+ return Cls(*self, **_xkwds(Cls_kwds, name=self.name))
366
+ else:
367
+ return _4Tuple2Cls(self, Cls, Cls_kwds)
368
+
369
+ @Property_RO
370
+ def groundrange(self):
371
+ '''Get the I{ground range}, distance (C{meter}).
372
+ '''
373
+ return _er2gr(self.elevation, self.slantrange) # PYCHOK _Tuple
374
+
375
+ @Property_RO
376
+ def xyzLocal(self):
377
+ '''Get this L{Aer4Tuple} as an L{XyzLocal}.
378
+ '''
379
+ return Aer(self).xyzLocal
380
+
381
+
382
+ class Attitude4Tuple(_NamedTuple):
383
+ '''4-Tuple C{(alt, tilt, yaw, roll)} with C{altitude} in (positive)
384
+ C{meter} and C{tilt}, C{yaw} and C{roll} in C{degrees} representing
385
+ the attitude of a plane or camera.
386
+ '''
387
+ _Names_ = (_alt_, _tilt_, _yaw_, _roll_)
388
+ _Units_ = ( Meter, Bearing, Degrees, Degrees)
389
+
390
+ @Property_RO
391
+ def atyr(self):
392
+ '''Return this attitude (L{Attitude4Tuple}).
393
+ '''
394
+ return self
395
+
396
+ @Property_RO
397
+ def tyr3d(self):
398
+ '''Get this attitude's (3-D) directional vector (L{Vector3d}).
399
+ '''
400
+ return _MODS.ltp.Attitude(self).tyr3d
401
+
402
+
403
+ class Ned(_NamedAerNed):
404
+ '''Local C{North-Eeast-Down} (NED) location in a I{local tangent plane}.
405
+
406
+ @see: L{Enu} and L{Ltp}.
407
+ '''
408
+ _down = _0_0 # down, -XyzLocal.z (C{meter}).
409
+ _east = _0_0 # east, XyzLocal.y (C{meter}).
410
+ # _ltp = None # local tangent plane (C{Ltp}), origin
411
+ _north = _0_0 # north, XyzLocal.x (C{meter})
412
+ _toStr = _ned_
413
+
414
+ def __init__(self, north_ned, east=0, down=0, ltp=None, name=NN):
415
+ '''New L{Ned} vector.
416
+
417
+ @arg north_ned: Scalar North component (C{meter}) or a previous
418
+ I{local} instance (L{Ned}, L{Ned4Tuple}, L{Aer},
419
+ L{Aer4Tuple}, L{Enu}, L{Enu4Tuple}, L{Local9Tuple},
420
+ L{XyzLocal} or L{Xyz4Tuple}).
421
+ @kwarg east: Scalar East component (C{meter}), only used with
422
+ scalar B{C{north_ned}}.
423
+ @kwarg down: Scalar Down component, normal to I{inside} surface
424
+ of the ellipsoid or sphere (C{meter}), only used with
425
+ scalar B{C{north_ned}}.
426
+ @kwarg ltp: The I{local tangent plane}, (geodetic) origin (L{Ltp},
427
+ L{LocalCartesian}).
428
+ @kwarg name: Optional name (C{str}).
429
+
430
+ @raise TypeError: Invalid B{C{north_ned}} or B{C{ltp}}.
431
+
432
+ @raise UnitError: Invalid B{C{north_ned}}, B{C{east}} or B{C{down}}.
433
+ '''
434
+ if _isMeter(north_ned):
435
+ self._north = Meter(north=north_ned or _0_0)
436
+ self._east = Meter(east=east or _0_0)
437
+ self._down = Meter(down=down or _0_0)
438
+ p, n = ltp, name
439
+ else: # PYCHOK no cover
440
+ p = _xyzLocal(Ned, Ned4Tuple, Aer, north_ned=north_ned)
441
+ ned = p.toNed() if p else north_ned
442
+ self._north, self._east, self._down = ned.north, ned.east, ned.down
443
+ p = _xattr(ned, ltp=ltp)
444
+ n = name or _xattr(ned, name=name)
445
+
446
+ if p:
447
+ self._ltp = _MODS.ltp._xLtp(p)
448
+ if n:
449
+ self.name = n
450
+
451
+ @Property_RO
452
+ def aer4(self):
453
+ '''Get the C{(azimuth, elevation, slantrange, ltp)} components (L{Aer4Tuple}).
454
+ '''
455
+ return _xyz2aer4(self)
456
+
457
+ @Property_RO
458
+ def azimuth(self):
459
+ '''Get the Azimuth, bearing from North (C{degrees360}).
460
+ '''
461
+ return self.aer4.azimuth
462
+
463
+ @deprecated_Property_RO
464
+ def bearing(self):
465
+ '''DEPRECATED, use C{azimuth}.'''
466
+ return self.azimuth
467
+
468
+ @Property_RO
469
+ def down(self):
470
+ '''Get the Down component (C{meter}).
471
+ '''
472
+ return self._down
473
+
474
+ @Property_RO
475
+ def east(self):
476
+ '''Get the East component (C{meter}).
477
+ '''
478
+ return self._east
479
+
480
+ @Property_RO
481
+ def elevation(self):
482
+ '''Get the Elevation, tilt above horizon (C{degrees90}).
483
+ '''
484
+ return self.aer4.elevation # neg(degrees90(asin1(self.down / self.length))))
485
+
486
+ @Property_RO
487
+ def groundrange(self):
488
+ '''Get the I{ground range}, distance (C{meter}).
489
+ '''
490
+ return Meter(groundrange=hypot(self.north, self.east))
491
+
492
+ @deprecated_Property_RO
493
+ def length(self):
494
+ '''DEPRECATED, use C{slantrange}.'''
495
+ return self.slantrange
496
+
497
+ @deprecated_Property_RO
498
+ def ned(self):
499
+ '''DEPRECATED, use property C{ned4}.'''
500
+ return _MODS.deprecated.classes.Ned3Tuple(self.north, self.east, self.down, name=self.name)
501
+
502
+ @Property_RO
503
+ def ned4(self):
504
+ '''Get the C{(north, east, down, ltp)} components (L{Ned4Tuple}).
505
+ '''
506
+ return Ned4Tuple(self.north, self.east, self.down, self.ltp, name=self.name)
507
+
508
+ @Property_RO
509
+ def north(self):
510
+ '''Get the North component (C{meter}).
511
+ '''
512
+ return self._north
513
+
514
+ @Property_RO
515
+ def slantrange(self):
516
+ '''Get the I{slant Range}, distance (C{meter}).
517
+ '''
518
+ return self.aer4.slantrange
519
+
520
+ @deprecated_method
521
+ def to3ned(self): # PYCHOK no cover
522
+ '''DEPRECATED, use property L{ned4}.'''
523
+ return self.ned # XXX deprecated too
524
+
525
+ def toRepr(self, prec=None, fmt=Fmt.SQUARE, sep=_COMMASPACE_, **unused): # PYCHOK expected
526
+ '''Return a string representation of this NED.
527
+
528
+ @kwarg prec: Number of (decimal) digits, unstripped (C{int}).
529
+ @kwarg fmt: Enclosing backets format (C{str}).
530
+ @kwarg sep: Separator to join (C{str}).
531
+
532
+ @return: This NED as "[N:meter, E:meter, D:meter]" (C{str}).
533
+ '''
534
+ a, t = _toStr2(self, prec=prec, fmt=NN, sep=NN)
535
+ return _xzipairs(a.upper(), t, sep=sep, fmt=fmt)
536
+
537
+ def toStr(self, **prec_fmt_sep): # PYCHOK expected
538
+ '''Return a string representation of this NED.
539
+
540
+ @kwarg prec_fmt_sep: Keyword arguments C{B{prec}=3} for the
541
+ number of (decimal) digits, unstripped
542
+ (C{int}), C{B{fmt}='[]'} the enclosing
543
+ backets format (C{str}) and separator
544
+ C{B{sep}=', '} to join (C{str}).
545
+
546
+ @return: This NED as "[meter, meter, meter]" (C{str}).
547
+ '''
548
+ _, t = _toStr2(self, **prec_fmt_sep)
549
+ return t
550
+
551
+ @deprecated_method
552
+ def toVector3d(self):
553
+ '''DEPRECATED, use property L{xyz}.'''
554
+ return self.xyz
555
+
556
+ @Property_RO
557
+ def up(self):
558
+ '''Get the Up component (C{meter}).
559
+ '''
560
+ return Meter(up=-self._down) # negated
561
+
562
+ @Property_RO
563
+ def x(self):
564
+ '''Get the X component (C{meter}).
565
+ '''
566
+ return Meter(x=self._east) # 2nd arg, E
567
+
568
+ @Property_RO
569
+ def xyz4(self):
570
+ '''Get the C{(x, y, z, ltp)} components (L{Xyz4Tuple}).
571
+ '''
572
+ return Xyz4Tuple(self.x, self.y, self.z, self.ltp, name=self.name)
573
+
574
+ @Property_RO
575
+ def y(self):
576
+ '''Get the Y component (C{meter}).
577
+ '''
578
+ return Meter(y=self._north) # 1st arg N
579
+
580
+ @Property_RO
581
+ def z(self):
582
+ '''Get the Z component (C{meter}).
583
+ '''
584
+ return Meter(z=-self._down) # negated
585
+
586
+
587
+ class Ned4Tuple(_NamedTuple):
588
+ '''4-Tuple C{(north, east, down, ltp)}, all in C{meter} except C{ltp}.
589
+ '''
590
+ _Names_ = (_north_, _east_, _down_, _ltp_)
591
+ _Units_ = ( Meter, Meter, Meter, _Pass)
592
+
593
+ def _toNed(self, Cls, Cls_kwds):
594
+ '''(INTERNAL) Return C{Cls(..., **Cls_kwds)} instance.
595
+ '''
596
+ if issubclassof(Cls, Ned):
597
+ return Cls(*self, **_xkwds(Cls_kwds, name=self.name))
598
+ else:
599
+ return _4Tuple2Cls(self, Cls, Cls_kwds)
600
+
601
+ @Property_RO
602
+ def xyzLocal(self):
603
+ '''Get this L{Ned4Tuple} as an L{XyzLocal}.
604
+ '''
605
+ return Ned(self).xyzLocal
606
+
607
+
608
+ class _Vector3d(Vector3d):
609
+
610
+ _toStr = _xyz_
611
+
612
+ def toRepr(self, prec=None, fmt=Fmt.SQUARE, sep=_COMMASPACE_, **unused): # PYCHOK expected
613
+ '''Return a string representation of this ENU/NED/XYZ.
614
+
615
+ @kwarg prec: Number of (decimal) digits, unstripped (C{int}).
616
+ @kwarg fmt: Enclosing backets format (C{str}).
617
+ @kwarg sep: Separator to join (C{str}).
618
+
619
+ @return: This XYZ/ENU as "[E:meter, N:meter, U:meter]",
620
+ "[N:meter, E:meter, D:meter]",
621
+ "[U:meter, V:meter, W:meter]" respectively
622
+ "[X:meter, Y:meter, Z:meter]" (C{str}).
623
+ '''
624
+ a, t = _toStr2(self, prec=prec, fmt=NN, sep=NN)
625
+ return _xzipairs(a.upper(), t, sep=sep, fmt=fmt)
626
+
627
+ def toStr(self, **prec_fmt_sep): # PYCHOK expected
628
+ '''Return a string representation of this XYZ.
629
+
630
+ @kwarg prec_fmt_sep: Keyword arguments C{B{prec}=3} for the
631
+ number of (decimal) digits, unstripped
632
+ (C{int}), C{B{fmt}='[]'} the enclosing
633
+ backets format (C{str}) and separator
634
+ C{B{sep}=', '} to join (C{str}).
635
+
636
+ @return: This XYZ as "[meter, meter, meter]" (C{str}).
637
+ '''
638
+ _, t = _toStr2(self, **prec_fmt_sep)
639
+ return t
640
+
641
+
642
+ class XyzLocal(_Vector3d):
643
+ '''Local C{(x, y, z)} in a I{local tangent plane} (LTP),
644
+ also base class for local L{Enu}.
645
+ '''
646
+ _ltp = None # local tangent plane (C{Ltp}), origin
647
+
648
+ def __init__(self, x_xyz, y=0, z=0, ltp=None, name=NN):
649
+ '''New L{XyzLocal}.
650
+
651
+ @arg x_xyz: Scalar X component (C{meter}), C{positive east} or a
652
+ previous I{local} instance (L{XyzLocal}, L{Xyz4Tuple},
653
+ L{Aer}, L{Aer4Tuple}, L{Enu}, L{Enu4Tuple},
654
+ L{Local9Tuple}, L{Ned} or L{Ned4Tuple}).
655
+ @kwarg y: Scalar Y component (C{meter}), only used with scalar
656
+ B{C{x_xyz}}, C{positive north}.
657
+ @kwarg z: Scalar Z component, normal C{positive up} from the
658
+ surface of the ellipsoid or sphere (C{meter}), only
659
+ used with scalar B{C{x_xyz}}.
660
+ @kwarg ltp: The I{local tangent plane}, (geodetic) origin (L{Ltp},
661
+ L{LocalCartesian}).
662
+
663
+ @raise TypeError: Invalid B{C{x_xyz}} or B{C{ltp}}.
664
+
665
+ @raise UnitError: Invalid scalar B{C{x_xyz}}, B{C{y}} or B{C{z}}.
666
+ '''
667
+ if _isMeter(x_xyz):
668
+ self._x = Meter(x=x_xyz or _0_0)
669
+ self._y = Meter(y=y or _0_0)
670
+ self._z = Meter(z=z or _0_0)
671
+ p, n = ltp, name
672
+ else:
673
+ xyz = _xyzLocal(XyzLocal, Xyz4Tuple, Local9Tuple, x_xyz=x_xyz) or x_xyz
674
+ self._x, self._y, self._z = xyz.x, xyz.y, xyz.z
675
+ p = _xattr(xyz, ltp=ltp)
676
+ n = name or _xattr(xyz, name=NN)
677
+
678
+ if p:
679
+ self._ltp = _MODS.ltp._xLtp(p)
680
+ if n:
681
+ self.name = n
682
+
683
+ def __str__(self):
684
+ return self.toStr()
685
+
686
+ @Property_RO
687
+ def aer4(self):
688
+ '''Get the C{(azimuth, elevation, slantrange, ltp)} components (L{Aer4Tuple}).
689
+ '''
690
+ return _xyz2aer4(self)
691
+
692
+ @Property_RO
693
+ def azimuth(self):
694
+ '''Get the Azimuth, bearing from North (C{degrees360}).
695
+
696
+ @see: U{Azimuth<https://GSSC.ESA.int/navipedia/index.php/
697
+ Transformations_between_ECEF_and_ENU_coordinates>}.
698
+ '''
699
+ return self.aer4.azimuth
700
+
701
+ def classof(self, *args, **kwds): # PYCHOK no cover
702
+ '''Create another instance of this very class.
703
+
704
+ @arg args: Optional, positional arguments.
705
+ @kwarg kwds: Optional, keyword arguments.
706
+
707
+ @return: New instance (C{self.__class__}).
708
+ '''
709
+ kwds = _xkwds(kwds, ltp=self.ltp, name=self.name)
710
+ return self.__class__(*args, **kwds)
711
+
712
+ @Property_RO
713
+ def down(self):
714
+ '''Get the Down component (C{meter}).
715
+ '''
716
+ return Meter(down=-self.z)
717
+
718
+ @property_RO
719
+ def ecef(self):
720
+ '''Get this LTP's ECEF converter (C{Ecef...} I{instance}).
721
+ '''
722
+ return self.ltp.ecef
723
+
724
+ @Property_RO
725
+ def east(self):
726
+ '''Get the East component (C{meter}).
727
+ '''
728
+ return Meter(east=self.x)
729
+
730
+ @Property_RO
731
+ def elevation(self):
732
+ '''Get the Elevation, tilt above horizon (C{degrees90}).
733
+
734
+ @see: U{Elevation<https://GSSC.ESA.int/navipedia/index.php/
735
+ Transformations_between_ECEF_and_ENU_coordinates>}.
736
+ '''
737
+ return self.aer4.elevation # neg(degrees90(asin1(self.down / self.length))))
738
+
739
+ @Property_RO
740
+ def enu4(self):
741
+ '''Get the C{(east, north, up, ltp)} components (L{Enu4Tuple}).
742
+ '''
743
+ return Enu4Tuple(self.east, self.north, self.up, self.ltp, name=self.name)
744
+
745
+ @Property_RO
746
+ def groundrange(self):
747
+ '''Get the I{ground range}, distance (C{meter}).
748
+ '''
749
+ return Meter(groundrange=hypot(self.x, self.y))
750
+
751
+ @Property_RO
752
+ def ltp(self):
753
+ '''Get the I{local tangent plane} (L{Ltp}).
754
+ '''
755
+ return self._ltp
756
+
757
+ @Property_RO
758
+ def ned4(self):
759
+ '''Get the C{(north, east, down, ltp)} components (L{Ned4Tuple}).
760
+ '''
761
+ return Ned4Tuple(self.north, self.east, self.down, self.ltp, name=self.name)
762
+
763
+ @Property_RO
764
+ def north(self):
765
+ '''Get the North component (C{meter}).
766
+ '''
767
+ return Meter(north=self.y)
768
+
769
+ @Property_RO
770
+ def slantrange(self):
771
+ '''Get the I{slant Range}, distance (C{meter}).
772
+ '''
773
+ return self.aer4.slantrange
774
+
775
+ def toAer(self, Aer=None, **Aer_kwds):
776
+ '''Get the local I{Azimuth, Elevation, slantRange} components.
777
+
778
+ @kwarg Aer: Class to return AER (L{Aer}) or C{None}.
779
+ @kwarg Aer_kwds: Optional, additional B{C{Aer}} keyword
780
+ arguments, ignored if C{B{Aer} is None}.
781
+
782
+ @return: AER as an L{Aer} instance or if C{B{Aer} is None}, an
783
+ L{Aer4Tuple}C{(azimuth, elevation, slantrange, ltp)}.
784
+
785
+ @raise TypeError: Invalid B{C{Aer}}.
786
+ '''
787
+ return self.aer4._toAer(Aer, Aer_kwds)
788
+
789
+ def toCartesian(self, Cartesian=None, ltp=None, **Cartesian_kwds):
790
+ '''Get the geocentric C{(x, y, z)} (ECEF) coordinates of this local.
791
+
792
+ @kwarg Cartesian: Optional class to return C{(x, y, z)} (C{Cartesian})
793
+ or C{None}.
794
+ @kwarg ltp: Optional I{local tangent plane} (LTP) (L{Ltp}),
795
+ overriding this C{ltp}.
796
+ @kwarg Cartesian_kwds: Optional, additional B{C{Cartesian}} keyword
797
+ arguments, ignored if C{B{Cartesian} is None}.
798
+
799
+ @return: A B{C{Cartesian}} instance of if C{B{Cartesian} is None}, an
800
+ L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)}
801
+ with C{M=None}, always.
802
+
803
+ @raise TypeError: Invalid B{C{ltp}}, B{C{Cartesian}} or
804
+ B{C{Cartesian_kwds}} argument.
805
+ '''
806
+ ltp = _MODS.ltp._xLtp(ltp, self.ltp)
807
+ if Cartesian is None:
808
+ r = ltp._local2ecef(self, nine=True)
809
+ else:
810
+ x, y, z = ltp._local2ecef(self)
811
+ kwds = _xkwds(Cartesian_kwds, datum=ltp.datum)
812
+ r = Cartesian(x, y, z, **kwds)
813
+ return _xnamed(r, self.name or ltp.name)
814
+
815
+ def toEnu(self, Enu=None, **Enu_kwds):
816
+ '''Get the local I{East, North, Up} (ENU) components.
817
+
818
+ @kwarg Enu: Class to return ENU (L{Enu}) or C{None}.
819
+ @kwarg Enu_kwds: Optional, additional B{C{Enu}} keyword
820
+ arguments, ignored if C{B{Enu} is None}.
821
+
822
+ @return: ENU as an L{Enu} instance or if C{B{Enu} is None},
823
+ an L{Enu4Tuple}C{(east, north, up, ltp)}.
824
+ '''
825
+ return self.enu4._toEnu(Enu, Enu_kwds)
826
+
827
+ def toLatLon(self, LatLon=None, ltp=None, **LatLon_kwds):
828
+ '''Get the geodetic C{(lat, lon, height)} coordinates if this local.
829
+
830
+ @kwarg LatLon: Optional class to return C{(x, y, z)} (C{LatLon})
831
+ or C{None}.
832
+ @kwarg ltp: Optional I{local tangent plane} (LTP) (L{Ltp}),
833
+ overriding this ENU/NED/AER/XYZ's LTP.
834
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
835
+ arguments, ignored if C{B{LatLon} is None}.
836
+
837
+ @return: An B{C{LatLon}} instance of if C{B{LatLon} is None}, an
838
+ L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M,
839
+ datum)} with C{M=None}, always.
840
+
841
+ @raise TypeError: Invalid B{C{ltp}}, B{C{LatLon}} or
842
+ B{C{LatLon_kwds}} argument.
843
+ '''
844
+ ltp = _MODS.ltp._xLtp(ltp, self.ltp)
845
+ r = ltp._local2ecef(self, nine=True)
846
+ if LatLon is None:
847
+ r = _xnamed(r, self.name or ltp.name)
848
+ else:
849
+ kwds = _xkwds(LatLon_kwds, height=r.height, datum=r.datum,
850
+ name=self.name or ltp.name)
851
+ r = LatLon(r.lat, r.lon, **kwds) # XXX ltp?
852
+ return r
853
+
854
+ def toLocal9Tuple(self, M=False, name=NN):
855
+ '''Get this local as a C{Local9Tuple}.
856
+
857
+ @kwarg M: Optionally include the rotation matrix (C{bool}).
858
+ @kwarg name: Optional name (C{str}).
859
+
860
+ @return: L{Local9Tuple}C{(x, y, z, lat, lon, height, ltp,
861
+ ecef, M)} with C{ltp} this C{Ltp}, C{ecef} an
862
+ L{Ecef9Tuple} and C{M} L{EcefMatrix} or C{None}.
863
+ '''
864
+ ltp = self.ltp # see C{self.toLatLon}
865
+ t = ltp._local2ecef(self, nine=True, M=M)
866
+ return Local9Tuple(self.x, self.y, self.z, t.lat, t.lon, t.height,
867
+ ltp, t, t.M, name=name or t.name)
868
+
869
+ def toNed(self, Ned=None, **Ned_kwds):
870
+ '''Get the local I{North, East, Down} (Ned) components.
871
+
872
+ @kwarg Ned: Class to return NED (L{Ned}) or C{None}.
873
+ @kwarg Ned_kwds: Optional, additional B{C{Ned}} keyword
874
+ arguments, ignored if C{B{Ned} is None}.
875
+
876
+ @return: NED as an L{Ned} instance or if C{B{Ned} is None},
877
+ an L{Ned4Tuple}C{(north, east, down, ltp)}.
878
+ '''
879
+ return self.ned4._toNed(Ned, Ned_kwds)
880
+
881
+ def toXyz(self, Xyz=None, **Xyz_kwds):
882
+ '''Get the local I{X, Y, Z} (XYZ) components.
883
+
884
+ @kwarg Xyz: Class to return XYZ (L{XyzLocal}, L{Enu},
885
+ L{Ned}, L{Aer}) or C{None}.
886
+ @kwarg Xyz_kwds: Optional, additional B{C{Xyz}} keyword
887
+ arguments, ignored if C{B{Xyz} is None}.
888
+
889
+ @return: XYZ as an B{C{Xyz}} instance or if C{B{Xyz} is None},
890
+ an L{Xyz4Tuple}C{(x, y, z, ltp)}.
891
+ '''
892
+ return self.xyz4._toXyz(Xyz, Xyz_kwds)
893
+
894
+ @Property_RO
895
+ def up(self):
896
+ '''Get the Up component (C{meter}).
897
+ '''
898
+ return Meter(up=self.z)
899
+
900
+ # @Property_RO
901
+ # def x(self): # see: Vector3d.x
902
+ # '''Get the X component (C{meter}).
903
+ # '''
904
+ # return self._x
905
+
906
+ # @Property_RO
907
+ # def xyz(self): # see: Vector3d.xyz
908
+ # '''Get the I{local} C{(X, Y, Z)} coordinates (L{Vector3Tuple}C{(x, y, z)}).
909
+ # '''
910
+ # return Vector3Tuple(self.x, self.y, self.z, name=self.name) # like Ecef9Tuple.xyz, Local6tuple.xyz
911
+
912
+ @Property_RO
913
+ def xyz4(self):
914
+ '''Get the C{(x, y, z, ltp)} components (L{Xyz4Tuple}).
915
+ '''
916
+ return Xyz4Tuple(self.x, self.y, self.z, self.ltp, name=self.name)
917
+
918
+ @Property_RO
919
+ def xyzLocal(self):
920
+ '''Get this L{XyzLocal}.
921
+ '''
922
+ return self
923
+
924
+ # @Property_RO
925
+ # def y(self): # see: Vector3d.y
926
+ # '''Get the Y component (C{meter}).
927
+ # '''
928
+ # return self._y
929
+
930
+ # @Property_RO
931
+ # def z(self): # see: Vector3d.z
932
+ # '''Get the Z component (C{meter}).
933
+ # '''
934
+ # return self._z
935
+
936
+
937
+ class Xyz4Tuple(_NamedTuple):
938
+ '''4-Tuple C{(x, y, z, ltp)}, all in C{meter} except C{ltp}.
939
+ '''
940
+ _Names_ = (_x_, _y_, _z_, _ltp_)
941
+ _Units_ = ( Meter, Meter, Meter, _Pass)
942
+
943
+ def _toXyz(self, Cls, Cls_kwds):
944
+ '''(INTERNAL) Return C{Cls(..., **Cls_kwds)} instance.
945
+ '''
946
+ if issubclassof(Cls, XyzLocal):
947
+ return Cls(*self, **_xkwds(Cls_kwds, name=self.name))
948
+ else:
949
+ return _4Tuple2Cls(self, Cls, Cls_kwds)
950
+
951
+ @Property_RO
952
+ def xyzLocal(self):
953
+ '''Get this L{Xyz4Tuple} as an L{XyzLocal}.
954
+ '''
955
+ return XyzLocal(*self, name=self.name)
956
+
957
+
958
+ class Enu(XyzLocal):
959
+ '''Local C{Eeast-North-Up} (ENU) location in a I{local tangent plane}.
960
+
961
+ @see: U{East, North, Up (ENU)<https://GSSC.ESA.int/navipedia/index.php/
962
+ Transformations_between_ECEF_and_ENU_coordinates>} coordinates.
963
+ '''
964
+ _toStr = _enu_
965
+
966
+ def __init__(self, east_enu, north=0, up=0, ltp=None, name=NN):
967
+ '''New L{Enu}.
968
+
969
+ @arg east_enu: Scalar East component (C{meter}) or a previous
970
+ I{local} instance (L{Enu}, L{Enu4Tuple}, L{Aer},
971
+ L{Aer4Tuple}, L{Local9Tuple}, L{Ned}, L{Ned4Tuple},
972
+ L{XyzLocal} or L{Xyz4Tuple}).
973
+ @kwarg north: Scalar North component (C{meter}) only used with
974
+ scalar B{C{east_enu}}.
975
+ @kwarg up: Scalar Up component only used with scalar B{C{east_enu}},
976
+ normal from the surface of the ellipsoid or sphere (C{meter}).
977
+ @kwarg ltp: The I{local tangent plane}, (geodetic) origin (L{Ltp},
978
+ L{LocalCartesian}).
979
+ @kwarg name: Optional name (C{str}).
980
+
981
+ @raise TypeError: Invalid B{C{east_enu}} or B{C{ltp}}.
982
+
983
+ @raise UnitError: Invalid B{C{east_enu}}, B{C{north}} or B{C{up}}.
984
+ '''
985
+ XyzLocal.__init__(self, east_enu, north, up, ltp=ltp, name=name)
986
+
987
+ def toUvw(self, location, Uvw=None, **Uvw_kwds):
988
+ '''Get the I{u, v, w} (UVW) components at a location.
989
+
990
+ @arg location: The geodetic (C{LatLon}) or geocentric (C{Cartesian},
991
+ L{Vector3d}) location, like a Point-Of-View.
992
+ @kwarg Uvw: Class to return UWV (L{Uvw}) or C{None}.
993
+ @kwarg Uvw_kwds: Optional, additional B{L{Uvw}} keyword
994
+ arguments, ignored if C{B{Uvw} is None}.
995
+
996
+ @return: UVW as a L{Uvw} instance or if C{B{Uvw} is None}, a
997
+ L{Uvw3Tuple}C{(u, v, w)}.
998
+
999
+ @raise TypeError: InvalidB{C{location}}.
1000
+
1001
+ @see: Function U{lookAtSpheroid<https://PyPI.org/project/pymap3d>}.
1002
+ '''
1003
+ try:
1004
+ sa, ca, sb, cb = sincos2_(*location.philam)
1005
+ except Exception as x:
1006
+ raise _TypeError(location=location, cause=x)
1007
+ e, n, u, _ = self.enu4
1008
+
1009
+ t = ca * u - sa * n
1010
+ U = cb * t - sb * e
1011
+ V = cb * e + sb * t
1012
+ W = ca * n + sa * u
1013
+ return Uvw3Tuple(U, V, W, name=self.name) if Uvw is None else \
1014
+ Uvw( U, V, W, **_xkwds(Uvw_kwds, name=self.name))
1015
+
1016
+ @Property_RO
1017
+ def xyzLocal(self):
1018
+ '''Get this ENU as an L{XyzLocal}.
1019
+ '''
1020
+ return XyzLocal(*self.xyz4, name=self.name)
1021
+
1022
+
1023
+ class Enu4Tuple(_NamedTuple):
1024
+ '''4-Tuple C{(east, north, up, ltp)}, in C{meter} except C{ltp}.
1025
+ '''
1026
+ _Names_ = (_east_, _north_, _up_, _ltp_)
1027
+ _Units_ = ( Meter, Meter, Meter, _Pass)
1028
+
1029
+ def _toEnu(self, Cls, Cls_kwds):
1030
+ '''(INTERNAL) Return C{Cls(..., **Cls_kwds)} instance.
1031
+ '''
1032
+ if issubclassof(Cls, XyzLocal):
1033
+ return Cls(*self, **_xkwds(Cls_kwds, name=self.name))
1034
+ else:
1035
+ return _4Tuple2Cls(self, Cls, Cls_kwds)
1036
+
1037
+ @Property_RO
1038
+ def xyzLocal(self):
1039
+ '''Get this L{Enu4Tuple} as an L{XyzLocal}.
1040
+ '''
1041
+ return XyzLocal(*self, name=self.name)
1042
+
1043
+
1044
+ class Local9Tuple(_NamedTuple):
1045
+ '''9-Tuple C{(x, y, z, lat, lon, height, ltp, ecef, M)} with I{local} C{x},
1046
+ C{y}, C{z} all in C{meter}, I{geodetic} C{lat}, C{lon}, C{height}, I{local
1047
+ tangent plane} C{ltp} (L{Ltp}), C{ecef} (L{Ecef9Tuple}) with I{geocentric}
1048
+ C{x}, C{y}, C{z}, I{geodetic} C{lat}, C{lon}, C{height} and I{concatenated}
1049
+ rotation matrix C{M} (L{EcefMatrix}) or C{None}.
1050
+ '''
1051
+ _Names_ = (_x_, _y_, _z_, _lat_, _lon_, _height_, _ltp_, _ecef_, _M_)
1052
+ _Units_ = ( Meter, Meter, Meter, Lat, Lon, Height, _Pass, _Pass, _Pass)
1053
+
1054
+ @Property_RO
1055
+ def azimuth(self):
1056
+ '''Get the I{local} Azimuth, bearing from North (C{degrees360}).
1057
+ '''
1058
+ return self.xyzLocal.aer4.azimuth
1059
+
1060
+ @Property_RO
1061
+ def down(self):
1062
+ '''Get the I{local} Down, C{-z} component (C{meter}).
1063
+ '''
1064
+ return -self.z
1065
+
1066
+ @Property_RO
1067
+ def east(self):
1068
+ '''Get the I{local} East, C{x} component (C{meter}).
1069
+ '''
1070
+ return self.x
1071
+
1072
+ @Property_RO
1073
+ def elevation(self):
1074
+ '''Get the I{local} Elevation, tilt I{above} horizon (C{degrees90}).
1075
+ '''
1076
+ return self.xyzLocal.aer4.elevation
1077
+
1078
+ @Property_RO
1079
+ def groundrange(self):
1080
+ '''Get the I{local} ground range, distance (C{meter}).
1081
+ '''
1082
+ return self.xyzLocal.aer4.groundrange
1083
+
1084
+ @Property_RO
1085
+ def lam(self):
1086
+ '''Get the I{geodetic} longitude in C{radians} (C{float}).
1087
+ '''
1088
+ return self.philam.lam
1089
+
1090
+ @Property_RO
1091
+ def latlon(self):
1092
+ '''Get the I{geodetic} lat-, longitude in C{degrees} (L{LatLon2Tuple}C{(lat, lon)}).
1093
+ '''
1094
+ return LatLon2Tuple(self.lat, self.lon, name=self.name)
1095
+
1096
+ @Property_RO
1097
+ def latlonheight(self):
1098
+ '''Get the I{geodetic} lat-, longitude in C{degrees} and height (L{LatLon3Tuple}C{(lat, lon, height)}).
1099
+ '''
1100
+ return self.latlon.to3Tuple(self.height)
1101
+
1102
+ @Property_RO
1103
+ def north(self):
1104
+ '''Get the I{local} North, C{y} component (C{meter}).
1105
+ '''
1106
+ return self.y
1107
+
1108
+ @Property_RO
1109
+ def phi(self):
1110
+ '''Get the I{geodetic} latitude in C{radians} (C{float}).
1111
+ '''
1112
+ return self.philam.phi
1113
+
1114
+ @Property_RO
1115
+ def philam(self):
1116
+ '''Get the I{geodetic} lat-, longitude in C{radians} (L{PhiLam2Tuple}C{(phi, lam)}).
1117
+ '''
1118
+ return PhiLam2Tuple(radians(self.lat), radians(self.lon), name=self.name)
1119
+
1120
+ @Property_RO
1121
+ def philamheight(self):
1122
+ '''Get the I{geodetic} lat-, longitude in C{radians} and height (L{PhiLam3Tuple}C{(phi, lam, height)}).
1123
+ '''
1124
+ return self.philam.to3Tuple(self.height)
1125
+
1126
+ @Property_RO
1127
+ def slantrange(self):
1128
+ '''Get the I{local} slant Range, distance (C{meter}).
1129
+ '''
1130
+ return self.xyzLocal.aer4.slantrange
1131
+
1132
+ def toAer(self, Aer=None, **Aer_kwds):
1133
+ '''Get the I{local} I{Azimuth, Elevation, slant Range} (AER) components.
1134
+
1135
+ @kwarg Aer: Class to return AER (L{Aer}) or C{None}.
1136
+ @kwarg Aer_kwds: Optional, additional B{L{Aer}} keyword
1137
+ arguments, ignored if B{C{Aer}} is C{None}.
1138
+
1139
+ @return: AER as an L{Aer} instance or if C{B{Aer} is None},
1140
+ an L{Aer4Tuple}C{(azimuth, elevation, slantrange, ltp)}.
1141
+ '''
1142
+ return self.xyzLocal.toAer(Aer=Aer, **Aer_kwds)
1143
+
1144
+ def toCartesian(self, Cartesian=None, **Cartesian_kwds):
1145
+ '''Convert this I{local} to I{geocentric} C{(x, y, z)} (ECEF).
1146
+
1147
+ @kwarg Cartesian: Optional class to return C{(x, y, z)} (C{Cartesian})
1148
+ or C{None}.
1149
+ @kwarg Cartesian_kwds: Optional, additional B{C{Cartesian}} keyword
1150
+ arguments, ignored if C{B{Cartesian} is None}.
1151
+
1152
+ @return: A C{B{Cartesian}(x, y, z, **B{Cartesian_kwds})} instance
1153
+ or a L{Vector4Tuple}C{(x, y, z, h)} if C{B{Cartesian} is None}.
1154
+
1155
+ @raise TypeError: Invalid B{C{Cartesian}} or B{C{Cartesian_kwds}}
1156
+ argument.
1157
+ '''
1158
+ return self.ecef.toCartesian(Cartesian=Cartesian, **Cartesian_kwds) # PYCHOK _Tuple
1159
+
1160
+ def toEnu(self, Enu=None, **Enu_kwds):
1161
+ '''Get the I{local} I{East, North, Up} (ENU) components.
1162
+
1163
+ @kwarg Enu: Class to return ENU (L{Enu}) or C{None}.
1164
+ @kwarg Enu_kwds: Optional, additional B{L{Enu}} keyword
1165
+ arguments, ignored if C{B{Enu} is None}.
1166
+
1167
+ @return: ENU as an L{Enu} instance or if C{B{Enu} is None},
1168
+ an L{Enu4Tuple}C{(east, north, up, ltp)}.
1169
+ '''
1170
+ return self.xyzLocal.toEnu(Enu=Enu, **Enu_kwds)
1171
+
1172
+ def toLatLon(self, LatLon=None, **LatLon_kwds):
1173
+ '''Convert this I{local} to I{geodetic} C{(lat, lon, height)}.
1174
+
1175
+ @kwarg LatLon: Optional class to return C{(lat, lon, height)}
1176
+ (C{LatLon}) or C{None}.
1177
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1178
+ arguments, ignored if C{B{LatLon} is None}.
1179
+
1180
+ @return: An instance of C{B{LatLon}(lat, lon, **B{LatLon_kwds})}
1181
+ or if C{B{LatLon} is None}, a L{LatLon3Tuple}C{(lat, lon,
1182
+ height)} respectively L{LatLon4Tuple}C{(lat, lon, height,
1183
+ datum)} depending on whether C{datum} is un-/specified.
1184
+
1185
+ @raise TypeError: Invalid B{C{LatLon}} or B{C{LatLon_kwds}}
1186
+ argument.
1187
+ '''
1188
+ return self.ecef.toLatLon(LatLon=LatLon, **LatLon_kwds) # PYCHOK _Tuple
1189
+
1190
+ def toNed(self, Ned=None, **Ned_kwds):
1191
+ '''Get the I{local} I{North, East, Down} (NED) components.
1192
+
1193
+ @kwarg Ned: Class to return NED (L{Ned}) or C{None}.
1194
+ @kwarg Ned_kwds: Optional, additional B{L{Ned}} keyword
1195
+ arguments, ignored if B{C{Ned}} is C{None}.
1196
+
1197
+ @return: NED as an L{Ned} instance or if C{B{Ned} is None},
1198
+ an L{Ned4Tuple}C{(north, east, down, ltp)}.
1199
+ '''
1200
+ return self.xyzLocal.toNed(Ned=Ned, **Ned_kwds)
1201
+
1202
+ def toXyz(self, Xyz=None, **Xyz_kwds):
1203
+ '''Get the I{local} I{X, Y, Z} (XYZ) components.
1204
+
1205
+ @kwarg Xyz: Class to return XYZ (L{XyzLocal}) or C{None}.
1206
+ @kwarg Xyz_kwds: Optional, additional B{C{Xyz}} keyword
1207
+ arguments, ignored if C{B{Xyz} is None}.
1208
+
1209
+ @return: XYZ as an B{C{Xyz}} instance or if C{B{Xyz} is None},
1210
+ an L{Xyz4Tuple}C{(x, y, z, ltp)}.
1211
+ '''
1212
+ return self.xyzLocal.toXyz(Xyz=Xyz, **Xyz_kwds)
1213
+
1214
+ @Property_RO
1215
+ def up(self):
1216
+ '''Get the I{local} Up, C{z} component (C{meter}).
1217
+ '''
1218
+ return self.z
1219
+
1220
+ @Property_RO
1221
+ def xyz(self):
1222
+ '''Get the I{local} C{(X, Y, Z)} components (L{Vector3Tuple}C{(x, y, z)}).
1223
+ '''
1224
+ return Vector3Tuple(self.x, self.y, self.z, name=self.name) # like Ecef9Tuple.xyz
1225
+
1226
+ @Property_RO
1227
+ def xyzLocal(self):
1228
+ '''Get this L{Local9Tuple} as an L{XyzLocal}.
1229
+ '''
1230
+ return XyzLocal(*self.xyz, ltp=self.ltp, name=self.name) # PYCHOK .ltp
1231
+
1232
+
1233
+ _XyzLocals4 = XyzLocal, Enu, Ned, Aer # PYCHOK in .ltp
1234
+ _XyzLocals5 = _XyzLocals4 + (Local9Tuple,) # PYCHOK in .ltp
1235
+
1236
+
1237
+ class Uvw(_Vector3d):
1238
+ '''3-D C{u-v-w} (UVW) components.
1239
+ '''
1240
+ _toStr = _uvw_
1241
+
1242
+ def __init__(self, u_uvw, v=0, w=0, name=NN):
1243
+ '''New L{Uvw}.
1244
+
1245
+ @arg u_uvw: Scalar U component (C{meter}) or a previous instance
1246
+ (L{Uvw}, L{Uvw3Tuple}, L{Vector3d}).
1247
+ @kwarg v: V component (C{meter}) only used with scalar B{C{u_uvw}}.
1248
+ @kwarg w: W component (C{meter}) only used with scalar B{C{u_uvw}}.
1249
+ @kwarg name: Optional name (C{str}).
1250
+
1251
+ @raise TypeError: Invalid B{C{east_enu}}.
1252
+
1253
+ @raise UnitError: Invalid B{C{east_enu}}, B{C{v}} or B{C{w}}.
1254
+ '''
1255
+ Vector3d.__init__(self, u_uvw, v, w, name=name)
1256
+
1257
+ def toEnu(self, location, Enu=Enu, **Enu_kwds):
1258
+ '''Get the I{East, North, Up} (ENU) components at a location.
1259
+
1260
+ @arg location: The geodetic (C{LatLon}) or geocentric (C{Cartesian},
1261
+ L{Vector3d}) location from where to cast the L{Los}.
1262
+ @kwarg Enu: Class to return ENU (L{Enu}) or C{None}.
1263
+ @kwarg Enu_kwds: Optional, additional B{L{Enu}} keyword
1264
+ arguments, ignored if C{B{Enu} is None}.
1265
+
1266
+ @return: ENU as an L{Enu} instance or if C{B{Enu} is None}, an
1267
+ L{Enu4Tuple}C{(east, north, up, ltp)} with C{ltp=None}.
1268
+
1269
+ @raise TypeError: InvalidB{C{location}}.
1270
+
1271
+ @see: Function U{lookAtSpheroid<https://PyPI.org/project/pymap3d>}.
1272
+ '''
1273
+ try:
1274
+ sa, ca, sb, cb = sincos2_(*location.philam)
1275
+ except Exception as x:
1276
+ raise _TypeError(location=location, cause=x)
1277
+ u, v, w = self.uvw
1278
+
1279
+ t = cb * u + sb * v
1280
+ E = cb * v - sb * u
1281
+ N = ca * w - sa * t
1282
+ U = ca * t + sa * w
1283
+ return Enu4Tuple(E, N, U, name=self.name) if Enu is None else \
1284
+ Enu( E, N, U, **_xkwds(Enu_kwds, name=self.name))
1285
+
1286
+ u = Vector3d.x
1287
+
1288
+ @Property_RO
1289
+ def uvw(self):
1290
+ '''Get the C{(U, V, W)} components (L{Uvw3Tuple}C{(u, v, w)}).
1291
+ '''
1292
+ return Uvw3Tuple(self.u, self.v, self.w, name=self.name)
1293
+
1294
+ v = Vector3d.y
1295
+ w = Vector3d.z
1296
+
1297
+
1298
+ class Uvw3Tuple(_NamedTuple):
1299
+ '''3-Tuple C{(u, v, w)}, in C{meter}.
1300
+ '''
1301
+ _Names_ = ('u', 'v', 'w')
1302
+ _Units_ = ( Meter, Meter, Meter)
1303
+
1304
+
1305
+ class Los(Aer):
1306
+ '''A Line-Of-Sight (LOS) from a C{LatLon} or C{Cartesian} location.
1307
+ '''
1308
+
1309
+ def __init__(self, azimuth_aer, elevation=0, name=NN):
1310
+ '''New L{Los}.
1311
+
1312
+ @arg azimuth_aer: Scalar azimuth, bearing from North (compass C{degrees})
1313
+ or a previous instance (L{Aer}, L{Aer4Tuple}, L{Enu},
1314
+ L{Enu4Tuple} or L{Los}).
1315
+ @kwarg elevation: Scalar angle I{above} the horizon (C{degrees}, horizon
1316
+ is 0, zenith +90, nadir -90), only used with scalar
1317
+ B{C{azimuth_aer}}.
1318
+ @kwarg name: Optional name (C{str}).
1319
+
1320
+ @raise TypeError: Invalid B{C{azimuth_aer}}.
1321
+
1322
+ @raise UnitError: Invalid B{C{azimuth_aer}} or B{C{elevation}}.
1323
+ '''
1324
+ t = Aer(azimuth_aer, elevation)
1325
+ Aer.__init__(self, t.azimuth, t.elevation, slantrange=_1_0, name=name)
1326
+
1327
+ def toUvw(self, location, Uvw=Uvw, **Uvw_kwds):
1328
+ '''Get this LOS' I{target} (UVW) components from a location.
1329
+
1330
+ @arg location: The geodetic (C{LatLon}) or geocentric (C{Cartesian},
1331
+ L{Vector3d}) location from where to cast the L{Los}.
1332
+
1333
+ @see: Method L{Enu.toUvw} for further details.
1334
+ '''
1335
+ return self.toEnu().toUvw(location, Uvw=Uvw, **Uvw_kwds)
1336
+
1337
+ def toEnu(self, Enu=Enu, **Enu_kwds):
1338
+ '''Get this LOS as I{East, North, Up} (ENU) components.
1339
+
1340
+ @see: Method L{Aer.toEnu} for further details.
1341
+ '''
1342
+ return Aer.toEnu(self, Enu=Enu, **Enu_kwds)
1343
+
1344
+
1345
+ class ChLV9Tuple(Local9Tuple):
1346
+ '''9-Tuple C{(Y, X, h_, lat, lon, height, ltp, ecef, M)} with I{B{unfalsed} Swiss
1347
+ (Y, X, h_)} coordinates and height, all in C{meter}, C{ltp} either a L{ChLV},
1348
+ L{ChLVa} or L{ChLVe} instance and C{ecef} (L{EcefKarney} I{at Bern, Ch}),
1349
+ otherwise like L{Local9Tuple}.
1350
+ '''
1351
+ _Names_ = (_Y_, _X_, _h__) + Local9Tuple._Names_[3:]
1352
+
1353
+ @Property_RO
1354
+ def E_LV95(self):
1355
+ '''Get the B{falsed} I{Swiss E_LV95} easting (C{meter}).
1356
+ '''
1357
+ return self.EN2_LV95.E_LV95
1358
+
1359
+ @Property_RO
1360
+ def EN2_LV95(self):
1361
+ '''Get the I{falsed Swiss (E_LV95, N_LV95)} easting and northing (L{ChLVEN2Tuple}).
1362
+ '''
1363
+ return ChLVEN2Tuple(*_MODS.ltp.ChLV.false2(self.Y, self.X, True), name=self.name)
1364
+
1365
+ @Property_RO
1366
+ def h_LV03(self):
1367
+ '''Get the I{Swiss h_} height (C{meter}).
1368
+ '''
1369
+ return self.h_
1370
+
1371
+ @Property_RO
1372
+ def h_LV95(self):
1373
+ '''Get the I{Swiss h_} height (C{meter}).
1374
+ '''
1375
+ return self.h_
1376
+
1377
+ @property_RO
1378
+ def isChLV(self):
1379
+ '''Is this a L{ChLV}-generated L{ChLV9Tuple}?.
1380
+ '''
1381
+ return self.ltp.__class__ is _MODS.ltp.ChLV
1382
+
1383
+ @property_RO
1384
+ def isChLVa(self):
1385
+ '''Is this a L{ChLVa}-generated L{ChLV9Tuple}?.
1386
+ '''
1387
+ return self.ltp.__class__ is _MODS.ltp.ChLVa
1388
+
1389
+ @property_RO
1390
+ def isChLVe(self):
1391
+ '''Is this a L{ChLVe}-generated L{ChLV9Tuple}?.
1392
+ '''
1393
+ return self.ltp.__class__ is _MODS.ltp.ChLVe
1394
+
1395
+ @Property_RO
1396
+ def N_LV95(self):
1397
+ '''Get the B{falsed} I{Swiss N_LV95} northing (C{meter}).
1398
+ '''
1399
+ return self.EN2_LV95.N_LV95
1400
+
1401
+ @Property_RO
1402
+ def x(self):
1403
+ '''Get the I{local x, Swiss Y} easting (C{meter}).
1404
+ '''
1405
+ return self.Y
1406
+
1407
+ @Property_RO
1408
+ def x_LV03(self):
1409
+ '''Get the B{falsed} I{Swiss x_LV03} northing (C{meter}).
1410
+ '''
1411
+ return self.yx2_LV03.x_LV03
1412
+
1413
+ @Property_RO
1414
+ def y(self):
1415
+ '''Get the I{local y, Swiss X} northing (C{meter}).
1416
+ '''
1417
+ return self.X
1418
+
1419
+ @Property_RO
1420
+ def y_LV03(self):
1421
+ '''Get the B{falsed} I{Swisss y_LV03} easting (C{meter}).
1422
+ '''
1423
+ return self.yx2_LV03.y_LV03
1424
+
1425
+ @Property_RO
1426
+ def YX(self):
1427
+ '''Get the B{unfalsed} easting and northing (L{ChLVYX2Tuple}).
1428
+ '''
1429
+ return ChLVYX2Tuple(self.Y, self.X, name=self.name)
1430
+
1431
+ @Property_RO
1432
+ def yx2_LV03(self):
1433
+ '''Get the B{falsed} I{Swiss (y_LV03, x_LV03)} easting and northing (L{ChLVyx2Tuple}).
1434
+ '''
1435
+ return ChLVyx2Tuple(*_MODS.ltp.ChLV.false2(self.Y, self.X, False), name=self.name)
1436
+
1437
+ @Property_RO
1438
+ def z(self):
1439
+ '''Get the I{local z, Swiss h_} height (C{meter}).
1440
+ '''
1441
+ return self.h_
1442
+
1443
+
1444
+ class ChLVYX2Tuple(_NamedTuple):
1445
+ '''2-Tuple C{(Y, X)} with B{unfalsed} I{Swiss LV95} easting and norting
1446
+ in C{meter}.
1447
+ '''
1448
+ _Names_ = (_Y_, _X_)
1449
+ _Units_ = ( Meter, Meter)
1450
+
1451
+ def false2(self, LV95=True):
1452
+ '''Return the falsed C{Swiss LV95} or C{LV03} version of the projection.
1453
+
1454
+ @see: Function L{ChLV.false2} for more information.
1455
+ '''
1456
+ return _MODS.ltp.ChLV.false2(*self, LV95=LV95, name=self.name)
1457
+
1458
+
1459
+ class ChLVEN2Tuple(_NamedTuple):
1460
+ '''2-Tuple C{(E_LV95, N_LV95)} with B{falsed} I{Swiss LV95} easting and
1461
+ norting in C{meter (2_600_000, 1_200_000)} and origin at C{Bern, Ch}.
1462
+ '''
1463
+ _Names_ = ('E_LV95', 'N_LV95')
1464
+ _Units_ = ChLVYX2Tuple._Units_
1465
+
1466
+ def unfalse2(self):
1467
+ '''Return this projection as an B{unfalsed} L{ChLVYX2Tuple}.
1468
+
1469
+ @see: Function L{ChLV.unfalse2} for more information.
1470
+ '''
1471
+ return _MODS.ltp.ChLV.unfalse2(*self, LV95=True, name=self.name)
1472
+
1473
+
1474
+ class ChLVyx2Tuple(_NamedTuple):
1475
+ '''2-Tuple C{(y_LV03, x_LV03)} with B{falsed} I{Swiss LV03} easting and
1476
+ norting in C{meter (600_000, 200_000)} and origin at C{Bern, Ch}.
1477
+ '''
1478
+ _Names_ = ('y_LV03', 'x_LV03')
1479
+ _Units_ = ChLVYX2Tuple._Units_
1480
+
1481
+ def unfalse2(self):
1482
+ '''Return this projection as an B{unfalsed} L{ChLVYX2Tuple}.
1483
+
1484
+ @see: Function L{ChLV.unfalse2} for more information.
1485
+ '''
1486
+ return _MODS.ltp.ChLV.unfalse2(*self, LV95=False, name=self.name)
1487
+
1488
+
1489
+ class Footprint5Tuple(_NamedTuple):
1490
+ '''5-Tuple C{(center, upperleft, upperight, loweright, lowerleft)}
1491
+ with the C{center} and 4 corners of the I{local} projection of
1492
+ a C{Frustum}, each an L{Xyz4Tuple}, L{XyzLocal}, C{LatLon}, etc.
1493
+
1494
+ @note: Misspelling of C{upperight} and C{loweright} is I{intentional}.
1495
+ '''
1496
+ _Names_ = (_center_, 'upperleft', 'upperight', 'loweright', 'lowerleft')
1497
+ _Units_ = (_Pass, _Pass, _Pass, _Pass, _Pass)
1498
+
1499
+ def toLatLon5(self, ltp=None, LatLon=None, **LatLon_kwds):
1500
+ '''Convert this footprint's C{center} and 4 corners to I{geodetic}
1501
+ C{LatLon(lat, lon, height)}s or C{LatLon3-} or C{-4Tuple}s.
1502
+
1503
+ @kwarg ltp: The I{local tangent plane} (L{Ltp}), overriding this
1504
+ footprint's C{center} or C{frustrum} C{ltp}.
1505
+ @kwarg LatLon: Optional I{geodetic} class (C{LatLon}) or C{None}.
1506
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
1507
+ arguments, ignored if C{B{LatLon} is None}.
1508
+
1509
+ @return: A L{Footprint5Tuple} of 5 C{B{LatLon}(lat, lon,
1510
+ **B{LatLon_kwds})} instances or if C{B{LatLon} is None},
1511
+ 5 L{LatLon3Tuple}C{(lat, lon, height)}s respectively
1512
+ 5 L{LatLon4Tuple}C{(lat, lon, height, datum)}s depending
1513
+ on keyword argument C{datum} is un-/specified.
1514
+
1515
+ @raise TypeError: Invalid B{C{ltp}}, B{C{LatLon}} or B{C{LatLon_kwds}}.
1516
+
1517
+ @see: Methods L{XyzLocal.toLatLon} and L{Footprint5Tuple.xyzLocal5}.
1518
+ '''
1519
+ kwds = _xkwds(LatLon_kwds, ltp=_MODS.ltp._xLtp(ltp, self.center.ltp), # PYCHOK .center
1520
+ LatLon=LatLon, name=self.name,)
1521
+ return Footprint5Tuple(t.toLatLon(**kwds) for t in self.xyzLocal5())
1522
+
1523
+ def xyzLocal5(self, ltp=None):
1524
+ '''Return this footprint's C{center} and 4 corners as 5 L{XyzLocal}s.
1525
+
1526
+ @kwarg ltp: The I{local tangent plane} (L{Ltp}), overriding
1527
+ the {center} and corner C{ltp}s.
1528
+
1529
+ @return: A L{Footprint5Tuple} of 5 L{XyzLocal} instances.
1530
+
1531
+ @raise TypeError: Invalid B{C{ltp}}.
1532
+ '''
1533
+ if ltp is None:
1534
+ p = self
1535
+ else:
1536
+ p = _MODS.ltp._xLtp(ltp)
1537
+ p = tuple(Xyz4Tuple(t.x, t.y, t.z, p) for t in self)
1538
+ return Footprint5Tuple(t.xyzLocal for t in p)
1539
+
1540
+
1541
+ __all__ += _ALL_DOCS(_NamedAerNed)
1542
+
1543
+ # **) MIT License
1544
+ #
1545
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1546
+ #
1547
+ # Permission is hereby granted, free of charge, to any person obtaining a
1548
+ # copy of this software and associated documentation files (the "Software"),
1549
+ # to deal in the Software without restriction, including without limitation
1550
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
1551
+ # and/or sell copies of the Software, and to permit persons to whom the
1552
+ # Software is furnished to do so, subject to the following conditions:
1553
+ #
1554
+ # The above copyright notice and this permission notice shall be included
1555
+ # in all copies or substantial portions of the Software.
1556
+ #
1557
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1558
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1559
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1560
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1561
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1562
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1563
+ # OTHER DEALINGS IN THE SOFTWARE.