Coverage for pygeodesy/ecef.py : 95%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
Geocentric conversions transcoded from I{Charles Karney}'s C++ class U{Geocentric <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1Geocentric.html>} into pure Python class L{EcefKarney}, class L{EcefSudano} based on I{John Sudano}'s U{paper<https://www.ResearchGate.net/publication/ 3709199_An_exact_conversion_from_an_Earth-centered_coordinate_system_to_latitude_longitude_and_altitude>}, class L{EcefVeness} transcoded from I{Chris Veness}' JavaScript classes U{LatLonEllipsoidal, Cartesian<https://www.Movable-Type.co.UK/scripts/geodesy/docs/latlon-ellipsoidal.js.html>}, class L{EcefYou} implementing I{Rey-Jer You}'s U{transformations <https://www.ResearchGate.net/publication/240359424>} and classes L{EcefFarrell22} and L{EcefFarrell22} from I{Jay A. Farrell}'s U{Table 2.1 and 2.2 <https://Books.Google.com/books?id=fW4foWASY6wC>}, page 29-30.
Following is a copy of I{Karney}'s U{Detailed Description <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1Geocentric.html>}.
Convert between geodetic coordinates C{lat}-, C{lon}gitude and height C{h} (measured vertically from the surface of the ellipsoid) to geocentric C{x}, C{y} and C{z} coordinates, also known as I{Earth-Centered, Earth-Fixed} (U{ECEF<https://WikiPedia.org/wiki/ECEF>}).
The origin of geocentric coordinates is at the center of the earth. The C{z} axis goes thru the North pole, C{lat} = 90°. The C{x} axis goes thru C{lat} = 0°, C{lon} = 0°.
The I{local (cartesian) origin} is at (C{lat0}, C{lon0}, C{height0}). The I{local} C{x} axis points East, the I{local} C{y} axis points North and the I{local} C{z} axis is normal to the ellipsoid. The plane C{z = -height0} is tangent to the ellipsoid, hence the alternate name I{local tangent plane}.
Forward conversion from geodetic to geocentric (ECEF) coordinates is straightforward.
For the reverse transformation we use Hugues Vermeille's U{Direct transformation from geocentric coordinates to geodetic coordinates <https://DOI.org/10.1007/s00190-002-0273-6>}, J. Geodesy (2002) 76, 451-454.
Several changes have been made to ensure that the method returns accurate results for all finite inputs (even if h is infinite). The changes are described in Appendix B of C. F. F. Karney U{Geodesics on an ellipsoid of revolution<https://ArXiv.org/abs/1102.1215v1>}, Feb. 2011, 85, 105-117 (U{preprint<https://ArXiv.org/abs/1102.1215v1>}). Vermeille similarly updated his method in U{An analytical method to transform geocentric into geodetic coordinates<https://DOI.org/10.1007/s00190-010-0419-x>}, J. Geodesy (2011) 85, 105-117. See U{Geocentric coordinates <https://GeographicLib.SourceForge.io/html/geocentric.html>} for more information.
The errors in these routines are close to round-off. Specifically, for points within 5,000 km of the surface of the ellipsoid (either inside or outside the ellipsoid), the error is bounded by 7 nm (7 nanometers) for the WGS84 ellipsoid. See U{Geocentric coordinates<https://GeographicLib.SourceForge.io/html/geocentric.html>} for further information on the errors.
@see: Module L{ltp} and class L{LocalCartesian}, a transcription of I{Charles Karney}'s C++ class U{LocalCartesian <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1LocalCartesian.html>}, providing conversion to and from I{local} cartesian cordinates in a I{local tangent plane} as opposed to I{geocentric} (ECEF) ones. '''
neg, map1, _xinstanceof, _xsubclassof # from pygeodesy.ellipsoids import a_f2Tuple # from .datums _TypesError, _xdatum, _xkwds _a_, _C_, _convergence_, _datum_, _ellipsoid_, \ _f_, _h_, _height_, _lat_, _lon_, _M_, _name_, \ _no_, _singular_, _SPACE_, _x_, _xyz_, _y_, _z_, \ _0_0, _0_5, _1_0, _1_0_T, _2_0, _3_0, _4_0, \ _6_0, _90_0 _Pass, _xnamed PhiLam2Tuple, Vector3Tuple, Vector4Tuple sincos2, sincos2_, sincos2d_
'''An ECEF or C{Ecef*} related issue. '''
'''(INTERNAL) Get C{lat, lon, h, name} as C{4-tuple}. ''' getattr(latlonh, _h_, height)) except AttributeError: lat, h, n = latlonh, height, NN
except (TypeError, ValueError) as x: t = _lat_, _lon_, _height_ if suffix: t = (_ + suffix for _ in t) d = dict(zip(t, (lat, lon, h))) raise Error(txt=str(x), **d)
'''(INTERNAL) Compute sin, cos and hypotenuse. ''' else:
'''(INTERNAL) Get an C{(x, y, z, name)} 4-tuple. ''' raise _TypesError(_xyz_, xyz, *Types) except AttributeError: t = map1(float, xyz, y, z) + (name,)
except (TypeError, ValueError) as x: d = dict(zip((_xyz_, _y_, _z_), (xyz, y, z))) raise Error(txt=str(x), **d)
'''(INTERNAL) Base class for L{EcefKarney}, L{EcefVeness} and L{EcefYou}. '''
'''New C{Ecef*} converter.
@arg a_ellipsoid: A (non-prolate) ellipsoid (L{Ellipsoid}, L{Ellipsoid2}, L{Datum} or L{a_f2Tuple}) or C{scalar} ellipsoid's equatorial radius (C{meter}). @kwarg f: C{None} or the ellipsoid flattening (C{scalar}), required for C{scalar} B{C{a_ellipsoid}}, C{B{f}=0} represents a sphere, negative B{C{f}} a prolate ellipsoid. @kwarg name: Optional name (C{str}).
@raise EcefError: If B{C{a_ellipsoid}} not L{Ellipsoid}, L{Ellipsoid2}, L{Datum} or L{a_f2Tuple} or C{scalar} or B{C{f}} not C{scalar} or if C{scalar} B{C{a_ellipsoid}} not positive or B{C{f}} not less than 1.0. ''' else: raise ValueError
raise ValueError
except (TypeError, ValueError) as x: t = unstr(self.classname, a=a_ellipsoid, f=f) raise EcefError(_SPACE_(t, _ellipsoid_), txt=str(x))
'''Compare this and an other Ecef.
@arg other: The other ecef (C{Ecef*}).
@return: C{True} if equal, C{False} otherwise. ''' other.ellipsoid == self.ellipsoid)
'''Get the I{equatorial} radius, semi-axis (C{meter}). '''
'''Get the datum (L{Datum}). '''
'''Get the ellipsoid (L{Ellipsoid} or L{Ellipsoid2}). '''
'''Get the I{flattening} (C{float}), M{(a - b) / a}, positive for I{oblate}, negative for I{prolate} or C{0} for I{near-spherical}. '''
'''(INTERNAL) Common for all C{Ecef*}. '''
else:
0, m, self.datum, name=name or self.name)
'''Convert from geodetic C{(lat, lon, height)} to geocentric C{(x, y, z)}.
@arg latlonh: Either a C{LatLon}, an L{Ecef9Tuple} or C{scalar} latitude (C{degrees}). @kwarg lon: Optional C{scalar} longitude for C{scalar} B{C{latlonh}} (C{degrees}). @kwarg height: Optional height (C{meter}), vertically above (or below) the surface of the ellipsoid. @kwarg M: Optionally, return the rotation L{EcefMatrix} (C{bool}). @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geocentric C{(x, y, z)} coordinates for the given geodetic ones C{(lat, lon, height)}, case C{C} 0, optional C{M} (L{EcefMatrix}) and C{datum} if available.
@raise EcefError: If B{C{latlonh}} not C{LatLon}, L{Ecef9Tuple} or C{scalar} or B{C{lon}} not C{scalar} for C{scalar} B{C{latlonh}} or C{abs(lat)} exceeds 90°.
@note: Use method C{.forward_} to specify C{lat} and C{lon} in C{radians} and avoid double angle conversions. '''
'''Like method C{.forward} except with geodetic lat- and longitude given in I{radians}.
@arg phi: Latitude in I{radians} (C{scalar}). @arg lam: Longitude in I{radians} (C{scalar}). @kwarg height: Optional height (C{meter}), vertically above (or below) the surface of the ellipsoid. @kwarg M: Optionally, return the rotation L{EcefMatrix} (C{bool}). @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with C{lat} set to C{degrees90(B{phi})} and C{lon} to C{degrees180(B{lam})}.
@raise EcefError: If B{C{phi}} or B{C{lam}} invalid or not C{scalar}. ''' except (TypeError, ValueError) as x: raise EcefError(phi=phi, lam=lam, height=height, txt=str(x))
'''(INTERNAL) Valid geocentric classes. '''
'''(INTERNAL) Is this an C{EcefYou}?. '''
'''Creation a rotation matrix.
@arg sa: C{sin(phi)} (C{float}). @arg ca: C{cos(phi)} (C{float}). @arg sb: C{sin(lambda)} (C{float}). @arg cb: C{cos(lambda)} (C{float}).
@return: An L{EcefMatrix}. '''
def reverse(self, xyz, y=None, z=None, M=False, name=NN): # PYCHOK no cover '''(INTERNAL) I{Must be overloaded}, see function C{notOverloaded}. ''' notOverloaded(self, xyz, y=y, z=z, M=M, name=name)
'''Return this C{Ecef*} as a string.
@kwarg prec: Precision, number of decimal digits (0..9).
@return: This C{Ecef*} representation (C{str}). '''
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates transcoded from I{Karney}'s C++ U{Geocentric <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1Geocentric.html>} methods.
@note: On methods C{.forward} and C{.forwar_}, let C{v} be a unit vector located at C{(lat, lon, h)}. We can express C{v} as column vectors in one of two ways, C{v1} in east, north, up coordinates (where the components are relative to a local coordinate system at C{C(lat0, lon0, h0)}) or as C{v0} in geocentric C{x, y, z} coordinates. Then, M{v0 = M ⋅ v1} where C{M} is the rotation matrix. '''
'''Get the distance or height limit (C{meter}, conventionally). '''
'''Convert from geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)}.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: Optionally, return the rotation L{EcefMatrix} (C{bool}). @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, case C{C}, optional C{M} (L{EcefMatrix}) and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}}.
@note: In general, there are multiple solutions and the result which minimizes C{height} is returned, i.e., C{(lat, lon)} corresponds to the closest point on the ellipsoid. If there are still multiple solutions with different latitudes (applies only if C{z} = 0), then the solution with C{lat} > 0 is returned. If there are still multiple solutions with different longitudes (applies only if C{x} = C{y} = 0) then C{lon} = 0 is returned. The returned C{height} value is not below M{−E.a * (1 − E.e2) / sqrt(1 − E.e2 * sin(lat)**2)}. The returned C{lon} is in the range [−180°, 180°]. Like C{forward} above, M{v1 = Transpose(M) ⋅ v0}. '''
if h > self.hmax: # PYCHOK no cover # We are really far away (> 12M light years). Treat the earth # as a point and h, above as an acceptable approximation to the # height. This avoids overflow, e.g., in the computation of disc # below. It's possible that h has overflowed to INF, that's OK. # Treat finite x, y, but R overflows to +INF by scaling by 2. sb, cb, R = _sch3(y * _0_5, x * _0_5) sa, ca, _ = _sch3(z * _0_5, R) C = 1
# Treat prolate spheroids by swapping R and Z here and by # switching the arguments to phi = atan2(...) at the end. p, q = q, p # Avoid possible division by zero when r = 0 by multiplying # equations for s and t by r^3 and r, respectively. # t is complex, but the way u is defined, the result is real. # There are three possible cube roots. We choose the root # which avoids cancellation. Note, disc < 0 implies r < 0. else: # Pick the sign on the sqrt to maximize abs(T3). This # minimizes loss of precision due to cancellation. The # result is unchanged because of the way the t is used # in definition of u. # N.B. cbrt always returns the real root, cbrt(-8) = -2. # t can be zero; but then r2 / t -> 0. # Avoid loss of accuracy when u < 0. Underflow doesn't occur in # E.e4 * q / (v - u) because u ~ e^4 when q is small and u < 0. # Need to guard against w going negative due to roundoff in uv - q. # Rearrange expression for k to avoid loss of accuracy due to # subtraction. Division by 0 not possible because uv > 0, w >= 0. k1 -= E.e2 else:
else: # e = E.e4 * q == 0 and r <= 0 # This leads to k = 0 (oblate, equatorial plane) and k + E.e^2 = 0 # (prolate, rotation axis) and the generation of 0/0 in the general # formulas for phi and h, using the general formula and division # by 0 in formula for h. Handle this case by taking the limits: # f > 0: z -> 0, k -> E.e2 * sqrt(q) / sqrt(E.e4 - p) # f < 0: r -> 0, k + E.e2 -> -E.e2 * sqrt(q) / sqrt(E.e4 - p) p, q = q, p e = E.a else: sa = neg(sa) # for tiny negative z, not for prolate
else: # E.e4 == 0, spherical case # Dealing with underflow in the general case with E.e2 = 0 is # difficult. Origin maps to North pole, same as with ellipsoid.
atan2d(sb, cb), h, C, m, self.datum, name=name or self.name)
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates based on I{Jay A. Farrell}'s U{Table 2.1<https://Books.Google.com/books?id=fW4foWASY6wC>}, page 29. '''
'''Convert from geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)} using I{Farrell}'s U{Table 2.1<https://Books.Google.com/books?id=fW4foWASY6wC>}, page 29.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: I{Ignored}, rotation matrix C{M} not available. @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, case C{C=1}, C{M=None} always and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}} or C{sqrt} domain or zero division error.
@see: L{EcefFarrell22} and L{EcefVeness}. '''
-P * ez / (Q * Q1), -P * p2 * _0_5))
except (ValueError, ZeroDivisionError) as e: raise EcefError(x=x, y=y, z=z, txt=str(e))
1, None, self.datum, name=name or self.name)
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates based on I{Jay A. Farrell}'s U{Table 2.2<https://Books.Google.com/books?id=fW4foWASY6wC>}, page 30. '''
'''Convert from geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)} using I{Farrell}'s U{Table 2.2<https://Books.Google.com/books?id=fW4foWASY6wC>}, page 30.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: I{Ignored}, rotation matrix C{M} not available. @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, case C{C=1}, C{M=None} always and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}} or C{sqrt} domain or zero division error.
@see: L{EcefFarrell21} and L{EcefVeness}. '''
p - E.e2 * a * c**3)
except (ValueError, ZeroDivisionError) as e: raise EcefError(x=x, y=y, z=z, txt=str(e))
1, None, self.datum, name=name or self.name)
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates based on I{John J. Sudano}'s U{paper <https://www.ResearchGate.net/publication/ 3709199_An_exact_conversion_from_an_Earth-centered_coordinate_system_to_latitude_longitude_and_altitude>}. '''
'''Convert from geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)} using I{Sudano}'s U{iterative method<https://www.ResearchGate.net/publication/ 3709199_An_exact_conversion_from_an_Earth-centered_coordinate_system_to_latitude_longitude_and_altitude>}.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: I{Ignored}, rotation matrix C{M} not available. @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, iteration C{C}, C{M=None} always and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}} or no convergence. '''
# Sudano's Eq (A-6) and (A-7) refactored/reduced, # replacing Rn from Eq (A-4) with n = E.a / ca: # N = ca**2 * ((z + E.e2 * n * sa) * ca - h * sa) # = ca**2 * (z * ca + E.e2 * E.a * sa - h * sa) # = ca**2 * (z * ca + (E.e2 * E.a - h) * sa) # D = ca**3 * (E.e2 * n / E.e2s2(sa)) - h # = ca**2 * (E.e2 * E.a / E.e2s2(sa) - h / ca**2) # N / D = (z * ca + (E.e2 * E.a - h) * sa) / # (E.e2 * E.a / E.e2s2(sa) - h / ca**2) if ca2 < EPS_2: # PYCHOK no cover ca = _0_0 break break else: t = unstr(self.reverse.__name__, x=x, y=y, z=z) raise EcefError(t, txt=_no_(_convergence_))
# since Sudano's Eq (7) doesn't provide the correct height # h = (abs(z) + h - E.a * cos(a + E.e12) * sa / ca) / (ca + sa)
C, None, self.datum, name=name or self.name)
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates transcoded from I{Chris Veness}' JavaScript classes U{LatLonEllipsoidal, Cartesian <https://www.Movable-Type.co.UK/scripts/geodesy/docs/latlon-ellipsoidal.js.html>}.
@see: U{A Guide to Coordinate Systems in Great Britain <https://www.OrdnanceSurvey.co.UK/documents/resources/guide-coordinate-systems-great-britain.pdf>}, section I{B) Converting between 3D Cartesian and ellipsoidal latitude, longitude and height coordinates}. '''
'''Convert from geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)} transcoded from I{Chris Veness}' U{JavaScript <https://www.Movable-Type.co.UK/scripts/geodesy/docs/latlon-ellipsoidal.js.html>}.
Uses B. R. Bowring’s formulation for μm precision in concise form: U{'The accuracy of geodetic latitude and height equations' <https://www.ResearchGate.net/publication/ 233668213_The_Accuracy_of_Geodetic_Latitude_and_Height_Equations>}, Survey Review, Vol 28, 218, Oct 1985.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: I{Ignored}, rotation matrix C{M} not available. @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, case C{C}, C{M=None} always and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}}.
@see: Ralph M. Toms U{'An Efficient Algorithm for Geocentric to Geodetic Coordinate Conversion'<https://www.OSTI.gov/scitech/biblio/110235>}, Sept 1995 and U{'An Improved Algorithm for Geocentric to Geodetic Coordinate Conversion'<https://www.OSTI.gov/scitech/servlets/purl/231228>}, Apr 1996, both from Lawrence Livermore National Laboratory (LLNL) and John J. Sudano U{An exact conversion from an Earth-centered coordinate system to latitude longitude and altitude<https://www.ResearchGate.net/ publication/3709199_An_exact_conversion_from_an_Earth-centered_coordinate_system_to_latitude_longitude_and_altitude>}. '''
# parametric latitude (Bowring eqn 17, replaced)
# geodetic latitude (Bowring eqn 18) p - E.e2 * E.a * c**3)
# height above ellipsoid (Bowring eqn 7) # r = E.a / E.e2s(sa) # length of normal terminated by minor axis # h = p * ca + z * sa - (E.a * E.a / r)
# see <https://GIS.StackExchange.com/questions/28446> C, lat, lon, h = 2, _0_0, atan2d(y, x), p - E.a
else: # polar lat, lon arbitrarily zero
C, None, # M=None self.datum, name=name or self.name)
'''Conversion between geodetic and geocentric, aka I{Earth-Centered, Earth-Fixed} (ECEF) coordinates using I{Rey-Jer You}'s U{transformation <https://www.ResearchGate.net/publication/240359424>}.
@see: W.E. Featherstone, S.J. (Sten) Claessens U{Closed-form transformation between geodetic and ellipsoidal coordinates <https://Espace.Curtin.edu.AU/bitstream/handle/20.500.11937/11589/115114_9021_geod2ellip_final.pdf>} Studia Geophysica et Geodaetica, 2008, 52, 1-18 and U{PyMap3D <https://PyPI.org/project/pymap3d>}. '''
raise EcefError(ellipsoid=E, txt=_prolate_)
'''Convert geocentric C{(x, y, z)} to geodetic C{(lat, lon, height)} using I{Rey-Jer You}'s transformation.
@arg xyz: A geocentric (C{Cartesian}, L{Ecef9Tuple}) or C{scalar} ECEF C{x} coordinate (C{meter}). @kwarg y: ECEF C{y} coordinate for C{scalar} B{C{xyz}} and B{C{z}} (C{meter}). @kwarg z: ECEF C{z} coordinate for C{scalar} B{C{xyz}} and B{C{y}} (C{meter}). @kwarg M: I{Ignored}, rotation matrix C{M} not available. @kwarg name: Optional name (C{str}).
@return: An L{Ecef9Tuple}C{(x, y, z, lat, lon, height, C, M, datum)} with geodetic coordinates C{(lat, lon, height)} for the given geocentric ones C{(x, y, z)}, case C{C=1}, C{M=None} always and C{datum} if available.
@raise EcefError: Invalid B{C{xyz}} or C{scalar} C{x} or B{C{y}} and/or B{C{z}} not C{scalar} for C{scalar} B{C{xyz}}. '''
raise EcefError(ellipsoid=E, txt=_prolate_)
raise EcefError(x=x, y=y, z=z, txt=_singular_) else:
atan2d(y, x), h, 1, None, # C=1, M=None self.datum, name=name or self.name)
'''A rotation matrix. ''' '_1_0_', '_1_1_', '_1_2_', '_2_0_', '_2_1_', '_2_2_')
'''(INTERNAL) Allow C{_Names_} with leading underscore. '''
'''New L{EcefMatrix} matrix.
@arg sa: C{sin(phi)} (C{float}). @arg ca: C{cos(phi)} (C{float}). @arg sb: C{sin(lambda)} (C{float}). @arg cb: C{cos(lambda)} (C{float}). @arg _more: (INTERNAL) from C{.multiply}.
@raise EcefError: If B{C{sa}}, B{C{ca}}, B{C{sb}} or B{C{cb}} outside M{[-1.0, +1.0]}. '''
raise EcefError(unstr(EcefMatrix.__name__, *t))
else: # build matrix from the following quaternion operations # qrot(lam, [0,0,1]) * qrot(phi, [0,-1,0]) * [1,1,1,1]/2 # or # qrot(pi/2 + lam, [0,0,1]) * qrot(-pi/2 + phi, [-1,0,0]) # where # qrot(t,v) = [cos(t/2), sin(t/2)*v[1], sin(t/2)*v[2], sin(t/2)*v[3]]
# Local X axis (east) in geocentric coords # M[0] = -slam; M[3] = clam; M[6] = 0; # Local Y axis (north) in geocentric coords # M[1] = -clam * sphi; M[4] = -slam * sphi; M[7] = cphi; # Local Z axis (up) in geocentric coords # M[2] = clam * cphi; M[5] = slam * cphi; M[8] = sphi; cb, -sb * sa, sb * ca, _0_0, ca, sa)
'''Get matrix B{C{column}} as 3-tuple. ''' raise _IndexError(column=column)
'''Make a shallow or deep copy of this instance.
@return: The copy (C{This class} or subclass thereof). '''
'''Matrix multiply M{M0' ⋅ M} this matrix transposed with an other matrix.
@arg other: The other matrix (L{EcefMatrix}).
@return: The matrix product (L{EcefMatrix}).
@raise TypeError: If B{C{other}} is not L{EcefMatrix}. '''
# like LocalCartesian.MatrixMultiply, transposed(self) X other # <https://GeographicLib.SourceForge.io/html/LocalCartesian_8cpp_source.html>
'''Forward rotation M{M0' ⋅ ([x, y, z] - [x0, y0, z0])'}.
@arg xyz: Local C{(x, y, z)} coordinates (C{3-tuple}). @arg xyz0: Optional, local C{(x0, y0, z0)} origin (C{3-tuple}).
@return: Rotated C{(x, y, z)} location (C{3-tuple}).
@raise LenError: Unequal C{len(B{xyz})} and C{len(B{xyz0})}. ''' raise LenError(self.rotate, xyz0=len(xyz0), xyz=len(xyz))
# x' = M[0] * x + M[3] * y + M[6] * z # y' = M[1] * x + M[4] * y + M[7] * z # z' = M[2] * x + M[5] * y + M[8] * z fdot(xyz, *self._column_1), fdot(xyz, *self._column_2))
'''Get matrix B{C{row}} as 3-tuple. ''' raise _IndexError(row=row)
'''Inverse rotation M{[x0, y0, z0] + M0 ⋅ [x,y,z]'}.
@arg xyz: Local C{(x, y, z)} coordinates (C{3-tuple}). @arg xyz0: Optional, local C{(x0, y0, z0)} origin (C{3-tuple}).
@return: Unrotated C{(x, y, z)} location (C{3-tuple}).
@raise LenError: Unequal C{len(B{xyz})} and C{len(B{xyz0})}. ''' raise LenError(self.unrotate, xyz0=len(xyz0), xyz=len(xyz))
# x' = x0 + M[0] * x + M[1] * y + M[2] * z # y' = y0 + M[3] * x + M[4] * y + M[5] * z # z' = z0 + M[6] * x + M[7] * y + M[8] * z fdot(_xyz, xyz0[1], *self._row_1), fdot(_xyz, xyz0[2], *self._row_2)) else: # x' = M[0] * x + M[1] * y + M[2] * z # y' = M[3] * x + M[4] * y + M[5] * z # z' = M[6] * x + M[7] * y + M[8] * z fdot(xyz, *self._row_1), fdot(xyz, *self._row_2))
'''9-Tuple C{(x, y, z, lat, lon, height, C, M, datum)} with I{geocentric} C{x}, C{y} and C{z} plus I{geodetic} C{lat}, C{lon} and C{height}, case C{C} (see the C{Ecef*.reverse} methods) and optionally, the rotation matrix C{M} (L{EcefMatrix}) and C{datum}, with C{lat} and C{lon} in C{degrees} and C{x}, C{y}, C{z} and C{height} in C{meter}, conventionally. '''
'''DEPRECATED, use method L{toDatum}.''' return self.toDatum(datum2)
'''Get the longitude in C{radians} (C{float}). '''
'''Get the longitude in C{radians [-PI*3/2..+PI*3/2]} after U{Vermeille <https://Search.ProQuest.com/docview/639493848>} (2004), p 95.
@see: U{Karney<https://GeographicLib.SourceForge.io/html/geocentric.html>}, U{Vermeille<https://Search.ProQuest.com/docview/847292978>} 2011, pp 112-113, 116 and U{Featherstone, et.al.<https://Search.ProQuest.com/docview/872827242>}, p 7. ''' else: # y == 0
'''Get the lat-, longitude in C{degrees} (L{LatLon2Tuple}C{(lat, lon)}). '''
'''Get the lat-, longitude in C{degrees} and height (L{LatLon3Tuple}C{(lat, lon, height)}). '''
'''Get the lat-, longitude in C{degrees} with height and datum (L{LatLon4Tuple}C{(lat, lon, height, datum)}). '''
'''Get the latitude and I{Vermeille} longitude in C{degrees [-225..+225]} (L{LatLon2Tuple}C{(lat, lon)}).
@see: Property C{lonVermeille}. '''
'''Get the longitude in C{degrees [-225..+225]} after U{Vermeille <https://Search.ProQuest.com/docview/639493848>} (2004), p 95.
@see: Property C{lamVermeille}. '''
'''(INTERNAL) Update M{self.M = T.multiply(self.M)}. ''' t = list(self) M = self._IndexM t[M] = T.multiply(t[M]) return self.classof(*t)
'''Get the latitude in C{radians} (C{float}). '''
'''Get the lat-, longitude in C{radians} (L{PhiLam2Tuple}C{(phi, lam)}). '''
'''Get the lat-, longitude in C{radians} and height (L{PhiLam3Tuple}C{(phi, lam, height)}). '''
'''Get the lat-, longitude in C{radians} with height and datum (L{PhiLam4Tuple}C{(phi, lam, height, datum)}). '''
'''Get the latitude and I{Vermeille} longitude in C{radians [-PI*3/2..+PI*3/2]} (L{PhiLam2Tuple}C{(phi, lam)}).
@see: Property C{lamVermeille}. '''
'''Return the geocentric C{(x, y, z)} coordinates as an ellipsoidal or spherical C{Cartesian}.
@kwarg Cartesian: Optional class to return C{(x, y, z)} (L{ellipsoidalKarney.Cartesian}, L{ellipsoidalNvector.Cartesian}, L{ellipsoidalVincenty.Cartesian}, L{sphericalNvector.Cartesian} or L{sphericalTrigonometry.Cartesian}) or C{None}. @kwarg Cartesian_kwds: Optional, additional B{C{Cartesian}} keyword arguments, ignored if C{B{Cartesian} is None}.
@return: A C{B{Cartesian}(x, y, z, **B{Cartesian_kwds})} instance or a L{Vector4Tuple}C{(x, y, z, h)} if C{B{Cartesian} is None}.
@raise TypeError: Invalid B{C{Cartesian}} or B{C{Cartesian_kwds}}. ''' r = self.xyzh r = self.xyz else:
'''Convert this C{Ecef9Tuple} to an other datum.
@arg datum2: Datum to convert I{to} (L{Datum}).
@return: The converted 9-Tuple (C{Ecef9Tuple}).
@raise TypeError: The B{C{datum2}} is not a L{Datum}. ''' r = self.copy() else: # c.toLatLon converts datum, x, y, z, lat, lon, etc. # and returns another Ecef9Tuple iff LatLon is None
'''Return the geodetic C{(lat, lon, height[, datum])} coordinates.
@kwarg LatLon: Optional class to return C{(lat, lon, height[, datum])} or C{None}. @kwarg LatLon_kwds: Optional B{C{height}}, B{C{datum}} and other B{C{LatLon}} keyword arguments.
@return: An instance of C{B{LatLon}(lat, lon, **B{LatLon_kwds})} or if B{C{LatLon}} is C{None}, a L{LatLon3Tuple}C{(lat, lon, height)} respectively L{LatLon4Tuple}C{(lat, lon, height, datum)} depending on whether C{datum} is un-/specified.
@raise TypeError: Invalid B{C{LatLon}} or B{C{LatLon_kwds}}. ''' else: _ = kwds.pop[_datum_]
'''Convert this geocentric to I{local} C{x}, C{y} and C{z}.
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}). @kwarg Xyz: Optional class to return C{x}, C{y} and C{z} (L{XyzLocal}, L{Enu}, L{Ned}) or C{None}. @kwarg Xyz_kwds: Optional, additional B{C{Xyz}} keyword arguments, ignored if C{B{Xyz} is None}.
@return: An B{C{Xyz}} instance or if C{B{Xyz} is None}, a L{Local9Tuple}C{(x, y, z, lat, lon, height, ltp, ecef, M)} with C{M=None}, always.
@raise TypeError: Invalid B{C{ltp}}. ''' return _MODS.ltp._xLtp(ltp)._ecef2local(self, Xyz, Xyz_kwds)
'''Return the geocentric C{(x, y, z)} coordinates as vector.
@kwarg Vector: Optional vector class to return C{(x, y, z)} or C{None}. @kwarg Vector_kwds: Optional, additional B{C{Vector}} keyword arguments, ignored if C{B{Vector} is None}.
@return: A C{Vector}C{(x, y, z, **Vector_kwds)} instance or a L{Vector3Tuple}C{(x, y, z)} if B{C{Vector}} is C{None}.
@see: Propertes C{xyz} and C{xyzh} ''' Vector(self.x, self.y, self.z, **Vector_kwds)) # PYCHOK Ecef9Tuple
'''Get the geocentric C{(x, y, z)} coordinates (L{Vector3Tuple}C{(x, y, z)}). '''
'''Get the geocentric C{(x, y, z)} coordinates and C{height} (L{Vector4Tuple}C{(x, y, z, h)}) '''
'''Return an ECEF converter for C{this} L{Datum} or L{Ellipsoid}. ''' else: _xinstanceof(*_Ecefs, Ecef=Ecef)
'''(INTERNAL) Validate B{C{Ecef}} I{class}. ''' if issubclassof(Ecef, _EcefBase): return Ecef raise _TypesError(_Ecef_, Ecef, *_Ecefs)
EcefFarrell21, EcefFarrell22)
# **) MIT License # # Copyright (C) 2016-2022 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |