Which coordinates of SetNormal and SetOrigin of 2 vtkPlanes I must set from points drawn via vtkPolyLineWidget?

I’ve a Volume with mapper vtkGPUVolumeRayCastMapper and vtkFixedPointVolumeRayCastMapper and I wanted to make to try to make a basic scissors (scalpel), decided to start with vtkPolyLineWidget and vtkPolyLineRepresentation (and try for start on basic vtkPolyDataMapper).

So in short I wanted from N-Points (translating from camera/display to world position when placing) of polyline generate N-vtkPlane (aka rays) to cut mapper with AddClippingPlane except I’m at loss due not able to understand how to correctly generate vtkPlanes which would cut mapper as I want, taking simple two points (i and i+1) kinda doesn’t work correctly.

from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkCylinderSource
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkInteractionWidgets import (
    vtkCameraOrientationWidget,
    vtkSplineWidget,
    vtkPolyLineWidget,
    vtkPolyLineRepresentation,
)
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer,
    vtkCoordinate,
)
import vtk

class MyInteractorStyle(vtkInteractorStyleTrackballCamera):
    def __init__(self, parent=None):
        self.father = parent
        #Change Trackball Mouse Buttons to make Left Button inactive but Right button to use Left Button functions (rotate)
        self.AddObserver('LeftButtonPressEvent', self.leftButtonPressEvent)
        self.AddObserver('LeftButtonReleaseEvent', self.leftButtonReleaseEvent)
        self.AddObserver('RightButtonPressEvent', self.rightButtonPressEvent)
        self.AddObserver('RightButtonReleaseEvent', self.rightButtonReleaseEvent)
        # self.AddObserver('MiddleButtonPressEvent', self.middle_button_press_event)
        # self.AddObserver('MiddleButtonReleaseEvent', self.middle_button_release_event)

    def rightButtonPressEvent(self, obj, event):
        self.OnLeftButtonDown()
        return

    def rightButtonReleaseEvent(self, obj, event):
        self.OnLeftButtonUp()
        return

    def leftButtonPressEvent(self, obj, event):
        self.father.managePolyLine()
        return
    
    def leftButtonReleaseEvent(self, obj, event):
        return

class RunVTK():
    def __init__(self) -> None:
        self.init_main()

    def init_main(self):
        colors = vtkNamedColors()
        colors.SetColor('ParaViewBkg', [82, 87, 110, 255])

        has_cow = False
        # if vtk_version_ok(9, 0, 20210718):
        cam_orient_manipulator = vtkCameraOrientationWidget()
        has_cow = True

        window_width = 800
        window_height = 600

        self.ren_win = vtkRenderWindow()
        self.ren_win.SetSize(window_width, window_height)
        iren = vtkRenderWindowInteractor()
        iren.SetRenderWindow(self.ren_win)
        style = MyInteractorStyle(self)
        iren.SetInteractorStyle(style)

        self.renderer = vtkRenderer()
        self.renderer.SetBackground(colors.GetColor3d('ParaViewBkg'))

        # Create a cylinder.
        cylinder = vtkCylinderSource()
        cylinder.SetCenter(0.0, 0.0, 0.0)
        cylinder.SetRadius(3.0)
        cylinder.SetHeight(5.0)
        cylinder.SetResolution(100)

        # Create a mapper and actor
        self.mapper = vtkPolyDataMapper()
        self.mapper.SetInputConnection(cylinder.GetOutputPort())

        self.actor = vtkActor()
        self.actor.GetProperty().SetColor(colors.GetColor3d('Cornsilk'))
        self.actor.SetMapper(self.mapper)
        # Add the actor to the scene
        self.renderer.AddActor(self.actor)

        self.ren_win.AddRenderer(self.renderer)
        # Important: The interactor must be set prior to enabling the widget.
        iren.SetRenderWindow(self.ren_win)

        if has_cow:
            cam_orient_manipulator.SetParentRenderer(self.renderer)
            # Enable the widget.
            cam_orient_manipulator.On()

        self.ren_win.Render()
        self.ren_win.SetWindowName('PolyLine Scissors')
        iren.Start()

    def managePolyLine(self):
        if not hasattr(self, "polyline"):
            print("Creating PoliLine")
            self.polyline_rep = vtkPolyLineRepresentation()
            self.polyline = vtkPolyLineWidget()
            self.polyline.SetRepresentation(self.polyline_rep)
            interactor = self.ren_win.GetInteractor()
            self.polyline.SetInteractor(interactor)
            self.polyline_rep.SetLineColor(255, 0, 0)
            self.polyline_rep.SetNumberOfHandles(1)
            self.polyline.On()
            self.polyline_rep.ClosedOn()
            x, y = interactor.GetEventPosition()
            coords = vtk.vtkCoordinate()
            coords.SetCoordinateSystemToDisplay()
            coords.SetValue(x, y, 0)
            x, y, z = coords.GetComputedWorldValue(self.renderer)
            del coords
            self.polyline_rep.SetHandlePosition(0, x, y, z)
        else:
            interactor = self.ren_win.GetInteractor()
            x, y = interactor.GetEventPosition()
            handles_count = self.polyline_rep.GetNumberOfHandles()
            self.polyline_rep.SetNumberOfHandles(handles_count + 1)
            coords = vtkCoordinate()
            coords.SetCoordinateSystemToDisplay()
            coords.SetValue(x, y, 0)
            x, y, z = coords.GetComputedWorldValue(self.renderer)
            del coords
            self.polyline_rep.SetHandlePosition(handles_count, x, y, z)
            
        #Test Version of Cutting should occur if points reaches beyond 4
        if self.polyline_rep.GetNumberOfHandles() == 4:
            vtk_array = self.polyline_rep.GetHandlePositions()
            vtk_array: vtk.vtkTypeFloat64Array
            for i in range(3):
                x1, y1, z1 = vtk_array.GetTuple(i)
                x2, y2, z2 = vtk_array.GetTuple(i+1)

        self.ren_win.Render()

if __name__ == '__main__':
    main = RunVTK()


Okay I kinda understood how vtkPlane works, it uses Origin points as position of plane (in center) and then uses its normal to set up its orientation (its usually like [0, 1, 0]).

So in my case I needed to generate a plane from a point between two points (as Origin) and then set Normal like [0, 1, 0] (but in reality I needed to calculate normal depending on XYZ coordinates).

But apparently this idea of scalpel is kinda not working due vtkPlane clipping mercilessly and intersecting each other (so Cut Inside would never work, while Cut Outside would in most cases work incorrectly)