def volume_tetrahedron( point_a: array_like, point_b: array_like, point_c: array_like, point_d: array_like, ) -> np.float64: """ Return the volume of a tetrahedron defined by four points. The points are the vertices of the tetrahedron. They must be 3D or less. Parameters ---------- point_a, point_b, point_c, point_d : array_like The four vertices of the tetrahedron. Returns ------- np.float64 The volume of the tetrahedron. References ---------- http://mathworld.wolfram.com/Tetrahedron.html Examples -------- >>> from skspatial.measurement import volume_tetrahedron >>> volume_tetrahedron([0, 0], [3, 2], [-3, 5], [1, 8]) 0.0 >>> volume_tetrahedron([0, 0, 0], [2, 0, 0], [1, 1, 0], [0, 0, 1]).round(3) 0.333 >>> volume_tetrahedron([0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]).round(3) 0.167 """ vector_ab = Vector.from_points(point_a, point_b) vector_ac = Vector.from_points(point_a, point_c) vector_ad = Vector.from_points(point_a, point_d) vector_cross = vector_ac.cross(vector_ad) # Set the dimension to 3 so it matches the cross product. vector_ab = vector_ab.set_dimension(3) return 1 / 6 * abs(vector_ab.dot(vector_cross))
def test_project_point(lines_or_planes, data): """Test projecting a point onto a line or plane.""" dim = data.draw(st.integers(min_value=DIM_MIN, max_value=DIM_MAX)) array = data.draw(arrays_fixed(dim)) line_or_plane = data.draw(lines_or_planes(dim)) point_projected = line_or_plane.project_point(array) # The projected point should lie on the line/plane. assert line_or_plane.contains_point(point_projected, abs_tol=ATOL) # The vector from the point to its projection # should be perpendicular to the line/plane. vector_projection = Vector.from_points(array, point_projected) # The distance from the point to its projection # should equal the distance to the line/plane. distance_projection = vector_projection.norm() distance_to_object = abs(line_or_plane.distance_point(array)) assert math.isclose(distance_to_object, distance_projection, rel_tol=1e-6) # The distance of the projection should be the # shortest distance from the point to the object. distance_points = line_or_plane.point.distance_point(array) assert distance_projection < distance_points or math.isclose( distance_projection, distance_points)
def test_from_points(arrays): array_a, array_b = arrays point_a = Point(array_a) vector_ab = Vector.from_points(array_a, array_b) assert (point_a + vector_ab).is_close(array_b)
def area_triangle(point_a: array_like, point_b: array_like, point_c: array_like) -> np.float64: """ Return the area of a triangle defined by three points. The points are the vertices of the triangle. They must be 3D or less. Parameters ---------- point_a, point_b, point_c : array_like The three vertices of the triangle. Returns ------- np.float64 The area of the triangle. References ---------- http://mathworld.wolfram.com/TriangleArea.html Examples -------- >>> from skspatial.measurement import area_triangle >>> area_triangle([0, 0], [0, 1], [1, 0]) 0.5 >>> area_triangle([0, 0], [0, 2], [1, 1]) 1.0 >>> area_triangle([3, -5, 1], [5, 2, 1], [9, 4, 2]).round(2) 12.54 """ vector_ab = Vector.from_points(point_a, point_b) vector_ac = Vector.from_points(point_a, point_c) # Normal vector of plane defined by the three points. vector_normal = vector_ab.cross(vector_ac) return 0.5 * vector_normal.norm()
""" 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_points(array_a, array_b, vector_expected): assert_array_equal(Vector.from_points(array_a, array_b), vector_expected)
def spatial_parameters(point_a_i: array_like, point_b: array_like, point_a_f: array_like) -> Dict[str, np.float64]: """ Calculate spatial gait parameters for a stride. Positions are input in temporal order (foot A initial, foot B, foot A final). Parameters ---------- point_a_i : array_like Initial position of foot A. point_b : array_like Position of foot B. point_a_f : array_like Final position of foot A. Returns ------- dict Dictionary consisting of stride length, absolute step length, step length, and stride width. Examples -------- >>> import numpy as np >>> point_l_1 = [764.253, 28.798] >>> point_r_1 = [696.834, 37.141] >>> point_l_2 = [637.172, 24.508] >>> point_r_2 = [579.102, 35.457] >>> point_l_3 = [518.030, 30.507] >>> values = list(spatial_parameters(point_l_1, point_r_1, point_l_2).values()) >>> np.round(values, 1) array([127.2, 61. , 60.1, 10.6]) >>> values = list(spatial_parameters(point_r_1, point_l_2, point_r_2).values()) >>> np.round(values, 1) array([117.7, 59.1, 57.9, 11.8]) >>> values = list(spatial_parameters(point_l_2, point_r_2, point_l_3).values()) >>> np.round(values, 1) array([119.3, 61.3, 60.7, 8. ]) """ line_a = Line.from_points(point_a_i, point_a_f) point_b_proj = line_a.project_point(point_b) stride_length = line_a.direction.norm() absolute_step_length = Vector.from_points(point_b, point_a_f).norm() step_length = Vector.from_points(point_b_proj, point_a_f).norm() stride_width = Vector.from_points(point_b_proj, point_b).norm() return { 'stride_length': stride_length, 'absolute_step_length': absolute_step_length, 'step_length': step_length, 'stride_width': stride_width, }