def _toZBab4(lat, lon, cmoff=True): '''(INTERNAL) Return zone, Band and central lat- and longitude in radians. @param lat: Latitude (C{degrees}). @param lon: Longitude (C{degrees}). @keyword cmoff: Offset i{lon} from zone's central meridian. @return: 4-Tuple (zone, Band, a, b). ''' # return zone, Band and lat- and medidian (in C{radians}) lat = wrap90(lat) if -80 > lat or lat > 84: raise RangeError('%s outside UTM: %s' % ('lat', lat)) B = _Bands[int(lat + 80) >> 3] lon = wrap180(lon) z = int((lon + 180) / 6) + 1 # longitudinal zone if B == 'X': x = {32: 9, 34: 21, 36: 33}.get(z, None) if x: # Svalbard z += 1 if lon >= x else -1 elif B == 'V' and z == 31 and lon >= 3: z += 1 # southern Norway a = radians(lat) # lat off equator if cmoff: # lon off central meridian lon -= _cmlon(z) return z, B, a, radians(lon)
def isantipode(lat1, lon1, lat2, lon2, eps=EPS): '''Check whether two points are antipodal, on diametrically opposite sides of the earth. @param lat1: Latitude of one point (C{degrees}). @param lon1: Longitude of one point (C{degrees}). @param lat2: Latitude of the other point (C{degrees}). @param lon2: Longitude of the other point (C{degrees}). @keyword eps: Tolerance for near-equality (C{degrees}). @return: C{True} if points are antipodal within the I{eps} tolerance, C{False} otherwise. @see: U{Geosphere<http://CRAN.R-Project.org/web/packages/geosphere/geosphere.pdf>}. ''' return abs(wrap90(lat1) + wrap90(lat2)) < eps and \ abs(abs(wrap180(lon1) - wrap180(lon2)) % 360 - 180) < eps
def antipode(lat, lon): '''Return the antipode, the point diametrically opposite to a given point. @param lat: Latitude (C{degrees}). @param lon: Longitude (C{degrees}). @return: A L{LatLon2Tuple}C{(lat, lon)}. @see: U{Geosphere<https://CRAN.R-Project.org/web/packages/geosphere/geosphere.pdf>}. ''' return LatLon2Tuple(-wrap90(lat), wrap180(lon + 180))
def point(self, ll): '''Create a pseudo-xy. @param ll: Point (C{LatLon}). @return: 3-Tuple (x, y, ll) of (float, float, I{ll}). ''' x, y = ll.lon, ll.lat # note, x, y = lon, lat if self._wrap: x, y = wrap180(x), wrap90(y) if self._deg2m: # convert degrees to meter x, y = x * self._deg2m, y * self._deg2m return x, y, ll
def _to3zll(lat, lon): # imported by .ups, .utm '''Wrap lat- and longitude and determine UTM zone. @param lat: Latitude (C{degrees}). @param lon: Longitude (C{degrees}). @return: 3-Tuple (C{zone, lat, lon}) as (C{int}, C{degrees90}, C{degrees180}) where C{zone} is C{1..60} for UTM. ''' x = wrap360(lon + 180) # use wrap360 to get ... z = int(x) // 6 + 1 # ... longitudinal UTM zone [1, 60] and ... lon = x - 180 # ... lon [-180, 180) i.e. -180 <= lon < 180 return z, wrap90(lat), lon
def _direct(self, distance, bearing, llr, height=None): '''(INTERNAL) Direct Karney method. ''' g = self.datum.ellipsoid.geodesic m = g.AZIMUTH if llr: m |= g.LATITUDE | g.LONGITUDE r = g.Direct(self.lat, self.lon, bearing, distance, m) t = wrap360(r['azi2']) if llr: a, b = wrap90(r['lat2']), wrap180(r['lon2']) h = self.height if height is None else height t = self.classof(a, b, height=h, datum=self.datum), t return t
def isenclosedBy(point, points, wrap=False): # MCCABE 15 '''Determine whether a point is enclosed by a polygon. @param point: The point (C{LatLon} or 2-tuple (lat, lon)). @param points: The polygon points (C{LatLon}[]). @keyword wrap: Wrap lat-, wrap and unroll longitudes (C{bool}). @return: C{True} if I{point} is inside the polygon, C{False} otherwise. @raise TypeError: Some I{points} are not C{LatLon}. @raise ValueError: Insufficient number of I{points} or invalid I{point}. @see: L{sphericalNvector.LatLon.isEnclosedBy}, L{sphericalTrigonometry.LatLon.isEnclosedBy} and U{MultiDop GeogContainPt<http://GitHub.com/NASA/MultiDop>} (U{Shapiro et al. 2009, JTECH <http://journals.AMetSoc.org/doi/abs/10.1175/2009JTECHA1256.1>} and U{Potvin et al. 2012, JTECH <http://journals.AMetSoc.org/doi/abs/10.1175/JTECH-D-11-00019.1>}). ''' try: y0, x0 = point.lat, point.lon except AttributeError: try: y0, x0 = map1(float, *point[:2]) except (IndexError, TypeError, ValueError): raise ValueError('%s invalid: %r' % ('point', point)) pts = LatLon2psxy(points, closed=True, radius=None, wrap=wrap) n = len(pts) if wrap: x0, y0 = wrap180(x0), wrap90(y0) def _dxy(x1, i): x2, y2, _ = pts[i] dx, x2 = unroll180(x1, x2, wrap=i < (n - 1)) return dx, x2, y2 else: x0 = fmod(x0, 360.0) # not x0 % 360 def _dxy(x1, i): # PYCHOK expected x, y, _ = pts[i] x %= 360.0 if x < (x0 - 180): x += 360 elif x >= (x0 + 180): x -= 360 return (x - x1), x, y e = m = False s = Fsum() _, x1, y1 = _dxy(x0, n - 1) for i in range(n): dx, x2, y2 = _dxy(x1, i) # ignore duplicate and near-duplicate pts if max(abs(dx), abs(y2 - y1)) > EPS: # determine if polygon edge (x1, y1)..(x2, y2) straddles # point (lat, lon) or is on boundary, but do not count # edges on boundary as more than one crossing if abs(dx) < 180 and (x1 < x0 <= x2 or x2 < x0 <= x1): m = not m dy = (x0 - x1) * (y2 - y1) - (y0 - y1) * dx if (dy > 0 and dx >= 0) or (dy < 0 and dx <= 0): e = not e s.fadd(sin(radians(y2))) x1, y1 = x2, y2 # An odd number of meridian crossings means, the polygon # contains a pole. Assume it is the pole on the hemisphere # containing the polygon mean point and if the polygon does # contain the North Pole, flip the result. if m and s.fsum() > 0: e = not e return e