diff --git a/pyvista/core/utilities/geometric_objects.py b/pyvista/core/utilities/geometric_objects.py index b4710bc84a..41152f30fd 100644 --- a/pyvista/core/utilities/geometric_objects.py +++ b/pyvista/core/utilities/geometric_objects.py @@ -56,14 +56,16 @@ def translate(surf, center=(0.0, 0.0, 0.0), direction=(1.0, 0.0, 0.0)): """ normx = np.array(direction) / np.linalg.norm(direction) - # assume temporary normy to calculate normz - norm_y_temp = [0.0, 1.0, 0.0] - normz = np.cross(normx, norm_y_temp) - if np.array_equal(normz, (0.0, 0.0, 0.0)): - # the assumed normy axis is parallel to normx, so shift its - # axis and recalculate normz - norm_y_temp = [-1.0, 0.0, 0.0] - normz = np.cross(normx, norm_y_temp) + normy_temp = [0.0, 1.0, 0.0] + + # Adjust normy if collinear with normx since cross-product will + # be zero otherwise + if np.allclose(normx, [0, 1, 0]): + normy_temp = [-1.0, 0.0, 0.0] + elif np.allclose(normx, [0, -1, 0]): + normy_temp = [1.0, 0.0, 0.0] + + normz = np.cross(normx, normy_temp) normz /= np.linalg.norm(normz) normy = np.cross(normz, normx) diff --git a/tests/core/test_geometric_objects.py b/tests/core/test_geometric_objects.py index 32d4ad5b74..8894c3f4f8 100644 --- a/tests/core/test_geometric_objects.py +++ b/tests/core/test_geometric_objects.py @@ -4,6 +4,8 @@ import pytest import pyvista as pv +from pyvista import examples +from pyvista.core.utilities.geometric_objects import translate def test_cylinder(): @@ -515,3 +517,30 @@ def test_icosphere(): icosahedron = pv.Icosahedron() assert icosahedron.n_faces * 4**nsub == icosphere.n_faces + + +@pytest.fixture() +def bunny(): + return examples.download_bunny() + + +@pytest.mark.parametrize("is_negative", (True, False)) +@pytest.mark.parametrize("delta", ([0, 0, 0], [1e-8, 0, 0], [0, 0, 1e-8])) +def test_translate_direction_collinear(is_negative, delta, bunny): + mesh_in = bunny + direction = np.array([0.0, 1.0, 0.0]) + delta + if is_negative: + direction *= -1 + mesh_out = mesh_in.copy() + translate(mesh_out, direction=direction) + points_in = mesh_in.points + points_out = mesh_out.points + + if is_negative: + assert np.allclose(points_in[:, 0], -points_out[:, 1]) + assert np.allclose(points_in[:, 1], points_out[:, 0]) + assert np.allclose(points_in[:, 2], points_out[:, 2]) + else: + assert np.allclose(points_in[:, 0], points_out[:, 1]) + assert np.allclose(points_in[:, 1], -points_out[:, 0]) + assert np.allclose(points_in[:, 2], points_out[:, 2]) diff --git a/tests/core/test_parametric_geometry.py b/tests/core/test_parametric_geometry.py index ed21916608..5121c046c5 100644 --- a/tests/core/test_parametric_geometry.py +++ b/tests/core/test_parametric_geometry.py @@ -153,10 +153,18 @@ def test_ParametricTorus(): def test_direction(): geom1 = pv.ParametricEllipsoid(300, 100, 10, direction=[1, 0, 0]) geom2 = pv.ParametricEllipsoid(300, 100, 10, direction=[0, 1, 0]) + geom3 = pv.ParametricEllipsoid(300, 100, 10, direction=[0, -1, 0]) assert geom1.n_points assert geom2.n_points + assert geom3.n_points points1 = geom1.points points2 = geom2.points + points3 = geom3.points + assert np.allclose(points1[:, 0], points2[:, 1]) assert np.allclose(points1[:, 1], -points2[:, 0]) assert np.allclose(points1[:, 2], points2[:, 2]) + + assert np.allclose(points1[:, 0], -points3[:, 1]) + assert np.allclose(points1[:, 1], points3[:, 0]) + assert np.allclose(points1[:, 2], points3[:, 2])