Esempio n. 1
0
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)
Esempio n. 2
0
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
Esempio n. 3
0
        (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])),
"""
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])
Esempio n. 5
0
        (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",
Esempio n. 6
0
"""
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),
)
Esempio n. 7
0
@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
Esempio n. 8
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]),
Esempio n. 9
0
def fit_mt_main_fault(well_dict, section='all', function='thin_plate_spline'):
    fault_depths = {
        'D1': (14.34, 19.63),
        'D2': (11.04, 16.39),
        'D3': (17.98, 20.58),
        'D4': (27.05, 28.44),
        'D5': (19.74, 22.66),
        'D6': (28.5, 31.4),
        'D7': (22.46, 25.54),
        'B2': (41.25, 45.65),
        'B1': (34.8, 42.25),
        'B9': (None, 55.7),
        'B10': (17.75, 21.7),
        '1': (38.15, 45.15),
        '2': (44.23, 49.62),
        '3': (38.62, 43.39)
    }
    if section == 'FS':
        fault_depths = {k: fault_depths[k] for k in ('1', '2', '3')}
    elif section == 'FSB':
        fault_depths = {
            k: fault_depths[k]
            for k in fault_depths.keys() if k[0] == 'B'
        }
    elif section == 'CSD':
        fault_depths = {
            k: fault_depths[k]
            for k in fault_depths.keys() if k[0] == 'D'
        }
    elif section == 'west':
        fault_depths = {
            k: fault_depths[k]
            for k in fault_depths.keys() if k[0] == 'D' or k in ('B2')
        }
    elif section == 'east':
        fault_depths = {
            k: fault_depths[k]
            for k in fault_depths.keys() if k[0] == 'B' or k in ('1', '2', '3')
        }
    elif section == 'all':
        pass
    else:
        print('Section {} is invalid'.format(section))
        return
    print('Section: {}'.format(section))
    # Do best fit plane
    tops = [
        depth_to_xyz(well_dict, well, d[0])
        for well, d in fault_depths.items() if d[0] and well in fault_depths
    ]
    bottoms = [
        depth_to_xyz(well_dict, well, d[1])
        for well, d in fault_depths.items() if well in fault_depths
    ]
    A_top = np.array(tops).T
    A_bot = np.array(bottoms).T
    c_top = A_top.sum(axis=1) / A_top.shape[1]
    c_bot = A_top.sum(axis=1) / A_top.shape[1]
    # Top first
    u, s, v = np.linalg.svd(A_top - c_top[:, np.newaxis])
    # Lsqr quadratic fit
    X, Y = np.meshgrid(np.arange(np.min(A_top[0, :]), np.max(A_top[0, :]), 2),
                       np.arange(np.min(A_top[1, :]), np.max(A_top[1, :]), 2))
    tops_array = np.array(tops)
    spline = Rbf(tops_array[:, 0],
                 tops_array[:, 1],
                 tops_array[:, 2],
                 function=function,
                 smooth=0)
    Z = spline(X, Y)
    u1, u2, u3 = u[:, -1]
    if u3 < 0:
        easting = u2
    else:
        easting = -u2
    if u3 > 0:
        northing = u1
    else:
        northing = -u1
    dip = np.rad2deg(np.arctan(np.sqrt(easting**2 + northing**2) / u3))
    if easting >= 0:
        partA_strike = easting**2 + northing**2
        strike = np.rad2deg(np.arccos(northing / np.sqrt(partA_strike)))
    else:
        partA_strike = northing / np.sqrt(easting**2 + northing**2)
        strike = np.rad2deg(2 * np.pi - np.arccos(partA_strike))
    print('SVD strike Top: {}'.format(strike))
    print('SVD dip Top: {}'.format(dip))
    # Now bottom
    u, s, v = np.linalg.svd(A_bot - c_bot[:, np.newaxis])
    u1, u2, u3 = u[:, -1]
    if u3 < 0:
        easting = u2
    else:
        easting = -u2
    if u3 > 0:
        northing = u1
    else:
        northing = -u1
    dip = np.rad2deg(np.arctan(np.sqrt(easting**2 + northing**2) / u3))
    if easting >= 0:
        partA_strike = easting**2 + northing**2
        strike = np.rad2deg(np.arccos(northing / np.sqrt(partA_strike)))
    else:
        partA_strike = northing / np.sqrt(easting**2 + northing**2)
        strike = np.rad2deg(2 * np.pi - np.arccos(partA_strike))
    print('SVD strike Bottom: {}'.format(strike))
    print('SVD dip Bottom: {}'.format(dip))
    # Now compute fit for all possible planes
    dips = np.arange(90)
    strikes = np.arange(360)
    dip_rads = np.deg2rad(dips)
    strike_rads = np.deg2rad(strikes)
    S, D = np.meshgrid(strike_rads, dip_rads)
    # Normal to plane
    a = np.sin(D.flatten()) * np.cos(S.flatten())  # East
    b = -np.sin(D.flatten()) * np.sin(S.flatten())  # North
    c = np.cos(D.flatten())
    c_top = c_top.squeeze()
    planes = [
        Plane(point=c_top.squeeze(), normal=np.array([a[i], b[i], c[i]]))
        for i in range(a.shape[0])
    ]
    rmss = np.array([
        np.sqrt(np.mean([p.distance_point_signed(t)**2 for t in tops]))
        for p in planes
    ])
    rmss = rmss.reshape(S.shape)
    print('Gridsearch Strike: {}'.format(
        np.rad2deg(S.flatten()[np.argmin(rmss)])))
    print('Grid search Dip: {}'.format(np.rad2deg(
        D.flatten()[np.argmin(rmss)])))
    print('Grid search RMS: {}'.format(np.min(rmss)))
    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')
    ax.plot_surface(np.rad2deg(S), np.rad2deg(D), rmss, cmap='viridis')
    ax.set_xlabel('Strike [deg]')
    ax.set_ylabel('Dip [deg]')
    ax.set_zlabel('RMS for plane [meters]')
    plt.show()
    return X, Y, Z
Esempio n. 10
0
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)

Esempio n. 11
0
        (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):
Esempio n. 12
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'),
)
Esempio n. 13
0
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)
Esempio n. 14
0
    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)
Esempio n. 15
0
        (Line([-6, 7], [5, 90]), Line([1, 4], [-4, 5]), True),
        (Line([0, 0, 1], [1, 1, 0]), Line([0, 0, 0], [0, 1, 0]), False),
        (Line([0, 0, 1], [1, 1, 0]), Line([0, 0, 1], [0, 1, 0]), True),
        (Line([0, 0, 1], [1, 0, 1]), Line([0, 0, 1], [2, 0, 2]), True),
    ],
)
def test_is_coplanar(line_a, line_b, bool_expected):

    assert line_a.is_coplanar(line_b) == bool_expected


@pytest.mark.parametrize(
    ("line_a", "line_b"),
    [
        (Line([0, 0], [1, 1]), Point([0, 0])),
        (Line([0, 0, 0], [1, 1, 0]), Plane([0, 0, 0], [0, 0, 1])),
    ],
)
def test_is_coplanar_failure(line_a, line_b):

    message_expected = "The input must also be a line."

    with pytest.raises(TypeError, match=message_expected):
        line_a.is_coplanar(line_b)


@pytest.mark.parametrize(
    ("point", "point_line", "vector_line", "point_expected", "dist_expected"),
    [
        ([0, 5], [0, 0], [0, 1], [0, 5], 0),
        ([0, 5], [0, 0], [0, 100], [0, 5], 0),
Esempio n. 16
0
        (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]),
Esempio n. 17
0
"""
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='--'),
)
Esempio n. 18
0
    [
        ([0, 0], Line([0, 0], [1, 0]), 0),
        ([8, 7], Line([0, 0], [1, 0]), 7),
        ([20, -3], Line([0, 0], [1, 0]), 3),
        ([20, -3, 1], Line([0, 0, 0], [1, 0, 0]), math.sqrt(10)),
    ],
)
def test_distance_point_line(array_point, line, dist_expected):

    assert math.isclose(line.distance_point(array_point), dist_expected)


@pytest.mark.parametrize(
    "point, plane, dist_signed_expected",
    [
        ([0, 0, 0], Plane([0, 0, 0], [0, 0, 1]), 0),
        ([50, -67, 0], Plane([0, 0, 0], [0, 0, 1]), 0),
        ([50, -67, 0], Plane([0, 0, 1], [0, 0, 1]), -1),
        ([5, 3, 8], Plane([0, 0, 0], [0, 0, 1]), 8),
        ([5, 3, 7], Plane([0, 0, 0], [0, 0, -50]), -7),
        ([5, 3, -8], Plane([0, 0, 0], [0, 0, 1]), -8),
    ],
)
def test_distance_point_plane(point, plane, dist_signed_expected):

    assert math.isclose(plane.distance_point_signed(point),
                        dist_signed_expected)
    assert math.isclose(plane.distance_point(point), abs(dist_signed_expected))


@pytest.mark.parametrize(