How to draw disconnected lines in mayavi and customize their colors without loops

42 views Asked by At

I want to plot many boxes in a scene. If I use mlab.plot3d, it will be very slow.

Therefore, I draw many line segments and then connect them to form boxes using plotting-many-lines-example. But, I do not know how to customize their colors.

1

There are 1 answers

0
ZhiHeng Feng On BEST ANSWER

I have found a solution. We can use mlab.quiver3d to draw many line segments at the same time by assigning mode="2ddash". Below is my code to draw many boxes at the same time with the option to specify the color of each box.

def vis_boxes(
        points: np.ndarray,
        boxes: np.ndarray,
        color: np.ndarray = None,
):
    """

    Args:
        points:  (N, 3)
        boxes:  (M, 6) xyzwlh
        color: (M, 4) RGBA

    Returns:

    """
    num_boxes = len(boxes)
    params = boxes.shape[1]
    if params not in (6, 9):
        raise ValueError(f"invalid number of box parameters {params}, only support 6, 9")

    fig = mlab.figure(bgcolor=(1, 1, 1), size=(1000, 750))

    mlab.points3d(points[:, 0], points[:, 1], points[:, 2], color=(1, 0, 0), figure=fig, scale_factor=0.1)

    center = boxes[:, 0:3]  # (M, 3)
    x_length = boxes[:, 3:4]  # (M, 1)
    y_length = boxes[:, 4:5]  # (M, 1)
    z_length = boxes[:, 5:6]  # (M, 1)
    forward = np.concatenate([np.ones_like(x_length), np.zeros_like(x_length), np.zeros_like(x_length)],
                             axis=-1) * x_length / 2  # (M, 3)
    right = np.concatenate([np.zeros_like(y_length), np.ones_like(y_length), np.zeros_like(y_length)],
                           axis=-1) * y_length / 2  # (M, 3)
    up = np.concatenate([np.zeros_like(z_length), np.zeros_like(z_length), np.ones_like(z_length)],
                        axis=-1) * z_length / 2  # (M, 3)

    def get_box_points(center, forward, right, up):
        p1 = center - forward - right - up  # (M, 3)
        p2 = center - forward + right - up
        p3 = center + forward + right - up
        p4 = center + forward - right - up
        p5 = center - forward - right + up
        p6 = center - forward + right + up
        p7 = center + forward + right + up
        p8 = center + forward - right + up
        start_points = np.stack([p1, p2, p3, p4, p5, p6, p7, p8, p1, p2, p3, p4], axis=-2)  # (M, 12, 3)
        end_points = np.stack([p2, p3, p4, p1, p6, p7, p8, p5, p5, p6, p7, p8], axis=-2)  # (M, 12, 3)
        return start_points, end_points

    src_start_points, src_end_points = get_box_points(center, forward, right, up)
    flow = src_end_points - src_start_points  # (M, 12, 3)
    start_points = np.reshape(src_start_points, (-1, 3))  # (M*12, 3)
    flow = flow.reshape(-1, 3)  # (M*12, 3)
    scalars = np.arange(num_boxes)  # (M, )
    scalars = np.repeat(scalars, 12)  # (M*12, )

    if color is None:
        cmap = matplotlib.colormaps["rainbow"]
        colors = cmap(np.linspace(0, 1, num_boxes)) * 255
        colors = colors.astype(np.uint8)

    q3d = mlab.quiver3d(
        start_points[:, 0],
        start_points[:, 1],
        start_points[:, 2],
        flow[:, 0],
        flow[:, 1],
        flow[:, 2],
        figure=fig,
        line_width=2,
        scale_factor=1,
        mode="2ddash",
        scalars=scalars,
    )
    q3d.glyph.color_mode = "color_by_scalar"  # Color by scalar
    q3d.module_manager.scalar_lut_manager.lut.table = colors
    mlab.draw()
    mlab.show()