def test_Rt(self):
        nt.assert_array_almost_equal(rot2(0.3), t2r(trot2(0.3)))
        nt.assert_array_almost_equal(trot2(0.3), r2t(rot2(0.3)))

        R = rot2(0.2)
        t = [1, 2]
        T = rt2tr(R, t)
        nt.assert_array_almost_equal(t2r(T), R)
        nt.assert_array_almost_equal(transl2(T), np.array(t))
def trinterp2(T0, T1=None, s=None):
    """
    Interpolate SE(2) matrices

    :param T0: first SE(2) matrix
    :type T0: np.ndarray, shape=(3,3)
    :param T1: second SE(2) matrix
    :type T1: np.ndarray, shape=(3,3)
    :param s: interpolation coefficient, range 0 to 1
    :type s: float
    :return: SE(2) matrix
    :rtype: np.ndarray, shape=(3,3)
    
    - ``trinterp2(T0, T1, S)`` is a homogeneous transform (3x3) interpolated
    between T0 when S=0 and T1 when S=1.  T0 and T1 are both homogeneous
    transforms (3x3).
    
    - ``trinterp2(T1, S)`` as above but interpolated between the identity matrix
    when S=0 to T1 when S=1.
    
    Notes::
    - Rotation angle is linearly interpolated.

    :seealso: :func:`~spatialmath.base.transforms3d.trinterp`
    
    %## 2d homogeneous trajectory
    """
    if T1 is None:
        #	TRINTERP2(T, s)

        th0 = math.atan2(T0[1, 0], T0[0, 0])
        p0 = transl2(T0)

        th = s * th0
        pr = s * p0
    else:
        #	TRINTERP2(T0, T1, s)

        th0 = math.atan2(T0[1, 0], T0[0, 0])
        th1 = math.atan2(T1[1, 0], T1[0, 0])

        p0 = transl2(T0)
        p1 = transl2(T1)

        pr = p0 * (1 - s) + s * p1
        th = th0 * (1 - s) + s * th1

    return trn.rt2tr(rot2(th), pr)
def trexp2(S, theta=None):
    """
    Exponential of so(2) or se(2) matrix

    :param S: so(2), se(2) matrix or equivalent velctor
    :type T: numpy.ndarray, shape=(2,2) or (3,3); array_like
    :param theta: motion
    :type theta: float
    :return: 2x2 or 3x3 matrix exponential in SO(2) or SE(2)
    :rtype: numpy.ndarray, shape=(2,2) or (3,3)

    An efficient closed-form solution of the matrix exponential for arguments
    that are so(2) or se(2).

    For so(2) the results is an SO(2) rotation matrix:

    - ``trexp2(S)`` is the matrix exponential of the so(3) element ``S`` which is a 2x2
      skew-symmetric matrix.
    - ``trexp2(S, THETA)`` as above but for an so(3) motion of S*THETA, where ``S`` is
      unit-norm skew-symmetric matrix representing a rotation axis and a rotation magnitude
      given by ``THETA``.
    - ``trexp2(W)`` is the matrix exponential of the so(2) element ``W`` expressed as
      a 1-vector (array_like).
    - ``trexp2(W, THETA)`` as above but for an so(3) motion of W*THETA where ``W`` is a
      unit-norm vector representing a rotation axis and a rotation magnitude
      given by ``THETA``. ``W`` is expressed as a 1-vector (array_like).


    For se(2) the results is an SE(2) homogeneous transformation matrix:

    - ``trexp2(SIGMA)`` is the matrix exponential of the se(2) element ``SIGMA`` which is
      a 3x3 augmented skew-symmetric matrix.
    - ``trexp2(SIGMA, THETA)`` as above but for an se(3) motion of SIGMA*THETA, where ``SIGMA``
      must represent a unit-twist, ie. the rotational component is a unit-norm skew-symmetric
      matrix.
    - ``trexp2(TW)`` is the matrix exponential of the se(3) element ``TW`` represented as
      a 3-vector which can be considered a screw motion.
    - ``trexp2(TW, THETA)`` as above but for an se(2) motion of TW*THETA, where ``TW``
      must represent a unit-twist, ie. the rotational component is a unit-norm skew-symmetric
      matrix.

     :seealso: trlog, trexp2
    """

    if argcheck.ismatrix(S, (3, 3)) or argcheck.isvector(S, 3):
        # se(2) case
        if argcheck.ismatrix(S, (3, 3)):
            # augmentented skew matrix
            tw = trn.vexa(S)
        else:
            # 3 vector
            tw = argcheck.getvector(S)

        if theta is None:
            (tw, theta) = vec.unittwist2(tw)
        else:
            assert vec.isunittwist2(
                tw), 'If theta is specified S must be a unit twist'

        t = tw[0:2]
        w = tw[2]

        R = trn._rodrigues(w, theta)

        skw = trn.skew(w)
        V = np.eye(2) * theta + (1.0 - math.cos(theta)) * skw + (
            theta - math.sin(theta)) * skw @ skw

        return trn.rt2tr(R, V @ t)

    elif argcheck.ismatrix(S, (2, 2)) or argcheck.isvector(S, 1):
        # so(2) case
        if argcheck.ismatrix(S, (2, 2)):
            # skew symmetric matrix
            w = trn.vex(S)
        else:
            # 1 vector
            w = argcheck.getvector(S)

        if theta is not None:
            assert vec.isunitvec(
                w), 'If theta is specified S must be a unit twist'

        # do Rodrigues' formula for rotation
        return trn._rodrigues(w, theta)
    else:
        raise ValueError(
            " First argument must be SO(2), 1-vector, SE(2) or 3-vector")
def trinterp2(end, start=None, s=None):
    """
    Interpolate SE(2) matrices

    :param end: final SE(3) matrix, value when s=1
    :type T0: np.ndarray, shape=(3,3)
    :param start: initial SE(3) matrix, value when s=0, optional, defaults to identity
    :type T1: np.ndarray, shape=(3,3)
    :param s: interpolation coefficient, range 0 to 1
    :type s: float
    :return: SE(2) matrix
    :rtype: np.ndarray, shape=(3,3)
    
    - ``trinterp2(T1, s=S)`` is a homogeneous transform (3x3) interpolated
      between identity when S=0 and T1 when S=1.
      
    - ``trinterp2(T1, start=T0, s=S)`` as above but interpolated
      between T0 when S=0 and T1 when S=1.  T0 and T1 are both homogeneous
      transforms (3x3).
    
    Notes:
        
    - Rotation angle is linearly interpolated.

    :seealso: :func:`~spatialmath.base.transforms3d.trinterp`
    
    %## 2d homogeneous trajectory
    """
    if argcheck.ismatrix(start, (2,2)):
        # SO(2) case
        if T1 is None:
            #	TRINTERP2(T, s)
            
            th0 = math.atan2(start[1,0], start[0,0])
            
            th = s * th0
        else:
            #	TRINTERP2(T0, T1, s)
            assert start.shape == end.shape, 'both matrices must be same shape'
        
            th0 = math.atan2(start[1,0], start[0,0])
            th1 = math.atan2(end[1,0], end[0,0])
            
            th = th0 * (1 - s) + s * th1
        
        return rot2(th)
    elif argcheck.ismatrix(start, (3,3)):
        if end is None:
            #	TRINTERP2(T, s)
            
            th0 = math.atan2(start[1,0], start[0,0])
            p0 = transl2(start)
            
            th = s * th0
            pr = s * p0
        else:
            #	TRINTERP2(T0, T1, s)
            assert start.shape == end.shape, 'both matrices must be same shape'
        
            th0 = math.atan2(start[1,0], start[0,0])
            th1 = math.atan2(end[1,0], end[0,0])
            
            p0 = transl2(start)
            p1 = transl2(end)
            
            pr = p0 * (1 - s) + s * p1;
            th = th0 * (1 - s) + s * th1
        
        return trn.rt2tr(rot2(th), pr)
    else:
        return ValueError('Argument must be SO(2) or SE(2)')
Beispiel #5
0
def trinterp2(start, end, s=None):
    """
    Interpolate SE(2) matrices

    :param start: initial SO(2) or SE(2) matrix value when s=0, if None then identity is used
    :type T1: np.ndarray, shape=(2,2), (3,3) or None
    :param end: final SO(2) or SE(2) matrix, value when s=1
    :type T0: np.ndarray, shape=(2,2), (3,3)
    :param s: interpolation coefficient, range 0 to 1
    :type s: float
    :return: SO(2) or SE(2) matrix
    :rtype: np.ndarray, shape=(2,2), (3,3)

    - ``trinterp2(None, T, S)`` is a homogeneous transform (3x3) interpolated
      between identity when S=0 and T (3x3) when S=1.
    - ``trinterp2(T0, T1, S)`` as above but interpolated
      between T0 (3x3) when S=0 and T1 (3x3) when S=1.
    - ``trinterp2(None, R, S)`` is a rotation matrix (2x2) interpolated
      between identity when S=0 and R (2x2) when S=1.
    - ``trinterp2(R0, R1, S)`` as above but interpolated
      between R0 (2x2) when S=0 and R1 (2x2) when S=1.

    Notes:

    - Rotation angle is linearly interpolated.

    :seealso: :func:`~spatialmath.base.transforms3d.trinterp`

    %## 2d homogeneous trajectory
    """
    if argcheck.ismatrix(end, (2, 2)):
        # SO(2) case
        if start is None:
            #	TRINTERP2(T, s)

            th0 = math.atan2(end[1, 0], end[0, 0])

            th = s * th0
        else:
            #	TRINTERP2(T1, start= s)
            assert start.shape == end.shape, 'start and end matrices must be same shape'

            th0 = math.atan2(start[1, 0], start[0, 0])
            th1 = math.atan2(end[1, 0], end[0, 0])

            th = th0 * (1 - s) + s * th1

        return rot2(th)
    elif argcheck.ismatrix(end, (3, 3)):
        if start is None:
            #	TRINTERP2(T, s)

            th0 = math.atan2(end[1, 0], end[0, 0])
            p0 = transl2(end)

            th = s * th0
            pr = s * p0
        else:
            #	TRINTERP2(T0, T1, s)
            assert start.shape == end.shape, 'both matrices must be same shape'

            th0 = math.atan2(start[1, 0], start[0, 0])
            th1 = math.atan2(end[1, 0], end[0, 0])

            p0 = transl2(start)
            p1 = transl2(end)

            pr = p0 * (1 - s) + s * p1
            th = th0 * (1 - s) + s * th1

        return trn.rt2tr(rot2(th), pr)
    else:
        return ValueError('Argument must be SO(2) or SE(2)')