Clean reset polydata normals

I’m building a feature that requires turning on and off the splitting option inside the vtkPolyDataNormals filter after a user action. The problem is the recalling of the normal filter on the polydata coming from the previous iteration. The splitting does not take effect after the second iteration. Below is an example.

This example works. After clicking a button, I got the splitting set correctly, because the normals are calculated from the original clear polydata.

var Splitting = true;
var filename = "path to a STL file";

var reader = new vtkSTLReader();
reader.SetFileName(filename);
reader.Update();

vtkCleanPolyData cleanFilter = new vtkCleanPolyData();
cleanFilter.SetInputData(reader.GetOutput());
cleanFilter.Update();

var PolyData = cleanFilter.GetOutput();

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputData(PolyData);
normals.SetSplitting(Splitting ? 1 : 0);
normals.Update();

Mapper = vtkPolyDataMapper.New();
Mapper.SetInputDataObject(normals.GetOutput());
Mapper.Update();

Actor = new vtkActor();
Actor.SetMapper(Mapper);

// Button clicked...
Splitting = false;

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputData(PolyData);
normals.SetSplitting(Splitting ? 1 : 0);
normals.Update();

Mapper.SetInputDataObject(normals.GetOutput());
Mapper.Update();

In this second example, the behavior is the same, but when I click the button and I run the normal filter on the already filtered polydata. I do not get the same correct result as the previous example.

var Splitting = true;
var filename = "path to a STL file";

var reader = new vtkSTLReader();
reader.SetFileName(filename);
reader.Update();

vtkCleanPolyData cleanFilter = new vtkCleanPolyData();
cleanFilter.SetInputData(reader.GetOutput());
cleanFilter.Update();

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputData(PolyData);
normals.SetSplitting(Splitting ? 1 : 0);
normals.Update();

var PolyData = normals.GetOutput();

Mapper = vtkPolyDataMapper.New();
Mapper.SetInputDataObject(PolyData);
Mapper.Update();

Actor = new vtkActor();
Actor.SetMapper(Mapper);

// Button clicked...
Splitting = false;

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputData(PolyData);
normals.SetSplitting(Splitting ? 1 : 0);
normals.Update();

Mapper.SetInputDataObject(normals.GetOutput());
Mapper.Update();

It seems that the normal filter checks if the normals are already created so it skips the process. So my question is how can reset the polydata normals to force the splitting set?

Thank you.

Hi @micheleivani,

I am not entirely sure what your expected result is in both cases. Could you specify?

And indeed if splitting is set to false no new normals are created as you can see here:

https://gitlab.kitware.com/vtk/vtk/-/blob/master/Filters/Core/vtkPolyDataNormals.cxx#L510

Best,
David

Hi @David_Berger,

according to the splitting On or Off the render of the actor is different. With splitting on (the vtk default one I guess) the rendering is a good one.

I’m building a feature that requires splitting off and I’m keeping in one of my classes a reference of the polydata coming from the vtkPolyDataNormals with splitting on.

When a call the callback of a particular action of my software, I use the polydata reference and I need to recalculate the normals but with slitting off. Doing that by re-applying the vtkPolyDataNormals to the polydata (that in the past has the normals already available with splicing omn) the result does not take effect.

In the example above I showed the behavior of applying a vtkPolyDataNormals filter for the second time to a polydata that already had the computed normals and not.

So I would like to understand if it’s possible to clear the normals of a polydata after applying the vtkPolyDataNormals filter or why if applying the vtkPolyDataNormals multiple times switching splitting on and off the result does not take effect.

I hope I was clear now.

Thank you.

Thank you for the clarification!

You defined your PolyData with GetOutput(), which means the geometry will be computed at that point. In your first example you call it before applying the normals filter, thus you can apply it with splitting on and splitting off and get the expected result.

In the second example I am not sure where the first PolyData is coming from, but I suspect it is the output of a normals filter, thus applying the normals filter another time with splitting off won’t work as expected.

As a solution, I suggest using .GetOutputPort() and .SetInputConnection() instead. This not only makes it easier to adjust your pipeline on the fly, but also avoids computing geometries that you won’t be using directly.

So something like this:

var filename = "path to a STL file";

var reader = new vtkSTLReader();
reader.SetFileName(filename);
reader.Update();

vtkCleanPolyData cleanFilter = new vtkCleanPolyData();
cleanFilter.SetInputConnection(reader.GetOutputPort());
cleanFilter.Update();

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputConnection(cleanFilter.GetOutputPort());
normals.SetSplitting(1);
normals.Update();

mapper = new vtkPolyDataMapper();
mapper.SetInputConnection(normals.GetOutputPort());
mapper.Update();

actor = new vtkActor();
actor.SetMapper(mapper);

Then the button-click could do the following:

normals.SetSplitting(0);
mapper.Update();

mapper.Update() should then re-compute the pipeline.

Does this solve your issue?

Best,
David

Thank you @David_Berger for your suggestion. I have tried it in a demo application and it works. The problem is that my official application (which is a very complex one) keeps a reference of the final polydata coming from the latest filter, then I keep a reference of the mapper and the actor. The polydata is used as input of several filters according to the feature that the user uses, so I can not keep the pipeline because I set new polydata to come from different filters to the mapper.

With your solution, I have to make a big refactor to my application so it’s not possible right now.

The point is, is it possible to reset/clean the normals of a vtkPolydata so when I apply the vtkPolydataNormal filter again it seems the first time?

Thank you!

Hi @micheleivani,

I see!

In VTK, normals are infact just PointData arrays. So you can do something like this to reset them:

polyData.GetPointData().RemoveArray("Normals");

Alternatively, you can use a filter for that if necessary: https://vtk.org/doc/nightly/html/classvtkPassArrays.html

Best,
David

@David_Berger unfortunately both did not work for me. According the vtkPassArrays documentation is replaced by vtkPassSelectedArrays.

vtkPassSelectedArrays filter = vtkPassSelectedArrays.New();
filter.SetInputData(PolyData);
filter.GetPointDataArraySelection().RemoveArrayByName("Normals");
filter.GetCellDataArraySelection().RemoveArrayByName("Normals");
filter.Update();

vtkPolyDataNormals normals = new vtkPolyDataNormals();
normals.SetInputData(filter.GetOutput());
normals.SetSplitting(Splitting ? 1 : 0);
normals.Update();

PolyData = normals.GetOutput();

Mapper.SetInputDataObject(normals.GetOutput());
Mapper.Update();

I also tried to make a copy of the polydata with just lines and points but when I render the windows the actor disappears.

var rawPolydatata = vtkPolyData.New();
rawPolydatata.SetPoints(PolyData.GetPoints());
rawPolydatata.SetLines(PolyData.GetLines());

Any other suggestions?

Thank you

I would try to make a DeepCopy of the points and lines before assigning them to the new PolyData

Hope it helps

Thank you @mau_igna_06 for your hint. I have tried

var points = vtkPoints.New();
points.DeepCopy(PolyData.GetPoints());

var cells = vtkCellArray.New();
cells.DeepCopy(PolyData.GetLines());

var rawPolydatata = vtkPolyData.New();
rawPolydatata.SetPoints(points);
rawPolydatata.SetLines(cells);

but it does not work the polydata disappears.

@David_Berger any news on that?

Thank you

Hi @micheleivani,

Is it possible that you share the .stl file with which this issue occurs?

Thank you
David

@David_Berger the problem is not related to the STL file, because I have tried with different ones and the issue is the same. Today I have made several tries and I found if I apply a vtkCleanPolyData filter on the second iteration, it seems to work. I do know if the filter deletes, resets the polydata normals, or just because it creates a new polydata based on the input one then the output will not have the normals anymore so applying the vtkPolyDataNormals the result works.

// In the button click callback.
vtkCleanPolyData cleanFilter = new vtkCleanPolyData();
cleanFilter.SetInputData(PolyData);
cleanFilter.Update();

vtkPolyDataNormals normals = new vtkPolyDataNormals();

normals.SetInputConnection(cleanFilter.GetOutputPort());
if (Splitting)
{
    normals.SplittingOn();
}
else
{
    normals.SplittingOff();
}

normals.Update();


PolyData = normals.GetOutput();

Mapper.SetInputDataObject(normals.GetOutput());
Mapper.Update();

I have found a solution, but I would like to know the reason why it works and if there is a better way to delete the normals of a polydata without applying a filter that does different things.

Thank you.

vtkCleanPolyData is merging duplicated points. This is why you need to call it again on a polydata that has its points split(ted).