Skip to content

Commit

Permalink
Merge pull request #25510 from moorepants/public-biomech-geom
Browse files Browse the repository at this point in the history
Make `physics.mechanics.wrapping_geometry` public
  • Loading branch information
brocksam committed Aug 15, 2023
2 parents 77010f3 + e3e4d2f commit d5d8c14
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 292 deletions.
1 change: 1 addition & 0 deletions doc/src/modules/physics/mechanics/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Mechanics API Reference
linearize.rst
expr_manip.rst
printing.rst
wrapping_geometry.rst
6 changes: 6 additions & 0 deletions doc/src/modules/physics/mechanics/api/wrapping_geometry.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==============================
Wrapping Geometry (Docstrings)
==============================

.. automodule:: sympy.physics.mechanics.wrapping_geometry
:members:
7 changes: 6 additions & 1 deletion sympy/physics/mechanics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
'PinJoint', 'PrismaticJoint', 'CylindricalJoint', 'PlanarJoint',
'SphericalJoint', 'WeldJoint',

'JointsMethod'
'JointsMethod',

'WrappingCylinder', 'WrappingGeometryBase', 'WrappingSphere',
]

from sympy.physics import vector
Expand Down Expand Up @@ -72,3 +74,6 @@

from .joint import (PinJoint, PrismaticJoint, CylindricalJoint, PlanarJoint,
SphericalJoint, WeldJoint)

from .wrapping_geometry import (WrappingCylinder, WrappingGeometryBase,
WrappingSphere)
47 changes: 19 additions & 28 deletions sympy/physics/mechanics/_pathway.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
from typing import TYPE_CHECKING

from sympy.core.backend import S
from sympy.physics.mechanics import Force, Point
from sympy.physics.mechanics._geometry import GeometryBase
from sympy.physics.mechanics import Force, Point, WrappingGeometryBase
from sympy.physics.vector import dynamicsymbols

if TYPE_CHECKING:
Expand Down Expand Up @@ -299,29 +298,21 @@ class WrappingPathway(PathwayBase):
>>> from sympy.physics.mechanics._pathway import WrappingPathway
To construct a wrapping pathway, a geometry object, which the pathway can
wrap, is required. Similar to above, the ``_geometry.py`` module is also
experimental so geometry classes needed to be imported directly from the
``sympy.physics.mechanics._geometry.py`` module. Let's create a wrapping
pathway that wraps around a cylinder. To do this we need to import the
``Cylinder`` class.
>>> from sympy.physics.mechanics._geometry import Cylinder
To construct a wrapping pathway, like other pathways, a pair of points must
be passed, followed by an instance of a geometry class as a keyword
argument. We'll use a cylinder with radius ``r`` and its axis parallel to
``N.x`` passing through a point ``pO``.
be passed, followed by an instance of a wrapping geometry class as a
keyword argument. We'll use a cylinder with radius ``r`` and its axis
parallel to ``N.x`` passing through a point ``pO``.
>>> from sympy import Symbol
>>> from sympy.physics.mechanics import Point, ReferenceFrame
>>> from sympy.physics.mechanics import (Point, ReferenceFrame,
... WrappingCylinder)
>>> r = Symbol('r')
>>> N = ReferenceFrame('N')
>>> pA, pB, pO = Point('pA'), Point('pB'), Point('pO')
>>> cylinder = Cylinder(r, pO, N.x)
>>> cylinder = WrappingCylinder(r, pO, N.x)
>>> wrapping_pathway = WrappingPathway(pA, pB, cylinder)
>>> wrapping_pathway
WrappingPathway(pA, pB, geometry=Cylinder(radius=r, point=pO,
WrappingPathway(pA, pB, geometry=WrappingCylinder(radius=r, point=pO,
axis=N.x))
Parameters
Expand All @@ -333,7 +324,7 @@ class WrappingPathway(PathwayBase):
attachment_2 : Point
The second of the pair of ``Point`` objects between which the wrapping
pathway spans.
geometry : GeometryBase
geometry : WrappingGeometryBase
The geometry about which the pathway wraps.
"""
Expand All @@ -342,7 +333,7 @@ def __init__(
self,
attachment_1: Point,
attachment_2: Point,
geometry: GeometryBase,
geometry: WrappingGeometryBase,
) -> None:
"""Initializer for ``WrappingPathway``.
Expand All @@ -355,30 +346,30 @@ def __init__(
attachment_2 : Point
The second of the pair of ``Point`` objects between which the
wrapping pathway spans.
geometry : GeometryBase
geometry : WrappingGeometryBase
The geometry about which the pathway wraps.
"""
super().__init__(attachment_1, attachment_2)
self.geometry = geometry

@property
def geometry(self) -> GeometryBase:
def geometry(self) -> WrappingGeometryBase:
"""The geometry around which the pathway wraps."""
return self._geometry

@geometry.setter
def geometry(self, geometry: GeometryBase) -> None:
def geometry(self, geometry: WrappingGeometryBase) -> None:
if hasattr(self, '_geometry'):
msg = (
f'Can\'t set attribute `geometry` to {repr(geometry)} as it '
f'is immutable.'
)
raise AttributeError(msg)
if not isinstance(geometry, GeometryBase):
if not isinstance(geometry, WrappingGeometryBase):
msg = (
f'Value {repr(geometry)} passed to `geometry` was of type '
f'{type(geometry)}, must be {GeometryBase}.'
f'{type(geometry)}, must be {WrappingGeometryBase}.'
)
raise TypeError(msg)
self._geometry = geometry
Expand Down Expand Up @@ -418,12 +409,12 @@ def compute_loads(self, force: ExprType) -> list[LoadBase]:
passes through a point ``pO``.
>>> from sympy import Symbol
>>> from sympy.physics.mechanics import Point, ReferenceFrame
>>> from sympy.physics.mechanics._geometry import Cylinder
>>> from sympy.physics.mechanics import (Point, ReferenceFrame,
... WrappingCylinder)
>>> N = ReferenceFrame('N')
>>> r = Symbol('r', positive=True)
>>> pO = Point('pO')
>>> cylinder = Cylinder(r, pO, N.z)
>>> cylinder = WrappingCylinder(r, pO, N.z)
Create the pathway of the actuator using the ``WrappingPathway`` class,
defined to span between two points ``pA`` and ``pB``. Both points lie
Expand Down Expand Up @@ -463,7 +454,7 @@ def compute_loads(self, force: ExprType) -> list[LoadBase]:
"""
pA, pB = self.attachments
pO = self.geometry.point
pA_force, pB_force = self.geometry._geodesic_end_vectors(pA, pB)
pA_force, pB_force = self.geometry.geodesic_end_vectors(pA, pB)
pO_force = -(pA_force + pB_force)

loads: list[LoadBase] = [
Expand Down
10 changes: 6 additions & 4 deletions sympy/physics/mechanics/tests/test_pathway.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
Force,
Point,
ReferenceFrame,
WrappingCylinder,
WrappingGeometryBase,
WrappingSphere,
dynamicsymbols,
)
from sympy.physics.mechanics._geometry import Cylinder, GeometryBase, Sphere
from sympy.physics.mechanics._pathway import (
LinearPathway,
PathwayBase,
Expand Down Expand Up @@ -202,8 +204,8 @@ def _wrapping_pathway_fixture(self) -> None:
self.pO = Point('pO')
self.N = ReferenceFrame('N')
self.ax = self.N.z
self.sphere = Sphere(self.r, self.pO)
self.cylinder = Cylinder(self.r, self.pO, self.ax)
self.sphere = WrappingSphere(self.r, self.pO)
self.cylinder = WrappingCylinder(self.r, self.pO, self.ax)
self.pathway = WrappingPathway(self.pA, self.pB, self.cylinder)
self.F = Symbol('F')

Expand All @@ -217,7 +219,7 @@ def test_valid_constructor(self) -> None:
assert isinstance(instance.attachments[1], Point)
assert instance.attachments[1] == self.pB
assert hasattr(instance, 'geometry')
assert isinstance(instance.geometry, GeometryBase)
assert isinstance(instance.geometry, WrappingGeometryBase)
assert instance.geometry == self.cylinder

@pytest.mark.parametrize(
Expand Down

0 comments on commit d5d8c14

Please sign in to comment.