| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- """Tests for the ``sympy.physics.mechanics.wrapping_geometry.py`` module."""
- import pytest
- from sympy import (
- Integer,
- Rational,
- S,
- Symbol,
- acos,
- cos,
- pi,
- sin,
- sqrt,
- )
- from sympy.core.relational import Eq
- from sympy.physics.mechanics import (
- Point,
- ReferenceFrame,
- WrappingCylinder,
- WrappingSphere,
- dynamicsymbols,
- )
- from sympy.simplify.simplify import simplify
- r = Symbol('r', positive=True)
- x = Symbol('x')
- q = dynamicsymbols('q')
- N = ReferenceFrame('N')
- class TestWrappingSphere:
- @staticmethod
- def test_valid_constructor():
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- assert isinstance(sphere, WrappingSphere)
- assert hasattr(sphere, 'radius')
- assert sphere.radius == r
- assert hasattr(sphere, 'point')
- assert sphere.point == pO
- @staticmethod
- @pytest.mark.parametrize('position', [S.Zero, Integer(2)*r*N.x])
- def test_geodesic_length_point_not_on_surface_invalid(position):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- p1 = Point('p1')
- p1.set_pos(pO, position)
- p2 = Point('p2')
- p2.set_pos(pO, position)
- error_msg = r'point .* does not lie on the surface of'
- with pytest.raises(ValueError, match=error_msg):
- sphere.geodesic_length(p1, p2)
- @staticmethod
- @pytest.mark.parametrize(
- 'position_1, position_2, expected',
- [
- (r*N.x, r*N.x, S.Zero),
- (r*N.x, r*N.y, S.Half*pi*r),
- (r*N.x, r*-N.x, pi*r),
- (r*-N.x, r*N.x, pi*r),
- (r*N.x, r*sqrt(2)*S.Half*(N.x + N.y), Rational(1, 4)*pi*r),
- (
- r*sqrt(2)*S.Half*(N.x + N.y),
- r*sqrt(3)*Rational(1, 3)*(N.x + N.y + N.z),
- r*acos(sqrt(6)*Rational(1, 3)),
- ),
- ]
- )
- def test_geodesic_length(position_1, position_2, expected):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- p1 = Point('p1')
- p1.set_pos(pO, position_1)
- p2 = Point('p2')
- p2.set_pos(pO, position_2)
- assert simplify(Eq(sphere.geodesic_length(p1, p2), expected))
- @staticmethod
- @pytest.mark.parametrize(
- 'position_1, position_2, vector_1, vector_2',
- [
- (r * N.x, r * N.y, N.y, N.x),
- (r * N.x, -r * N.y, -N.y, N.x),
- (
- r * N.y,
- sqrt(2)/2 * r * N.x - sqrt(2)/2 * r * N.y,
- N.x,
- sqrt(2)/2 * N.x + sqrt(2)/2 * N.y,
- ),
- (
- r * N.x,
- r / 2 * N.x + sqrt(3)/2 * r * N.y,
- N.y,
- sqrt(3)/2 * N.x - 1/2 * N.y,
- ),
- (
- r * N.x,
- sqrt(2)/2 * r * N.x + sqrt(2)/2 * r * N.y,
- N.y,
- sqrt(2)/2 * N.x - sqrt(2)/2 * N.y,
- ),
- ]
- )
- def test_geodesic_end_vectors(position_1, position_2, vector_1, vector_2):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- p1 = Point('p1')
- p1.set_pos(pO, position_1)
- p2 = Point('p2')
- p2.set_pos(pO, position_2)
- expected = (vector_1, vector_2)
- assert sphere.geodesic_end_vectors(p1, p2) == expected
- @staticmethod
- @pytest.mark.parametrize(
- 'position',
- [r * N.x, r * cos(q) * N.x + r * sin(q) * N.y]
- )
- def test_geodesic_end_vectors_invalid_coincident(position):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- p1 = Point('p1')
- p1.set_pos(pO, position)
- p2 = Point('p2')
- p2.set_pos(pO, position)
- with pytest.raises(ValueError):
- _ = sphere.geodesic_end_vectors(p1, p2)
- @staticmethod
- @pytest.mark.parametrize(
- 'position_1, position_2',
- [
- (r * N.x, -r * N.x),
- (-r * N.y, r * N.y),
- (
- r * cos(q) * N.x + r * sin(q) * N.y,
- -r * cos(q) * N.x - r * sin(q) * N.y,
- )
- ]
- )
- def test_geodesic_end_vectors_invalid_diametrically_opposite(
- position_1,
- position_2,
- ):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- sphere = WrappingSphere(r, pO)
- p1 = Point('p1')
- p1.set_pos(pO, position_1)
- p2 = Point('p2')
- p2.set_pos(pO, position_2)
- with pytest.raises(ValueError):
- _ = sphere.geodesic_end_vectors(p1, p2)
- class TestWrappingCylinder:
- @staticmethod
- def test_valid_constructor():
- N = ReferenceFrame('N')
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, N.x)
- assert isinstance(cylinder, WrappingCylinder)
- assert hasattr(cylinder, 'radius')
- assert cylinder.radius == r
- assert hasattr(cylinder, 'point')
- assert cylinder.point == pO
- assert hasattr(cylinder, 'axis')
- assert cylinder.axis == N.x
- @staticmethod
- @pytest.mark.parametrize(
- 'position, expected',
- [
- (S.Zero, False),
- (r*N.y, True),
- (r*N.z, True),
- (r*(N.y + N.z).normalize(), True),
- (Integer(2)*r*N.y, False),
- (r*(N.x + N.y), True),
- (r*(Integer(2)*N.x + N.y), True),
- (Integer(2)*N.x + r*(Integer(2)*N.y + N.z).normalize(), True),
- (r*(cos(q)*N.y + sin(q)*N.z), True)
- ]
- )
- def test_point_is_on_surface(position, expected):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, N.x)
- p1 = Point('p1')
- p1.set_pos(pO, position)
- assert cylinder.point_on_surface(p1) is expected
- @staticmethod
- @pytest.mark.parametrize('position', [S.Zero, Integer(2)*r*N.y])
- def test_geodesic_length_point_not_on_surface_invalid(position):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, N.x)
- p1 = Point('p1')
- p1.set_pos(pO, position)
- p2 = Point('p2')
- p2.set_pos(pO, position)
- error_msg = r'point .* does not lie on the surface of'
- with pytest.raises(ValueError, match=error_msg):
- cylinder.geodesic_length(p1, p2)
- @staticmethod
- @pytest.mark.parametrize(
- 'axis, position_1, position_2, expected',
- [
- (N.x, r*N.y, r*N.y, S.Zero),
- (N.x, r*N.y, N.x + r*N.y, S.One),
- (N.x, r*N.y, -x*N.x + r*N.y, sqrt(x**2)),
- (-N.x, r*N.y, x*N.x + r*N.y, sqrt(x**2)),
- (N.x, r*N.y, r*N.z, S.Half*pi*sqrt(r**2)),
- (-N.x, r*N.y, r*N.z, Integer(3)*S.Half*pi*sqrt(r**2)),
- (N.x, r*N.z, r*N.y, Integer(3)*S.Half*pi*sqrt(r**2)),
- (-N.x, r*N.z, r*N.y, S.Half*pi*sqrt(r**2)),
- (N.x, r*N.y, r*(cos(q)*N.y + sin(q)*N.z), sqrt(r**2*q**2)),
- (
- -N.x, r*N.y,
- r*(cos(q)*N.y + sin(q)*N.z),
- sqrt(r**2*(Integer(2)*pi - q)**2),
- ),
- ]
- )
- def test_geodesic_length(axis, position_1, position_2, expected):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, axis)
- p1 = Point('p1')
- p1.set_pos(pO, position_1)
- p2 = Point('p2')
- p2.set_pos(pO, position_2)
- assert simplify(Eq(cylinder.geodesic_length(p1, p2), expected))
- @staticmethod
- @pytest.mark.parametrize(
- 'axis, position_1, position_2, vector_1, vector_2',
- [
- (N.z, r * N.x, r * N.y, N.y, N.x),
- (N.z, r * N.x, -r * N.x, N.y, N.y),
- (N.z, -r * N.x, r * N.x, -N.y, -N.y),
- (-N.z, r * N.x, -r * N.x, -N.y, -N.y),
- (-N.z, -r * N.x, r * N.x, N.y, N.y),
- (N.z, r * N.x, -r * N.y, N.y, -N.x),
- (
- N.z,
- r * N.y,
- sqrt(2)/2 * r * N.x - sqrt(2)/2 * r * N.y,
- - N.x,
- - sqrt(2)/2 * N.x - sqrt(2)/2 * N.y,
- ),
- (
- N.z,
- r * N.x,
- r / 2 * N.x + sqrt(3)/2 * r * N.y,
- N.y,
- sqrt(3)/2 * N.x - 1/2 * N.y,
- ),
- (
- N.z,
- r * N.x,
- sqrt(2)/2 * r * N.x + sqrt(2)/2 * r * N.y,
- N.y,
- sqrt(2)/2 * N.x - sqrt(2)/2 * N.y,
- ),
- (
- N.z,
- r * N.x,
- r * N.x + N.z,
- N.z,
- -N.z,
- ),
- (
- N.z,
- r * N.x,
- r * N.y + pi/2 * r * N.z,
- sqrt(2)/2 * N.y + sqrt(2)/2 * N.z,
- sqrt(2)/2 * N.x - sqrt(2)/2 * N.z,
- ),
- (
- N.z,
- r * N.x,
- r * cos(q) * N.x + r * sin(q) * N.y,
- N.y,
- sin(q) * N.x - cos(q) * N.y,
- ),
- ]
- )
- def test_geodesic_end_vectors(
- axis,
- position_1,
- position_2,
- vector_1,
- vector_2,
- ):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, axis)
- p1 = Point('p1')
- p1.set_pos(pO, position_1)
- p2 = Point('p2')
- p2.set_pos(pO, position_2)
- expected = (vector_1, vector_2)
- end_vectors = tuple(
- end_vector.simplify()
- for end_vector in cylinder.geodesic_end_vectors(p1, p2)
- )
- assert end_vectors == expected
- @staticmethod
- @pytest.mark.parametrize(
- 'axis, position',
- [
- (N.z, r * N.x),
- (N.z, r * cos(q) * N.x + r * sin(q) * N.y + N.z),
- ]
- )
- def test_geodesic_end_vectors_invalid_coincident(axis, position):
- r = Symbol('r', positive=True)
- pO = Point('pO')
- cylinder = WrappingCylinder(r, pO, axis)
- p1 = Point('p1')
- p1.set_pos(pO, position)
- p2 = Point('p2')
- p2.set_pos(pO, position)
- with pytest.raises(ValueError):
- _ = cylinder.geodesic_end_vectors(p1, p2)
|