"""Helper variable or function for UI Elements."""
import numpy as np
from fury.decorators import warn_on_args_to_kwargs
TWO_PI = 2 * np.pi
[docs]
@warn_on_args_to_kwargs()
def clip_overflow(textblock, width, *, side="right"):
    """Clips overflowing text of TextBlock2D with respect to width.
    Parameters
    ----------
    textblock : TextBlock2D
        The textblock object whose text needs to be clipped.
    width : int
        Required width of the clipped text.
    side : str, optional
        Clips the overflowing text according to side.
        It takes values "left" or "right".
    Returns
    -------
    clipped text : str
        Clipped version of the text.
    """
    original_str = textblock.message
    prev_bg = textblock.have_bg
    clip_idx = check_overflow(textblock, width, overflow_postfix="...", side=side)
    if clip_idx == 0:
        return original_str
    textblock.have_bg = prev_bg
    return textblock.message 
[docs]
@warn_on_args_to_kwargs()
def wrap_overflow(textblock, wrap_width, *, side="right"):
    """Wraps overflowing text of TextBlock2D with respect to width.
    Parameters
    ----------
    textblock : TextBlock2D
        The textblock object whose text needs to be wrapped.
    wrap_width : int
        Required width of the wrapped text.
    side : str, optional
        Clips the overflowing text according to side.
        It takes values "left" or "right".
    Returns
    -------
    wrapped text : str
        Wrapped version of the text.
    """
    original_str = textblock.message
    str_copy = textblock.message
    wrap_idxs = []
    wrap_idx = check_overflow(textblock, wrap_width, overflow_postfix="", side=side)
    if wrap_idx == 0:
        return original_str
    wrap_idxs.append(wrap_idx)
    while wrap_idx != 0:
        str_copy = str_copy[wrap_idx:]
        textblock.message = str_copy
        wrap_idx = check_overflow(textblock, wrap_width, overflow_postfix="", side=side)
        if wrap_idx != 0:
            wrap_idxs.append(wrap_idxs[-1] + wrap_idx + 1)
    for idx in wrap_idxs:
        original_str = original_str[:idx] + "\n" + original_str[idx:]
    textblock.message = original_str
    return textblock.message 
[docs]
@warn_on_args_to_kwargs()
def check_overflow(textblock, width, *, overflow_postfix="", side="right"):
    """Checks if the text is overflowing.
    Parameters
    ----------
    textblock : TextBlock2D
        The textblock object whose text is to be checked.
    width: int
        Required width of the text.
    overflow_postfix: str, optional
        Postfix to be added to the text if it is overflowing.
    Returns
    -------
    mid_ptr: int
        Overflow index of the text.
    """
    side = side.lower()
    if side not in ["left", "right"]:
        raise ValueError("side can only take values 'left' or 'right'")
    original_str = textblock.message
    start_ptr = 0
    mid_ptr = 0
    end_ptr = len(original_str)
    if side == "left":
        original_str = original_str[::-1]
    if textblock.cal_size_from_message()[0] <= width:
        return 0
    while start_ptr < end_ptr:
        mid_ptr = (start_ptr + end_ptr) // 2
        textblock.message = original_str[:mid_ptr] + overflow_postfix
        if textblock.cal_size_from_message()[0] < width:
            start_ptr = mid_ptr
        elif textblock.cal_size_from_message()[0] > width:
            end_ptr = mid_ptr
        if (
            mid_ptr == (start_ptr + end_ptr) // 2
            or textblock.cal_size_from_message()[0] == width
        ):
            if side == "left":
                textblock.message = textblock.message[::-1]
            return mid_ptr 
[docs]
def cal_bounding_box_2d(vertices):
    """Calculate the min, max position and the size of the bounding box.
    Parameters
    ----------
    vertices : ndarray
        vertices of the actors.
    """
    if vertices.ndim != 2 or vertices.shape[1] not in [2, 3]:
        raise IOError("vertices should be a 2D array with shape (n,2) or (n,3).")
    if vertices.shape[1] == 3:
        vertices = vertices[:, :-1]
    min_x, min_y = vertices[0]
    max_x, max_y = vertices[0]
    for x, y in vertices:
        if x < min_x:
            min_x = x
        if y < min_y:
            min_y = y
        if x > max_x:
            max_x = x
        if y > max_y:
            max_y = y
    bounding_box_min = np.asarray([min_x, min_y], dtype="int")
    bounding_box_max = np.asarray([max_x, max_y], dtype="int")
    bounding_box_size = np.asarray([max_x - min_x, max_y - min_y], dtype="int")
    return bounding_box_min, bounding_box_max, bounding_box_size 
[docs]
def rotate_2d(vertices, angle):
    """Rotate the given vertices by an angle.
    Parameters
    ----------
    vertices : ndarray
        vertices of the actors.
    angle: float
        Value by which the vertices are rotated in radian.
    """
    if vertices.ndim != 2 or vertices.shape[1] != 3:
        raise IOError("vertices should be a 2D array with shape (n,3).")
    rotation_matrix = np.array(
        [
            [np.cos(angle), np.sin(angle), 0],
            [-np.sin(angle), np.cos(angle), 0],
            [0, 0, 1],
        ]
    )
    new_vertices = np.matmul(vertices, rotation_matrix)
    return new_vertices