Source code for ddg.jupyter._k3d

import k3d
import numpy as np

# for clear functions
import ddg
import ddg._error_messages as em
from ddg.arrays import (
    Curve,
    CurveList,
    Mesh,
    Points,
    _default_curve_radius,
    _default_curve_sampling,
    _default_point_radius,
    _default_subspace_size,
    _default_surface_sampling,
)
from ddg.math.discrete_objects import triangulated_faces

point_size = 0.1
line_size = 0.01

_conversion_modes = ["FACES", "EDGES", "POINTS"]


def _raise_mode_not_matched():
    raise ValueError(f"Mesh mode should be a value in {_conversion_modes}")


def _from_points(points, color, radius=_default_point_radius):
    """Convert points array to k3d.objects.Points

    Parameters
    ----------
    points: array_like of shape (_, 3)
        The positions of the points in 3D euclidean space.
    color: int, hexadecimal between 0x000000 and 0xffffff
        RGB color value as hexadecimal interger
    radius: float
        Radius of the points

    Returns
    -------
    k3d.objects.Points
    """
    points = points.astype(np.float32)
    return k3d.points(points, point_size=radius, shader="mesh", color=color)


def _from_curve(curve, color, mode, radius=_default_curve_radius):
    """Convert curve array to instance of k3d.objects.Drawable

    Parameters
    ----------
    curve: ddg.arrays.Curve
        a curve in R^3
    color: int, hexadecimal between 0x000000 and 0xffffff
        RGB color value as hexadecimal interger
    mode: str in ["FACES", "EDGES", "POINTS"]
        Conversion mode.
    radius: float
        Radius of the curve

    Returns
    -------
    k3d.objects.Points or k3d.objects.Line
    """
    points, periodicity = curve
    points = points.astype(np.float32)
    match mode:
        case "FACES" | "EDGES":
            if periodicity:
                points = np.vstack((points, points[0]))
            return k3d.line(points, width=radius, shader="mesh", color=color)
        case "POINTS":
            return _from_points(points, color)
        case _:
            _raise_mode_not_matched()


def _from_mesh(
    mesh_array,
    color,
    mode,
    curve_radius=_default_curve_radius,
    point_radius=_default_point_radius,
):
    """Convert mesh array to instance of k3d.objects.Drawable

    Parameters
    ----------
    mesh_array: ddg.arrays.Mesh
        a mesh in R^3
    color: int, hexadecimal between 0x000000 and 0xffffff
        RGB color value as hexadecimal interger
    mode: str in ["FACES", "EDGES", "POINTS"]
        Conversion mode.
    curve_radius: float
        Radius of the edges (in the case mode="EDGES")
    point_radius: float
        Radius of the vertices (in the case mode="POINTS")

    Returns
    -------
    k3d.objects.Points, k3d.objects.Mesh or k3d.objects.Lines
    """
    points, faces, _ = mesh_array
    if len(points) == 0:
        # empty object
        return None
    points = points.astype(np.float32)
    faces = faces.astype(np.uint32)
    match mode:
        case "FACES":
            faces = triangulated_faces(faces)
            mesh = k3d.mesh(
                points, faces, side="double", flat_shading=False, color=color
            )
            return mesh
        case "EDGES":
            edges = ddg.arrays.edges(mesh_array).astype(np.float32)
            lines = k3d.lines(
                points,
                edges,
                indices_type="segment",
                width=curve_radius,
                shader="mesh",
                color=color,
            )
            return lines
        case "POINTS":
            return _from_points(points, color, radius=point_radius)
        case _:
            _raise_mode_not_matched()


def _to_k3d(
    convertible,
    color=0x888888,
    mode="FACES",
    curve_sampling=_default_curve_sampling,
    surface_sampling=_default_surface_sampling,
    subspace_size=_default_subspace_size,
    curve_radius=_default_curve_radius,
    point_radius=_default_point_radius,
):
    """Convert pyddg objects, points, curves and meshes to K3D objects.

    Parameters
    ----------
    convertible:
        The object to convert
    mode: str in ["FACES", "EDGES", "POINTS"]
        Conversion mode.
    color: int, hexadecimal between 0x000000 and 0xffffff
        RGB color value as hexadecimal interger
    curve_sampling : tuple of an int and a float
        (default=_default_curve_sampling)
        Determines the sample number and stepsize for curves
    surface_sampling : tuple of an int and a float
        (default=_default_surface_sampling)
        Determines the sample number and stepsize for surfaces
    subspace_size : float
        (default=_default_subspace_size)
        Determines the size of subspaces
    curve_radius : float (default=_default_curve_radius)
        Radius for curves, set as `bobj.data.bevel_depth`
    point_radius : float (default=_default_point_radius)
        Radius of the sphere representing points


    Returns
    -------
    k3d.objects.Group
    """
    arrays = ddg.arrays.convert(
        convertible,
        curve_sampling=curve_sampling,
        surface_sampling=surface_sampling,
        subspace_size=subspace_size,
    )
    embedded = ddg.arrays._embed(arrays)

    objects = []

    match embedded:
        case Points(points):
            objects.append(_from_points(points, color, radius=point_radius))
        case Curve() as curve:
            objects.append(_from_curve(curve, color, mode, radius=curve_radius))
        case CurveList() as curves:
            objects += [
                _from_curve(curve, color, mode, radius=curve_radius) for curve in curves
            ]
        case Mesh() as mesh:
            obj = _from_mesh(
                mesh, color, mode, curve_radius=curve_radius, point_radius=point_radius
            )
            if obj is not None:
                objects.append(obj)
            else:
                # emtpy object
                pass
        case _:
            raise Exception(em.should_never_happen)

    group = k3d.objects.Group(objects)
    for obj in group:
        obj.color = color
        if isinstance(obj, k3d.objects.Line):
            obj.width = curve_radius

    return group


[docs]def convert( convertible, color=0x888888, curve_sampling=_default_curve_sampling, surface_sampling=_default_surface_sampling, subspace_size=_default_subspace_size, curve_radius=_default_curve_radius, point_radius=_default_point_radius, ): """Convert pyddg objects, points, curves and meshes to K3D objects. Default conversion mode showing faces. Parameters ---------- convertible: The object to convert color: int, hexadecimal between 0x000000 and 0xffffff RGB color value as hexadecimal interger curve_sampling : tuple of an int and a float (default=_default_curve_sampling) Determines the sample number and stepsize for curves surface_sampling : tuple of an int and a float (default=_default_surface_sampling) Determines the sample number and stepsize for surfaces subspace_size : float (default=_default_subspace_size) Determines the size of subspaces curve_radius : float (default=_default_curve_radius) Radius for curves, set as `bobj.data.bevel_depth` point_radius : float (default=_default_point_radius) Radius of the sphere representing points Returns ------- k3d.objects.Group """ return _to_k3d( convertible, color=color, mode="FACES", curve_sampling=curve_sampling, surface_sampling=surface_sampling, subspace_size=subspace_size, curve_radius=curve_radius, point_radius=point_radius, )
[docs]def edges( convertible, color=0x000000, radius=_default_curve_radius, curve_sampling=_default_curve_sampling, surface_sampling=_default_surface_sampling, subspace_size=_default_subspace_size, ): """Convert pyddg objects, points, curves and meshes to K3D objects. Special conversion mode showing edges. Parameters ---------- convertible: The object to convert color: int, hexadecimal between 0x000000 and 0xffffff RGB color value as hexadecimal interger radius : float (default=_default_curve_radius) Sets the radius of the edges as `bobj.data.bevel_depth` curve_sampling : tuple of an int and a float (default=_default_curve_sampling) Determines the sample number and stepsize for curves surface_sampling : tuple of an int and a float (default=_default_surface_sampling) Determines the sample number and stepsize for surfaces subspace_size : float (default=_default_subspace_size) Determines the size of subspaces Returns ------- k3d.objects.Group """ return _to_k3d( convertible, color=color, mode="EDGES", curve_sampling=curve_sampling, surface_sampling=surface_sampling, subspace_size=subspace_size, curve_radius=radius, )
[docs]def vertices( convertible, color=0x000000, radius=_default_point_radius, curve_sampling=_default_curve_sampling, surface_sampling=_default_surface_sampling, subspace_size=_default_subspace_size, ): """Convert pyddg objects, points, curves and meshes to K3D objects. Special conversion mode showing points as spheres. Parameters ---------- convertible: The object to convert color: int, hexadecimal between 0x000000 and 0xffffff RGB color value as hexadecimal interger curve_sampling : tuple of an int and a float (default=_default_curve_sampling) Determines the sample number and stepsize for curves surface_sampling : tuple of an int and a float (default=_default_surface_sampling) Determines the sample number and stepsize for surfaces subspace_size : float (default=_default_subspace_size) Determines the size of subspaces Returns ------- k3d.objects.Group """ return _to_k3d( convertible, color=color, mode="POINTS", curve_sampling=curve_sampling, surface_sampling=surface_sampling, subspace_size=subspace_size, point_radius=radius, )
[docs]def setup_plot(): """Setup and return a K3D plot. Returns ------- k3d.plot.Plot """ return k3d.plot( grid_visible=False, camera_mode="orbit", camera_auto_fit=False, antialias=5 )
[docs]def clear_plot(plot): """Remove objects from plot Parameters ---------- plot: k3d.plot.Plot Plot from which to remove the objects from. """ while plot.objects: obj = plot.objects[0] plot -= obj
[docs]def show_3d(*drawables): """Plot a 3D scene containing the drawables. Parameters ---------- drawables: k3d.objects.Drawable The objects to plot. Returns ------- k3d.plot.Plot """ plot = setup_plot() camera_positon = [0, -8, 3] camera_target = [0, 0, 0] camera_up = [0, 0, 1] plot.camera = camera_positon + camera_target + camera_up for drawable in drawables: plot += drawable return plot
[docs]def show_2d(*drawables): """Plot a 2D scene containing the drawables. Parameters ---------- drawables: k3d.objects.Drawable The objects to plot. Returns ------- k3d.plot.Plot """ plot = setup_plot() plot.camera_fov = 90 plot.lighting = 0 camera_positon = [0, 0, 3] camera_target = [0, 0, 0] camera_up = [0, 1, 0] plot.camera = camera_positon + camera_target + camera_up for drawable in drawables: plot += drawable return plot