def translate(self, p1, p2): """ Translate the surface for a specific distance along a specific azimuth direction. Parameters are two points (instances of :class:`nhlib.geo.point.Point`) representing the direction and an azimuth for translation. The resulting surface corner points will be that far along that azimuth from respective corner points of this surface as ``p2`` is located with respect to ``p1``. :returns: A new :class:`PlanarSurface` object with the same mesh spacing, dip, strike, width, length and depth but with corners longitudes and latitudes translated. """ azimuth = geodetic.azimuth(p1.longitude, p1.latitude, p2.longitude, p2.latitude) distance = geodetic.geodetic_distance(p1.longitude, p1.latitude, p2.longitude, p2.latitude) # avoid calling PlanarSurface's constructor nsurf = object.__new__(PlanarSurface) # but do call BaseSurface's one BaseSurface.__init__(nsurf) nsurf.mesh_spacing = self.mesh_spacing nsurf.dip = self.dip nsurf.strike = self.strike nsurf.corner_lons, nsurf.corner_lats = geodetic.point_at( self.corner_lons, self.corner_lats, azimuth, distance ) nsurf.corner_depths = self.corner_depths.copy() nsurf._init_plane() nsurf.width = self.width nsurf.length = self.length return nsurf
def average_azimuth(self): """ Calculate and return weighted average azimuth of all line's segments in decimal degrees. Uses formula from http://en.wikipedia.org/wiki/Mean_of_circular_quantities >>> from nhlib.geo.point import Point as P >>> str(Line([P(0, 0), P(1e-5, 1e-5)]).average_azimuth()) '45.0' >>> str(Line([P(0, 0), P(0, 1e-5), P(1e-5, 1e-5)]).average_azimuth()) '45.0' >>> line = Line([P(0, 0), P(-2e-5, 0), P(-2e-5, 1.154e-5)]) >>> '%.1f' % line.average_azimuth() '300.0' """ if len(self.points) == 2: return self.points[0].azimuth(self.points[1]) lons = numpy.array([point.longitude for point in self.points]) lats = numpy.array([point.latitude for point in self.points]) azimuths = geodetic.azimuth(lons[:-1], lats[:-1], lons[1:], lats[1:]) distances = geodetic.geodetic_distance(lons[:-1], lats[:-1], lons[1:], lats[1:]) azimuths = numpy.radians(azimuths) # convert polar coordinates to Cartesian ones and calculate # the average coordinate of each component avg_x = numpy.mean(distances * numpy.sin(azimuths)) avg_y = numpy.mean(distances * numpy.cos(azimuths)) # find the mean azimuth from that mean vector azimuth = numpy.degrees(numpy.arctan2(avg_x, avg_y)) if azimuth < 0: azimuth += 360 return azimuth
def test_arrays(self): lons1 = numpy.array([[156.49676849, 150.03697145], [-77.96053914, -109.36694411]]) lats1 = numpy.array([[-79.78522764, -89.15044328], [-32.28244296, -25.11092309]]) lons2 = numpy.array([[-84.6732372, 140.08382287], [82.69227935, -18.9919318]]) lats2 = numpy.array([[82.16896786, 26.16081412], [41.21501474, -2.88241099]]) eazimuths = numpy.array([[47.07336955, 350.11740733], [54.46959147, 92.76923701]]) az = geodetic.azimuth(lons1, lats1, lons2, lats2) self.assertTrue(numpy.allclose(az, eazimuths), str(az))
def get_middle_point(lon1, lat1, lon2, lat2): """ Given two points return the point exactly in the middle lying on the same great circle arc. Parameters are point coordinates in degrees. :returns: Tuple of longitude and latitude of the point in the middle. """ if lon1 == lon2 and lat1 == lat2: return lon1, lat1 dist = geodetic.geodetic_distance(lon1, lat1, lon2, lat2) azimuth = geodetic.azimuth(lon1, lat1, lon2, lat2) return geodetic.point_at(lon1, lat1, azimuth, dist / 2.0)
def azimuth(self, point): """ Compute the azimuth (in decimal degrees) between this point and the given point. :param point: Destination point. :type point: Instance of :class:`Point` :returns: The azimuth, value in a range ``[0, 360)``. :rtype: float """ return geodetic.azimuth(self.longitude, self.latitude, point.longitude, point.latitude)
def test_equator(self): az = geodetic.azimuth(0, 0, 1, 0) self.assertEqual(az, 90) az = geodetic.azimuth(1, 0, 0, 0) self.assertEqual(az, 270)
def test_meridians(self): az = geodetic.azimuth(0, 0, 0, 1) self.assertEqual(az, 0) az = geodetic.azimuth(0, 2, 0, 1) self.assertEqual(az, 180)
def test_quadrants(self): az = geodetic.azimuth(0, 0, [0.01, 0.01, -0.01, -0.01], [0.01, -0.01, -0.01, 0.01]) self.assertTrue(numpy.allclose(az, [45, 135, 225, 315]), str(az))
def test_LAX_to_JFK(self): az = geodetic.azimuth(*(LAX + JFK)) self.assertAlmostEqual(az, 360 - 65.8922, places=4)