def resolution2(prec1, prec2=None): '''Determine the (geographic) resolutions of given L{Geohash} precisions. @arg prec1: The given primary (longitudinal) precision (C{int} 1..12). @kwarg prec2: Optional, secondary (latitudinal) precision (C{int} 1..12). @return: 2-Tuple (C{res1, res2}) with the (geographic) resolutions (C{degrees}) where C{res2} is C{res1} if no I{prec2} is given. @raise ValueError: Invalid B{C{prec1}} or B{C{prec2}}. @see: C++ class U{Geohash <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1Geohash.html>}. ''' res1, res2 = 360.0, 180.0 if prec1: p = 5 * max(0, min(Precision_(prec1, name='prec1', low=None), _MaxPrec)) res1 = res2 = ldexp(res1, -(p - p // 2)) if prec2: p = 5 * max(0, min(Precision_(prec2, name='prec2', low=None), _MaxPrec)) res2 = ldexp(res2, -(p // 2)) return res1, res2
def __new__(cls, cll, precision=3, name=''): '''New L{Georef} from an other L{Georef} instance or georef C{str} or from a C{LatLon} instance or lat-/longitude C{str}. @arg cll: Cell or location (L{Georef} or C{str}, C{LatLon} or C{str}). @kwarg precision: Optional, the desired georef resolution and length (C{int} 0..11), see function L{wgrs.encode} for more details. @kwarg name: Optional name (C{str}). @return: New L{Georef}. @raise RangeError: Invalid B{C{cll}} lat- or longitude. @raise TypeError: Invalid B{C{cll}}. @raise WGRSError: INValid or non-alphanumeric B{C{cll}}. ''' h = None if isinstance(cll, Georef): g, p = _2geostr2(str(cll)) self = str.__new__(cls, g) self._latlon = LatLon2Tuple(*cll._latlon) self._name = cll._name self._precision = p # cll._precision elif isstr(cll): if ',' in cll: lat, lon, h = _2fllh(*parse3llh(cll, height=None)) g = encode(lat, lon, precision=precision, height=h) # PYCHOK false self = str.__new__(cls, g) self._latlon = LatLon2Tuple(lat, lon) self._precision = Precision_(precision, high=_MaxPrec) else: self = str.__new__(cls, cll.upper()) self._decode() else: # assume LatLon try: lat, lon, h = _2fllh(cll.lat, cll.lon) h = getattr(cll, 'height', h) except AttributeError: raise IsnotError('valid', **{Georef.__name__: cll}) g = encode(lat, lon, precision=precision, height=h) # PYCHOK false self = str.__new__(cls, g) self._latlon = LatLon2Tuple(lat, lon) self._precision = Precision_(precision, high=_MaxPrec) if h not in (None, _MISSING): self._height = Height(h) if name: self.name = name return self
def __new__(cls, cll, precision=1, name=''): '''New L{Garef} from an other L{Garef} instance or garef C{str} or from a C{LatLon} instance or lat-/longitude C{str}. @arg cll: Cell or location (L{Garef} or C{str}, C{LatLon} or C{str}). @kwarg precision: Optional, the desired garef resolution and length (C{int} 0..2), see function L{gars.encode} for more details. @kwarg name: Optional name (C{str}). @return: New L{Garef}. @raise RangeError: Invalid B{C{cll}} lat- or longitude. @raise TypeError: Invalid B{C{cll}}. @raise GARSError: INValid or non-alphanumeric B{C{cll}}. ''' if isinstance(cll, Garef): g, p = _2garstr2(str(cll)) self = str.__new__(cls, g) self._latlon = LatLon2Tuple(*cll._latlon) self._name = cll._name self._precision = p # cll._precision elif isstr(cll): if ',' in cll: lat, lon = _2fll(*parse3llh(cll)) cll = encode(lat, lon, precision=precision) # PYCHOK false self = str.__new__(cls, cll) self._latlon = LatLon2Tuple(lat, lon) self._precision = Precision_(precision, high=_MaxPrec) else: self = str.__new__(cls, cll.upper()) self._decode() else: # assume LatLon try: lat, lon = _2fll(cll.lat, cll.lon) except AttributeError: raise TypeError('%s: %r' % (Garef.__name__, cll)) cll = encode(lat, lon, precision=precision) # PYCHOK false self = str.__new__(cls, cll) self._latlon = LatLon2Tuple(lat, lon) self._precision = Precision_(precision, high=_MaxPrec) if name: self.name = name return self
def precision(form, prec=None): '''Set the default precison for a given F_ form. @arg form: L{F_D}, L{F_DM}, L{F_DMS}, L{F_DEG}, L{F_MIN}, L{F_SEC}, L{F__E}, L{F__F}, L{F__G} or L{F_RAD} (C{str}). @kwarg prec: Optional number of decimal digits (0..9 or C{None} for default). Trailing zero decimals are stripped for B{C{prec}} values of 1 and above, but kept for negative B{C{prec}}. @return: Previous precision (C{int}). @raise ValueError: Invalid B{C{form}} or B{C{prec}} or B{C{prec}} outside valid range. ''' try: p = _F_prec[form] except KeyError: raise _ValueError(form=form) if prec is not None: from pygeodesy.units import Precision_ _F_prec[form] = Precision_(prec=prec, low=-9, high=9) return p
def encode(lat, lon, precision=3, height=None, radius=None): # MCCABE 14 '''Encode a lat-/longitude as a C{georef} of the given precision. @arg lat: Latitude (C{degrees}). @arg lon: Longitude (C{degrees}). @kwarg precision: Optional, the desired C{georef} resolution and length (C{int} 0..11). @kwarg height: Optional, height in C{meter}, see U{Designation of area <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}. @kwarg radius: Optional, radius in C{meter}, see U{Designation of area <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}. @return: The C{georef} (C{str}). @raise RangeError: Invalid B{C{lat}} or B{C{lon}}. @raise WGRSError: Invalid B{C{precision}}, B{C{height}} or B{C{radius}}. @note: The B{C{precision}} value differs from U{Georef<https:// GeographicLib.SourceForge.io/html/classGeographicLib_1_1Georef.html>}. The C{georef} length is M{2 * (precision + 1)} and the C{georef} resolution is I{15°} for B{C{precision}} 0, I{1°} for 1, I{1′} for 2, I{0.1′} for 3, I{0.01′} for 4, ... M{10**(2 - precision)}. ''' 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)) def _pstr(p, x): return '%0*d' % (p, x) p = Precision_(precision, Error=WGRSError, low=0, high=_MaxPrec) lat, lon, _ = _2fllh(lat, lon) if lat == 90: lat *= EPS1_2 xt, xd, x = _2divmod3(lon, _LonOrig_M) yt, yd, y = _2divmod3(lat, _LatOrig_M) g = _LonTile[xt], _LatTile[yt] if p > 0: g += _Degrees[xd], _Degrees[yd] p -= 1 if p > 0: d = pow(_Base, _MaxPrec - p) x = _pstr(p, x // d) y = _pstr(p, y // d) g += x, y if radius is not None: # R before H g += _option('radius', radius, m2NM, 1.0), if height is not None: # H is last g += _option('height', height, m2ft, 1e-3), return ''.join(g)
def resolution(prec): '''Determine the (geographic) resolution of a given L{Garef} precision. @arg prec: The given precision (C{int}). @return: The (geographic) resolution (C{degrees}). @raise ValueError: Invalid B{C{prec}}. @see: Function L{gars.encode} for more C{precision} details. ''' p = Precision_(prec, name='prec', low=None) return _Resolutions[max(0, min(p, _MaxPrec))]
def resolution(prec): '''Determine the (geographic) resolution of a given L{Georef} precision. @arg prec: The given precision (C{int}). @return: The (geographic) resolution (C{degrees}). @raise ValueError: Invalid B{C{prec}}. @see: Function L{wgrs.encode} for more C{precision} details. ''' p = Precision_(prec, name='prec', low=None) if p < 1: r = float(_Tile) elif p == 1: r = 1.0 else: r = 1.0 / (60.0 * pow(_Base, min(p, _MaxPrec) - 1)) return r
def _2Precision(precision): '''(INTERNAL) Return a L{Precision_} instance. ''' return Precision_(precision, Error=WGRSError, low=0, high=_MaxPrec)
def encode(lat, lon, precision=None): '''Encode a lat-/longitude as a C{geohash}, either to the specified precision or if not provided, to an automatically evaluated precision. @arg lat: Latitude (C{degrees}). @arg lon: Longitude (C{degrees}). @kwarg precision: Optional, the desired geohash length (C{int} 1..12). @return: The C{geohash} (C{str}). @raise GeohashError: Invalid B{C{lat}}, B{C{lon}} or B{C{precision}}. @example: >>> geohash.encode(52.205, 0.119, 7) # 'u120fxw' >>> geohash.encode(52.205, 0.119, 12) # 'u120fxwshvkg' >>> geohash.encode(52.205, 0.1188, 12) # 'u120fxws0jre' >>> geohash.encode(52.205, 0.1188) # 'u120fxw' >>> geohash.encode( 0, 0) # 's00000000000' ''' lat, lon = _2fll(lat, lon) if precision is None: # Infer precision by refining geohash until # it matches precision of supplied lat/lon. for p in range(1, _MaxPrec + 1): gh = encode(lat, lon, p) ll = map2(float, decode(gh)) if abs(lat - ll[0]) < EPS and \ abs(lon - ll[1]) < EPS: return gh p = _MaxPrec else: p = Precision_(precision, Error=GeohashError, low=1, high=_MaxPrec) s, w, n, e = _Bounds4 b = i = 0 d, gh = True, [] while len(gh) < p: i += i if d: # bisect longitude m = favg(e, w) if lon < m: e = m else: w = m i += 1 else: # bisect latitude m = favg(n, s) if lat < m: n = m else: s = m i += 1 d = not d b += 1 if b == 5: # 5 bits gives a character: # append it and start over gh.append(_GeohashBase32[i]) b = i = 0 return ''.join(gh)