def test_project_point_plane(point, point_plane, normal_plane, point_expected, dist_expected): plane = Plane(point_plane, normal_plane) point_projected = plane.project_point(point) distance_signed = plane.distance_point_signed(point) assert point_projected.is_close(point_expected) assert math.isclose(distance_signed, dist_expected)
def test_best_fit_plane(points, plane_expected): points = Points(points).set_dimension(3) plane_fit = Plane.best_fit(points) assert plane_fit.is_close(plane_expected) assert plane_fit.point.is_close(plane_expected.point)
def test_from_points(arrays): points = Points(arrays) assume(not points.are_collinear(tol=1)) # The plane must contain each point. plane = Plane.from_points(*points) points = points.set_dimension(plane.dimension) for point in points: assert plane.contains_point(point, abs_tol=ATOL) # The plane of best fit should be the same # as the plane from three points. plane_fit = Plane.best_fit(points) assert plane_fit.is_close(plane, abs_tol=ATOL)
def test_from_vectors(array_point, array_a, array_b, plane_expected): plane = Plane.from_vectors(array_point, array_a, array_b) assert plane.is_close(plane_expected) # Also ensure that the vector is exactly as expected. assert plane.vector.is_close(plane_expected.vector)
def calc_point_vectors(self): for i,point in enumerate(self.point_data): #find center of each cluster, as well as its endpoints using a convex hull dists, indeces = self.kd_tree.query(point,10) points = [] for i in range(1,len(indeces)-1): points.append(self.point_data[indeces[i]]) plane = Plane.best_fit(points) self.point_vectors.append(plane.project_vector(point)) printProgressBar(i,len(self.point_cloud)-1)
def Reorient_Planes(plane_list,npoints): #using plane with most orient the rest i= np.where(npoints == np.max(npoints))[0][0] signs = np.sign(plane_list[i].normal) orient_line = Line(plane_list[i].normal,plane_list[i].point) newplane = [] for i in range(len(plane_list)): normalvector = np.abs(np.array(plane_list[i].normal))*signs points = np.array(plane_list[i].intersect_line(orient_line)) newplane.append(Plane(points,normalvector)) return newplane
def Plane_fitting(Limage): unique_planes = np.unique(Limage) numpoints = [] planes = [] for i in range(1,len(unique_planes)): loc = np.where(Limage==unique_planes[i]) numpoints.append(len(loc[0])) extractedpoints = np.vstack(loc).transpose() plane = Plane.best_fit(extractedpoints) planes.append(plane) return planes,numpoints
def fit_plane_scipy(P=None): from skspatial.objects import Points, Plane from skspatial.plotting import plot_3d points = Points([[0, 0, 0], [1, 3, 5], [-5, 6, 3], [3, 6, 7], [-2, 6, 7] ]) if P is None else Points(P) plane = Plane.best_fit(points) plot_3d( points.plotter(c='k', s=0.1, depthshade=False), plane.plotter(alpha=0.8, lims_x=(-5, 5), lims_y=(-5, 5)), ) plt.show()
def find_normals(points, k=3): normals = [] for point in points: from skspatial.objects import Points, Plane distance = np.linalg.norm(points - point, axis=1) #closest_inds = np.argpartition(distance, 3) #x0, x1, x2 = points[closest_inds[:3]] #normal = np.cross((x1 - x0), (x2 - x0)) closest_inds = np.argpartition(distance, k) close_points = points[closest_inds[:k]] normal = np.asarray(Plane.best_fit(close_points).normal) normals.append(normal) return normals
def compute(self): if len(self.points) < 3 or self.origin is None or self.vector is None: return points = Points(self.points) self.plane = Plane.best_fit(points) self.vector = np.array(self.plane.project_point(self.vector)) self.origin = np.array(self.plane.project_point(self.origin)) self.xAxis = self.normalizeVector(self.vector - self.origin) self.normal = np.array(self.plane.normal) a = np.argmax(np.abs(self.normal)) if self.normal[a] < 0: self.normal *= -1 self.zAxis = self.normalizeVector(self.normal) self.yAxis = -np.cross(self.xAxis, self.zAxis) self.vectorBasis = [self.xAxis, self.yAxis, self.zAxis] self.quaternion = self.get_quaternion( [[1, 0, 0], [0, 1, 0], [0, 0, 1]], self.vectorBasis)
def test_best_fit_plane(data): n_points = data.draw(st.integers(min_value=3, max_value=5)) points = Points([data.draw(arrays_fixed(3)) for _ in range(n_points)]) assume(not points.are_collinear(tol=ATOL)) plane_fit = Plane.best_fit(points) # The best fit plane could have a higher dimension than the points # (e.g., 2D points have a 3D plane of best fit). # So, we convert the points dimension to that of the best fit plane. dim_fit = plane_fit.dimension points = points.set_dimension(dim_fit) plane = data.draw(planes(dim_fit)) error_plane = plane.sum_squares(points) error_fit = plane_fit.sum_squares(points) assert error_fit <= error_plane + ATOL
def test_best_fit_plane_failure(points, message_expected): with pytest.raises(ValueError, match=message_expected): Plane.best_fit(points)
with pytest.raises( ValueError, match="The point and vector must have the same dimension."): class_spatial(point, vector) @pytest.mark.parametrize( "obj_1, obj_2, bool_expected", [ (Line([0, 0], [1, 0]), Line([0, 0], [1, 0]), True), (Line([0, 0], [1, 0]), Line([1, 0], [1, 0]), True), (Line([0, 0], [1, 0]), Line([-5, 0], [1, 0]), True), (Line([0, 0], [1, 0]), Line([-5, 0], [7, 0]), True), (Line([0, 0], [1, 0]), Line([-5, 0], [-20, 0]), True), (Line([0, 0], [1, 0]), Line([-5, 1], [1, 0]), False), (Plane([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [0, 0, 1]), True), (Plane([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [0, 0, 2]), True), (Plane([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [0, 0, -10]), True), (Plane([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [1, 0, -10]), False), (Line([0, 0], [1, 0]), Plane([0, 0], [1, 0]), None), (Plane([0, 0], [1, 0]), Line([0, 0], [1, 0]), None), ], ) def test_is_close(obj_1, obj_2, bool_expected): if bool_expected is None: with pytest.raises( TypeError, match="The input must have the same type as the object."): obj_1.is_close(obj_2)
(Line([0, 0], [1, 0]), [[0, 1], [0, -1]], 2), (Line([0, 0], [1, 0]), [[0, 5]], 25), (Line([0, 0], [1, 0]), [[0, 3], [0, -2]], 13), (Line([0, 0], [-20, 0]), [[1, 3], [2, -2], [3, -5]], 38), ], ) def test_sum_squares_line(line, points, error_expected): error = line.sum_squares(points) assert math.isclose(error, error_expected) @pytest.mark.parametrize( "plane, points, error_expected", [ (Plane([0, 0, 0], [0, 0, 1]), [[25, 3, 0], [-6, 5, 0]], 0), (Plane([25, 9, 0], [0, 0, 1]), [[25, 3, 0], [-6, 5, 0]], 0), (Plane([25, 9, -2], [0, 0, 1]), [[25, 3, 0], [-6, 5, 0]], 8), (Plane([0, 0, 0], [0, 0, 1]), [[25, 3, 2], [-6, 5, 0]], 4), (Plane([0, 0, 0], [0, 0, 5]), [[25, 3, 2], [-6, 5, 0]], 4), (Plane([0, 0, 0], [0, 0, -5]), [[25, 3, 2], [-6, 5, 0]], 4), ], ) def test_sum_squares_plane(plane, points, error_expected): error = plane.sum_squares(points) assert math.isclose(error, error_expected) @pytest.mark.parametrize( "points, line_expected",
""" Plane-Line Intersection ======================= """ from skspatial.objects import Line, Plane from skspatial.plotting import plot_3d plane = Plane(point=[0, 0, 0], normal=[1, 1, 1]) line = Line(point=[-1, -1, 0], direction=[0, 0, 1]) point_intersection = plane.intersect_line(line) plot_3d( plane.plotter(lims_x=[-2, 2], lims_y=[-2, 2], alpha=0.2), line.plotter(t_2=5), point_intersection.plotter(c='k', s=75), )
@pytest.mark.parametrize( ("obj_spatial", "repr_expected"), [ (Point([0]), "Point([0])"), (Point([0, 0]), "Point([0, 0])"), (Point([0.5, 0]), "Point([0.5, 0. ])"), (Point([-11, 0]), "Point([-11, 0])"), (Vector([-11, 0]), "Vector([-11, 0])"), (Vector([-11.0, 0.0]), "Vector([-11., 0.])"), (Vector([0, 0]), "Vector([0, 0])"), (Vector([0.5, 0]), "Vector([0.5, 0. ])"), (Points([[1.5, 2], [5, 3]]), "Points([[1.5, 2. ],\n [5. , 3. ]])"), (Line([0, 0], [1, 0]), "Line(point=Point([0, 0]), direction=Vector([1, 0]))"), (Line([-1, 2, 3], [5, 4, 2]), "Line(point=Point([-1, 2, 3]), direction=Vector([5, 4, 2]))"), (Line(np.zeros(2), [1, 0]), "Line(point=Point([0., 0.]), direction=Vector([1, 0]))"), (Plane([0, 0], [1, 0]), "Plane(point=Point([0, 0]), normal=Vector([1, 0]))"), (Plane([-1, 2, 3], [5, 4, 2]), "Plane(point=Point([-1, 2, 3]), normal=Vector([5, 4, 2]))"), (Circle([0, 0], 1), "Circle(point=Point([0, 0]), radius=1)"), (Circle([0, 0], 2.5), "Circle(point=Point([0, 0]), radius=2.5)"), (Sphere([0, 0, 0], 1), "Sphere(point=Point([0, 0, 0]), radius=1)"), ( Triangle([0, 0], [0, 1], [1, 0]), "Triangle(point_a=Point([0, 0]), point_b=Point([0, 1]), point_c=Point([1, 0]))", ), (Cylinder([0, 0, 0], [0, 0, 1], 1), "Cylinder(point=Point([0, 0, 0]), vector=Vector([0, 0, 1]), radius=1)"), ], ) def test_repr(obj_spatial, repr_expected): assert repr(obj_spatial) == repr_expected
def test_from_points_failure(point_a, point_b, point_c): with pytest.raises(Exception): Plane.from_points(point_a, point_b, point_c)
def test_from_points_failure(point_a, point_b, point_c): message_expected = "The points must not be collinear." with pytest.raises(ValueError, match=message_expected): Plane.from_points(point_a, point_b, point_c)
(Line([0, 0], [1, 0]), [1, 1], [1, 0]), (Line([-56, 72], [1, 0]), [1, 1], [1, 0]), (Line([-56, 72], [200, 0]), [5, 9], [5, 0]), (Line([-56, 72], [200, 0]), [-5, 9], [-5, 0]), ], ) def test_project_vector_line(line, vector, vector_expected): vector_projected = line.project_vector(vector) assert vector_projected.is_close(vector_expected) @pytest.mark.parametrize( "plane, vector, vector_expected", [ (Plane([0, 0, 0], [0, 0, 1]), [1, 1, 0], [1, 1, 0]), (Plane([0, 0, 0], [0, 0, 1]), [1, 1, 1], [1, 1, 0]), (Plane([0, 0, 0], [0, 0, 1]), [7, -5, 20], [7, -5, 0]), (Plane([0, 0, 0], [0, 0, -10]), [7, -5, 20], [7, -5, 0]), ], ) def test_project_vector_plane(plane, vector, vector_expected): vector_projected = plane.project_vector(vector) assert vector_projected.is_close(vector_expected) @pytest.mark.parametrize( "circle, point, point_expected", [ (Circle([0, 0], 1), [1, 0], [1, 0]),
""" Plane-Plane Intersection ======================== """ from skspatial.objects import Plane from skspatial.plotting import plot_3d plane_a = Plane([0, 0, 0], [1, 0, 0]) plane_b = Plane([0, 0, 0], [1, 0, 1]) line_intersection = plane_a.intersect_plane(plane_b) plot_3d( plane_a.plotter(alpha=0.2), plane_b.plotter(alpha=0.2), line_intersection.plotter(t_1=-1, c='k'), )
""" Vector-Plane Projection ======================= Project a vector onto a plane. """ from skspatial.objects import Plane from skspatial.objects import Vector from skspatial.plotting import plot_3d plane = Plane([0, 0, 0], [0, 0, 1]) vector = Vector([1, 1, 1]) vector_projected = plane.project_vector(vector) _, ax = plot_3d( plane.plotter(lims_x=(-5, 5), lims_y=(-5, 5), alpha=0.3), vector.plotter(point=plane.point, color='k'), vector_projected.plotter(point=plane.point, color='r', linewidth=2, zorder=3), ) ax.set_zlim([-1, 1])
import pytest from skspatial.objects import Plane, Sphere, Points @pytest.mark.parametrize( "plane, points_expected", [ (Plane([0, 0, 0], [0, 0, 1]), [[-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0]]), (Plane([1, 0, 0], [0, 0, 1]), [[0, -1, 0], [2, -1, 0], [0, 1, 0], [2, 1, 0]]), (Plane([0, 0, 0], [0, 0, -1]), [[-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0]]), (Plane([0, 0, 0], [0, 0, 5]), [[-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0]]), (Plane([0, 0, 0], [0, 1, 0]), [[-1, 0, -1], [1, 0, -1], [-1, 0, 1], [1, 0, 1]]), (Plane([0, 0, 0], [1, 0, 0]), [[0, -1, -1], [0, 1, -1], [0, -1, 1], [0, 1, 1]]), (Plane([0, 0, 0], [1, 1, 0]), [[-1, 1, -1], [1, -1, -1], [-1, 1, 1], [1, -1, 1]]), ], ) def test_plane_points(plane, points_expected): points = plane.to_points() assert points.is_close(points_expected)
import math import pytest from skspatial._functions import _allclose from skspatial.objects import Line from skspatial.objects import Plane from skspatial.objects import Points @pytest.mark.parametrize( ("array_point", "array_a", "array_b", "plane_expected"), [ ([0, 0], [1, 0], [0, 1], Plane([0, 0, 0], [0, 0, 1])), ([1, 2], [1, 0], [0, 1], Plane([1, 2, 0], [0, 0, 1])), ([0, 0], [0, 1], [1, 0], Plane([0, 0, 0], [0, 0, -1])), ([0, 0], [2, 0], [0, 1], Plane([0, 0, 0], [0, 0, 2])), ([0, 0], [2, 0], [0, 2], Plane([0, 0, 0], [0, 0, 4])), ([1, 2, 3], [2, 0], [0, 2], Plane([1, 2, 3], [0, 0, 4])), ([-3, 2, 6], [1, 4, 6], [-1, 5, 8], Plane([-3, 2, 6], [2, -14, 9])), ], ) def test_from_vectors(array_point, array_a, array_b, plane_expected): plane = Plane.from_vectors(array_point, array_a, array_b) assert plane.is_close(plane_expected) # Also ensure that the vector is exactly as expected. assert plane.vector.is_close(plane_expected.vector)
(Line([0, 0], [0, 1]), [1, 10], 1), (Line([0, 0], [0, 1]), [1, -10], 1), (Line([0, 0], [0, 1]), [-1, 0], -1), (Line([0, 0], [0, 1]), [-1, 1], -1), (Line([0, 0], [0, 1]), [-1, -25], -1), ], ) def test_side_point_line(line, point, value_expected): assert line.side_point(point) == value_expected @pytest.mark.parametrize( "plane, point, value_expected", [ (Plane([0, 0], [1, 1]), [2, 2], 1), (Plane([0, 0], [1, 1]), [0, 0], 0), (Plane([0, 1], [1, 1]), [0, 0], -1), (Plane([0, 0, 0], [1, 0, 0]), [0, 0, 0], 0), (Plane([0, 0, 0], [1, 0, 0]), [1, 0, 0], 1), (Plane([0, 0, 0], [1, 0, 0]), [-1, 0, 0], -1), (Plane([0, 0, 0], [1, 0, 0]), [25, 53, -105], 1), (Plane([0, 0, 0], [1, 0, 0]), [-2, 53, -105], -1), (Plane([0, 0, 0], [1, 0, 0]), [0, 38, 19], 0), (Plane([0, 0, 0], [1, 0, 0]), [0, 101, -45], 0), (Plane([0, 0, 0], [-1, 0, 0]), [1, 0, 0], -1), (Plane([5, 0, 0], [1, 0, 0]), [1, 0, 0], -1), ], ) def test_side_point_plane(plane, point, value_expected):
(Line([0, 0], [0, 1]), Line([0, 0], [0, 5])), (Line([0, 0], [1, 0]), Line([0, 0], [-1, 0])), (Line([0, 0], [1, 0]), Line([5, 5], [-1, 0])), (Line([0, 0, 0], [1, 1, 1]), Line([0, 1, 0], [-1, 0, 0])), ], ) def test_intersect_lines_failure(line_a, line_b): with pytest.raises(Exception): line_a.intersect_line(line_b) @pytest.mark.parametrize( "line, plane, array_expected", [ (Line([0, 0, 0], [1, 0, 0]), Plane([0, 0, 0], [1, 0, 0]), [0, 0, 0]), (Line([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [0, 0, 1]), [0, 0, 0]), (Line([5, -3, 0], [0, 0, 1]), Plane([0, 0, 0], [0, 0, 1]), [5, -3, 0]), ], ) def test_intersect_line_plane(line, plane, array_expected): point_intersection = plane.intersect_line(line) assert point_intersection.is_close(array_expected) @pytest.mark.parametrize( "line, plane", [ (Line([0, 0, 0], [1, 0, 0]), Plane([0, 0, 0], [0, 0, 1])), (Line([0, 0, 0], [0, 0, 1]), Plane([0, 0, 0], [1, 0, 0])),
import pytest from skspatial._functions import _allclose from skspatial.objects import Plane @pytest.mark.parametrize( "point_a, point_b, point_c, plane_expected", [ ([0, 0], [1, 0], [0, 1], Plane([0, 0, 0], [0, 0, 1])), # The spacing between the points is irrelevant. ([0, 0], [9, 0], [0, 9], Plane([0, 0, 0], [0, 0, 1])), # The first point is used as the plane point. ([0, 0.1], [1, 0], [0, 1], Plane([0, 0.1, 0], [0, 0, 1])), # The order of points is relevant. ([0, 0], [0, 1], [1, 0], Plane([0, 0, 0], [0, 0, -1])), ], ) def test_from_points(point_a, point_b, point_c, plane_expected): plane = Plane.from_points(point_a, point_b, point_c) assert plane.point.is_close(plane_expected.point) assert plane.is_close(plane_expected) @pytest.mark.parametrize( "point_a, point_b, point_c", [ # The points cannot be collinear. ([0, 0], [0, 0], [0, 0]),
""" 3D Plane of Best Fit ==================== Fit a plane to multiple 3D points. """ from skspatial.objects import Plane from skspatial.objects import Points from skspatial.plotting import plot_3d points = Points([[0, 0, 0], [1, 3, 5], [-5, 6, 3], [3, 6, 7], [-2, 6, 7]]) plane = Plane.best_fit(points) plot_3d( points.plotter(c='k', s=50, depthshade=False), plane.plotter(alpha=0.2, lims_x=(-5, 5), lims_y=(-5, 5)), )
def test_from_points(point_a, point_b, point_c, plane_expected): plane = Plane.from_points(point_a, point_b, point_c) assert plane.point.is_close(plane_expected.point) assert plane.is_close(plane_expected)
""" Point-Plane Projection ====================== Project a point onto a plane. """ from skspatial.objects import Plane from skspatial.objects import Point from skspatial.objects import Vector from skspatial.plotting import plot_3d plane = Plane(point=[0, 0, 2], normal=[1, 0, 2]) point = Point([5, 9, 3]) point_projected = plane.project_point(point) vector_projection = Vector.from_points(point, point_projected) plot_3d( plane.plotter(lims_x=(0, 10), lims_y=(0, 15), alpha=0.3), point.plotter(s=75, c='k'), point_projected.plotter(c='r', s=75, zorder=3), vector_projection.plotter(point=point, c='k', linestyle='--'), )
def test_from_vectors_failure(array_point, array_a, array_b): message_expected = "The vectors must not be parallel." with pytest.raises(ValueError, match=message_expected): Plane.from_vectors(array_point, array_a, array_b)