def flatten(reference: s2sphere.LatLng, point: s2sphere.LatLng) -> Tuple[float, float]: """Locally flatten a lat-lng point to (dx, dy) in meters from reference.""" return ((point.lng().degrees - reference.lng().degrees) * EARTH_CIRCUMFERENCE_KM * math.cos(reference.lat().radians) * 1000 / 360, (point.lat().degrees - reference.lat().degrees) * EARTH_CIRCUMFERENCE_KM * 1000 / 360)
def unflatten(reference: s2sphere.LatLng, point: Tuple[float, float]) -> s2sphere.LatLng: """Locally unflatten a (dx, dy) point to an absolute lat-lng point.""" return s2sphere.LatLng.from_degrees( reference.lat().degrees + point[1] * 360 / (EARTH_CIRCUMFERENCE_KM * 1000), reference.lng().degrees + point[0] * 360 / (EARTH_CIRCUMFERENCE_KM * 1000 * math.cos(reference.lat().radians)))
def compute_circle(center: s2sphere.LatLng, radius_km: float) -> typing.Iterator[s2sphere.LatLng]: """Compute a circle with given center and radius :param center: Center of the circle :param radius_km: Radius of the circle :type center: s2sphere.LatLng :type radius_km: float :return: circle :rtype: typing.Iterator[s2sphere.LatLng] """ first = None delta_angle = 0.1 angle = 0.0 geod = Geodesic.WGS84 while angle < 360.0: d = geod.Direct( center.lat().degrees, center.lng().degrees, angle, radius_km * 1000.0, Geodesic.LONGITUDE | Geodesic.LATITUDE | Geodesic.LONG_UNROLL, ) latlng = create_latlng(d["lat2"], d["lon2"]) if first is None: first = latlng yield latlng angle = angle + delta_angle if first: yield first
def adjust(cls, time: datetime.datetime, latlng: s2sphere.LatLng) -> datetime.datetime: # If a timezone is set, there's nothing to do. if time.utcoffset(): return time assert cls._timezonefinder # if tz_name name is None set it to UTC tz_name = cls._timezonefinder.timezone_at( lat=latlng.lat().degrees, lng=latlng.lng().degrees) or "UTC" tz = pytz.timezone(tz_name) tz_time = time.astimezone(tz) return tz_time
def mercator(latlng: s2sphere.LatLng) -> typing.Tuple[float, float]: """Mercator projection :param latlng: LatLng object :type latlng: s2sphere.LatLng :return: tile values of given LatLng :rtype: tuple """ lat = latlng.lat().radians lng = latlng.lng().radians return lng / (2 * math.pi) + 0.5, ( 1 - math.log(math.tan(lat) + (1 / math.cos(lat))) / math.pi) / 2
def get_location(self, latlng: s2sphere.LatLng) -> str: lat1000 = int(round(latlng.lat().degrees * 1000)) lng1000 = int(round(latlng.lng().degrees * 1000)) key = f"{lat1000}:{lng1000}" if key in self._cache: return self._cache[key] if self._load_cache(key): return self._cache[key] location = self._geocoder.reverse( f"{lat1000 * 0.001:f}, {lng1000 * 0.001:f}") if "address" in location.raw: address = location.raw["address"] country = address["country"] if "country" in address else None city = None for city_key in ["hamlet", "village", "town", "city"]: if city_key in address: city = address[city_key] break a = [] if city is not None: a.append(city) if country is not None: a.append(country) if len(a) > 0: self._cache[key] = ", ".join(a) else: self._cache[key] = "Unknown" else: self._cache[key] = "Unknown" self._store_cache(key) return self._cache[key]
def latlng2xy(latlng: s2.LatLng) -> XY: return XY(lng2x(latlng.lng().degrees), lat2y(latlng.lat().degrees))