Skip to content

Commit

Permalink
Fix geometric_objects.translate() bug for collinear axes case (#4884)
Browse files Browse the repository at this point in the history
* Fix collinear direction bug

* Separate test cases for inexact direction

* Use fixture to avoid mesh each time

---------

Co-authored-by: Erik Bedard <bedarder@gmail.com>
Co-authored-by: Tetsuo Koyama <tkoyama010@gmail.com>
  • Loading branch information
3 people committed Sep 15, 2023
1 parent a89da78 commit c698a33
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
18 changes: 10 additions & 8 deletions pyvista/core/utilities/geometric_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
29 changes: 29 additions & 0 deletions tests/core/test_geometric_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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])
8 changes: 8 additions & 0 deletions tests/core/test_parametric_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])

0 comments on commit c698a33

Please sign in to comment.