How to draw arrow for cell normal(not point normal)

Hello,use these code:

/*
 * @Creator		 : alex 
 * @Create at	 : Jan 6, 2022 5:53:08 PM
 * @Modified by : alex
 * @Modified at : Jan 6, 2022 5:53:08 PM
 * @Description :	SphereCellNormal.cpp
 */
#include <vtkVersion.h>
#include <vtkSmartPointer.h>

#include <vtkSurfaceReconstructionFilter.h>
#include <vtkProgrammableSource.h>
#include <vtkContourFilter.h>
#include <vtkReverseSense.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkUnstructuredGrid.h>
#include <vtkDataSetMapper.h>
#include <vtkPolyDataNormals.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkArrowSource.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkGlyph3D.h>
#include <vtkOBJReader.h>

int main(int argc, char *argv[]) {
	vtkSmartPointer<vtkSphereSource> source = vtkSmartPointer<vtkSphereSource>::New();
	source->SetPhiResolution(10);
	source->SetThetaResolution(10);

//	std::string filePath = "/home/alex/workspace/Geometry-Python/files/cube_ball.obj";
//	auto source = vtkSmartPointer<vtkOBJReader>::New();
//	source->SetFileName(filePath.c_str());

	source->Update();

	vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputConnection(source->GetOutputPort());
	mapper->Update();

	vtkSmartPointer<vtkActor> surfaceActor = vtkSmartPointer<vtkActor>::New();
	surfaceActor->SetMapper(mapper);

	vtkSmartPointer<vtkPolyDataNormals> pdNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
	pdNormals->SetInputConnection(source->GetOutputPort());
	pdNormals->SplittingOff();
	pdNormals->FlipNormalsOff();
//	pdNormals->ComputePointNormalsOn();
//	pdNormals->ComputePointNormalsOff();
	pdNormals->ComputeCellNormalsOn();
	pdNormals->ConsistencyOn();
	pdNormals->AutoOrientNormalsOn();
	pdNormals->Update();

	auto arrow = vtkSmartPointer<vtkArrowSource>::New();
	arrow->SetTipResolution(8);
	arrow->SetTipLength(0.3);
	arrow->SetTipRadius(0.1);

	vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();
	glyph->SetSourceConnection(arrow->GetOutputPort());
	glyph->SetVectorModeToUseNormal();
	glyph->SetInputData(pdNormals->GetOutput());
	glyph->SetScaleFactor(0.2);
	glyph->OrientOn();
	glyph->SetScaleModeToDataScalingOff();
	glyph->Update();

	vtkSmartPointer<vtkPolyDataMapper> spikeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	spikeMapper->SetInputConnection(glyph->GetOutputPort());

	vtkSmartPointer<vtkActor> spikeActor = vtkSmartPointer<vtkActor>::New();
	spikeActor->SetMapper(spikeMapper);
	spikeActor->GetProperty()->SetColor(0.0, 0.79, 0.34);

	// Create the RenderWindow, Renderer and both Actors
	vtkSmartPointer<vtkRenderer> ren = vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
	renWin->AddRenderer(ren);
	vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	iren->SetRenderWindow(renWin);

	// Add the actors to the renderer, set the background and size
	ren->AddActor(surfaceActor);
	ren->AddActor(spikeActor);
	ren->SetBackground(.2, .3, .4);

	surfaceActor->GetProperty()->EdgeVisibilityOn();
	surfaceActor->GetProperty()->SetColor(0, 0, 1);
	surfaceActor->GetProperty()->SetEdgeColor(1, 1, 1);

	renWin->Render();
	iren->Start();

	return EXIT_SUCCESS;
}

I can draw arrows to represent point normal?Questions is:

How to draw arrow for cell normal?
I mean each cell has only one arrow from the center of the cell,not 3(or N) arrows from each point.

Hi,

What happens if you enable pdNormals->ComputePointNormalsOff(); along pdNormals->ComputeCellNormalsOn()?

regards,

PC

vtkCellCenters is a filter that takes as input any dataset and generates on output points at the center of the cells in the dataset. These points can be used for placing glyphs (vtkGlyph3D) or labeling (vtkLabeledDataMapper). (The center is the parametric center of the cell, not necessarily the geometric or bounding box center.) The cell attributes will be associated with the points on output.

This will get you halfway there.

1 Like

After these, all arrows poin toward to the right.

I have the same issue. Normals placed at the centers but all point in the same direction

How did you compute the normals? According to the class descriptions (I haven’t tried it), it should be something like this:

  1. apply vtkPolyDataNormals with ComputeCellNormalsOn()
  2. apply vtkCellCenters
  3. feed the output of vtkCellCenters into vtkGlyph3D
import vtk

source = vtk.vtkPlatonicSolidSource()
source.SetSolidType(1)
source.Update()

centers = vtk.vtkCellCenters()
centers.SetInputConnection(source.GetOutputPort())
centers.Update()

normals = vtk.vtkPolyDataNormals()
normals.SetInputConnection(centers.GetOutputPort())
normals.ComputeCellNormalsOn()
normals.Update()

arrow = vtk.vtkArrowSource()


glyphs = vtk.vtkGlyph3D()
glyphs.SetInputConnection(normals.GetOutputPort())
glyphs.SetSourceConnection(arrow.GetOutputPort())
glyphs.SetScaleModeToScaleByVector()
glyphs.SetScaleFactor(1)
glyphs.SetInputArrayToProcess(
    0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS_THEN_CELLS, "Normals")
glyphs.Update()

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyphs.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)

renderer= vtk.vtkRenderer()
renderer.AddActor(actor)

win = vtk.vtkRenderWindow()
win.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(win)

iren.Start()

I am sure that I have done something stupid. I saw a few other posts where other people have encountered this issue. Perhaps when it is working, I could fix a bug in vtkPlatonicSource and upload an example where normals are shown at cell centers. Interchanging the order of vtkCellCenters and vtkPolyDataNormals did no difference. The CellData are empty

Most VTK sources only produce point normals, not cell normals. So I think you will still need to compute the cell normals before using vtkCellCenters.

I can see that cell normals are present and correct after vtkPolyDataNormals but after vtkCellCenters the cell data are empty. I will debug this - I may have hit a corner case where number of points equals number of cells

Try using glyphs.SetVectorModeToUseNormal(), instead of glyphs.SetInputArrayToProcess(). I don’t know why it matters, but it does.

import vtk

source = vtk.vtkPlatonicSolidSource()
source.SetSolidType(1)
source.Update()

normals = vtk.vtkPolyDataNormals()
normals.SetInputConnection(source.GetOutputPort())
normals.ComputeCellNormalsOn()
normals.Update()

centers = vtk.vtkCellCenters()
centers.SetInputConnection(normals.GetOutputPort())
centers.Update()

arrow = vtk.vtkArrowSource()


glyphs = vtk.vtkGlyph3D()
glyphs.SetInputConnection(centers.GetOutputPort())
glyphs.SetSourceConnection(arrow.GetOutputPort())
glyphs.SetScaleModeToScaleByVector()
glyphs.SetScaleFactor(1)
glyphs.SetVectorModeToUseNormal()
#glyphs.SetInputArrayToProcess(
#    0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS_THEN_CELLS, "Normals")
glyphs.Update()

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyphs.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)

renderer= vtk.vtkRenderer()
renderer.AddActor(actor)

win = vtk.vtkRenderWindow()
win.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(win)

iren.Start()
1 Like

You mean that the code that I posted does not work for you? That’s strange, because it works for me.

It works. The normals appear as normals for the new points and the original cell data is removed. It makes perfect sense. I was just expecting further points to be added as well as normals. But then it would be impossible to distinguish vertex points from points at the cell centers.

Inspecting the code, I can see that this also works

glyphs.SetInputArrayToProcess(1, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS_THEN_CELLS, vtk.vtkDataSetAttributes.NORMALS)

This was a bit tricky. Thanks David