class_docstr: A solid (infinite) cylindrical object.
  
  Explanation
  ===========
  
  A wrapping geometry that allows for circular arcs to be defined between
  pairs of points. These paths are always geodetic (the shortest possible) in
  the sense that they will be a straight line on the unwrapped cylinder's
  surface. However, it is also possible for a direction to be specified, i.e.
  paths can be influenced such that they either wrap along the shortest side
  or the longest side of the cylinder. To define these directions, rotations
  are in the positive direction following the right-hand rule.
  
  Examples
  ========
  
  To create a ``WrappingCylinder`` instance, a ``Symbol`` denoting its
  radius, a ``Vector`` defining its axis, and a ``Point`` through which its
  axis passes are needed:
  
  >>> from sympy import symbols
  >>> from sympy.physics.mechanics import (Point, ReferenceFrame,
  ...     WrappingCylinder)
  >>> N = ReferenceFrame('N')
  >>> r = symbols('r')
  >>> pO = Point('pO')
  >>> ax = N.x
  
  A cylinder with radius ``r``, and axis parallel to ``N.x`` passing through
  ``pO`` can be instantiated with:
  
  >>> WrappingCylinder(r, pO, ax)
  WrappingCylinder(radius=r, point=pO, axis=N.x)
  
  Parameters
  ==========
  
  radius : Symbol
      The radius of the cylinder.
  point : Point
      A point through which the cylinder's axis passes.
  axis : Vector
      The axis along which the cylinder is aligned.
  
  See Also
  ========
  
  WrappingSphere: Spherical geometry where the wrapping direction is always
      geodetic.
docstr: The shortest distance between two points on a geometry's surface.
  
  Explanation
  ===========
  
  The geodesic length, i.e. the shortest arc along the surface of a
  cylinder, connecting two points. It can be calculated using Pythagoras'
  theorem. The first short side is the distance between the two points on
  the cylinder's surface parallel to the cylinder's axis. The second
  short side is the arc of a circle between the two points of the
  cylinder's surface perpendicular to the cylinder's axis. The resulting
  hypotenuse is the geodesic length.
  
  Examples
  ========
  
  A geodesic length can only be calculated between two points on the
  cylinder's surface. Firstly, a ``WrappingCylinder`` instance must be
  created along with two points that will lie on its surface:
  
  >>> from sympy import symbols, cos, sin
  >>> from sympy.physics.mechanics import (Point, ReferenceFrame,
  ...     WrappingCylinder, dynamicsymbols)
  >>> N = ReferenceFrame('N')
  >>> r = symbols('r')
  >>> pO = Point('pO')
  >>> pO.set_vel(N, 0)
  >>> cylinder = WrappingCylinder(r, pO, N.x)
  >>> p1 = Point('p1')
  >>> p2 = Point('p2')
  
  Let's assume that ``p1`` is located at ``N.x + r*N.y`` relative to
  ``pO`` and that ``p2`` is located at ``r*(cos(q)*N.y + sin(q)*N.z)``
  relative to ``pO``, where ``q(t)`` is a generalized coordinate
  specifying the angle rotated around the ``N.x`` axis according to the
  right-hand rule where ``N.y`` is zero. These positions can be set with:
  
  >>> q = dynamicsymbols('q')
  >>> p1.set_pos(pO, N.x + r*N.y)
  >>> p1.pos_from(pO)
  N.x + r*N.y
  >>> p2.set_pos(pO, r*(cos(q)*N.y + sin(q)*N.z).normalize())
  >>> p2.pos_from(pO).simplify()
  r*cos(q(t))*N.y + r*sin(q(t))*N.z
  
  The geodesic length, which is in this case a is the hypotenuse of a
  right triangle where the other two side lengths are ``1`` (parallel to
  the cylinder's axis) and ``r*q(t)`` (parallel to the cylinder's cross
  section), can be calculated using the ``geodesic_length`` method:
  
  >>> cylinder.geodesic_length(p1, p2).simplify()
  sqrt(r**2*q(t)**2 + 1)
  
  If the ``geodesic_length`` method is passed an argument ``Point`` that
  doesn't lie on the sphere's surface then a ``ValueError`` is raised
  because it's not possible to calculate a value in this case.
  
  Parameters
  ==========
  
  point_1 : Point
      Point from which the geodesic length should be calculated.
  point_2 : Point
      Point to which the geodesic length should be calculated.
code: def geodesic_length(self, point_1, point_2):
      """The shortest distance between two points on a geometry's surface.
  
      Explanation
      ===========
  
      The geodesic length, i.e. the shortest arc along the surface of a
      cylinder, connecting two points. It can be calculated using Pythagoras'
      theorem. The first short side is the distance between the two points on
      the cylinder's surface parallel to the cylinder's axis. The second
      short side is the arc of a circle between the two points of the
      cylinder's surface perpendicular to the cylinder's axis. The resulting
      hypotenuse is the geodesic length.
  
      Examples
      ========
  
      A geodesic length can only be calculated between two points on the
      cylinder's surface. Firstly, a ``WrappingCylinder`` instance must be
      created along with two points that will lie on its surface:
  
      >>> from sympy import symbols, cos, sin
      >>> from sympy.physics.mechanics import (Point, ReferenceFrame,
      ...     WrappingCylinder, dynamicsymbols)
      >>> N = ReferenceFrame('N')
      >>> r = symbols('r')
      >>> pO = Point('pO')
      >>> pO.set_vel(N, 0)
      >>> cylinder = WrappingCylinder(r, pO, N.x)
      >>> p1 = Point('p1')
      >>> p2 = Point('p2')
  
      Let's assume that ``p1`` is located at ``N.x + r*N.y`` relative to
      ``pO`` and that ``p2`` is located at ``r*(cos(q)*N.y + sin(q)*N.z)``
      relative to ``pO``, where ``q(t)`` is a generalized coordinate
      specifying the angle rotated around the ``N.x`` axis according to the
      right-hand rule where ``N.y`` is zero. These positions can be set with:
  
      >>> q = dynamicsymbols('q')
      >>> p1.set_pos(pO, N.x + r*N.y)
      >>> p1.pos_from(pO)
      N.x + r*N.y
      >>> p2.set_pos(pO, r*(cos(q)*N.y + sin(q)*N.z).normalize())
      >>> p2.pos_from(pO).simplify()
      r*cos(q(t))*N.y + r*sin(q(t))*N.z
  
      The geodesic length, which is in this case a is the hypotenuse of a
      right triangle where the other two side lengths are ``1`` (parallel to
      the cylinder's axis) and ``r*q(t)`` (parallel to the cylinder's cross
      section), can be calculated using the ``geodesic_length`` method:
  
      >>> cylinder.geodesic_length(p1, p2).simplify()
      sqrt(r**2*q(t)**2 + 1)
  
      If the ``geodesic_length`` method is passed an argument ``Point`` that
      doesn't lie on the sphere's surface then a ``ValueError`` is raised
      because it's not possible to calculate a value in this case.
  
      Parameters
      ==========
  
      point_1 : Point
          Point from which the geodesic length should be calculated.
      point_2 : Point
          Point to which the geodesic length should be calculated.
  
      """
      for point in (point_1, point_2):
          if not self.point_on_surface(point):
              msg = (
                  f"Geodesic length cannot be calculated as point {point} "
                  f"with radius {point.pos_from(self.point).magnitude()} "
                  f"from the cylinder's center {self.point} does not lie on "
                  f"the surface of {self} with radius {self.radius} and axis "
                  f"{self.axis}."
              )
              raise ValueError(msg)
  
      relative_position = point_2.pos_from(point_1)
      parallel_length = relative_position.dot(self.axis)
  
      point_1_relative_position = point_1.pos_from(self.point)
      point_1_perpendicular_vector = (
          point_1_relative_position
          - point_1_relative_position.dot(self.axis) * self.axis
      ).normalize()
  
      point_2_relative_position = point_2.pos_from(self.point)
      point_2_perpendicular_vector = (
          point_2_relative_position
          - point_2_relative_position.dot(self.axis) * self.axis
      ).normalize()
  
      central_angle = _directional_atan(
          cancel(
              point_1_perpendicular_vector.cross(
                  point_2_perpendicular_vector
              ).dot(self.axis)
          ),
          cancel(
              point_1_perpendicular_vector.dot(
                  point_2_perpendicular_vector
              )
          ),
      )
  
      planar_arc_length = self.radius * central_angle
      geodesic_length = sqrt(
          parallel_length**2 + planar_arc_length**2
      )
      return geodesic_length
  
imports: from abc import ABC, abstractmethod
  from sympy import Integer, acos, pi, sqrt, sympify, tan
  from sympy.core.relational import Eq
  from sympy.functions.elementary.trigonometric import atan2
  from sympy.polys.polytools import cancel
  from sympy.physics.vector import Vector, dot
  from sympy.simplify.simplify import trigsimp
label_desc: Use image node_id 9 for calling the WrappingCylinder obj's underlying member method code with example usage: obj.geodesic_length(point_1, point_2) and returns: geodesic_length