Source code for gempy.modules.data_manipulation.orientations_from_surface_points

from typing import Optional

import numpy as np
from numpy.linalg import svd

from gempy.core.data import SurfacePointsTable, OrientationsTable


[docs] def create_orientations_from_surface_points_coords(xyz_coords: np.ndarray, subset: Optional[np.ndarray] = None, element_name: Optional[str] = "Generated") -> OrientationsTable: # Initialize the arrays center = np.empty((len(subset) if subset is not None else 1, 3)) normal = np.empty((len(subset) if subset is not None else 1, 3)) if subset is None: center[0], normal[0] = _plane_fit(xyz_coords) else: for idx, i in enumerate(subset): center[idx], normal[idx] = _plane_fit(xyz_coords[i]) orientations = OrientationsTable.from_arrays( x=center[:, 0], y=center[:, 1], z=center[:, 2], G_x=normal[:, 0], G_y=normal[:, 1], G_z=normal[:, 2], names=[element_name] ) return orientations
def _plane_fit(point_list): """ Fit plane to points in PointSet Fit an d-dimensional plane to the points in a point set. adjusted from: http://stackoverflow.com/questions/12299540/plane-fitting-to-4-or-more-xyz-points Args: point_list (array_like): array of points XYZ Returns: Return a point, p, on the plane (the point-cloud centroid), and the normal, n. """ points = point_list.T points = np.reshape(points, (np.shape(points)[0], -1)) # Collapse trialing dimensions assert points.shape[0] <= points.shape[1], "There are only {} points in {} dimensions.".format(points.shape[1], points.shape[0]) ctr = points.mean(axis=1) x = points - ctr[:, np.newaxis] M = np.dot(x, x.T) # Could also use np.cov(x) here. # ctr = Point(x=ctr[0], y=ctr[1], z=ctr[2], type='utm', zone=self.points[0].zone) normal = svd(M)[0][:, -1] # return ctr, svd(M)[0][:, -1] if normal[2] < 0: normal = - normal return ctr, normal