Finds intersection of 2 rays.

    This functions finds the parameter values for the 1st and 2nd input rays and returns a tuple of
    ``(parameter for ray1, parameter for ray2, intersection status)``.
    ``status`` value is a enum type which reports the case which the intersection operation encounters.

    The intersection operation can encounter 3 different cases:

    * Intersecting: This is the anticipated solution. Returns ``(t1, t2, RayIntersection.INTERSECT)``
    * Colinear: The rays can be parallel or coincident. Returns ``(t1, t2, RayIntersection.COLINEAR)``
    * Skew:  The rays are neither parallel nor intersecting. Returns ``(t1, t2, RayIntersection.SKEW)``

    For the colinear case, ``t1`` and ``t2`` are the parameter values that give the starting point of the ray2 and ray1,
    respectively. Therefore;

    .. code-block:: python

        ray1.eval(t1) == ray2.p
        ray2.eval(t2) == ray1.p

    Please note that this operation is only implemented for 2- and 3-dimensional rays.

    :param ray1: 1st ray
    :param ray2: 2nd ray
    :return: a tuple of the parameter (t) for ray1 and ray2, and status of the intersection
    :rtype: tuple

def intersect(ray1, ray2, **kwargs):
    """ Finds intersection of 2 rays.

    This functions finds the parameter values for the 1st and 2nd input rays and returns a tuple of
    ``(parameter for ray1, parameter for ray2, intersection status)``.
    ``status`` value is a enum type which reports the case which the intersection operation encounters.

    The intersection operation can encounter 3 different cases:

    * Intersecting: This is the anticipated solution. Returns ``(t1, t2, RayIntersection.INTERSECT)``
    * Colinear: The rays can be parallel or coincident. Returns ``(t1, t2, RayIntersection.COLINEAR)``
    * Skew:  The rays are neither parallel nor intersecting. Returns ``(t1, t2, RayIntersection.SKEW)``

    For the colinear case, ``t1`` and ``t2`` are the parameter values that give the starting point of the ray2 and ray1,
    respectively. Therefore;

    .. code-block:: python

        ray1.eval(t1) == ray2.p
        ray2.eval(t2) == ray1.p

    Please note that this operation is only implemented for 2- and 3-dimensional rays.

    :param ray1: 1st ray
    :param ray2: 2nd ray
    :return: a tuple of the parameter (t) for ray1 and ray2, and status of the intersection
    :rtype: tuple
    """
    if not isinstance(ray1, Ray) or not isinstance(ray2, Ray):
        raise TypeError("The input arguments must be instances of the Ray object")

    if ray1.dimension != ray2.dimension:
        raise ValueError("Dimensions of the input rays must be the same")

    # Keyword arguments
    tol = kwargs.get('tol', 10e-17)

    # Call intersection method
    if ray1.dimension == 2:
        return _intersect2d(ray1, ray2, tol)
    elif ray1.dimension == 3:
        return _intersect3d(ray1, ray2, tol)
    else:
        raise NotImplementedError("Intersection operation for the current type of rays has not been implemented yet")