1

2# -*- coding: utf-8 -*-

3

4 u'''(INTERNAL) ECEF to local coodinate conversions, separated from

5 module C{ecef} to defer importing the latter into C{CartesianBase}

6 and C{LatLonBase}.

7'''

8

9 from pygeodesy.basics import _isin, _xsubclassof

10# from pygeodesy.ecef import EcefKarney # _MODS

11 from pygeodesy.errors import _xkwds_item2, _xkwds_pop2

12 from 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

15 from pygeodesy.named import _Named, notOverloaded

16 from pygeodesy.props import Property_RO, property_RO, property_ROver

17

18__all__ = _ALL_LAZY.ecefLocals

19__version__ = '25.04.28'

20

21_ltp = _MODS.into(ltp=__name__)

22_ltpTuples = _MODS.into(ltpTuples=__name__)

23

24

25 class _EcefLocal(_Named):

26 '''(INTERNAL) Base class for C{CartesianBase}, C{Ecef9Tuple} and

27 C{LatLonBase}, providing ECEF to local coordinate conversions.

28 '''

29

30 @property_ROver

31 def Ecef(self):

32 '''Get the ECEF I{class} (L{EcefKarney}), I{once}.

33 '''

34 return _MODS.ecef.EcefKarney

35

36 @property_RO

37 def _ecef9(self):

38 '''I{Must be overloaded}.'''

39 notOverloaded(self)

40

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

48

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)

54

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_)

65

66 def toAer(self, ltp=None, **Aer_and_kwds):

67 '''Convert this instance to I{local} I{Azimuth, Elevation, slant Range} (AER) components.

68

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.

73

74 @return: An B{C{Aer}} instance.

75

76 @raise TypeError: Invalid B{C{ltp}}.

77

78 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.

79 '''

80 return self._ltp_ecef2local(ltp, Aer_and_kwds, Aer=_ltpTuples.Aer)

81

82 def toEnu(self, ltp=None, **Enu_and_kwds):

83 '''Convert this instance to I{local} I{East, North, Up} (ENU) components.

84

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.

89

90 @return: An B{C{Enu}} instance.

91

92 @raise TypeError: Invalid B{C{ltp}}.

93

94 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.

95 '''

96 return self._ltp_ecef2local(ltp, Enu_and_kwds, Enu=_ltpTuples.Enu)

97

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)

100

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}.

107

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}).

110

111 @raise TypeError: Invalid B{C{ltp}}.

112 '''

113 return self._ltp_ecef2local(ltp, Xyz_kwds, Xyz=Xyz, _None=Xyz)

114

115 def toLtp(self, Ecef=None, **name):

116 '''Return the I{local tangent plane} (LTP) for this instance.

117

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}).

121

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

130

131 def toNed(self, ltp=None, **Ned_and_kwds):

132 '''Convert this instance to I{local} I{North, East, Down} (NED) components.

133

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.

138

139 @return: An B{C{Ned}} instance.

140

141 @raise TypeError: Invalid B{C{ltp}}.

142

143 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.

144 '''

145 return self._ltp_ecef2local(ltp, Ned_and_kwds, Ned=_ltpTuples.Ned)

146

147 def toXyz(self, ltp=None, **Xyz_and_kwds):

148 '''Convert this instance to I{local} I{X, Y, Z} (XYZ) components.

149

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.

154

155 @return: An B{C{Xyz}} instance.

156

157 @raise TypeError: Invalid B{C{ltp}}.

158

159 @see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.

160 '''

161 return self._ltp_ecef2local(ltp, Xyz_and_kwds, Xyz=_ltpTuples.XyzLocal)

162

163

164__all__ += _ALL_DOCS(_EcefLocal)

165

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.