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.
- PyGeodesy-24.3.24.dist-info/METADATA +272 -0
- PyGeodesy-24.3.24.dist-info/RECORD +115 -0
- PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
- PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
- pygeodesy/LICENSE +21 -0
- pygeodesy/__init__.py +615 -0
- pygeodesy/__main__.py +103 -0
- pygeodesy/albers.py +867 -0
- pygeodesy/auxilats/_CX_4.py +218 -0
- pygeodesy/auxilats/_CX_6.py +314 -0
- pygeodesy/auxilats/_CX_8.py +475 -0
- pygeodesy/auxilats/__init__.py +54 -0
- pygeodesy/auxilats/__main__.py +86 -0
- pygeodesy/auxilats/auxAngle.py +548 -0
- pygeodesy/auxilats/auxDLat.py +302 -0
- pygeodesy/auxilats/auxDST.py +296 -0
- pygeodesy/auxilats/auxLat.py +848 -0
- pygeodesy/auxilats/auxily.py +272 -0
- pygeodesy/azimuthal.py +1150 -0
- pygeodesy/basics.py +892 -0
- pygeodesy/booleans.py +2031 -0
- pygeodesy/cartesianBase.py +1062 -0
- pygeodesy/clipy.py +704 -0
- pygeodesy/constants.py +516 -0
- pygeodesy/css.py +660 -0
- pygeodesy/datums.py +752 -0
- pygeodesy/deprecated/__init__.py +61 -0
- pygeodesy/deprecated/bases.py +40 -0
- pygeodesy/deprecated/classes.py +262 -0
- pygeodesy/deprecated/consterns.py +54 -0
- pygeodesy/deprecated/datum.py +40 -0
- pygeodesy/deprecated/functions.py +375 -0
- pygeodesy/deprecated/nvector.py +48 -0
- pygeodesy/deprecated/rhumbBase.py +32 -0
- pygeodesy/deprecated/rhumbaux.py +33 -0
- pygeodesy/deprecated/rhumbsolve.py +33 -0
- pygeodesy/deprecated/rhumbx.py +33 -0
- pygeodesy/dms.py +986 -0
- pygeodesy/ecef.py +1348 -0
- pygeodesy/elevations.py +279 -0
- pygeodesy/ellipsoidalBase.py +1224 -0
- pygeodesy/ellipsoidalBaseDI.py +913 -0
- pygeodesy/ellipsoidalExact.py +343 -0
- pygeodesy/ellipsoidalGeodSolve.py +343 -0
- pygeodesy/ellipsoidalKarney.py +403 -0
- pygeodesy/ellipsoidalNvector.py +685 -0
- pygeodesy/ellipsoidalVincenty.py +590 -0
- pygeodesy/ellipsoids.py +2476 -0
- pygeodesy/elliptic.py +1198 -0
- pygeodesy/epsg.py +243 -0
- pygeodesy/errors.py +804 -0
- pygeodesy/etm.py +1190 -0
- pygeodesy/fmath.py +1013 -0
- pygeodesy/formy.py +1818 -0
- pygeodesy/frechet.py +865 -0
- pygeodesy/fstats.py +760 -0
- pygeodesy/fsums.py +1898 -0
- pygeodesy/gars.py +358 -0
- pygeodesy/geodesicw.py +581 -0
- pygeodesy/geodesicx/_C4_24.py +1699 -0
- pygeodesy/geodesicx/_C4_27.py +2395 -0
- pygeodesy/geodesicx/_C4_30.py +3301 -0
- pygeodesy/geodesicx/__init__.py +48 -0
- pygeodesy/geodesicx/__main__.py +91 -0
- pygeodesy/geodesicx/gx.py +1382 -0
- pygeodesy/geodesicx/gxarea.py +535 -0
- pygeodesy/geodesicx/gxbases.py +154 -0
- pygeodesy/geodesicx/gxline.py +669 -0
- pygeodesy/geodsolve.py +426 -0
- pygeodesy/geohash.py +914 -0
- pygeodesy/geoids.py +1884 -0
- pygeodesy/hausdorff.py +892 -0
- pygeodesy/heights.py +1155 -0
- pygeodesy/interns.py +687 -0
- pygeodesy/iters.py +545 -0
- pygeodesy/karney.py +919 -0
- pygeodesy/ktm.py +633 -0
- pygeodesy/latlonBase.py +1766 -0
- pygeodesy/lazily.py +960 -0
- pygeodesy/lcc.py +684 -0
- pygeodesy/ltp.py +1107 -0
- pygeodesy/ltpTuples.py +1563 -0
- pygeodesy/mgrs.py +721 -0
- pygeodesy/named.py +1324 -0
- pygeodesy/namedTuples.py +683 -0
- pygeodesy/nvectorBase.py +695 -0
- pygeodesy/osgr.py +781 -0
- pygeodesy/points.py +1686 -0
- pygeodesy/props.py +628 -0
- pygeodesy/resections.py +1048 -0
- pygeodesy/rhumb/__init__.py +46 -0
- pygeodesy/rhumb/aux_.py +397 -0
- pygeodesy/rhumb/bases.py +1148 -0
- pygeodesy/rhumb/ekx.py +563 -0
- pygeodesy/rhumb/solve.py +572 -0
- pygeodesy/simplify.py +647 -0
- pygeodesy/solveBase.py +472 -0
- pygeodesy/sphericalBase.py +724 -0
- pygeodesy/sphericalNvector.py +1264 -0
- pygeodesy/sphericalTrigonometry.py +1447 -0
- pygeodesy/streprs.py +627 -0
- pygeodesy/trf.py +2079 -0
- pygeodesy/triaxials.py +1484 -0
- pygeodesy/units.py +969 -0
- pygeodesy/unitsBase.py +349 -0
- pygeodesy/ups.py +538 -0
- pygeodesy/utily.py +1231 -0
- pygeodesy/utm.py +762 -0
- pygeodesy/utmups.py +318 -0
- pygeodesy/utmupsBase.py +517 -0
- pygeodesy/vector2d.py +785 -0
- pygeodesy/vector3d.py +968 -0
- pygeodesy/vector3dBase.py +1049 -0
- pygeodesy/webmercator.py +383 -0
- 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.
|