SafeDownCast and subclassing vtkPolyData in Python

Hello, I have defined a subclass of vtkPolyData in my Python project. It works well and I am able to use standard vtkXMLPolyDataWriter to save it to disk. However, when reloading the objects from file, I would like to cast the vtkPolyData that I get from the vtkXMLPolyDataReader to my subclass. I figured out it would be as simple as:

my_object = MyClass()  # MyClass is derived from vtkPolyData

pd_reader = vtk.vtkXMLPolyDataReader()
pd_reader.SetFileName(<my_file_name>)
pd_reader.Update()

my_object.SafeDownCast(pd_reader.GetOutput())
my_object.Modified()

But I always get an empty my_object (and I have checked: the output from pd_reader is a proper vtkPolyData object).

Could somebody help?

Thanks very much!

The reader doesn’t know how to create an instance of your derived class, so it won’t be an instance. SafeDownCast is analogous to dynamic_cast, so if it isn’t an instance of your class, it will return None. You’ll need a method on your class to take another vtkPolyData and add your class’ bits around it.

Hello, I was assuming that the following post was correct.

“ A downcast is a cast from a base class to a class derived from the base class. A downcast is only safe if the object addressed at runtime is actually addressing a derived class object.”

https://vtk.org/pipermail/vtkusers/2011-September/069645.html

MyClass() is derived from vtkPolyData(), so it should have satisfied the condition above. But either I am not understanding, or the post cited above is incorrect.

In any case, could you suggest an example showing how to “ add my class’ bits around a polydata“? I thought that this is the actual purpose of casting (but probably I’m wrong), and I am a bit confused since MyClass() simply adds methods to vtkPolyData(), so in principle a MyClass() instance is just a vtkPolyData() with more methods that are “revealed” dynamically when called, but for instance the data arrays etc are exactly the same.

Thanks very much!

I have also tried dynamic_cast, but it raises an error in Python.

As @ben.boeckel said, the xml poly data reader produces an output of static type vtkPolyData, so you cannot downcast this to your new type. The only way I see for you is to create a filter that shallow copies a vtkPolyData into your custom type.

Note that your custom type can only be produced by filters that inherit from vtkPassInputTypeAlgorithm. Any filter inheriting from vtkPolyDataAlgorithm will produce a vtkPolyData for the same reason the xml poly data reader produces a vtkPolyData.

Shallow-copying is pretty cheap, so it should be a good enough solution in your case.

A downcast only changes the type of the pointer, it cannot change the type of the object. That is why they say that a downcast is only safe when the pointer is “addressing a derived class object.” This is a subtle distinction, but a very important one!

The reader returns a pointer of type vtkPolyData*, and this pointer holds the address of a vtkPolyData object. That is the important thing: the object provided by the reader does not belong to your subclass, therefore you cannot downcast it. The only possible way to convert the object is by creating a new object that belongs to your class, and then copying the data.

my_object = MyClass()
my_object.ShallowCopy(pd_reader.GetOutput())
# my_object.DeepCopy(pd_reader.GetOutput()) # do this if ShallowCopy() doesn't work
1 Like

Dear @dgobbi and @Yohann_Bearzi, thanks very much for the explanation and the solution! It works!

I add here the complete solution for whoever might be interested.

my_object = MyClass() # derived from vtkPolyData()
pd_reader = vtk.vtkXMLPolyDataReader()
pd_reader.SetFileName("my_file_name")
pd_reader.Update()
my_object.ShallowCopy(pd_reader.GetOutput())
my_object.Modified()

Thanks to everybody!

vtk_object.Modified()

Ideally, Modified() should be called inside ShallowCopy, if you actually change internal buffers.

@Yohann_Bearzi, I guess I made an error, now corrected, in copy/pasting my code above. The instance of My_Class() returned at the end must be my_object created in the first line. Please see if it makes sense for you now.

Actually, you don’t need to call Modified at all. It is already being called when you call ShallowCopy in the class hierarchy. We usually try to make Modified almost invisible to the user by calling it directly inside classes methods when an internal attribute is changed, because managing it “by hand” is error prone (people are very likely to forget to call it). So you usually don’t need to call Modified, unless you have good reasons to do so, inside a class you wrote yourself. vtkSetMacro automatically calls Modified.

1 Like

Perfect, thanks!