Ejemplo n.º 1
0
def _keypress(iren, event):
    # qt creates and passes a vtkGenericRenderWindowInteractor

    vp = settings.plotter_instance
    key = iren.GetKeySym()
    #print('Pressed key:', key, [vp])

    if key in ["q", "Q", "space", "Return"]:
        iren.ExitCallback()
        return

    elif key == "Escape":
        sys.stdout.flush()
        settings.plotter_instance.closeWindow()

    elif key in ["F1", "Pause"]:
        sys.stdout.flush()
        colors.printc('\n[F1] Execution aborted. Exiting python now.')
        settings.plotter_instance.closeWindow()
        sys.exit(0)

    elif key == "m":
        if vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetOpacity(0.02)
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp and hasattr(vp.clickedActor, "_bfprop"):
                vp.clickedActor._bfprop = bfp  # save it
                vp.clickedActor.SetBackfaceProperty(None)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    a.GetProperty().SetOpacity(0.02)
                    bfp = a.GetBackfaceProperty()
                    if bfp and hasattr(a, "_bfprop"):
                        a._bfprop = bfp
                        a.SetBackfaceProperty(None)

    elif key == "comma":
        if vp.clickedActor in vp.getActors():
            ap = vp.clickedActor.GetProperty()
            aal = max([ap.GetOpacity() * 0.75, 0.01])
            ap.SetOpacity(aal)
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp and hasattr(vp.clickedActor, "_bfprop"):
                vp.clickedActor._bfprop = bfp
                vp.clickedActor.SetBackfaceProperty(None)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    ap = a.GetProperty()
                    aal = max([ap.GetOpacity() * 0.75, 0.01])
                    ap.SetOpacity(aal)
                    bfp = a.GetBackfaceProperty()
                    if bfp and hasattr(a, "_bfprop"):
                        a._bfprop = bfp
                        a.SetBackfaceProperty(None)

    elif key == "period":
        if vp.clickedActor in vp.getActors():
            ap = vp.clickedActor.GetProperty()
            aal = min([ap.GetOpacity() * 1.25, 1.0])
            ap.SetOpacity(aal)
            if aal == 1 and hasattr(vp.clickedActor,
                                    "_bfprop") and vp.clickedActor._bfprop:
                # put back
                vp.clickedActor.SetBackfaceProperty(vp.clickedActor._bfprop)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    ap = a.GetProperty()
                    aal = min([ap.GetOpacity() * 1.25, 1.0])
                    ap.SetOpacity(aal)
                    if aal == 1 and hasattr(a, "_bfprop") and a._bfprop:
                        a.SetBackfaceProperty(a._bfprop)

    elif key == "slash":
        if vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetOpacity(1)
            if hasattr(vp.clickedActor, "_bfprop") and vp.clickedActor._bfprop:
                vp.clickedActor.SetBackfaceProperty(vp.clickedActor._bfprop)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    a.GetProperty().SetOpacity(1)
                    if hasattr(a, "_bfprop") and a._bfprop:
                        a.clickedActor.SetBackfaceProperty(a._bfprop)

    elif key == "P":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if ia.GetPickable():
                try:
                    ps = ia.GetProperty().GetPointSize()
                    if ps > 1:
                        ia.GetProperty().SetPointSize(ps - 1)
                    ia.GetProperty().SetRepresentationToPoints()
                except AttributeError:
                    pass

    elif key == "p":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if ia.GetPickable():
                try:
                    ps = ia.GetProperty().GetPointSize()
                    ia.GetProperty().SetPointSize(ps + 2)
                    ia.GetProperty().SetRepresentationToPoints()
                except AttributeError:
                    pass

    elif key == "w":
        if vp.clickedActor and vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetRepresentationToWireframe()
        else:
            for a in vp.getActors():
                if a and a.GetPickable():
                    if a.GetProperty().GetRepresentation() == 1:  # toggle
                        a.GetProperty().SetRepresentationToSurface()
                    else:
                        a.GetProperty().SetRepresentationToWireframe()

    elif key == "r":
        vp.renderer.ResetCamera()

    #############################################################
    ### now intercept custom observer ###########################
    #############################################################
    if vp.keyPressFunction:
        if key not in ["Shift_L", "Control_L", "Super_L", "Alt_L"]:
            if key not in ["Shift_R", "Control_R", "Super_R", "Alt_R"]:
                vp.verbose = False
                vp.keyPressFunction(key)
                return

    if key == "h":
        from vtkplotter.docs import tips

        tips()
        return

    if key == "a":
        iren.ExitCallback()
        cur = iren.GetInteractorStyle()
        if isinstance(cur, vtk.vtkInteractorStyleTrackballCamera):
            print("\nInteractor style changed to TrackballActor")
            print("  you can now move and rotate individual meshes:")
            print("  press X twice to save the repositioned mesh,")
            print("  press 'a' to go back to normal style.")
            iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballActor())
        else:
            iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
        iren.Start()
        return

    if key == "j":
        iren.ExitCallback()
        cur = iren.GetInteractorStyle()
        if isinstance(cur, vtk.vtkInteractorStyleJoystickCamera):
            iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
        else:
            print("\nInteractor style changed to Joystick,", end="")
            print(" press j to go back to normal.")
            iren.SetInteractorStyle(vtk.vtkInteractorStyleJoystickCamera())
        iren.Start()
        return

    if key == "S":
        screenshot("screenshot.png")
        colors.printc("~camera Saved rendering window as screenshot.png",
                      c="blue")
        return

    if key == "C":
        cam = vp.renderer.GetActiveCamera()
        print('\n### Example code to position this vtkCamera:')
        print('vp = vtkplotter.Plotter()\n...')
        print('vp.camera.SetPosition(',
              [round(e, 3) for e in cam.GetPosition()], ')')
        print('vp.camera.SetFocalPoint(',
              [round(e, 3) for e in cam.GetFocalPoint()], ')')
        print('vp.camera.SetViewUp(', [round(e, 3) for e in cam.GetViewUp()],
              ')')
        print('vp.camera.SetDistance(', round(cam.GetDistance(), 3), ')')
        print('vp.camera.SetClippingRange(',
              [round(e, 3) for e in cam.GetClippingRange()], ')')
        return

    if key == "s":
        if vp.clickedActor and vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetRepresentationToSurface()
        else:
            for a in vp.getActors():
                if a and a.GetPickable():
                    a.GetProperty().SetRepresentationToSurface()

    elif key == "V":
        if not (vp.verbose):
            vp._tips()
        vp.verbose = not (vp.verbose)
        print("Verbose: ", vp.verbose)

    elif key == "1":
        vp.icol += 1
        if vp.clickedActor and hasattr(vp.clickedActor, "GetProperty"):
            vp.clickedActor.GetMapper().ScalarVisibilityOff()
            vp.clickedActor.GetProperty().SetColor(colors.colors1[(vp.icol) %
                                                                  10])
        else:
            for i, ia in enumerate(vp.getActors()):
                if not ia.GetPickable():
                    continue
                ia.GetProperty().SetColor(colors.colors1[(i + vp.icol) % 10])
                ia.GetMapper().ScalarVisibilityOff()
        addons.addLegend()

    elif key == "2":
        vp.icol += 1
        if vp.clickedActor and hasattr(vp.clickedActor, "GetProperty"):
            vp.clickedActor.GetMapper().ScalarVisibilityOff()
            vp.clickedActor.GetProperty().SetColor(colors.colors2[(vp.icol) %
                                                                  10])
        else:
            for i, ia in enumerate(vp.getActors()):
                if not ia.GetPickable():
                    continue
                ia.GetProperty().SetColor(colors.colors2[(i + vp.icol) % 10])
                ia.GetMapper().ScalarVisibilityOff()
        addons.addLegend()

    elif key == "3":
        c = colors.getColor("gold")
        acs = vp.getActors()
        if len(acs) == 0: return
        alpha = 1.0 / len(acs)
        for ia in acs:
            if not ia.GetPickable():
                continue
            ia.GetProperty().SetColor(c)
            ia.GetProperty().SetOpacity(alpha)
            ia.GetMapper().ScalarVisibilityOff()
        addons.addLegend()

    elif key == "4":
        for ia in vp.getActors():
            if not ia.GetPickable():
                continue
            if isinstance(ia, Actor):
                iascals = ia.scalars()
                if len(iascals):
                    stype, sname = iascals[ia._scals_idx]
                    if "ormal" not in sname:  # exclude normals
                        ia.scalars(ia._scals_idx)
                        ia.GetMapper().ScalarVisibilityOn()
                        colors.printc("..active scalars set to:",
                                      sname,
                                      "\ttype:",
                                      stype,
                                      c='g',
                                      bold=0)
                    ia._scals_idx += 1
                    if ia._scals_idx >= len(iascals):
                        ia._scals_idx = 0
        addons.addLegend()

    elif key == "5":
        bgc = numpy.array(vp.renderer.GetBackground()).sum() / 3
        if bgc <= 0:
            bgc = 0.223
        elif 0 < bgc < 1:
            bgc = 1
        else:
            bgc = 0
        vp.renderer.SetBackground(bgc, bgc, bgc)

    elif "KP_" in key:  # change axes style
        asso = {
            "KP_Insert": 0,
            "KP_0": 0,
            "KP_End": 1,
            "KP_1": 1,
            "KP_Down": 2,
            "KP_2": 2,
            "KP_Next": 3,
            "KP_3": 3,
            "KP_Left": 4,
            "KP_4": 4,
            "KP_Begin": 5,
            "KP_5": 5,
            "KP_Right": 6,
            "KP_6": 6,
            "KP_Home": 7,
            "KP_7": 7,
            "KP_Up": 8,
            "KP_8": 8,
            "KP_Prior": 9,
            "KP_9": 9,
        }
        clickedr = vp.renderers.index(vp.renderer)
        if key in asso.keys():
            if vp.axes_instances[clickedr]:
                if hasattr(vp.axes_instances[clickedr],
                           "EnabledOff"):  # widget
                    vp.axes_instances[clickedr].EnabledOff()
                else:
                    vp.renderer.RemoveActor(vp.axes_instances[clickedr])
                vp.axes_instances[clickedr] = None
            addons.addAxes(axtype=asso[key], c=None)
            vp.interactor.Render()

    elif key in ["k", "K"]:
        for a in vp.getActors():
            ptdata = a.GetMapper().GetInput().GetPointData()
            cldata = a.GetMapper().GetInput().GetCellData()

            arrtypes = dict()
            arrtypes[vtk.VTK_UNSIGNED_CHAR] = "UNSIGNED_CHAR"
            arrtypes[vtk.VTK_UNSIGNED_INT] = "UNSIGNED_INT"
            arrtypes[vtk.VTK_FLOAT] = "FLOAT"
            arrtypes[vtk.VTK_DOUBLE] = "DOUBLE"
            foundarr = 0

            if key == "k":
                for i in range(ptdata.GetNumberOfArrays()):
                    name = ptdata.GetArrayName(i)
                    if name == "Normals":
                        continue
                    ptdata.SetActiveScalars(name)
                    foundarr = 1
                if not foundarr:
                    print("No vtkArray is associated to points", end="")
                    if hasattr(a, "_legend"):
                        print(" for actor:", a._legend)
                    else:
                        print()

            if key == "K":
                for i in range(cldata.GetNumberOfArrays()):
                    name = cldata.GetArrayName(i)
                    if name == "Normals":
                        continue
                    cldata.SetActiveScalars(name)
                    foundarr = 1
                if not foundarr:
                    print("No vtkArray is associated to cells", end="")
                    if hasattr(a, "_legend"):
                        print(" for actor:", a._legend)
                    else:
                        print()

            a.GetMapper().ScalarVisibilityOn()

    elif key == "l":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if not ia.GetPickable():
                continue
            try:
                ev = ia.GetProperty().GetEdgeVisibility()
                ia.GetProperty().SetEdgeVisibility(not ev)
                ia.GetProperty().SetRepresentationToSurface()
                ia.GetProperty().SetLineWidth(0.1)
            except AttributeError:
                pass

    elif key == "n":  # show normals to an actor
        from vtkplotter.analysis import normalLines

        if vp.clickedActor in vp.getActors():
            if vp.clickedActor.GetPickable():
                vp.renderer.AddActor(normalLines(vp.clickedActor))
                iren.Render()
        else:
            print("Click an actor and press n to add normals.")

    elif key == "x":
        if vp.justremoved is None:
            if vp.clickedActor in vp.getActors() or isinstance(
                    vp.clickedActor, vtk.vtkAssembly):
                vp.justremoved = vp.clickedActor
                vp.renderer.RemoveActor(vp.clickedActor)
            if hasattr(vp.clickedActor, '_legend') and vp.clickedActor._legend:
                print('...removing actor: ' + str(vp.clickedActor._legend) +
                      ', press x to put it back')
            else:
                print("Click an actor and press x to toggle it.")
        else:
            vp.renderer.AddActor(vp.justremoved)
            vp.renderer.Render()
            vp.justremoved = None
        addons.addLegend()

    elif key == "X":
        if vp.clickedActor:
            if not vp.cutterWidget:
                addons.addCutterTool(vp.clickedActor)
            else:
                fname = "clipped.vtk"
                confilter = vtk.vtkPolyDataConnectivityFilter()
                if isinstance(vp.clickedActor, vtk.vtkActor):
                    confilter.SetInputData(
                        vp.clickedActor.GetMapper().GetInput())
                elif isinstance(vp.clickedActor, vtk.vtkAssembly):
                    act = vp.clickedActor.getActors()[0]
                    confilter.SetInputData(act.GetMapper().GetInput())
                else:
                    confilter.SetInputData(vp.clickedActor.polydata(True))
                confilter.SetExtractionModeToLargestRegion()
                confilter.Update()
                cpd = vtk.vtkCleanPolyData()
                cpd.SetInputData(confilter.GetOutput())
                cpd.Update()
                w = vtk.vtkPolyDataWriter()
                w.SetInputData(cpd.GetOutput())
                w.SetFileName(fname)
                w.Write()
                colors.printc("~save Saved file:", fname, c="m")
                vp.cutterWidget.Off()
                vp.cutterWidget = None
        else:
            for a in vp.actors:
                if isinstance(a, vtk.vtkVolume):
                    addons.addCutterTool(a)
                    return

            colors.printc(
                "Click an actor and press X to open the cutter box widget.",
                c=4)

    elif key == "i":  # print info
        if vp.clickedActor:
            utils.printInfo(vp.clickedActor)
        else:
            utils.printInfo(vp)

    if iren:
        iren.Render()
Ejemplo n.º 2
0
 def print(self):
     """Print  ``Mesh``, ``Assembly``, ``Volume`` or ``Image`` infos."""
     utils.printInfo(self)
     return self
Ejemplo n.º 3
0
 def printInfo(self):
     """Print information about a vtk object."""
     utils.printInfo(self)
     return self
Ejemplo n.º 4
0
def _keypress(vp, obj, event):

    key = obj.GetKeySym()
    #print ('Pressed key:', key, event)

    if key in ["q", "Q", "space", "Return"]:
        vp.interactor.ExitCallback()
        return

    elif key == "e":
        if vp.verbose:
            print("closing window...")
        vp.interactor.GetRenderWindow().Finalize()
        vp.interactor.TerminateApp()
        return

    elif key == "Escape":
        print()
        sys.stdout.flush()
        vp.interactor.TerminateApp()
        vp.interactor.GetRenderWindow().Finalize()
        vp.interactor.TerminateApp()
        sys.exit(0)

    elif key == "m":
        if vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetOpacity(0.02)
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp:
                bfp.SetOpacity(0.02)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    a.GetProperty().SetOpacity(0.02)
                    bfp = a.GetBackfaceProperty()
                    if bfp:
                        bfp.SetOpacity(0.02)

    elif key == "slash":
        if vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetOpacity(1)
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp:
                bfp.SetOpacity(1)
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    a.GetProperty().SetOpacity(1)
                    bfp = a.GetBackfaceProperty()
                    if bfp:
                        bfp.SetOpacity(1)

    elif key == "comma":
        if vp.clickedActor in vp.getActors():
            ap = vp.clickedActor.GetProperty()
            ap.SetOpacity(max([ap.GetOpacity() * 0.75, 0.01]))
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp:
                bfp.SetOpacity(ap.GetOpacity())
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    ap = a.GetProperty()
                    ap.SetOpacity(max([ap.GetOpacity() * 0.75, 0.01]))
                    bfp = a.GetBackfaceProperty()
                    if bfp:
                        bfp.SetOpacity(ap.GetOpacity())

    elif key == "period":
        if vp.clickedActor in vp.getActors():
            ap = vp.clickedActor.GetProperty()
            ap.SetOpacity(min([ap.GetOpacity() * 1.25, 1.0]))
            bfp = vp.clickedActor.GetBackfaceProperty()
            if bfp:
                bfp.SetOpacity(ap.GetOpacity())
        else:
            for a in vp.getActors():
                if a.GetPickable():
                    ap = a.GetProperty()
                    ap.SetOpacity(min([ap.GetOpacity() * 1.25, 1.0]))
                    bfp = a.GetBackfaceProperty()
                    if bfp:
                        bfp.SetOpacity(ap.GetOpacity())

    elif key == "P":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if ia.GetPickable():
                try:
                    ps = ia.GetProperty().GetPointSize()
                    if ps > 1:
                        ia.GetProperty().SetPointSize(ps - 1)
                    ia.GetProperty().SetRepresentationToPoints()
                except AttributeError:
                    pass

    elif key == "p":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if ia.GetPickable():
                try:
                    ps = ia.GetProperty().GetPointSize()
                    ia.GetProperty().SetPointSize(ps + 2)
                    ia.GetProperty().SetRepresentationToPoints()
                except AttributeError:
                    pass

    elif key == "w":
        if vp.clickedActor and vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetRepresentationToWireframe()
        else:
            for a in vp.getActors():
                if a and a.GetPickable():
                    a.GetProperty().SetRepresentationToWireframe()

    elif key == "r":
        vp.renderer.ResetCamera()

    ### now intercept custom observer ###########################
    if vp.keyPressFunction:
        if key not in ['Shift_L', 'Control_L', 'Super_L', 'Alt_L']:
            if key not in ['Shift_R', 'Control_R', 'Super_R', 'Alt_R']:
                vp.verbose = False
                vp.keyPressFunction(key)
                return

    if key == "S":
        vp.screenshot('screenshot.png')
        colors.printc('Saved rendering window as screenshot.png', c='blue')
        return

    elif key == "C":
        cam = vp.renderer.GetActiveCamera()
        print('\n### Example code to position this vtkCamera:')
        print('vp = vtkplotter.Plotter()\n...')
        print('vp.camera.SetPosition(',
              [round(e, 3) for e in cam.GetPosition()], ')')
        print('vp.camera.SetFocalPoint(',
              [round(e, 3) for e in cam.GetFocalPoint()], ')')
        print('vp.camera.SetViewUp(', [round(e, 3) for e in cam.GetViewUp()],
              ')')
        print('vp.camera.SetDistance(', round(cam.GetDistance(), 3), ')')
        print('vp.camera.SetClippingRange(',
              [round(e, 3) for e in cam.GetClippingRange()], ')')
        return

    elif key == "s":
        if vp.clickedActor and vp.clickedActor in vp.getActors():
            vp.clickedActor.GetProperty().SetRepresentationToSurface()
        else:
            for a in vp.getActors():
                if a and a.GetPickable():
                    a.GetProperty().SetRepresentationToSurface()

    elif key == "V":
        if not (vp.verbose):
            vp._tips()
        vp.verbose = not (vp.verbose)
        print("Verbose: ", vp.verbose)

    elif key in ["1", "KP_End", "KP_1"]:
        if vp.clickedActor and hasattr(vp.clickedActor, 'GetProperty'):
            vp.clickedActor.GetProperty().SetColor(colors.colors1[(vp.icol) %
                                                                  10])
        else:
            for i, ia in enumerate(vp.getActors()):
                if not ia.GetPickable(): continue
                ia.GetProperty().SetColor(colors.colors1[(i + vp.icol) % 10])
                ia.GetMapper().ScalarVisibilityOff()
        vp.icol += 1
        vp._draw_legend()

    elif key in ["2", "KP_Down", "KP_2"]:
        if vp.clickedActor and hasattr(vp.clickedActor, 'GetProperty'):
            vp.clickedActor.GetProperty().SetColor(colors.colors2[(vp.icol) %
                                                                  10])
        else:
            for i, ia in enumerate(vp.getActors()):
                if not ia.GetPickable(): continue
                ia.GetProperty().SetColor(colors.colors2[(i + vp.icol) % 10])
                ia.GetMapper().ScalarVisibilityOff()
        vp.icol += 1
        vp._draw_legend()

    elif key in ["3", "KP_Left", "KP_4"]:
        c = colors.getColor('gold')
        acs = vp.getActors()
        alpha = 1. / len(acs)
        for ia in acs:
            if not ia.GetPickable(): continue
            ia.GetProperty().SetColor(c)
            ia.GetProperty().SetOpacity(alpha)
            ia.GetMapper().ScalarVisibilityOff()
        vp._draw_legend()

    elif key in ["k", "K"]:
        for a in vp.getActors():
            ptdata = a.polydata().GetPointData()
            cldata = a.polydata().GetCellData()

            arrtypes = dict()
            arrtypes[vtk.VTK_UNSIGNED_CHAR] = 'VTK_UNSIGNED_CHAR'
            arrtypes[vtk.VTK_UNSIGNED_INT] = 'VTK_UNSIGNED_INT'
            arrtypes[vtk.VTK_FLOAT] = 'VTK_FLOAT'
            arrtypes[vtk.VTK_DOUBLE] = 'VTK_DOUBLE'
            foundarr = 0

            if key == 'k':
                for i in range(ptdata.GetNumberOfArrays()):
                    name = ptdata.GetArrayName(i)
                    if name == 'Normals':
                        continue
                    ptdata.SetActiveScalars(name)
                    foundarr = 1
                if not foundarr:
                    print('No vtkArray is associated to points', end='')
                    if hasattr(a, 'legend'):
                        print(' for actor:', a.legend)
                    else:
                        print()

            if key == 'K':
                for i in range(cldata.GetNumberOfArrays()):
                    name = cldata.GetArrayName(i)
                    if name == 'Normals':
                        continue
                    cldata.SetActiveScalars(name)
                    foundarr = 1
                if not foundarr:
                    print('No vtkArray is associated to cells', end='')
                    if hasattr(a, 'legend'):
                        print(' for actor:', a.legend)
                    else:
                        print()

            a.GetMapper().ScalarVisibilityOn()

    elif key == "L":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if not ia.GetPickable(): continue
            try:
                ia.GetProperty().SetRepresentationToSurface()
                ls = ia.GetProperty().GetLineWidth()
                if ls <= 1:
                    ls = 1
                    ia.GetProperty().EdgeVisibilityOff()
                else:
                    ia.GetProperty().EdgeVisibilityOn()
                    ia.GetProperty().SetLineWidth(ls - 1)
            except AttributeError:
                pass

    elif key == "l":
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if not ia.GetPickable(): continue
            try:
                ia.GetProperty().EdgeVisibilityOn()
                c = ia.GetProperty().GetColor()
                ia.GetProperty().SetEdgeColor(c)
                ls = ia.GetProperty().GetLineWidth()
                ia.GetProperty().SetLineWidth(ls + 1)
            except AttributeError:
                pass

    elif key == "n":  # show normals to an actor
        from vtkplotter.analysis import normals as ana_normals
        if vp.clickedActor in vp.getActors():
            acts = [vp.clickedActor]
        else:
            acts = vp.getActors()
        for ia in acts:
            if not ia.GetPickable(): continue
            alpha = ia.GetProperty().GetOpacity()
            c = ia.GetProperty().GetColor()
            a = ana_normals(ia, ratio=1, c=c, alpha=alpha)
            try:
                i = vp.actors.index(ia)
                vp.actors[i] = a
                vp.renderer.RemoveActor(ia)
                vp.interactor.Render()
            except ValueError:
                pass
            vp.render(a)

    elif key == "x":
        if vp.justremoved is None:
            if vp.clickedActor in vp.getActors() or isinstance(
                    vp.clickedActor, vtk.vtkAssembly):
                vp.justremoved = vp.clickedActor
                vp.renderer.RemoveActor(vp.clickedActor)
            if hasattr(vp.clickedActor, 'legend') and vp.clickedActor.legend:
                colors.printc('...removing actor: ' +
                              str(vp.clickedActor.legend) +
                              ', press x to put it back')
            else:
                if vp.verbose:
                    colors.printc('Click an actor and press x to toggle it.',
                                  c=5)
        else:
            vp.renderer.AddActor(vp.justremoved)
            vp.renderer.Render()
            vp.justremoved = None
        vp._draw_legend()

    elif key == "X":
        if len(vp.actors):
            vp.clickedActor = vp.actors[-1]
        if vp.clickedActor:
            if not vp.cutterWidget:
                vp.cutterWidget = vp.addCutterTool(vp.clickedActor)
            else:
                fname = 'clipped.vtk'
                confilter = vtk.vtkPolyDataConnectivityFilter()
                confilter.SetInputData(vp.clickedActor.polydata(True))
                confilter.SetExtractionModeToLargestRegion()
                confilter.Update()
                cpd = vtk.vtkCleanPolyData()
                cpd.SetInputData(confilter.GetOutput())
                cpd.Update()
                w = vtk.vtkPolyDataWriter()
                w.SetInputData(cpd.GetOutput())
                w.SetFileName(fname)
                w.Write()
                colors.printc("  -> Saved file:", fname, c='m')
                vp.cutterWidget.Off()
                vp.cutterWidget = None

        else:
            colors.printc(
                'Click an actor and press X to open the cutter box widget.',
                c=4)

    elif key == 'i':  # print info
        if vp.clickedActor:
            utils.printInfo(vp.clickedActor)
        else:
            utils.printInfo(vp)

    if vp.interactor:
        vp.interactor.Render()