Coverage for pygeodesy/ecefLocals.py: 92%
49 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-05-29 12:40 -0400
« prev ^ index » next coverage.py v7.6.1, created at 2025-05-29 12:40 -0400
2# -*- coding: utf-8 -*-
4u'''(INTERNAL) ECEF to local coodinate conversions, separated from
5module C{ecef} to defer importing the latter into C{CartesianBase}
6and C{LatLonBase}.
7'''
9from pygeodesy.basics import _isin, _xsubclassof
10# from pygeodesy.ecef import EcefKarney # _MODS
11from pygeodesy.errors import _xkwds_item2, _xkwds_pop2
12from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
13# from pygeodesy import ltp as _ltp # _MODS.into
14# from pygeodesy import ltpTuples as _ltpTuples # _MODS.into
15from pygeodesy.named import _Named, notOverloaded
16from pygeodesy.props import Property_RO, property_RO, property_ROver
18__all__ = _ALL_LAZY.ecefLocals
19__version__ = '25.04.28'
21_ltp = _MODS.into(ltp=__name__)
22_ltpTuples = _MODS.into(ltpTuples=__name__)
25class _EcefLocal(_Named):
26 '''(INTERNAL) Base class for C{CartesianBase}, C{Ecef9Tuple} and
27 C{LatLonBase}, providing ECEF to local coordinate conversions.
28 '''
30 @property_ROver
31 def Ecef(self):
32 '''Get the ECEF I{class} (L{EcefKarney}), I{once}.
33 '''
34 return _MODS.ecef.EcefKarney
36 @property_RO
37 def _ecef9(self):
38 '''I{Must be overloaded}.'''
39 notOverloaded(self)
41 @property_RO
42 def _ecef9datum(self):
43 try:
44 d = self.datum # PYCHOK C{CartesianBase}, ...
45 except AttributeError:
46 d = None
47 return d or self._ecef9.datum
49 @Property_RO
50 def _ltp(self):
51 '''(INTERNAL) Cache this instance' LTP (L{Ltp}).
52 '''
53 return _ltp.Ltp(self._ecef9, ecef=self.Ecef(self._ecef9datum), name=self.name)
55 def _ltp_ecef2local(self, ltp, Xyz_kwds, _None=None, **Xyz): # in C{Ecef9Tuple}
56 '''(INTERNAL) Invoke C{_ltp._xLtp(ltp, self._ltp)._ecef2local}.
57 '''
58 C, _ = Xyz_ = _xkwds_pop2(Xyz_kwds, **Xyz)
59 if C is not _None: # validate C, see .toLocal
60 n, X = _xkwds_item2(Xyz)
61 if X is not C:
62 _xsubclassof(X, **{n: C})
63 ltp = _ltp._xLtp(ltp, self._ltp)
64 return ltp._ecef2local(self._ecef9, *Xyz_)
66 def toAer(self, ltp=None, **Aer_and_kwds):
67 '''Convert this instance to I{local} I{Azimuth, Elevation, slant Range} (AER) components.
69 @kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
70 instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
71 @kwarg Aer_and_kwds: Optional AER class C{B{Aer}=}L{Aer<pygeodesy.ltpTuples.Aer>}
72 to use and optionally, additional B{C{Aer}} keyword arguments.
74 @return: An B{C{Aer}} instance.
76 @raise TypeError: Invalid B{C{ltp}}.
78 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
79 '''
80 return self._ltp_ecef2local(ltp, Aer_and_kwds, Aer=_ltpTuples.Aer)
82 def toEnu(self, ltp=None, **Enu_and_kwds):
83 '''Convert this instance to I{local} I{East, North, Up} (ENU) components.
85 @kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
86 instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
87 @kwarg Enu_and_kwds: Optional ENU class C{B{Enu}=}L{Enu<pygeodesy.ltpTuples.Enu>}
88 to use and optionally, additional B{C{Enu}} keyword arguments.
90 @return: An B{C{Enu}} instance.
92 @raise TypeError: Invalid B{C{ltp}}.
94 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
95 '''
96 return self._ltp_ecef2local(ltp, Enu_and_kwds, Enu=_ltpTuples.Enu)
98 def toLocal(self, Xyz=None, ltp=None, **Xyz_kwds):
99 '''Convert this instance to I{local} components in a I{local tangent plane} (LTP)
101 @kwarg Xyz: Optional I{local} components class (L{XyzLocal}, L{Aer}, L{Enu},
102 L{Ned}) or C{None}.
103 @kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
104 cartesian's L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
105 @kwarg Xyz_kwds: Optionally, additional B{C{Xyz}} keyword arguments, ignored
106 if C{B{Xyz} is None}.
108 @return: An B{C{Xyz}} instance or a L{Local9Tuple}C{(x, y, z, lat, lon,
109 height, ltp, ecef, M)} if C{B{Xyz} is None} (with C{M=None}).
111 @raise TypeError: Invalid B{C{ltp}}.
112 '''
113 return self._ltp_ecef2local(ltp, Xyz_kwds, Xyz=Xyz, _None=Xyz)
115 def toLtp(self, Ecef=None, **name):
116 '''Return the I{local tangent plane} (LTP) for this instance.
118 @kwarg Ecef: Optional ECEF I{class} (L{EcefKarney}, ... L{EcefYou}), overriding
119 this instance' L{Ecef<pygeodesy.ecefLocals._EcefLocal.Ecef>}.
120 @kwarg name: Optional C{B{name}=NN} (C{str}).
122 @return: An B{C{Ltp}} instance.
123 '''
124 if _isin(Ecef, None, self.Ecef) and not name:
125 ltp = self._ltp
126 else: # like self._ltp
127 ecef = (Ecef if Ecef else self.Ecef)(self._ecef9datum)
128 ltp = _ltp.Ltp(self._ecef9, ecef=ecef, name=self._name__(name))
129 return ltp
131 def toNed(self, ltp=None, **Ned_and_kwds):
132 '''Convert this instance to I{local} I{North, East, Down} (NED) components.
134 @kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
135 instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
136 @kwarg Ned_and_kwds: Optional NED class C{B{Ned}=}L{Ned<pygeodesy.ltpTuples.Ned>}
137 to use and optionally, additional B{C{Ned}} keyword arguments.
139 @return: An B{C{Ned}} instance.
141 @raise TypeError: Invalid B{C{ltp}}.
143 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
144 '''
145 return self._ltp_ecef2local(ltp, Ned_and_kwds, Ned=_ltpTuples.Ned)
147 def toXyz(self, ltp=None, **Xyz_and_kwds):
148 '''Convert this instance to I{local} I{X, Y, Z} (XYZ) components.
150 @kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
151 instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
152 @kwarg Xyz_and_kwds: Optional XYZ class C{B{Xyz}=}L{Xyz<pygeodesy.ltpTuples.XyzLocal>}
153 to use and optionally, additional B{C{Xyz}} keyword arguments.
155 @return: An B{C{Xyz}} instance.
157 @raise TypeError: Invalid B{C{ltp}}.
159 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
160 '''
161 return self._ltp_ecef2local(ltp, Xyz_and_kwds, Xyz=_ltpTuples.XyzLocal)
164__all__ += _ALL_DOCS(_EcefLocal)
166# **) MIT License
167#
168# Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
169#
170# Permission is hereby granted, free of charge, to any person obtaining a
171# copy of this software and associated documentation files (the "Software"),
172# to deal in the Software without restriction, including without limitation
173# the rights to use, copy, modify, merge, publish, distribute, sublicense,
174# and/or sell copies of the Software, and to permit persons to whom the
175# Software is furnished to do so, subject to the following conditions:
176#
177# The above copyright notice and this permission notice shall be included
178# in all copies or substantial portions of the Software.
179#
180# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
181# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
182# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
183# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
184# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
185# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
186# OTHER DEALINGS IN THE SOFTWARE.