Ejemplo n.º 1
0
def arrow(startPoint,
          endPoint,
          c='r',
          s=None,
          alpha=1,
          legend=None,
          texture=None,
          res=12,
          rwSize=(800, 800)):
    '''
    Build a 3D arrow from `startPoint` to `endPoint` of section size `s`,
    expressed as the fraction of the window size.
    
    .. note:: If ``s=None`` the arrow is scaled proportionally to its length,
              otherwise it represents the fraction of the window size.
    '''
    axis = np.array(endPoint) - np.array(startPoint)
    length = np.linalg.norm(axis)
    if not length:
        return None
    axis = axis / length
    theta = np.arccos(axis[2])
    phi = np.arctan2(axis[1], axis[0])
    arr = vtk.vtkArrowSource()
    arr.SetShaftResolution(res)
    arr.SetTipResolution(res)
    if s:
        sz = 0.02
        arr.SetTipRadius(sz)
        arr.SetShaftRadius(sz / 1.75)
        arr.SetTipLength(sz * 15)
    arr.Update()
    t = vtk.vtkTransform()
    t.RotateZ(phi * 57.3)
    t.RotateY(theta * 57.3)
    t.RotateY(-90)  # put it along Z
    if s:
        w, h = rwSize
        sz = (w + h) / 2 * s
        t.Scale(length, sz, sz)
    else:
        t.Scale(length, length, length)
    tf = vtk.vtkTransformPolyDataFilter()
    tf.SetInputData(arr.GetOutput())
    tf.SetTransform(t)
    tf.Update()

    actor = Actor(tf.GetOutput(), c, alpha, legend=legend, texture=texture)
    actor.GetProperty().SetInterpolationToPhong()
    actor.SetPosition(startPoint)
    actor.DragableOff()
    actor.PickableOff()
    actor.base = np.array(startPoint)
    actor.top = np.array(endPoint)
    return actor
Ejemplo n.º 2
0
def Arrow(startPoint, endPoint, s=None, c="r", alpha=1, res=12):
    """
    Build a 3D arrow from `startPoint` to `endPoint` of section size `s`,
    expressed as the fraction of the window size.

    .. note:: If ``s=None`` the arrow is scaled proportionally to its length,
              otherwise it represents the fraction of the window size.

    |OrientedArrow|
    """
    axis = np.array(endPoint) - np.array(startPoint)
    length = np.linalg.norm(axis)
    if length:
        axis = axis / length
    theta = np.arccos(axis[2])
    phi = np.arctan2(axis[1], axis[0])
    arr = vtk.vtkArrowSource()
    arr.SetShaftResolution(res)
    arr.SetTipResolution(res)
    if s:
        sz = 0.02
        arr.SetTipRadius(sz)
        arr.SetShaftRadius(sz / 1.75)
        arr.SetTipLength(sz * 15)
    arr.Update()
    t = vtk.vtkTransform()
    t.RotateZ(np.rad2deg(phi))
    t.RotateY(np.rad2deg(theta))
    t.RotateY(-90)  # put it along Z
    if s:
        sz = 800.0 * s
        t.Scale(length, sz, sz)
    else:
        t.Scale(length, length, length)
    tf = vtk.vtkTransformPolyDataFilter()
    tf.SetInputData(arr.GetOutput())
    tf.SetTransform(t)
    tf.Update()

    actor = Actor(tf.GetOutput(), c, alpha)
    actor.GetProperty().SetInterpolationToPhong()
    actor.SetPosition(startPoint)
    actor.DragableOff()
    actor.PickableOff()
    actor.base = np.array(startPoint)
    actor.top = np.array(endPoint)
    settings.collectable_actors.append(actor)
    return actor
Ejemplo n.º 3
0
def grid(pos=[0, 0, 0],
         normal=[0, 0, 1],
         sx=1,
         sy=1,
         c='g',
         bc='darkgreen',
         lw=1,
         alpha=1,
         legend=None,
         resx=10,
         resy=10):
    '''Return a grid plane.

    .. hint:: Example: `brownian2D.py <https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/brownian2D.py>`_

        .. image:: https://user-images.githubusercontent.com/32848391/50738948-73ce8300-11d9-11e9-8ef6-fc4f64c4a9ce.gif
    '''
    ps = vtk.vtkPlaneSource()
    ps.SetResolution(resx, resy)
    ps.Update()
    poly0 = ps.GetOutput()
    t0 = vtk.vtkTransform()
    t0.Scale(sx, sy, 1)
    tf0 = vtk.vtkTransformPolyDataFilter()
    tf0.SetInputData(poly0)
    tf0.SetTransform(t0)
    tf0.Update()
    poly = tf0.GetOutput()
    axis = np.array(normal) / np.linalg.norm(normal)
    theta = np.arccos(axis[2])
    phi = np.arctan2(axis[1], axis[0])
    t = vtk.vtkTransform()
    t.PostMultiply()
    t.RotateY(theta * 57.3)
    t.RotateZ(phi * 57.3)
    tf = vtk.vtkTransformPolyDataFilter()
    tf.SetInputData(poly)
    tf.SetTransform(t)
    tf.Update()
    pd = tf.GetOutput()
    actor = Actor(pd, c=c, bc=bc, alpha=alpha, legend=legend)
    actor.GetProperty().SetRepresentationToWireframe()
    actor.GetProperty().SetLineWidth(lw)
    actor.SetPosition(pos)
    actor.PickableOff()
    return actor
Ejemplo n.º 4
0
def Grid(pos=(0, 0, 0),
         normal=(0, 0, 1),
         sx=1,
         sy=1,
         c="g",
         bc="darkgreen",
         lw=1,
         alpha=1,
         resx=10,
         resy=10):
    """Return a grid plane.

    .. hint:: |brownian2D| |brownian2D.py|_
    """
    ps = vtk.vtkPlaneSource()
    ps.SetResolution(resx, resy)
    ps.Update()
    poly0 = ps.GetOutput()
    t0 = vtk.vtkTransform()
    t0.Scale(sx, sy, 1)
    tf0 = vtk.vtkTransformPolyDataFilter()
    tf0.SetInputData(poly0)
    tf0.SetTransform(t0)
    tf0.Update()
    poly = tf0.GetOutput()
    axis = np.array(normal) / np.linalg.norm(normal)
    theta = np.arccos(axis[2])
    phi = np.arctan2(axis[1], axis[0])
    t = vtk.vtkTransform()
    t.PostMultiply()
    t.RotateY(theta * 57.3)
    t.RotateZ(phi * 57.3)
    tf = vtk.vtkTransformPolyDataFilter()
    tf.SetInputData(poly)
    tf.SetTransform(t)
    tf.Update()
    pd = tf.GetOutput()
    actor = Actor(pd, c=c, bc=bc, alpha=alpha)
    actor.GetProperty().SetRepresentationToWireframe()
    actor.GetProperty().SetLineWidth(lw)
    actor.SetPosition(pos)
    actor.PickableOff()
    return actor
Ejemplo n.º 5
0
def plane(pos=[0, 0, 0],
          normal=[0, 0, 1],
          sx=1,
          sy=None,
          c='g',
          bc='darkgreen',
          alpha=1,
          legend=None,
          texture=None):
    '''
    Draw a plane of size `sx` and `sy` oriented perpendicular to vector `normal`
    and so that it passes through point `pos`.
    '''
    if sy is None:
        sy = sx
    ps = vtk.vtkPlaneSource()
    ps.SetResolution(1, 1)
    tri = vtk.vtkTriangleFilter()
    tri.SetInputConnection(ps.GetOutputPort())
    tri.Update()
    poly = tri.GetOutput()
    axis = np.array(normal) / np.linalg.norm(normal)
    theta = np.arccos(axis[2])
    phi = np.arctan2(axis[1], axis[0])
    t = vtk.vtkTransform()
    t.PostMultiply()
    t.Scale(sx, sy, 1)
    t.RotateY(theta * 57.3)
    t.RotateZ(phi * 57.3)
    tf = vtk.vtkTransformPolyDataFilter()
    tf.SetInputData(poly)
    tf.SetTransform(t)
    tf.Update()
    pd = tf.GetOutput()
    actor = Actor(pd, c=c, bc=bc, alpha=alpha, legend=legend, texture=texture)
    actor.SetPosition(pos)
    actor.PickableOff()
    return actor
Ejemplo n.º 6
0
def Text(
    txt,
    pos=3,
    normal=(0, 0, 1),
    s=1,
    depth=0.1,
    justify="bottom-left",
    c=None,
    alpha=1,
    bc=None,
    bg=None,
    font="courier",
    followcam=False,
):
    """
    Returns a ``vtkActor`` that shows a 3D text.

    :param pos: position in 3D space,
                if an integer is passed [1,8],
                a 2D text is placed in one of the 4 corners:

                    1, bottom-left
                    2, bottom-right
                    3, top-left
                    4, top-right
                    5, bottom-middle
                    6, middle-right
                    7, middle-left
                    8, top-middle

    :type pos: list, int
    :param float s: size of text.
    :param float depth: text thickness.
    :param str justify: text justification
        (bottom-left, bottom-right, top-left, top-right, centered).
    :param bg: background color of corner annotations. Only applies of `pos` is ``int``.
    :param str font: either `arial`, `courier` or `times`. Only applies of `pos` is ``int``.
    :param followcam: if `True` the text will auto-orient itself to the active camera.
        A ``vtkCamera`` object can also be passed.
    :type followcam: bool, vtkCamera

    .. hint:: |colorcubes.py|_ |markpoint.py|_ |annotations.py|_

        |colorcubes| |markpoint|
    """
    if c is None:  # automatic black or white
        if settings.plotter_instance and settings.plotter_instance.renderer:
            c = (0.9, 0.9, 0.9)
            if np.sum(
                    settings.plotter_instance.renderer.GetBackground()) > 1.5:
                c = (0.1, 0.1, 0.1)
        else:
            c = (0.6, 0.6, 0.6)

    if isinstance(pos, int):
        if pos > 8:
            pos = 8
        if pos < 1:
            pos = 1

        ca = vtk.vtkCornerAnnotation()
        ca.SetNonlinearFontScaleFactor(s / 2.7)
        ca.SetText(pos - 1, str(txt))

        ca.PickableOff()
        cap = ca.GetTextProperty()
        cap.SetColor(colors.getColor(c))
        if font.lower() == "courier":
            cap.SetFontFamilyToCourier()
        elif font.lower() == "times":
            cap.SetFontFamilyToTimes()
        else:
            cap.SetFontFamilyToArial()
        if bg:
            bgcol = colors.getColor(bg)
            cap.SetBackgroundColor(bgcol)
            cap.SetBackgroundOpacity(alpha * 0.5)
            cap.SetFrameColor(bgcol)
            cap.FrameOn()

        setattr(ca, 'renderedAt', set())
        settings.collectable_actors.append(ca)
        return ca

    tt = vtk.vtkVectorText()
    tt.SetText(str(txt))
    tt.Update()
    ttmapper = vtk.vtkPolyDataMapper()
    if followcam:
        depth = 0
        normal = (0, 0, 1)
    if depth:
        extrude = vtk.vtkLinearExtrusionFilter()
        extrude.SetInputConnection(tt.GetOutputPort())
        extrude.SetExtrusionTypeToVectorExtrusion()
        extrude.SetVector(0, 0, 1)
        extrude.SetScaleFactor(depth)
        ttmapper.SetInputConnection(extrude.GetOutputPort())
    else:
        ttmapper.SetInputConnection(tt.GetOutputPort())
    if followcam:
        ttactor = vtk.vtkFollower()
        if isinstance(followcam, vtk.vtkCamera):
            ttactor.SetCamera(followcam)
        else:
            ttactor.SetCamera(settings.plotter_instance.camera)
    else:
        ttactor = Actor()
    ttactor.SetMapper(ttmapper)
    ttactor.GetProperty().SetColor(colors.getColor(c))
    ttmapper.Update()

    bb = tt.GetOutput().GetBounds()
    dx, dy = (bb[1] - bb[0]) / 2 * s, (bb[3] - bb[2]) / 2 * s
    cm = np.array([(bb[1] + bb[0]) / 2, (bb[3] + bb[2]) / 2,
                   (bb[5] + bb[4]) / 2]) * s
    shift = -cm
    if "cent" in justify:
        pass
    elif "bottom-left" in justify:
        shift += np.array([dx, dy, 0])
    elif "top-left" in justify:
        shift += np.array([dx, -dy, 0])
    elif "bottom-right" in justify:
        shift += np.array([-dx, dy, 0])
    elif "top-right" in justify:
        shift += np.array([-dx, -dy, 0])
    else:
        colors.printc("~lightning Text(): Unknown justify type", justify, c=1)

    ttactor.GetProperty().SetOpacity(alpha)

    nax = np.linalg.norm(normal)
    if nax:
        normal = np.array(normal) / nax
    theta = np.arccos(normal[2])
    phi = np.arctan2(normal[1], normal[0])
    ttactor.SetScale(s, s, s)
    ttactor.RotateZ(np.rad2deg(phi))
    ttactor.RotateY(np.rad2deg(theta))
    ttactor.SetPosition(pos + shift)
    if bc:  # defines a specific color for the backface
        backProp = vtk.vtkProperty()
        backProp.SetDiffuseColor(colors.getColor(bc))
        backProp.SetOpacity(alpha)
        ttactor.SetBackfaceProperty(backProp)
    ttactor.PickableOff()
    settings.collectable_actors.append(ttactor)
    return ttactor
Ejemplo n.º 7
0
def hexHistogram(
    xvalues,
    yvalues,
    xtitle="",
    ytitle="",
    ztitle="",
    bins=12,
    norm=1,
    fill=True,
    c=None,
    cmap="terrain_r",
    alpha=1,
):
    """
    Build a hexagonal histogram from a list of x and y values.

    :param bool bins: nr of bins for the smaller range in x or y.
    :param float norm: sets a scaling factor for the z axis (freq. axis).
    :param bool fill: draw solid hexagons.
    :param str cmap: color map name for elevation.

    |histoHexagonal| |histoHexagonal.py|_
    """
    if xtitle:
        from vtkplotter import settings

        settings.xtitle = xtitle
    if ytitle:
        from vtkplotter import settings

        settings.ytitle = ytitle
    if ztitle:
        from vtkplotter import settings

        settings.ztitle = ztitle

    xmin, xmax = np.min(xvalues), np.max(xvalues)
    ymin, ymax = np.min(yvalues), np.max(yvalues)
    dx, dy = xmax - xmin, ymax - ymin

    if xmax - xmin < ymax - ymin:
        n = bins
        m = np.rint(dy / dx * n / 1.2 + 0.5).astype(int)
    else:
        m = bins
        n = np.rint(dx / dy * m * 1.2 + 0.5).astype(int)

    src = vtk.vtkPointSource()
    src.SetNumberOfPoints(len(xvalues))
    src.Update()
    pointsPolydata = src.GetOutput()

    #values = list(zip(xvalues, yvalues))
    values = np.stack((xvalues, yvalues), axis=1)
    zs = [[0.0]] * len(values)
    values = np.append(values, zs, axis=1)

    pointsPolydata.GetPoints().SetData(numpy_to_vtk(values, deep=True))
    cloud = Actor(pointsPolydata)

    col = None
    if c is not None:
        col = colors.getColor(c)

    hexs, binmax = [], 0
    ki, kj = 1.33, 1.12
    r = 0.47 / n * 1.2 * dx
    for i in range(n + 3):
        for j in range(m + 2):
            cyl = vtk.vtkCylinderSource()
            cyl.SetResolution(6)
            cyl.CappingOn()
            cyl.SetRadius(0.5)
            cyl.SetHeight(0.1)
            cyl.Update()
            t = vtk.vtkTransform()
            if not i % 2:
                p = (i / ki, j / kj, 0)
            else:
                p = (i / ki, j / kj + 0.45, 0)
            q = (p[0] / n * 1.2 * dx + xmin, p[1] / m * dy + ymin, 0)
            ids = cloud.closestPoint(q, radius=r, returnIds=True)
            ne = len(ids)
            if fill:
                t.Translate(p[0], p[1], ne / 2)
                t.Scale(1, 1, ne * 10)
            else:
                t.Translate(p[0], p[1], ne)
            t.RotateX(90)  # put it along Z
            tf = vtk.vtkTransformPolyDataFilter()
            tf.SetInputData(cyl.GetOutput())
            tf.SetTransform(t)
            tf.Update()
            if c is None:
                col = i
            h = Actor(tf.GetOutput(), c=col, alpha=alpha).flat()
            h.GetProperty().SetSpecular(0)
            h.GetProperty().SetDiffuse(1)
            h.PickableOff()
            hexs.append(h)
            if ne > binmax:
                binmax = ne

    if cmap is not None:
        for h in hexs:
            z = h.GetBounds()[5]
            col = colors.colorMap(z, cmap, 0, binmax)
            h.color(col)

    asse = Assembly(hexs)
    asse.SetScale(1.2 / n * dx, 1 / m * dy, norm / binmax * (dx + dy) / 4)
    asse.SetPosition(xmin, ymin, 0)
    return asse
Ejemplo n.º 8
0
def histogram2D(xvalues, yvalues, bins=12, norm=1, c='g', alpha=1, fill=False):        
    '''
    Build a 2D hexagonal histogram from a list of x and y values.
    
    bins, nr of bins for the smaller range in x or y
    
    norm, sets a scaling factor for the z axis
    
    fill, draw solid hexagons
    '''       
    xmin, xmax = np.min(xvalues), np.max(xvalues)
    ymin, ymax = np.min(yvalues), np.max(yvalues)
    dx, dy = xmax-xmin, ymax-ymin
    
    if xmax-xmin < ymax - ymin:
        n = bins
        m = np.rint(dy/dx*n/1.2+.5).astype(int)
    else:
        m = bins
        n = np.rint(dx/dy*m*1.2+.5).astype(int)
   
    src = vtk.vtkPointSource()
    src.SetNumberOfPoints(len(xvalues))
    src.Update()
    pointsPolydata = src.GetOutput()
    
    values = list(zip(xvalues, yvalues))
    zs = [[0.0]]*len(values) 
    values = np.append(values, zs, axis=1)

    pointsPolydata.GetPoints().SetData(numpy_to_vtk(values, deep=True))
    cloud = Actor(pointsPolydata)
    
    c1 = vc.getColor(c)
    c2 = np.array(c1)*.7
    r = 0.47/n*1.2*dx

    hexs, binmax = [], 0
    for i in range(n+3):
        for j in range(m+2):
            cyl = vtk.vtkCylinderSource()
            cyl.SetResolution(6)
            cyl.CappingOn()
            cyl.SetRadius(0.5)
            cyl.SetHeight(0.1)
            cyl.Update()
            t = vtk.vtkTransform()
            if not i%2:
                p = (i/1.33, j/1.12, 0) 
                c = c1
            else:
                p = (i/1.33, j/1.12+0.443, 0)
                c = c2
            q = (p[0]/n*1.2*dx+xmin, p[1]/m*dy+ymin, 0)
            ids = cloud.closestPoint(q, radius=r, returnIds=True)
            ne = len(ids)
            if fill:
                t.Translate(p[0], p[1], ne/2)
                t.Scale(1, 1, ne*5)
            else:
                t.Translate(p[0], p[1], ne)
            t.RotateX(90)  # put it along Z
            tf = vtk.vtkTransformPolyDataFilter()
            tf.SetInputData(cyl.GetOutput())
            tf.SetTransform(t)
            tf.Update()
            h = Actor(tf.GetOutput(), c=c, alpha=alpha)
            h.PickableOff()
            hexs.append(h)
            if ne > binmax:
                binmax = ne

    asse = Assembly(hexs)
    asse.PickableOff()
    asse.SetScale(1/n*1.2*dx, 1/m*dy, norm/binmax*(dx+dy)/4)
    asse.SetPosition(xmin,ymin,0)
    return asse
Ejemplo n.º 9
0
def addAxes(axtype=None, c=None):
    """Draw axes on scene. Available axes types:

    :param int axtype:

          - 0,  no axes,
          - 1,  draw three gray grid walls
          - 2,  show cartesian axes from (0,0,0)
          - 3,  show positive range of cartesian axes from (0,0,0)
          - 4,  show a triad at bottom left
          - 5,  show a cube at bottom left
          - 6,  mark the corners of the bounding box
          - 7,  draw a simple ruler at the bottom of the window
          - 8,  show the ``vtkCubeAxesActor`` object
          - 9,  show the bounding box outLine
          - 10, show three circles representing the maximum bounding box
    """
    vp = settings.plotter_instance
    if axtype is not None:
        vp.axes = axtype  # overrride

    r = vp.renderers.index(vp.renderer)

    if not vp.axes:
        return

    if c is None:  # automatic black or white
        c = (0.9, 0.9, 0.9)
        if numpy.sum(vp.renderer.GetBackground()) > 1.5:
            c = (0.1, 0.1, 0.1)

    if not vp.renderer:
        return

    if vp.axes_exist[r]:
        return

    # calculate max actors bounds
    bns = []
    for a in vp.actors:
        if a and a.GetPickable():
            b = a.GetBounds()
            if b:
                bns.append(b)
    if len(bns):
        max_bns = numpy.max(bns, axis=0)
        min_bns = numpy.min(bns, axis=0)
        vbb = (min_bns[0], max_bns[1], min_bns[2], max_bns[3], min_bns[4],
               max_bns[5])
    else:
        vbb = vp.renderer.ComputeVisiblePropBounds()
        max_bns = vbb
        min_bns = vbb
    sizes = (max_bns[1] - min_bns[0], max_bns[3] - min_bns[2],
             max_bns[5] - min_bns[4])

    ############################################################
    if vp.axes == 1 or vp.axes == True:  # gray grid walls
        nd = 4  # number of divisions in the smallest axis
        off = -0.04  # label offset
        step = numpy.min(sizes) / nd
        if not step:
            # bad proportions, use vtkCubeAxesActor
            vp.addAxes(axtype=8, c=c)
            vp.axes = 1
            return

        rx, ry, rz = numpy.rint(sizes / step).astype(int)
        if max([rx / ry, ry / rx, rx / rz, rz / rx, ry / rz, rz / ry]) > 15:
            # bad proportions, use vtkCubeAxesActor
            vp.addAxes(axtype=8, c=c)
            vp.axes = 1
            return

        gxy = shapes.Grid(pos=(0.5, 0.5, 0),
                          normal=[0, 0, 1],
                          bc=None,
                          resx=rx,
                          resy=ry)
        gxz = shapes.Grid(pos=(0.5, 0, 0.5),
                          normal=[0, 1, 0],
                          bc=None,
                          resx=rz,
                          resy=rx)
        gyz = shapes.Grid(pos=(0, 0.5, 0.5),
                          normal=[1, 0, 0],
                          bc=None,
                          resx=rz,
                          resy=ry)
        gxy.alpha(0.06).wire(False).color(c).lineWidth(1)
        gxz.alpha(0.04).wire(False).color(c).lineWidth(1)
        gyz.alpha(0.04).wire(False).color(c).lineWidth(1)

        xa = shapes.Line([0, 0, 0], [1, 0, 0], c=c, lw=1)
        ya = shapes.Line([0, 0, 0], [0, 1, 0], c=c, lw=1)
        za = shapes.Line([0, 0, 0], [0, 0, 1], c=c, lw=1)

        xt, yt, zt, ox, oy, oz = [None] * 6
        if vp.xtitle:
            xtitle = vp.xtitle
            if min_bns[0] <= 0 and max_bns[1] > 0:  # mark x origin
                ox = shapes.Cube([-min_bns[0] / sizes[0], 0, 0],
                                 side=0.008,
                                 c=c)
            if len(vp.xtitle) == 1:  # add axis length info
                xtitle = vp.xtitle + " /" + utils.precision(sizes[0], 4)
            wpos = [1 - (len(vp.xtitle) + 1) / 40, off, 0]
            xt = shapes.Text(xtitle,
                             pos=wpos,
                             normal=(0, 0, 1),
                             s=0.025,
                             c=c,
                             justify="bottom-right")

        if vp.ytitle:
            if min_bns[2] <= 0 and max_bns[3] > 0:  # mark y origin
                oy = shapes.Cube([0, -min_bns[2] / sizes[1], 0],
                                 side=0.008,
                                 c=c)
            yt = shapes.Text(vp.ytitle,
                             pos=(0, 0, 0),
                             normal=(0, 0, 1),
                             s=0.025,
                             c=c,
                             justify="bottom-right")
            if len(vp.ytitle) == 1:
                wpos = [off, 1 - (len(vp.ytitle) + 1) / 40, 0]
                yt.pos(wpos)
            else:
                wpos = [off * 0.7, 1 - (len(vp.ytitle) + 1) / 40, 0]
                yt.rotateZ(90).pos(wpos)

        if vp.ztitle:
            if min_bns[4] <= 0 and max_bns[5] > 0:  # mark z origin
                oz = shapes.Cube([0, 0, -min_bns[4] / sizes[2]],
                                 side=0.008,
                                 c=c)
            zt = shapes.Text(vp.ztitle,
                             pos=(0, 0, 0),
                             normal=(1, -1, 0),
                             s=0.025,
                             c=c,
                             justify="bottom-right")
            if len(vp.ztitle) == 1:
                wpos = [off * 0.6, off * 0.6, 1 - (len(vp.ztitle) + 1) / 40]
                zt.rotate(90, (1, -1, 0)).pos(wpos)
            else:
                wpos = [off * 0.3, off * 0.3, 1 - (len(vp.ztitle) + 1) / 40]
                zt.rotate(180, (1, -1, 0)).pos(wpos)

        acts = [gxy, gxz, gyz, xa, ya, za, xt, yt, zt, ox, oy, oz]
        for a in acts:
            if a:
                a.PickableOff()
        aa = Assembly(acts)
        aa.pos(min_bns[0], min_bns[2], min_bns[4])
        aa.SetScale(sizes)
        aa.PickableOff()
        vp.renderer.AddActor(aa)
        vp.axes_exist[r] = aa

    elif vp.axes == 2 or vp.axes == 3:
        vbb = vp.renderer.ComputeVisiblePropBounds()  # to be double checked
        xcol, ycol, zcol = "db", "dg", "dr"
        s = 1
        alpha = 1
        centered = False
        x0, x1, y0, y1, z0, z1 = vbb
        dx, dy, dz = x1 - x0, y1 - y0, z1 - z0
        aves = numpy.sqrt(dx * dx + dy * dy + dz * dz) / 2
        x0, x1 = min(x0, 0), max(x1, 0)
        y0, y1 = min(y0, 0), max(y1, 0)
        z0, z1 = min(z0, 0), max(z1, 0)

        if vp.axes == 3:
            if x1 > 0:
                x0 = 0
            if y1 > 0:
                y0 = 0
            if z1 > 0:
                z0 = 0

        dx, dy, dz = x1 - x0, y1 - y0, z1 - z0
        acts = []
        if x0 * x1 <= 0 or y0 * z1 <= 0 or z0 * z1 <= 0:  # some ranges contain origin
            zero = shapes.Sphere(r=aves / 120 * s, c="k", alpha=alpha, res=10)
            acts += [zero]

        if len(vp.xtitle) and dx > aves / 100:
            xl = shapes.Cylinder([[x0, 0, 0], [x1, 0, 0]],
                                 r=aves / 250 * s,
                                 c=xcol,
                                 alpha=alpha)
            xc = shapes.Cone(pos=[x1, 0, 0],
                             c=xcol,
                             alpha=alpha,
                             r=aves / 100 * s,
                             height=aves / 25 * s,
                             axis=[1, 0, 0],
                             res=10)
            wpos = [
                x1 - (len(vp.xtitle) + 1) * aves / 40 * s, -aves / 25 * s, 0
            ]  # aligned to arrow tip
            if centered:
                wpos = [(x0 + x1) / 2 - len(vp.xtitle) / 2 * aves / 40 * s,
                        -aves / 25 * s, 0]
            xt = shapes.Text(vp.xtitle,
                             pos=wpos,
                             normal=(0, 0, 1),
                             s=aves / 40 * s,
                             c=xcol)
            acts += [xl, xc, xt]

        if len(vp.ytitle) and dy > aves / 100:
            yl = shapes.Cylinder([[0, y0, 0], [0, y1, 0]],
                                 r=aves / 250 * s,
                                 c=ycol,
                                 alpha=alpha)
            yc = shapes.Cone(pos=[0, y1, 0],
                             c=ycol,
                             alpha=alpha,
                             r=aves / 100 * s,
                             height=aves / 25 * s,
                             axis=[0, 1, 0],
                             res=10)
            wpos = [
                -aves / 40 * s, y1 - (len(vp.ytitle) + 1) * aves / 40 * s, 0
            ]
            if centered:
                wpos = [
                    -aves / 40 * s,
                    (y0 + y1) / 2 - len(vp.ytitle) / 2 * aves / 40 * s, 0
                ]
            yt = shapes.Text(vp.ytitle,
                             pos=(0, 0, 0),
                             normal=(0, 0, 1),
                             s=aves / 40 * s,
                             c=ycol)
            yt.rotate(90, [0, 0, 1]).pos(wpos)
            acts += [yl, yc, yt]

        if len(vp.ztitle) and dz > aves / 100:
            zl = shapes.Cylinder([[0, 0, z0], [0, 0, z1]],
                                 r=aves / 250 * s,
                                 c=zcol,
                                 alpha=alpha)
            zc = shapes.Cone(pos=[0, 0, z1],
                             c=zcol,
                             alpha=alpha,
                             r=aves / 100 * s,
                             height=aves / 25 * s,
                             axis=[0, 0, 1],
                             res=10)
            wpos = [
                -aves / 50 * s, -aves / 50 * s,
                z1 - (len(vp.ztitle) + 1) * aves / 40 * s
            ]
            if centered:
                wpos = [
                    -aves / 50 * s, -aves / 50 * s,
                    (z0 + z1) / 2 - len(vp.ztitle) / 2 * aves / 40 * s
                ]
            zt = shapes.Text(vp.ztitle,
                             pos=(0, 0, 0),
                             normal=(1, -1, 0),
                             s=aves / 40 * s,
                             c=zcol)
            zt.rotate(180, (1, -1, 0)).pos(wpos)
            acts += [zl, zc, zt]
        for a in acts:
            a.PickableOff()
        ass = Assembly(acts)
        ass.PickableOff()
        vp.renderer.AddActor(ass)
        vp.axes_exist[r] = ass

    elif vp.axes == 4:
        axact = vtk.vtkAxesActor()
        axact.SetShaftTypeToCylinder()
        axact.SetCylinderRadius(0.03)
        axact.SetXAxisLabelText(vp.xtitle)
        axact.SetYAxisLabelText(vp.ytitle)
        axact.SetZAxisLabelText(vp.ztitle)
        axact.GetXAxisShaftProperty().SetColor(0, 0, 1)
        axact.GetZAxisShaftProperty().SetColor(1, 0, 0)
        axact.GetXAxisTipProperty().SetColor(0, 0, 1)
        axact.GetZAxisTipProperty().SetColor(1, 0, 0)
        bc = numpy.array(vp.renderer.GetBackground())
        if numpy.sum(bc) < 1.5:
            lc = (1, 1, 1)
        else:
            lc = (0, 0, 0)
        axact.GetXAxisCaptionActor2D().GetCaptionTextProperty().BoldOff()
        axact.GetYAxisCaptionActor2D().GetCaptionTextProperty().BoldOff()
        axact.GetZAxisCaptionActor2D().GetCaptionTextProperty().BoldOff()
        axact.GetXAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff()
        axact.GetYAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff()
        axact.GetZAxisCaptionActor2D().GetCaptionTextProperty().ItalicOff()
        axact.GetXAxisCaptionActor2D().GetCaptionTextProperty().ShadowOff()
        axact.GetYAxisCaptionActor2D().GetCaptionTextProperty().ShadowOff()
        axact.GetZAxisCaptionActor2D().GetCaptionTextProperty().ShadowOff()
        axact.GetXAxisCaptionActor2D().GetCaptionTextProperty().SetColor(lc)
        axact.GetYAxisCaptionActor2D().GetCaptionTextProperty().SetColor(lc)
        axact.GetZAxisCaptionActor2D().GetCaptionTextProperty().SetColor(lc)
        axact.PickableOff()
        icn = addIcon(axact, size=0.1)
        vp.axes_exist[r] = icn

    elif vp.axes == 5:
        axact = vtk.vtkAnnotatedCubeActor()
        axact.GetCubeProperty().SetColor(0.75, 0.75, 0.75)
        axact.SetTextEdgesVisibility(0)
        axact.SetFaceTextScale(0.4)
        axact.GetXPlusFaceProperty().SetColor(colors.getColor("b"))
        axact.GetXMinusFaceProperty().SetColor(colors.getColor("db"))
        axact.GetYPlusFaceProperty().SetColor(colors.getColor("g"))
        axact.GetYMinusFaceProperty().SetColor(colors.getColor("dg"))
        axact.GetZPlusFaceProperty().SetColor(colors.getColor("r"))
        axact.GetZMinusFaceProperty().SetColor(colors.getColor("dr"))
        axact.PickableOff()
        icn = addIcon(axact, size=0.06)
        vp.axes_exist[r] = icn

    elif vp.axes == 6:
        ocf = vtk.vtkOutlineCornerFilter()
        ocf.SetCornerFactor(0.1)
        largestact, sz = None, -1
        for a in vp.actors:
            if a.GetPickable():
                b = a.GetBounds()
                d = max(b[1] - b[0], b[3] - b[2], b[5] - b[4])
                if sz < d:
                    largestact = a
                    sz = d
        if isinstance(largestact, Assembly):
            ocf.SetInputData(largestact.getActor(0).GetMapper().GetInput())
        else:
            ocf.SetInputData(largestact.polydata())
        ocf.Update()
        ocMapper = vtk.vtkHierarchicalPolyDataMapper()
        ocMapper.SetInputConnection(0, ocf.GetOutputPort(0))
        ocActor = vtk.vtkActor()
        ocActor.SetMapper(ocMapper)
        bc = numpy.array(vp.renderer.GetBackground())
        if numpy.sum(bc) < 1.5:
            lc = (1, 1, 1)
        else:
            lc = (0, 0, 0)
        ocActor.GetProperty().SetColor(lc)
        ocActor.PickableOff()
        vp.renderer.AddActor(ocActor)
        vp.axes_exist[r] = ocActor

    elif vp.axes == 7:
        # draws a simple ruler at the bottom of the window
        ls = vtk.vtkLegendScaleActor()
        ls.RightAxisVisibilityOff()
        ls.TopAxisVisibilityOff()
        ls.LegendVisibilityOff()
        ls.LeftAxisVisibilityOff()
        ls.GetBottomAxis().SetNumberOfMinorTicks(1)
        ls.GetBottomAxis().GetProperty().SetColor(c)
        ls.GetBottomAxis().GetLabelTextProperty().SetColor(c)
        ls.GetBottomAxis().GetLabelTextProperty().BoldOff()
        ls.GetBottomAxis().GetLabelTextProperty().ItalicOff()
        ls.GetBottomAxis().GetLabelTextProperty().ShadowOff()
        ls.PickableOff()
        vp.renderer.AddActor(ls)
        vp.axes_exist[r] = ls

    elif vp.axes == 8:
        ca = vtk.vtkCubeAxesActor()
        ca.SetBounds(vbb)
        if vp.camera:
            ca.SetCamera(vp.camera)
        else:
            ca.SetCamera(vp.renderer.GetActiveCamera())
        ca.GetXAxesLinesProperty().SetColor(c)
        ca.GetYAxesLinesProperty().SetColor(c)
        ca.GetZAxesLinesProperty().SetColor(c)
        for i in range(3):
            ca.GetLabelTextProperty(i).SetColor(c)
            ca.GetTitleTextProperty(i).SetColor(c)
        ca.SetTitleOffset(5)
        ca.SetFlyMode(3)
        ca.SetXTitle(vp.xtitle)
        ca.SetYTitle(vp.ytitle)
        ca.SetZTitle(vp.ztitle)
        if vp.xtitle == "":
            ca.SetXAxisVisibility(0)
            ca.XAxisLabelVisibilityOff()
        if vp.ytitle == "":
            ca.SetYAxisVisibility(0)
            ca.YAxisLabelVisibilityOff()
        if vp.ztitle == "":
            ca.SetZAxisVisibility(0)
            ca.ZAxisLabelVisibilityOff()
        ca.PickableOff()
        vp.renderer.AddActor(ca)
        vp.axes_exist[r] = ca
        return

    elif vp.axes == 9:
        src = vtk.vtkCubeSource()
        src.SetXLength(vbb[1] - vbb[0])
        src.SetYLength(vbb[3] - vbb[2])
        src.SetZLength(vbb[5] - vbb[4])
        src.Update()
        ca = Actor(src.GetOutput(), c=c, alpha=0.5, wire=1)
        ca.pos((vbb[0] + vbb[1]) / 2, (vbb[3] + vbb[2]) / 2,
               (vbb[5] + vbb[4]) / 2)
        ca.PickableOff()
        vp.renderer.AddActor(ca)
        vp.axes_exist[r] = ca

    elif vp.axes == 10:
        x0 = (vbb[0] + vbb[1]) / 2, (vbb[3] + vbb[2]) / 2, (vbb[5] +
                                                            vbb[4]) / 2
        rx, ry, rz = (vbb[1] - vbb[0]) / 2, (vbb[3] - vbb[2]) / 2, (vbb[5] -
                                                                    vbb[4]) / 2
        rm = max(rx, ry, rz)
        xc = shapes.Disc(x0, (0, 0, 1),
                         r1=rm,
                         r2=rm,
                         c='lr',
                         bc=None,
                         res=1,
                         resphi=72)
        yc = shapes.Disc(x0, (0, 1, 0),
                         r1=rm,
                         r2=rm,
                         c='lg',
                         bc=None,
                         res=1,
                         resphi=72)
        zc = shapes.Disc(x0, (1, 0, 0),
                         r1=rm,
                         r2=rm,
                         c='lb',
                         bc=None,
                         res=1,
                         resphi=72)
        xc.clean().alpha(0.2).wire().lineWidth(2.5).PickableOff()
        yc.clean().alpha(0.2).wire().lineWidth(2.5).PickableOff()
        zc.clean().alpha(0.2).wire().lineWidth(2.5).PickableOff()
        ca = xc + yc + zc
        ca.PickableOff()
        vp.renderer.AddActor(ca)
        vp.axes_exist[r] = ca

    else:
        colors.printc('~bomb Keyword axes must be in range [0-10].', c=1)
        colors.printc('''
  ~target Available axes types:
  0 = no axes,
  1 = draw three gray grid walls
  2 = show cartesian axes from (0,0,0)
  3 = show positive range of cartesian axes from (0,0,0)
  4 = show a triad at bottom left
  5 = show a cube at bottom left
  6 = mark the corners of the bounding box
  7 = draw a simple ruler at the bottom of the window
  8 = show the vtkCubeAxesActor object
  9 = show the bounding box outline
  10 = show three circles representing the maximum bounding box
  ''',
                      c=1,
                      bold=0)

    if not vp.axes_exist[r]:
        vp.axes_exist[r] = True
    return
Ejemplo n.º 10
0
def text(txt,
         pos=(0, 0, 0),
         normal=(0, 0, 1),
         s=1,
         depth=0.1,
         justify='bottom-left',
         c='k',
         alpha=1,
         bc=None,
         texture=None,
         followcam=False,
         cam=None):
    '''
    Returns a ``vtkActor`` that shows a 3D text.

    :param pos: position in 3D space, 
                if an integer is passed [1,8], place text in one of the 4 corners.
    :type pos: list, int
    :param float s: size of text.
    :param float depth: text thickness.
    :param str justify: text justification (bottom-left, bottom-right, top-left, top-right, centered).
    :param bool followcam: if `True` the text will auto-orient itself to the cam.

    .. hint:: Example: `colorcubes.py <https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/colorcubes.py>`_
    
        .. image:: https://user-images.githubusercontent.com/32848391/50738867-c0658e80-11d8-11e9-9e05-ac69b546b7ec.png
    '''
    if isinstance(pos, int):
        cornerAnnotation = vtk.vtkCornerAnnotation()
        cornerAnnotation.SetNonlinearFontScaleFactor(s / 3)
        cornerAnnotation.SetText(pos - 1, str(txt))
        cornerAnnotation.GetTextProperty().SetColor(colors.getColor(c))
        return cornerAnnotation

    tt = vtk.vtkVectorText()
    tt.SetText(str(txt))
    tt.Update()
    ttmapper = vtk.vtkPolyDataMapper()
    if followcam:
        depth = 0
        normal = (0, 0, 1)
    if depth:
        extrude = vtk.vtkLinearExtrusionFilter()
        extrude.SetInputConnection(tt.GetOutputPort())
        extrude.SetExtrusionTypeToVectorExtrusion()
        extrude.SetVector(0, 0, 1)
        extrude.SetScaleFactor(depth)
        ttmapper.SetInputConnection(extrude.GetOutputPort())
    else:
        ttmapper.SetInputConnection(tt.GetOutputPort())
    if followcam:
        ttactor = vtk.vtkFollower()
        ttactor.SetCamera(cam)
    else:
        ttactor = Actor()
    ttactor.SetMapper(ttmapper)
    ttactor.GetProperty().SetColor(colors.getColor(c))
    ttmapper.Update()

    bb = tt.GetOutput().GetBounds()
    dx, dy = (bb[1] - bb[0]) / 2 * s, (bb[3] - bb[2]) / 2 * s
    cm = np.array([(bb[1] + bb[0]) / 2, (bb[3] + bb[2]) / 2,
                   (bb[5] + bb[4]) / 2]) * s
    shift = -cm
    if 'cent' in justify:
        pass
    elif 'bottom-left' in justify:
        shift += np.array([dx, dy, 0])
    elif 'top-left' in justify:
        shift += np.array([dx, -dy, 0])
    elif 'bottom-right' in justify:
        shift += np.array([-dx, dy, 0])
    elif 'top-right' in justify:
        shift += np.array([-dx, -dy, 0])
    else:
        colors.printc("text(): Unknown justify type", justify, c=1)

    # check if color string contains a float, in this case ignore alpha
    al = colors._getAlpha(c)
    if al:
        alpha = al
    ttactor.GetProperty().SetOpacity(alpha)

    nax = np.linalg.norm(normal)
    if nax:
        normal = np.array(normal) / nax
    theta = np.arccos(normal[2])
    phi = np.arctan2(normal[1], normal[0])
    ttactor.SetScale(s, s, s)
    ttactor.RotateZ(phi * 57.3)
    ttactor.RotateY(theta * 57.3)
    ttactor.SetPosition(pos + shift)
    if bc:  # defines a specific color for the backface
        backProp = vtk.vtkProperty()
        backProp.SetDiffuseColor(colors.getColor(bc))
        backProp.SetOpacity(alpha)
        ttactor.SetBackfaceProperty(backProp)
    if texture:
        ttactor.texture(texture)
    ttactor.PickableOff()
    return ttactor