def triangulate(self): """ Convert mesh points to vectors in Cartesian space. :returns: Tuple of four elements, each being 2d numpy array of 3d vectors (the same structure and shape as the mesh itself). Those arrays are: #. points vectors, #. vectors directed from each point (excluding the last column) to the next one in a same row →, #. vectors directed from each point (excluding the first row) to the previous one in a same column ↑, #. vectors pointing from a bottom left point of each mesh cell to top right one ↗. So the last three arrays of vectors allow to construct triangles covering the whole mesh. """ points = geo_utils.spherical_to_cartesian(self.lons, self.lats, self.depths) # triangulate the mesh by defining vectors of triangles edges: # → along_azimuth = points[:, 1:] - points[:, :-1] # ↑ updip = points[:-1] - points[1:] # ↗ diag = points[:-1, 1:] - points[1:, :-1] return points, along_azimuth, updip, diag
def _polygon_wkt_to_xyz(polygon, as_wkt=False): '''Converts a polygon in 'POLYGON' wkt format to xyz. If as_wkt is True, will return the xyz output back as a wkt format, otherwise it will return an array''' polygon = wkt.loads(polygon) polygon = polygon.boundary.xy number_nodes = len(polygon[0]) xyz = spherical_to_cartesian(polygon[0], polygon[1], np.zeros(number_nodes, dtype=float)) if as_wkt: xyz = asPolygon(xyz[:, :-1]).wkt return xyz
def __init__(self, catalogue): '''Instantiate :param catalogue: Instance of MTKCatalogue Class ''' self.catalogue = deepcopy(catalogue) self.time_value = decimal_time(catalogue['year'], catalogue['month'], catalogue['day'], catalogue['hour'], catalogue['minute'], catalogue['second']) self.catalogue_mesh = Mesh(catalogue['longitude'], catalogue['latitude'], catalogue['depth']) if not isinstance(catalogue['xyz'], np.ndarray): self.catalogue['xyz'] = spherical_to_cartesian( self.catalogue['longitude'], self.catalogue['latitude'], self.catalogue['depth']) self.number_events = len(catalogue['eventID'])
def _init_plane(self): """ Prepare everything needed for projecting arbitrary points on a plane containing the surface. """ tl, tr, bl, br = geo_utils.spherical_to_cartesian( self.corner_lons, self.corner_lats, self.corner_depths ) # these two parameters define the plane that contains the surface # (in 3d Cartesian space): a normal unit vector, self.normal = geo_utils.normalized(numpy.cross(tl - tr, tl - bl)) # ... and scalar "d" parameter from the plane equation (uses # an equation (3) from http://mathworld.wolfram.com/Plane.html) self.d = - (self.normal * tl).sum() # these two 3d vectors together with a zero point represent surface's # coordinate space (the way to translate 3d Cartesian space with # a center in earth's center to 2d space centered in surface's top # left corner with basis vectors directed to top right and bottom left # corners. see :meth:`_project`. self.uv1 = geo_utils.normalized(tr - tl) self.uv2 = numpy.cross(self.normal, self.uv1) self.zero_zero = tl
def select_within_polygon(self, polygon, distance=None, **kwargs): '''Select earthquakes within polygon :param point: Centre point as instance of nhlib.geo.polygon.Polygon class :param distance: Buffer distance (km) (can take negative values) :returns: Selected catalogue (as dictionary) and number of selected events ''' if distance: zone_polygon = polygon.dilate(distance) else: zone_polygon = polygon zone_polygon = spherical_to_cartesian( zone_polygon.lons, zone_polygon.lats, np.zeros(len(zone_polygon.lons), dtype=float)) # Initially all points are invalid valid_id = np.zeros(self.number_events, dtype=bool) # Make valid all events inside depth range upper_depth, lower_depth = _check_depth_limits(kwargs) valid_depth = np.logical_and(self.catalogue['depth'] >= upper_depth, self.catalogue['depth'] < lower_depth) # Events outside polygon returned to invalid assignment valid_id[valid_depth] = points_inside_poly( self.catalogue['xyz'][valid_depth, :2], zone_polygon[:, :2]) number_selected = np.sum(valid_id) valid_id = np.logical_not(valid_id) return purge_catalogue(self.catalogue, valid_id.astype(int)), \ number_selected
def _project(self, lons, lats, depths): """ Project points to a surface's plane. Parameters are lists or numpy arrays of coordinates of points to project. :returns: A tuple of three items: distances between original points and surface's plane in km, "x" and "y" coordinates of points' projections to the plane (in a surface's coordinate space). """ points = geo_utils.spherical_to_cartesian(lons, lats, depths) # uses method from http://www.9math.com/book/projection-point-plane dists = (self.normal * points).sum(axis=-1) + self.d t0 = - dists projs = points + self.normal * t0.reshape(t0.shape + (1, )) # translate projected points' to surface's coordinate space vectors2d = projs - self.zero_zero xx = (vectors2d * self.uv1).sum(axis=-1) yy = (vectors2d * self.uv2).sum(axis=-1) return dists, xx, yy
def test_from_vector(self): point = geo.Point(12.34, -56.78, 91.011) vector = spherical_to_cartesian(point.longitude, point.latitude, point.depth) self.assertEqual(point, geo.Point.from_vector(vector))
def _hypocentres_to_xyz(self): '''Converts the catalogue hypocentres into a cartesian coordinate system''' self.data['xyz'] = spherical_to_cartesian( self.data['longitude'], self.data['latitude'], self.data['depth'])