def toLatLon(self, LatLon=None, unfalse=True): '''Convert this UPS coordinate to an (ellipsoidal) geodetic point. @keyword LatLon: Optional, ellipsoidal (sub-)class to return the point (C{LatLon}) or C{None}. @keyword unfalse: Unfalse I{easting} and I{northing} if falsed (C{bool}). @return: This UPS coordinate as (I{LatLon}) or 5-tuple (C{lat, lon, datum, convergence, scale}) if I{LatLon} is C{None}. @raise TypeError: If I{LatLon} is not ellipsoidal. @raise UPSError: Invalid meridional radius or H-value. ''' if self._latlon: return self._latlon5(LatLon) E = self.datum.ellipsoid # XXX vs LatLon.datum.ellipsoid f = self.falsed if unfalse else 0 x = self.easting - f y = self.northing - f r = hypot(x, y) t = (r / (2 * self.scale0 * E.a / E.es_c)) if r > 0 else EPS**2 t = E.es_tauf((1 / t - t) * 0.5) if self.pole == 'N': a, b, c = atan(t), atan2(x, -y), 1 else: a, b, c = -atan(t), atan2(x, y), -1 a, b = degrees90(a), degrees180(b) if not self._band: self._band = _Band(a, b) if not self._hemisphere: self._hemisphere = _hemi(a) ll = _LLEB(a, b, datum=self._datum, name=self.name) ll._convergence = b * c # gamma ll._scale = _scale(E, r, t) if r > 0 else self.scale0 self._latlon = ll return self._latlon5(LatLon)
def toOsgr(latlon, lon=None, datum=Datums.WGS84, Osgr=Osgr, name=''): '''Convert a lat-/longitude point to an OSGR coordinate. @param latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic C{LatLon} point. @keyword lon: Optional longitude in degrees (scalar or C{None}). @keyword datum: Optional datum to convert (C{Datum}). @keyword Osgr: Optional (sub-)class to return the OSGR coordinate (L{Osgr}) or C{None}. @keyword name: Optional I{Osgr} name (C{str}). @return: The OSGR coordinate (L{Osgr}) or 2-tuple (easting, northing) if I{Osgr} is C{None}. @raise TypeError: Non-ellipsoidal I{latlon} or I{datum} conversion failed. @raise ValueError: Invalid I{latlon} or I{lon}. @example: >>> p = LatLon(52.65798, 1.71605) >>> r = toOsgr(p) # TG 51409 13177 >>> # for conversion of (historical) OSGB36 lat-/longitude: >>> r = toOsgr(52.65757, 1.71791, datum=Datums.OSGB36) ''' if not isinstance(latlon, _LLEB): # XXX fix failing _LLEB.convertDatum() latlon = _LLEB(*parseDMS2(latlon, lon), datum=datum) elif lon is not None: raise ValueError('%s not %s: %r' % ('lon', None, lon)) elif not name: # use latlon.name name = _nameof(latlon) or name # PYCHOK no effect E = _OSGB36.ellipsoid ll = _ll2datum(latlon, _OSGB36, 'latlon') a, b = map1(radians, ll.lat, ll.lon) sa, ca = sincos2(a) s = E.e2s2(sa) v = E.a * _F0 / sqrt(s) # nu r = s / E.e12 # nu / rho == v / (v * E.e12 / s) x2 = r - 1 # η2 ta = tan(a) ca3, ca5 = fpowers(ca, 5, 3) # PYCHOK false! ta2, ta4 = fpowers(ta, 4, 2) # PYCHOK false! vsa = v * sa I4 = (E.b * _F0 * _M(E.Mabcd, a) + _N0, (vsa / 2) * ca, (vsa / 24) * ca3 * fsum_(5, -ta2, 9 * x2), (vsa / 720) * ca5 * fsum_(61, ta4, -58 * ta2)) V4 = (_E0, (v * ca), (v / 6) * ca3 * (r - ta2), (v / 120) * ca5 * fdot( (-18, 1, 14, -58), ta2, 5 + ta4, x2, ta2 * x2)) d, d2, d3, d4, d5, d6 = fpowers(b - _B0, 6) # PYCHOK false! n = fdot(I4, 1, d2, d4, d6) e = fdot(V4, 1, d, d3, d5) return (e, n) if Osgr is None else _xnamed(Osgr(e, n), name)
def toLatLon(self, LatLon=None, datum=Datums.WGS84): '''Convert this OSGR coordinate to an (ellipsoidal) geodetic point. I{Note formulation implemented here due to Thomas, Redfearn, etc. is as published by OS, but is inferior to Krüger as used by e.g. Karney 2011.} @keyword LatLon: Optional ellipsoidal (sub-)class to return the point (C{LatLon}) or C{None}. @keyword datum: Optional datum to use (C{Datum}). @return: The geodetic point (I{LatLon}) or 3-tuple (C{degrees90}, C{degrees180}, I{datum}) if I{LatLon} is C{None}. @raise TypeError: If I{LatLon} is not ellipsoidal or if I{datum} conversion failed. @example: >>> from pygeodesy import ellipsoidalVincenty as eV >>> g = Osgr(651409.903, 313177.270) >>> p = g.toLatLon(eV.LatLon) # 52°39′28.723″N, 001°42′57.787″E >>> # to obtain (historical) OSGB36 lat-/longitude point >>> p = g.toLatLon(eV.LatLon, datum=Datums.OSGB36) # 52°39′27.253″N, 001°43′04.518″E ''' if self._latlon: return self._latlon3(LatLon, datum) E = _OSGB36.ellipsoid # Airy130 a_F0 = E.a * _F0 b_F0 = E.b * _F0 e, n = self._easting, self._northing n_N0 = n - _N0 a, M = _A0, 0 sa = Fsum(a) while True: t = n_N0 - M if t < _10um: break a = sa.fsum_(t / a_F0) M = b_F0 * _M(E.Mabcd, a) sa, ca = sincos2(a) s = E.e2s2(sa) v = a_F0 / sqrt(s) # nu r = v * E.e12 / s # rho vr = v / r # == s / E.e12 x2 = vr - 1 # η2 ta = tan(a) v3, v5, v7 = fpowers(v, 7, 3) # PYCHOK false! ta2, ta4, ta6 = fpowers(ta**2, 3) # PYCHOK false! tar = ta / r V4 = (a, tar / (2 * v), tar / (24 * v3) * fdot( (1, 3, -9), 5 + x2, ta2, ta2 * x2), tar / (720 * v5) * fdot( (61, 90, 45), 1, ta2, ta4)) csa = 1.0 / ca X5 = (_B0, csa / v, csa / (6 * v3) * fsum_(vr, ta, ta), csa / (120 * v5) * fdot( (5, 28, 24), 1, ta2, ta4), csa / (5040 * v7) * fdot( (61, 662, 1320, 720), ta, ta2, ta4, ta6)) d, d2, d3, d4, d5, d6, d7 = fpowers(e - _E0, 7) # PYCHOK false! a = fdot(V4, 1, -d2, d4, -d6) b = fdot(X5, 1, d, -d3, d5, -d7) self._latlon = _LLEB(degrees90(a), degrees180(b), datum=_OSGB36, name=self.name) return self._latlon3(LatLon, datum)
def toLatLon(self, LatLon=None): '''Convert this UTM coordinate to an (ellipsoidal) geodetic point. @keyword LatLon: Optional, ellipsoidal (sub-)class to use for the point (C{LatLon}) or C{None}. @return: This UTM coordinate as (I{LatLon}) or 5-tuple (lat, lon, datum, convergence, scale) if I{LatLon} is C{None}. @raise TypeError: If I{LatLon} is not ellipsoidal. @raise UTMError: Invalid meridional radius or H-value. @example: >>> u = Utm(31, 'N', 448251.795, 5411932.678) >>> from pygeodesy import ellipsoidalVincenty as eV >>> ll = u.toLatLon(eV.LatLon) # 48°51′29.52″N, 002°17′40.20″E ''' if self._latlon: return self._latlon5(LatLon) E = self._datum.ellipsoid # XXX vs LatLon.datum.ellipsoid x = self._easting - _FalseEasting # relative to central meridian y = self._northing if self._hemi == 'S': # relative to equator y -= _FalseNorthing # from Karney 2011 Eq 15-22, 36 A0 = _K0 * E.A if A0 < EPS: raise UTMError('%s invalid: %r' % ('meridional', E.A)) x /= A0 # η eta y /= A0 # ξ ksi Ks = _Kseries(E.BetaKs, x, y) # Krüger series y = -Ks.ys(-y) # ξ' x = -Ks.xs(-x) # η' shx = sinh(x) cy, sy = cos(y), sin(y) H = hypot(shx, cy) if H < EPS: raise UTMError('%s invalid: %r' % ('H', H)) T = t0 = sy / H # τʹ q = 1.0 / E.e12 d = 1 sd = Fsum(T) # toggles on +/-1.12e-16 eg. 31 N 400000 5000000 while abs(d) > EPS: # 1e-12 h = hypot1(T) s = sinh(E.e * atanh(E.e * T / h)) t = T * hypot1(s) - s * h d = (t0 - t) / hypot1(t) * (q + T**2) / h T = sd.fsum_(d) # τi a = atan(T) # lat b = atan2(shx, cy) + radians(_cmlon(self._zone)) ll = _LLEB(degrees90(a), degrees180(b), datum=self._datum, name=self.name) # convergence: Karney 2011 Eq 26, 27 p = -Ks.ps(-1) q = Ks.qs(0) ll._convergence = degrees(atan(tan(y) * tanh(x)) + atan2(q, p)) # scale: Karney 2011 Eq 28 ll._scale = E.e2s(sin(a)) * hypot1(T) * H * (A0 / E.a / hypot(p, q)) self._latlon = ll return self._latlon5(LatLon)
def _tdef(self, lat): '''(INTERNAL) Compute t(lat). ''' return max(0, tanPI_2_2(-lat) / self._pdef(lat)) def _xdef(self, t_x): '''(INTERNAL) Compute x(t_x). ''' return PI_2 - 2 * atan(t_x) # XXX + self._lat0 Conics = _NamedEnum('Conics', Conic) #: Registered conics. Conics._assert( # <https://SpatialReference.org/ref/sr-org/...> # AsLb = Conic(_LLEB(-14.2666667, 170, datum=Datums.NAD27), 0, 0, E0=500000, N0=0, name='AsLb', auth='EPSG:2155'), # American Samoa ... SP=1 ! Be08Lb=Conic(_LLEB(50.7978150, 4.359215833, datum=Datums.GRS80), 49.833333, 51.166667, E0=649328.0, N0=665262.0, name='Be08Lb', auth='EPSG:9802'), # Belgium Be72Lb=Conic(_LLEB(90, 4.3674867, datum=Datums.NAD83), 49.8333339, 51.1666672, E0=150000.013, N0=5400088.438, name='Be72Lb', auth='EPSG:31370'), # Belgium Fr93Lb=Conic(_LLEB(46.5, 3, datum=Datums.WGS84), 49,
def toLatLon(self, LatLon=None, eps=EPS, unfalse=True): '''Convert this UTM coordinate to an (ellipsoidal) geodetic point. @keyword LatLon: Optional, ellipsoidal (sub-)class to return the point (C{LatLon}) or C{None}. @keyword eps: Optional convergence limit, L{EPS} or above (C{float}). @keyword unfalse: Unfalse I{easting} and I{northing} if falsed (C{bool}). @return: This UTM coordinate as (I{LatLon}) or 5-tuple (lat, lon, datum, convergence, scale) if I{LatLon} is C{None}. @raise TypeError: If I{LatLon} is not ellipsoidal. @raise UTMError: Invalid meridional radius or H-value. @example: >>> u = Utm(31, 'N', 448251.795, 5411932.678) >>> from pygeodesy import ellipsoidalVincenty as eV >>> ll = u.toLatLon(eV.LatLon) # 48°51′29.52″N, 002°17′40.20″E ''' if eps < EPS: eps = EPS # less doesn't converge if self._latlon and self._latlon_eps == eps: return self._latlon5(LatLon) E = self._datum.ellipsoid # XXX vs LatLon.datum.ellipsoid x = self._easting y = self._northing if unfalse and self._falsed: x -= _FalseEasting # relative to central meridian if self._hemisphere == 'S': # relative to equator y -= _FalseNorthing # from Karney 2011 Eq 15-22, 36 A0 = _K0 * E.A if A0 < EPS: raise UTMError('%s invalid: %r' % ('meridional', E.A)) x /= A0 # η eta y /= A0 # ξ ksi Ks = _Kseries(E.BetaKs, x, y) # Krüger series y = -Ks.ys(-y) # ξ' x = -Ks.xs(-x) # η' shx = sinh(x) sy, cy = sincos2(y) H = hypot(shx, cy) if H < EPS: raise UTMError('%s invalid: %r' % ('H', H)) d = 1.0 + eps q = 1.0 / E.e12 T = t0 = sy / H # τʹ sd = Fsum(T) while abs(d) > eps: h = hypot1(T) s = sinh(E.e * atanh(E.e * T / h)) t = T * hypot1(s) - s * h d = (t0 - t) / hypot1(t) * ((q + T**2) / h) T, d = sd.fsum2_(d) # τi, (τi - τi-1) a = atan(T) # lat b = atan2(shx, cy) + radians(_cmlon(self._zone)) ll = _LLEB(degrees90(a), degrees180(b), datum=self._datum, name=self.name) # convergence: Karney 2011 Eq 26, 27 p = -Ks.ps(-1) q = Ks.qs(0) ll._convergence = degrees(atan(tan(y) * tanh(x)) + atan2(q, p)) # scale: Karney 2011 Eq 28 ll._scale = E.e2s(sin(a)) * hypot1(T) * H * (A0 / E.a / hypot(p, q)) self._latlon, self._latlon_eps = ll, eps return self._latlon5(LatLon)