def transform_points(points,
                     matrix,
                     translate=True):
    """
    Returns points, rotated by transformation matrix

    If points is (n,2), matrix must be (3,3)
    if points is (n,3), matrix must be (4,4)

    Parameters
    ----------
    points : (n, d) float
      Points where d is 2 or 3
    matrix : (3,3) or (4,4) float
      Homogenous rotation matrix
    translate : bool
      Apply translation from matrix or not

    Returns
    ----------
    transformed : (n,d) float
      Transformed points
    """
    points = np.asanyarray(points, dtype=np.float64)
    # no points no cry
    if len(points) == 0:
        return points.copy()

    matrix = np.asanyarray(matrix, dtype=np.float64)
    if (len(points.shape) != 2 or
            (points.shape[1] + 1 != matrix.shape[1])):
        raise ValueError('matrix shape ({}) doesn\'t match points ({})'.format(
            matrix.shape,
            points.shape))

    # check to see if we've been passed an identity matrix
    identity = np.abs(matrix - np.eye(matrix.shape[0])).max()
    if identity < 1e-8:
        return np.ascontiguousarray(points.copy())

    dimension = points.shape[1]
    column = np.zeros(len(points)) + int(bool(translate))
    stacked = np.column_stack((points, column))
    transformed = np.dot(matrix, stacked.T).T[:, :dimension]
    transformed = np.ascontiguousarray(transformed)
    return transformed
Returns points, rotated by transformation matrix

    If points is (n,2), matrix must be (3,3)
    if points is (n,3), matrix must be (4,4)

    Parameters
    ----------
    points : (n, d) float
      Points where d is 2 or 3
    matrix : (3,3) or (4,4) float
      Homogenous rotation matrix
    translate : bool
      Apply translation from matrix or not

    Returns
    ----------
    transformed : (n,d) float
      Transformed points