Search code examples
pythonvtknormals

How display normal on a vtkPolyData vtkCylinderSource with vtkPolyDataNormals?


I'm trying to display the normalsof each cell of a cylinder source vtkCylinderSource. I'm using vtkPolyDataNormals class and vtkGlyph3D but the normals are not showing up on the QT view. I don't undersand what I'm doing wrong. Here the code I use for now

from PyQt5.QtWidgets import *
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor

class Cylinder(QMainWindow):
    def __init__(self, parent=None):
        super(Cylinder, self).__init__( )

        self.parent=parent
        self.frame = QFrame()

        self.vl = QVBoxLayout()
        self.vtkWidget = QVTKRenderWindowInteractor(self.frame)
        self.vl.addWidget(self.vtkWidget)

        self.ren = vtk.vtkRenderer()
        self.ren.SetBackground(.2, .3, .3)
        self.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
        self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()
        style =vtk.vtkInteractorStyleTrackballCamera( )
        style.SetDefaultRenderer(self.ren)
        self.iren.SetInteractorStyle(style)
        self.ren.ResetCamera()
        self.frame.setLayout(self.vl)
        self.setCentralWidget(self.frame)
        self.show()
        self.iren.Initialize()
        self.iren.Start()

        self.draw_Electrode()

    def set_center(self):
        self.ren.ResetCamera()

    def Render(self, ):
        self.iren.GetRenderWindow().Render()

    def draw_Electrode(self):
        source = vtk.vtkCylinderSource()
        source.SetCenter(0, 0, 0)
        source.SetRadius(20)
        source.SetResolution(100)
        source.SetHeight(10)

        trans = vtk.vtkTransform()
        trans.PostMultiply()
        trans.RotateX(90)
        trans.RotateY(0)
        trans.Translate(0, 0, 0)

        trans_filter = vtk.vtkTransformPolyDataFilter()
        trans_filter.SetInputConnection(source.GetOutputPort())
        trans_filter.SetTransform(trans)

        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(trans_filter.GetOutputPort())

        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(1, 1, 1)
        actor.GetProperty().SetOpacity(0.5)

        self.ren.AddActor(actor)

        poly_data = trans_filter.GetOutput()
        nbcells = poly_data.GetNumberOfCells()
        cells = []
        for i in range(nbcells):
            cells.append(poly_data.GetCell(i))

        normalsCalc = vtk.vtkPolyDataNormals()

        normalsCalc.SetInputData(poly_data)
        normalsCalc.ComputePointNormalsOn()
        normalsCalc.ComputeCellNormalsOff()
        # normalsCalc.SetSplitting(0)
        # normalsCalc.FlipNormalsOff()
        # normalsCalc.ConsistencyOn()
        # normalsCalc.AutoOrientNormalsOn()
        normalsCalc.Update()

        arrowSource = vtk.vtkArrowSource()

        glyph3D = vtk.vtkGlyph3D()
        glyph3D.SetInputData(normalsCalc.GetOutput())
        glyph3D.SetSourceConnection(arrowSource.GetOutputPort())
        glyph3D.OrientOn()
        glyph3D.SetVectorModeToUseNormal()
        glyph3D.SetScaleFactor(200)
        glyph3D.Update()

        mapper2 = vtk.vtkPolyDataMapper()
        mapper2.SetInputConnection(glyph3D.GetOutputPort())

        actor2 = vtk.vtkActor()
        actor2.SetMapper(mapper2)
        actor2.GetProperty().SetColor(1, 1, 1)

        self.ren.AddActor(actor2)
        self.set_center()
        self.Render()



def main():
    import sys
    app = QApplication(sys.argv)


    ex = Cylinder(app)
    ex.setWindowTitle('Cylinder')
    # ex.showMaximized()
    ex.show()
    sys.exit(app.exec())


if __name__ == '__main__':
    main()

Solution

  • If you use the glyph configuration from this example and set scale factor to 1.0 it works.

    See your modified function draw_Electrode() here:

    def draw_Electrode(self):
        source = vtk.vtkCylinderSource()
        source.SetCenter(0, 0, 0)
        source.SetRadius(20)
        source.SetResolution(100)
        source.SetHeight(10)
    
        trans = vtk.vtkTransform()
        trans.PostMultiply()
        trans.RotateX(90)
        trans.RotateY(0)
        trans.Translate(0, 0, 0)
    
        trans_filter = vtk.vtkTransformPolyDataFilter()
        trans_filter.SetInputConnection(source.GetOutputPort())
        trans_filter.SetTransform(trans)
    
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(trans_filter.GetOutputPort())
    
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(1, 1, 1)
        actor.GetProperty().SetOpacity(0.5)
    
        self.ren.AddActor(actor)
    
        normals = vtk.vtkPolyDataNormals()
        normals.SetInputConnection(trans_filter.GetOutputPort())
    
        arrow= vtk.vtkArrowSource()
    
        glyph = vtk.vtkGlyph3D()
        glyph.SetInputConnection(normals.GetOutputPort())
        glyph.SetSourceConnection(arrow.GetOutputPort())
        glyph.SetVectorModeToUseNormal()
        glyph.SetScaleModeToScaleByVector()
        glyph.SetScaleFactor(1)
    
        mapper2 = vtk.vtkPolyDataMapper()
        mapper2.SetInputConnection(glyph.GetOutputPort())
    
        actor2 = vtk.vtkActor()
        actor2.SetMapper(mapper2)
        actor2.GetProperty().SetColor(1, 0, 0)
    
        self.ren.AddActor(actor2)
        self.set_center()
        self.Render()