def nearest_edge(elon, elat, poly): """ Return the distance from a point to the nearest edge of a polygon. Args: elon (float): The longitude of the reference point. elat (float): The latitude of the reference point. poly (Polygon): An instance of a shapely Polygon. Returns: float: The distance (in km) from the reference point to the nearest edge (or vertex) of the polygon. """ elon_arr = np.array([elon]) elat_arr = np.array([elat]) x, y = poly.exterior.xy nearest = 99999. for ix in range(1, len(x) - 1): dd = min_distance_to_segment(np.array(x[ix - 1:ix + 1]), np.array(y[ix - 1:ix + 1]), elon_arr, elat_arr) if np.abs(dd[0]) < nearest: nearest = dd[0] return nearest
def test_three(self): # Positive distance halfspace - outside segment dist = geodetic.min_distance_to_segment(self.slons, self.slats, lons=numpy.array([3.0]), lats=numpy.array([0.0])) self.assertAlmostEqual(dist, 186.394507344)
def test_four(self): # Negative distance halfspace - outside segment dist = float(geodetic.min_distance_to_segment( self.slons, self.slats, lons=numpy.array([-2.0]), lats=numpy.array([0.5]))) self.assertAlmostEqual(dist, -125.802091893)
def test_two(self): # Negative distance halfspace - within segment dist = geodetic.min_distance_to_segment(self.slons, self.slats, lons=numpy.array([0.0]), lats=numpy.array([2.0])) self.assertAlmostEqual(dist, -205.18959626)
def test_one(self): # Positive distance halfspace - within segment dist = geodetic.min_distance_to_segment(self.slons, self.slats, lons=numpy.array([0.0]), lats=numpy.array([-2.0])) self.assertAlmostEqual(dist, 219.90986712)
def nearest_edge(elon, elat, poly): """ Return the distance from a point to the nearest edge of a polygon. Args: elon (float): The longitude of the reference point. elat (float): The latitude of the reference point. poly (Polygon): An instance of a shapely Polygon. Returns: float: The distance (in km) from the reference point to the nearest edge (or vertex) of the polygon. """ elon_arr = np.array([elon]) elat_arr = np.array([elat]) x, y = poly.exterior.xy nearest = 99999. for ix in range(1, len(x) - 1): dd = min_distance_to_segment(np.array(x[ix - 1:ix + 1]), np.array(y[ix - 1:ix + 1]), elon_arr, elat_arr) if np.abs(dd[0]) < nearest: nearest = dd[0] return nearest
def get_min_distance(line, pnts): """ Get distances between a line and a set of points :parameter line: An instance of :class:`openquake.hazardlib.geo.line.Line` :parameter pnts: A nx2 array """ # # assert isinstance(pnts, numpy.ndarray) coo = numpy.array([(pnt.longitude, pnt.latitude) for pnt in line.points]) # # this handles the case of a multiine if len(coo[:, 0]) > 2: cx = numpy.stack((coo[:-1, 0], coo[1:, 0])) else: cx = [coo[:, 0]] if len(coo[:, 0]) > 2: cy = list(numpy.stack((coo[:-1, 1], coo[1:, 1]))) else: cy = [ coo[:, 1]] # # calculate distances distances = numpy.zeros_like(pnts[:, 0]) distances[:] = 1e+100 for segx, segy in zip(cx, cy): sdx = segx[1] - segx[0] sdy = segy[1] - segy[0] pdx = segx[0] - pnts[:, 0] pdy = segy[0] - pnts[:, 1] dot1 = sdx * pdx + sdy * pdy pdx = segx[1] - pnts[:, 0] pdy = segy[1] - pnts[:, 1] dot2 = sdx * pdx + sdy * pdy idx = numpy.nonzero((numpy.sign(dot1) < 0) & (numpy.sign(dot2) > 0)) dst = min_distance_to_segment(segx, segy, pnts[idx[0], 0], pnts[idx[0], 1]) distances[idx[0]] = dst return distances
def get_rx_distance(self, mesh): """ Compute distance between each point of mesh and surface's great circle arc. Distance is measured perpendicular to the rupture strike, from the surface projection of the updip edge of the rupture, with the down dip direction being positive (this distance is usually called ``Rx``). In other words, is the horizontal distance to top edge of rupture measured perpendicular to the strike. Values on the hanging wall are positive, values on the footwall are negative. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate Rx-distance to. :returns: Numpy array of distances in km. """ top_edge = self.mesh[0:1] dists = [] ia = 0 ib = top_edge.lons.shape[1] - 2 if (self.__class__.__name__ == 'KiteSurface'): idxs = numpy.nonzero(numpy.isfinite(top_edge.lons[0, :]))[0] ia = min(idxs) ib = sorted(idxs)[-2] if top_edge.lons.shape[1] < 3: i = 0 if ((self.__class__.__name__ == 'KiteSurface') and (numpy.isnan(top_edge.lons[0, i]) or numpy.isnan(top_edge.lons[0, i + 1]))): msg = 'Rx calculation. Top of rupture has less than two points' raise ValueError(msg) p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats)) else: for i in range(top_edge.lons.shape[1] - 1): if ((self.__class__.__name__ == 'KiteSurface') and (numpy.isnan(top_edge.lons[0, i]) or numpy.isnan(top_edge.lons[0, i + 1]))): continue p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == ia or i == ib: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( numpy.array([p1.longitude, p2.longitude]), numpy.array([p1.latitude, p2.latitude]), mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] if numpy.any(numpy.isnan(dst)): raise ValueError('NaN in Rx') return dst
def get_rx_distance(self, mesh): """ Compute distance between each point of mesh and surface's great circle arc. Distance is measured perpendicular to the rupture strike, from the surface projection of the updip edge of the rupture, with the down dip direction being positive (this distance is usually called ``Rx``). In other words, is the horizontal distance to top edge of rupture measured perpendicular to the strike. Values on the hanging wall are positive, values on the footwall are negative. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate Rx-distance to. :returns: Numpy array of distances in km. """ top_edge = self.mesh[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats)) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( numpy.array([p1.longitude, p2.longitude]), numpy.array([p1.latitude, p2.latitude]), mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] return dst
def test_three(self): # Positive distance halfspace - outside segment dist = float(geodetic.min_distance_to_segment( self.slons, self.slats, lons=numpy.array([3.0]), lats=numpy.array([0.0]))) self.assertAlmostEqual(dist, 186.394507344)
def test_two(self): # Negative distance halfspace - within segment dist = float(geodetic.min_distance_to_segment( self.slons, self.slats, lons=numpy.array([0.0]), lats=numpy.array([2.0]))) self.assertAlmostEqual(dist, -205.18959626)
def test_one(self): # Positive distance halfspace - within segment dist = float(geodetic.min_distance_to_segment( self.slons, self.slats, lons=numpy.array([0.0]), lats=numpy.array([-2.0]))) self.assertAlmostEqual(dist, 219.90986712)
def get_rx_distance(self, mesh): """ See :meth:`superclass method <.base.BaseSurface.get_rx_distance>` for spec of input and result values. The method extracts the top edge of the surface. For each point in mesh it computes the Rx distance to each segment the top edge is made of. The calculation is done by calling the function :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx distance matrix is then constructed by taking, for each point in mesh, the minimum Rx distance value computed. """ top_edge = self.get_mesh()[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats ) ) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment([p1.longitude, p2.longitude], [p1.latitude, p2.latitude], mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] return dst
def get_rx_distance(self, mesh): """ Compute distance between each point of mesh and surface's great circle arc. Distance is measured perpendicular to the rupture strike, from the surface projection of the updip edge of the rupture, with the down dip direction being positive (this distance is usually called ``Rx``). In other words, is the horizontal distance to top edge of rupture measured perpendicular to the strike. Values on the hanging wall are positive, values on the footwall are negative. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate Rx-distance to. :returns: Numpy array of distances in km. """ top_edge = self.mesh[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats ) ) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( numpy.array([p1.longitude, p2.longitude]), numpy.array([p1.latitude, p2.latitude]), mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] return dst