def boundsOf(self, wide, high, radius=R_M): '''Return the SE and NW lat-/longitude of a great circle bounding box centered at this location. @arg wide: Longitudinal box width (C{meter}, same units as B{C{radius}} or C{degrees} if B{C{radius}} is C{None}). @arg high: Latitudinal box height (C{meter}, same units as B{C{radius}} or C{degrees} if B{C{radius}} is C{None}). @kwarg radius: Mean earth radius (C{meter}). @return: A L{Bounds2Tuple}C{(latlonSW, latlonNE)}, the lower-left and upper-right corner (C{LatLon}). @see: U{https://www.Movable-Type.co.UK/scripts/latlong-db.html} ''' w = Scalar_(wide, name='wide') * _0_5 h = Scalar_(high, name='high') * _0_5 if radius is not None: r = Radius_(radius) c = cos(self.phi) w = degrees(asin(w / r) / c) if c > EPS else _0_0 # XXX h = degrees(h / r) w, h = abs(w), abs(h) r = Bounds2Tuple(self.classof(self.lat - h, self.lon - w, height=self.height), self.classof(self.lat + h, self.lon + w, height=self.height)) return self._xnamed(r)
def isequalTo(self, other, eps=None): '''Compare this point with an other point, I{ignoring} height. @arg other: The other point (C{LatLon}). @kwarg eps: Tolerance for equality (C{degrees}). @return: C{True} if both points are identical, I{ignoring} height, C{False} otherwise. @raise TypeError: The B{C{other}} point is not C{LatLon} or mismatch of the B{C{other}} and this C{class} or C{type}. @raise ValueError: Invalid B{C{eps}}. @see: Method L{isequalTo3}. @example: >>> p = LatLon(52.205, 0.119) >>> q = LatLon(52.205, 0.119) >>> e = p.isequalTo(q) # True ''' self.others(other) e = _0_0 if eps in (None, 0, _0_0) else Scalar_(eps, name='eps') if e > 0: return max(map1(abs, self.lat - other.lat, self.lon - other.lon)) < e else: return self.lat == other.lat and \ self.lon == other.lon
def __init__(self, latlon0, par1, par2=None, E0=0, N0=0, k0=1, opt3=0, name='', auth=''): '''New Lambert conformal conic projection. @arg latlon0: Origin with (ellipsoidal) datum (C{LatLon}). @arg par1: First standard parallel (C{degrees90}). @kwarg par2: Optional, second standard parallel (C{degrees90}). @kwarg E0: Optional, false easting (C{meter}). @kwarg N0: Optional, false northing (C{meter}). @kwarg k0: Optional scale factor (C{scalar}). @kwarg opt3: Optional meridian (C{degrees180}). @kwarg name: Optional name of the conic (C{str}). @kwarg auth: Optional authentication authority (C{str}). @return: A Lambert projection (L{Conic}). @raise TypeError: Non-ellipsoidal B{C{latlon0}}. @raise ValueError: Invalid B{C{par1}}, B{C{par2}}, B{C{E0}}, B{C{N0}}, B{C{k0}} or B{C{opt3}}. @example: >>> from pygeodesy import Conic, Datums, ellipsoidalNvector >>> ll0 = ellipsoidalNvector.LatLon(23, -96, datum=Datums.NAD27) >>> Snyder = Conic(ll0, 33, 45, E0=0, N0=0, name='Snyder') ''' if latlon0 is not None: _xinstanceof(_LLEB, latlon0=latlon0) self._phi0, self._lam0 = latlon0.philam self._par1 = Phi_(par1, name='par1') self._par2 = self._par1 if par2 is None else Phi_(par2, name='par2') if k0 != 1: self._k0 = Scalar_(k0, name='k0') if E0: self._E0 = Northing(E0, name='E0', falsed=True) if N0: self._N0 = Easting(N0, name='N0', falsed=True) if opt3: self._opt3 = Lam_(opt3, name='opt3') self.toDatum(latlon0.datum)._dup2(self) self._register(Conics, name) elif name: self._name = name if auth: self._auth = auth
def k0(self, k0): '''Set the central scale factor (C{float}), aka I{C{scale0}}. @raise ETMError: Invalid B{C{k0}}. ''' self._k0 = Scalar_(k0, name=_k0_, Error=ETMError, low=_TOL_10, high=1.0) # if not self._k0 > 0: # raise Scalar_.Error_(Scalar_, k0, name=_k0_, Error=ETMError) self._k0_a = self._k0 * self._a
def epsilon(self, eps): '''Set the convergence epsilon. @arg eps: New epsilon (C{scalar}). @raise TypeError: Non-scalar B{C{eps}}. @raise ValueError: Out of bounds B{C{eps}}. ''' self._epsilon = Scalar_(eps, name='epsilon')
def precision(res1, res2=None): '''Determine the L{Geohash} precisions to meet a given (geographic) resolutions. @arg res1: The required, primary (longitudinal) resolution (C{degrees}). @kwarg res2: Optional, required, secondary (latitudinal resolution (C{degrees}). @return: The L{Geohash} precision or length (C{int} 1..12). @raise ValueError: Invalid B{C{res1}} or B{C{res2}}. @see: C++ class U{Geohash <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1Geohash.html>}. ''' r1 = Scalar_(res1, name='res1') r2 = r1 if res2 is None else Scalar_(res2, name='res2') for p in range(1, _MaxPrec): if resolution2(p, None if res2 is None else p) <= (r1, r2): return p return _MaxPrec
def precision(res): '''Determine the L{Georef} precision to meet a required (geographic) resolution. @arg res: The required resolution (C{degrees}). @return: The L{Georef} precision (C{int} 0..11). @raise ValueError: Invalid B{C{res}}. @see: Function L{wgrs.encode} for more C{precision} details. ''' r = Scalar_(res=res) for p in range(_MaxPrec): if resolution(p) <= r: return p return _MaxPrec
def rescale0(self, lat, scale0=_K0): '''Set the central scale factor for this UPS projection. @arg lat: Northern latitude (C{degrees}). @arg scale0: UPS k0 scale at B{C{lat}} latitude (C{scalar}). @raise RangeError: If B{C{lat}} outside the valid range and L{rangerrors} set to C{True}. @raise UPSError: Invalid B{C{scale}}. ''' s0 = Scalar_(scale0, Error=UPSError, name='scale0', low=EPS) # <= 1.003 or 1.0016? u = toUps8(abs(Lat(lat)), 0, datum=self.datum, Ups=_UpsK1) k = s0 / u.scale if self.scale0 != k: self._band = NN # force re-compute self._latlon = self._epsg = self._mgrs = self._utm = None self._scale0 = Scalar(k)
def reset(self, k2=0, alpha2=0, kp2=None, alphap2=None): # MCCABE 13 '''Reset the modulus and parameter. @kwarg k2: modulus squared (C{float}, 0 <= k^2<= 1). @kwarg alpha2: parameter (C{float}, 0 <= α^2 <= 1). @kwarg kp2: complementary modulus squared (C{float}, k'^2 >= 0). @kwarg alphap2: complementary parameter squared (C{float}, α'^2 >= 0). @raise EllipticError: Invalid B{C{k2}}, B{C{alpha2}}, B{C{kp2}} or B{C{alphap2}} or no convergence. @note: The arguments must satisfy I{B{C{k2}} + B{C{kp2}} = 1} and I{B{C{alpha2}} + B{C{alphap2}} = 1}. No checking is done that these conditions are met to enable accuracy to be maintained, e.g., when C{k} is very close to unity. ''' self._k2 = k2 = Scalar_(k2, name='k2', Error=EllipticError, high=1.0) self._alpha2 = alpha2 = Scalar_(alpha2, name='alpha2', Error=EllipticError, high=1.0) self._kp2 = kp2 = Scalar_(((1 - k2) if kp2 is None else kp2), name='kp2', Error=EllipticError) self._alphap2 = alphap2 = Scalar_(((1 - alpha2) if alphap2 is None else alphap2), name='alphap2', Error=EllipticError) # Values of complete elliptic integrals for k = 0,1 and alpha = 0,1 # K E D # k = 0: pi/2 pi/2 pi/4 # k = 1: inf 1 inf # Pi G H # k = 0, alpha = 0: pi/2 pi/2 pi/4 # k = 1, alpha = 0: inf 1 1 # k = 0, alpha = 1: inf inf pi/2 # k = 1, alpha = 1: inf inf inf # # G(0, k) = Pi(0, k) = H(1, k) = E(k) # H(0, k) = K(k) - D(k) # Pi(alpha2, 0) = G(alpha2, 0) = pi / (2 * sqrt(1 - alpha2)) # H( alpha2, 0) = pi / (2 * (sqrt(1 - alpha2) + 1)) # Pi(alpha2, 1) = inf # G( alpha2, 1) = H(alpha2, 1) = RC(1, alphap2) if k2: if kp2: self._eps = k2 / (sqrt(kp2) + 1)**2 # D(k) = (K(k) - E(k))/k2, Carlson eq.4.3 # <https://DLMF.NIST.gov/19.25.E1> self._cD = _RD_3(0, kp2, 1) self._cKE = k2 * self.cD # Complete elliptic integral E(k), Carlson eq. 4.2 # <https://DLMF.NIST.gov/19.25.E1> self._cE = _RG_(kp2, 1) * 2 # Complete elliptic integral K(k), Carlson eq. 4.1 # <https://DLMF.NIST.gov/19.25.E1> self._cK = _RF_(kp2, 1) else: self._eps = k2 self._cD = self._cK = self._cKE = INF self._cE = 1.0 else: self._eps = EPS # delattr(self, '_eps') self._cD = PI_4 self._cE = self._cK = PI_2 self._cKE = 0.0 # k2 * self._cD if alpha2: if alphap2: # <https://DLMF.NIST.gov/19.25.E2> if kp2: rj_3 = _RJ_3(0, kp2, 1, alphap2) # G(alpha2, k) self._cG = self.cK + (alpha2 - k2) * rj_3 # H(alpha2, k) self._cH = self.cK - alphap2 * rj_3 # Pi(alpha2, k) self._cPi = self.cK + alpha2 * rj_3 else: self._cG = self._cH = _RC(1, alphap2) self._cPi = INF # XXX or NAN? else: self._cG = self._cH = self._cPi = INF # XXX or NAN? else: self._cG = self.cE self._cPi = self.cK # cH = cK - cD but this involves large cancellations # if k2 is close to 1. So write (for alpha2 = 0) # cH = int(cos(phi)**2/sqrt(1-k2*sin(phi)**2),phi,0,pi/2) # = 1/sqrt(1-k2) * int(sin(phi)**2/sqrt(1-k2/kp2*sin(phi)**2,...) # = 1/kp * D(i*k/kp) # and use D(k) = RD(0, kp2, 1) / 3 # so cH = 1/kp * RD(0, 1/kp2, 1) / 3 # = kp2 * RD(0, 1, kp2) / 3 # using <https://DLMF.NIST.gov/19.20.E18> # Equivalently # RF(x, 1) - RD(0, x, 1)/3 = x * RD(0, 1, x)/3 for x > 0 # For k2 = 1 and alpha2 = 0, we have # cH = int(cos(phi),...) = 1 self._cH = kp2 * _RD_3(0, 1, kp2) if kp2 else 1.0
def _option(name, m, m2_, K): f = Scalar_(m, name=name, Error=WGRSError) return NN(name[0].upper(), int(m2_(f * K) + _0_5))
def _Ks(**name_k): '''(INTERNAL) Scale C{B{k} >= EPS}. ''' return Scalar_(Error=AlbersError, low=EPS, **name_k) # > 0
def k0(self, factor): '''Set the central scale factor (C{scalar}). ''' n = Stereographic.k0.fget.__name__ self._k0 = Scalar_(factor, name=n, low=EPS, high=2) # XXX high=1, 2, other?
def _Ks(k, name): '''(INTERNAL) Scale C{B{k} >= EPS}. ''' return Scalar_(k, name=name, Error=AlbersError, low=EPS) # > 0
def _option(name, m, m2_, K): f = Scalar_(m, name=name, Error=WGRSError) return '%s%d' % (name[0].upper(), int(m2_(f * K) + 0.5))