Skip to content

Commit 7a24b32

Browse files
committed
Change picking manager to not own objects associated with pickers
When adding a vtkPicker to the picking manager, a vtkObject can optionally be associated with the picker. This commit changes the behavior of vtkPickingManager to not own (i.e. increment the reference count) of these associated objects. Instead, the object references are held in a raw pointer. The widget framework is the primary client of the picking manager. The typical vtkWidgetRepresentation subclass adds its pickers to the picking manager and includes an associated object reference to itself: pickingManager->AddPicker(picker, this); When the widget/representation are destroyed, the vtkWidgetRepresentation destructor unregisters its pickers: pickingManager->RemoveObject(this); However, because the picking manager took ownership of the associated objects, the vtkWidgetRepresentation instances and their pickers are not destroyed until the vtkPickingManager is destroyed. In particular applications, this could lead to a large number of objects referenced only by vtkPickingManager that would exist until application exit. The picking manager test is updated for the use case demonstrated by the widget framework.
1 parent 9fe2433 commit 7a24b32

File tree

2 files changed

+105
-31
lines changed

2 files changed

+105
-31
lines changed

Rendering/Core/Testing/Cxx/TestPickingManager.cxx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class PickingManagerTest
5353
bool TestAddPickers();
5454
bool TestRemovePickers();
5555
bool TestRemoveObjects();
56+
bool TestObjectOwnership();
5657

5758
bool VTKVerify(bool test, const char* errorStr, int line);
5859
void PrintErrorMessage(int line, const char* errorStr);
@@ -87,6 +88,73 @@ class PickingManagerTest
8788
vtkSmartPointer<vtkPickingManager> PickingManager;
8889
};
8990

91+
//------------------------------------------------------------------------------
92+
// Test picking manager client that removes itself from the picking manager
93+
// in its destructor. This mimics the behavior of the VTK widget framework.
94+
class PickingManagerClient : public vtkObject
95+
{
96+
public:
97+
static PickingManagerClient* New();
98+
vtkTypeMacro(PickingManagerClient, vtkObject);
99+
100+
void SetPickingManager(vtkPickingManager *pm);
101+
void RegisterPicker();
102+
vtkPicker* GetPicker();
103+
104+
protected:
105+
PickingManagerClient();
106+
~PickingManagerClient();
107+
108+
private:
109+
vtkPickingManager *PickingManager;
110+
vtkPicker *Picker;
111+
112+
PickingManagerClient(const PickingManagerClient&); //Not implemented
113+
void operator=(const PickingManagerClient&); //Not implemented
114+
};
115+
116+
vtkStandardNewMacro(PickingManagerClient);
117+
118+
//------------------------------------------------------------------------------
119+
PickingManagerClient::PickingManagerClient()
120+
{
121+
this->Picker = vtkPicker::New();
122+
}
123+
124+
//------------------------------------------------------------------------------
125+
PickingManagerClient::~PickingManagerClient()
126+
{
127+
this->Picker->Delete();
128+
129+
if (this->PickingManager)
130+
{
131+
this->PickingManager->RemoveObject(this);
132+
}
133+
}
134+
135+
//------------------------------------------------------------------------------
136+
void PickingManagerClient::SetPickingManager(vtkPickingManager *pm)
137+
{
138+
this->PickingManager = pm;
139+
}
140+
141+
//------------------------------------------------------------------------------
142+
void PickingManagerClient::RegisterPicker()
143+
{
144+
if (!this->PickingManager)
145+
{
146+
return;
147+
}
148+
149+
this->PickingManager->AddPicker(this->Picker, this);
150+
}
151+
152+
//------------------------------------------------------------------------------
153+
vtkPicker* PickingManagerClient::GetPicker()
154+
{
155+
return this->Picker;
156+
}
157+
90158
//------------------------------------------------------------------------------
91159
int TestPickingManager(int, char*[])
92160
{
@@ -98,6 +166,7 @@ int TestPickingManager(int, char*[])
98166
res = res && pickingManagerTest.TestAddPickers();
99167
res = res && pickingManagerTest.TestRemovePickers();
100168
res = res && pickingManagerTest.TestRemoveObjects();
169+
res = res && pickingManagerTest.TestObjectOwnership();
101170

102171
return res ? EXIT_SUCCESS : EXIT_FAILURE;
103172
}
@@ -253,6 +322,28 @@ bool PickingManagerTest::TestRemoveObjects()
253322
return res;
254323
}
255324

325+
//------------------------------------------------------------------------------
326+
bool PickingManagerTest::TestObjectOwnership()
327+
{
328+
bool res = true;
329+
330+
this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
331+
vtkSmartPointer<PickingManagerClient> client =
332+
vtkSmartPointer<PickingManagerClient>::New();
333+
client->SetPickingManager(this->PickingManager.GetPointer());
334+
client->RegisterPicker();
335+
336+
res = VTK_VERIFY(this->CheckState(1, client->GetPicker(), 1),
337+
"Error after client registers picker:") && res;
338+
339+
client = NULL;
340+
341+
res = VTK_VERIFY(this->CheckState(0, NULL, 0),
342+
"Error after setting client object to NULL:") && res;
343+
344+
return res;
345+
}
346+
256347
//------------------------------------------------------------------------------
257348
std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> > PickingManagerTest::
258349
AddPickerObject(int pickerType, int objectType)

Rendering/Core/vtkPickingManager.cxx

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ class vtkPickingManager::vtkInternal
8888
// Create a new list of associated observers
8989
void CreateDefaultCollection(vtkAbstractPicker* picker, vtkObject* object);
9090

91-
// Instead of a vtkCollection we are using a vector of a vtkSmartPointer
91+
// vtkCollection doesn't allow NULL values. Instead we use a vector
9292
// containing vtkObject to allow using 0 as a valid value because it is
9393
// allowed the return a picker event if he is not associated to a specific
9494
// object.
9595
// This is related with the capacity when a picker associated with a given
9696
// object does not manage others object,
9797
// it will automatically be removed from the list as well.
98-
typedef std::vector<vtkSmartPointer<vtkObject> > CollectionType;
98+
typedef std::vector<vtkObject*> CollectionType;
9999

100100
// For code clearance and performances during the computation std::map is
101101
// used instead of a vector of pair. Nevertheless, it makes internally use of
@@ -138,23 +138,6 @@ class vtkPickingManager::vtkInternal
138138
vtkAbstractPicker* Picker;
139139
};
140140

141-
// Predicate comparing a vtkObject*
142-
// and a vtkSmartPointer<vtkObject> using the PickerObjectsType.
143-
// As we use a vtkSmartPointer, this predicate allows to compare the equality
144-
// of a pointer on a vtkObject with the adress contained in
145-
// a corresponding vtkSmartPointer.
146-
struct equal_smartPtrObject
147-
{
148-
equal_smartPtrObject(vtkObject* object) : Object(object) {}
149-
150-
bool operator () (const vtkSmartPointer<vtkObject>& smartObj) const
151-
{
152-
return this->Object == smartObj.GetPointer();
153-
}
154-
155-
vtkObject* Object;
156-
};
157-
158141
PickerObjectsType Pickers; // Map the picker with the objects
159142
vtkTimeStamp CurrentInteractionTime; // Time of the last interaction event
160143
vtkTimeStamp LastPickingTime; // Time of the last picking process
@@ -202,9 +185,9 @@ CreateDefaultCollection(vtkAbstractPicker* picker, vtkObject* object)
202185
void vtkPickingManager::vtkInternal::
203186
LinkPickerObject(const PickerObjectsType::iterator& it, vtkObject* object)
204187
{
205-
CollectionType::iterator itObj = std::find_if(it->second.begin(),
206-
it->second.end(),
207-
equal_smartPtrObject(object));
188+
CollectionType::iterator itObj = std::find(it->second.begin(),
189+
it->second.end(),
190+
object);
208191

209192
if (itObj != it->second.end() && object)
210193
{
@@ -234,9 +217,9 @@ IsObjectLinked(vtkAbstractPicker* picker, vtkObject* obj)
234217
return false;
235218
}
236219

237-
CollectionType::iterator itObj = std::find_if(itPick->second.begin(),
238-
itPick->second.end(),
239-
equal_smartPtrObject(obj));
220+
CollectionType::iterator itObj = std::find(itPick->second.begin(),
221+
itPick->second.end(),
222+
obj);
240223
return (itObj != itPick->second.end());
241224
}
242225

@@ -418,9 +401,9 @@ void vtkPickingManager::RemovePicker(vtkAbstractPicker* picker,
418401
}
419402

420403
vtkPickingManager::vtkInternal::CollectionType::iterator itObj =
421-
std::find_if(it->second.begin(),
422-
it->second.end(),
423-
vtkPickingManager::vtkInternal::equal_smartPtrObject(object));
404+
std::find(it->second.begin(),
405+
it->second.end(),
406+
object);
424407

425408
// The object is not associated with the given picker.
426409
if (itObj == it->second.end())
@@ -446,9 +429,9 @@ void vtkPickingManager::RemoveObject(vtkObject* object)
446429
for(; it != this->Internal->Pickers.end();)
447430
{
448431
vtkPickingManager::vtkInternal::CollectionType::iterator itObj =
449-
std::find_if(it->second.begin(),
450-
it->second.end(),
451-
vtkPickingManager::vtkInternal::equal_smartPtrObject(object));
432+
std::find(it->second.begin(),
433+
it->second.end(),
434+
object);
452435

453436
if (itObj != it->second.end())
454437
{

0 commit comments

Comments
 (0)