Skip to content

Commit 2e79edc

Browse files
committed
Permit filtering identifiers for UpdateStatesFromObjects
- Extend the vtkObjectManager with a new method that allows one to replicate behavior of `UpdateStatesFromObjects` only for a given list of identifiers.
1 parent 6bcbb54 commit 2e79edc

File tree

4 files changed

+150
-2
lines changed

4 files changed

+150
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Add method that allows updating states of specific objects.
2+
3+
You can now call the `void UpdateStatesFromObjects(const std::vector<vtkTypeUInt32>& identifiers)` method on the `vtkObjectManager`
4+
to only update states of objects corresponding to the vector of identifiers. This method allows you to efficiently update a specific
5+
object and it's dependencies without touching other unrelated objects.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from vtkmodules.test import Testing as vtkTesting
2+
3+
class TestFilteredUpdateStatesFromObjects(vtkTesting.vtkTest):
4+
def test(self):
5+
from vtkmodules.vtkSerializationManager import vtkObjectManager
6+
from vtkmodules.vtkRenderingCore import vtkRenderWindow, vtkRenderer, vtkRenderWindowInteractor, vtkPolyDataMapper, vtkActor
7+
from vtkmodules.vtkFiltersSources import vtkSphereSource, vtkConeSource
8+
# from vtkmodules.vtkCommonCore import vtkLogger
9+
import json
10+
11+
sphereActor = vtkActor(mapper = (vtkSphereSource() >> vtkPolyDataMapper()).last)
12+
coneActor = vtkActor(mapper = (vtkConeSource() >> vtkPolyDataMapper()).last)
13+
14+
sphereRenderWindow = vtkRenderWindow()
15+
sphereRenderer = vtkRenderer()
16+
sphereRenderWindow.AddRenderer(sphereRenderer)
17+
sphereRenderer.AddActor(sphereActor)
18+
19+
coneRenderWindow = vtkRenderWindow()
20+
coneRenderer = vtkRenderer()
21+
coneRenderWindow.AddRenderer(coneRenderer)
22+
coneRenderer.AddActor(coneActor)
23+
24+
sphereInteractor = vtkRenderWindowInteractor(render_window = sphereRenderWindow)
25+
coneInteractor = vtkRenderWindowInteractor(render_window = coneRenderWindow)
26+
27+
sphereInteractor.Render()
28+
coneInteractor.Render()
29+
30+
manager = vtkObjectManager()
31+
manager.Initialize()
32+
33+
# manager.SetObjectManagerLogVerbosity(vtkLogger.VERBOSITY_WARNING)
34+
# manager.serializer.SetSerializerLogVerbosity(vtkLogger.VERBOSITY_WARNING)
35+
36+
sphereRenderWindowId = manager.RegisterObject(sphereRenderWindow)
37+
coneRenderWindowId = manager.RegisterObject(coneRenderWindow)
38+
39+
manager.UpdateStatesFromObjects()
40+
41+
# Keep track of the property IDs for verification later
42+
spherePropertyId = manager.GetId(sphereActor.property)
43+
conePropertyId = manager.GetId(coneActor.property)
44+
45+
sphereActor.property.opacity = 0.5 # Change sphere opacity to see if it gets updated correctly
46+
manager.UpdateStatesFromObjects([sphereRenderWindowId])
47+
self.assertIn("vtk-object-manager-kept-alive", json.loads(manager.GetState(sphereRenderWindowId)), "vtk-object-manager-kept-alive key not found in sphere render window state")
48+
# verify that the sphere opacity change is reflected in the state
49+
self.assertEqual(json.loads(manager.GetState(spherePropertyId))['Opacity'], 0.5)
50+
sphereActor.property.opacity = 1.0 # Change sphere opacity back to original value
51+
52+
coneActor.property.opacity = 0.3 # Change cone opacity to see if it gets updated correctly
53+
manager.UpdateStatesFromObjects([coneRenderWindowId])
54+
self.assertIn("vtk-object-manager-kept-alive", json.loads(manager.GetState(coneRenderWindowId)), "vtk-object-manager-kept-alive key not found in cone render window state")
55+
# verify that the cone opacity change is reflected in the state
56+
self.assertEqual(json.loads(manager.GetState(conePropertyId))['Opacity'], 0.3)
57+
58+
# Since we only updated the cone render window, the sphere's opacity should not have changed
59+
self.assertEqual(json.loads(manager.GetState(spherePropertyId))['Opacity'], 0.5)
60+
61+
if __name__ == "__main__":
62+
vtkTesting.main([(TestFilteredUpdateStatesFromObjects, 'test')])

Serialization/Manager/vtkObjectManager.cxx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,76 @@ void vtkObjectManager::UpdateStatesFromObjects()
566566
this->PruneUnusedObjects();
567567
}
568568

569+
//------------------------------------------------------------------------------
570+
void vtkObjectManager::UpdateStatesFromObjects(const std::vector<vtkTypeUInt32>& identifiers)
571+
{
572+
// get objects with strong references held by the manager.
573+
const auto managerOwnershipKey = this->OWNERSHIP_KEY();
574+
const auto managerStrongObjectsIter = this->Context->StrongObjects().find(managerOwnershipKey);
575+
// get objects with strong references held by the deserializer.
576+
const auto deserializerOwnershipKey = this->Deserializer->GetObjectDescription();
577+
const auto deserStrongObjectsIter = this->Context->StrongObjects().find(deserializerOwnershipKey);
578+
// get objects with strong references held by the invoker.
579+
const auto invokerOwnershipKey = this->Invoker->GetObjectDescription();
580+
const auto invokerStrongObjectsIter = this->Context->StrongObjects().find(invokerOwnershipKey);
581+
582+
// for each identifier, serialize the object and mark it as kept alive where necessary.
583+
for (const auto& identifier : identifiers)
584+
{
585+
const auto dependencies = this->GetAllDependencies(identifier);
586+
for (const auto& depId : dependencies)
587+
{
588+
// Reset dependency cache as it will be rebuilt.
589+
this->Context->ResetDirectDependenciesForNode(depId);
590+
}
591+
// The concered strong objects go under the top level root node
592+
vtkMarshalContext::ScopedParentTracker rootNodeTracker(this->Context, vtkObjectManager::ROOT());
593+
if (managerStrongObjectsIter != this->Context->StrongObjects().end())
594+
{
595+
for (const auto& object : managerStrongObjectsIter->second)
596+
{
597+
// The object must have already been registered in the context and have a valid identifier.
598+
if (this->Context->GetId(object) == identifier)
599+
{
600+
const auto stateId = this->Serializer->SerializeJSON(object);
601+
if (const auto idIter = stateId.find("Id"); idIter != stateId.end())
602+
{
603+
if (idIter->is_number_unsigned() && idIter->get<vtkTypeUInt32>() == identifier)
604+
{
605+
auto& state = this->Context->GetState(idIter->get<vtkTypeUInt32>());
606+
state["vtk-object-manager-kept-alive"] = true;
607+
}
608+
}
609+
}
610+
}
611+
}
612+
if (deserStrongObjectsIter != this->Context->StrongObjects().end())
613+
{
614+
for (const auto& object : deserStrongObjectsIter->second)
615+
{
616+
if (this->Context->GetId(object) == identifier)
617+
{
618+
this->Serializer->SerializeJSON(object);
619+
}
620+
}
621+
}
622+
if (invokerStrongObjectsIter != this->Context->StrongObjects().end())
623+
{
624+
for (const auto& object : invokerStrongObjectsIter->second)
625+
{
626+
if (this->Context->GetId(object) == identifier)
627+
{
628+
this->Serializer->SerializeJSON(object);
629+
}
630+
}
631+
}
632+
}
633+
// Remove unused states
634+
this->PruneUnusedStates();
635+
// Remove unused objects
636+
this->PruneUnusedObjects();
637+
}
638+
569639
//------------------------------------------------------------------------------
570640
void vtkObjectManager::UpdateObjectFromState(const std::string& state)
571641
{

Serialization/Manager/vtkObjectManager.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,21 @@ class VTKSERIALIZATIONMANAGER_EXPORT vtkObjectManager : public vtkObject
145145
void UpdateObjectsFromStates();
146146

147147
/**
148-
* Serialize registered objects into vtk states.
148+
* Serialize registered objects into states.
149149
*/
150150
void UpdateStatesFromObjects();
151151

152+
/**
153+
* This method is similar to `void UpdateStatesFromObjects()`. The only difference is that this
154+
* method is far more efficient when updating a specific object and it's dependencies. The
155+
* identifiers must be valid and correspond to registered objects.
156+
*
157+
* @warning This method prunes all unused states and objects after serialization. Ensure that
158+
* `void UpdateStatesFromObjects()` is called atleast once before this method if you want to
159+
* preserve objects that were registered but not specified in `identifiers`.
160+
*/
161+
void UpdateStatesFromObjects(const std::vector<vtkTypeUInt32>& identifiers);
162+
152163
///@{
153164
/**
154165
* Deserialize the state into vtk object.
@@ -192,7 +203,7 @@ class VTKSERIALIZATIONMANAGER_EXPORT vtkObjectManager : public vtkObject
192203
void Import(const std::string& stateFileName, const std::string& blobFileName);
193204

194205
/**
195-
* Removes all objects that are neither referenced by this manager or any other object.
206+
* Removes all states whose corresponding objects no longer exist.
196207
*/
197208
void PruneUnusedStates();
198209

0 commit comments

Comments
 (0)