Skip to content

Commit

Permalink
BUG: 3241 Fix transform not applied to volume when scene is read from…
Browse files Browse the repository at this point in the history
… a file

When a scene is loaded, vtkMRMLScene::UpdateNodeReferences doesn't handle event registration.
Except for vtkCommand::ModifiedEvent, any other events need to be registered via OnNodeReferenceAdded API.
Fixes #3241
  • Loading branch information
yuzhengZ committed Aug 27, 2013
1 parent 5590234 commit deb391f
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Libs/MRML/Core/Testing/CMakeLists.txt
Expand Up @@ -75,6 +75,7 @@ create_test_sourcelist(Tests ${KIT}CxxTests.cxx
vtkMRMLStorageNodeTest1.cxx
vtkMRMLTensorVolumeNodeTest1.cxx
vtkMRMLTransformableNodeReferenceSaveImportTest.cxx
vtkMRMLTransformableNodeOnNodeReferenceAddTest.cxx
vtkMRMLTransformNodeTest1.cxx
vtkMRMLTransformStorageNodeTest1.cxx
vtkMRMLTransformableNodeTest1.cxx
Expand Down Expand Up @@ -171,6 +172,7 @@ simple_test( vtkMRMLStorableNodeTest1 )
simple_test( vtkMRMLStorageNodeTest1 )
simple_test( vtkMRMLTensorVolumeNodeTest1 )
simple_test( vtkMRMLTransformableNodeReferenceSaveImportTest )
simple_test( vtkMRMLTransformableNodeOnNodeReferenceAddTest )
simple_test( vtkMRMLTransformableNodeTest1 )
simple_test( vtkMRMLTransformNodeTest1 )
simple_test( vtkMRMLTransformStorageNodeTest1 )
Expand Down
@@ -0,0 +1,127 @@
/*=auto=========================================================================
Program: 3D Slicer
Copyright (c) Kitware Inc.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Yuzheng Zhou, Kitware Inc.
and was partially funded by NIH grant 3P41RR013218-12S1
=========================================================================auto=*/

// MRML includes
#include "vtkMRMLCoreTestingMacros.h"
#include "vtkMRMLLinearTransformNode.h"
#include "vtkMRMLTransformableNode.h"
#include "vtkMRMLScalarVolumeNode.h"
#include "vtkMRMLScene.h"

// VTK includes
#include <vtkGeneralTransform.h>
#include <vtkNew.h>
#include <vtkSmartPointer.h>

namespace
{

void populateScene(vtkMRMLScene* scene);

} // end of anonymous namespace

//---------------------------------------------------------------------------
int vtkMRMLTransformableNodeOnNodeReferenceAddTest(int , char * [] )
{
// Save a scene containing a viewnode and a sceneview node.
vtkNew<vtkMRMLScene> scene;
populateScene(scene.GetPointer());

scene->SetSaveToXMLString(1);
scene->Commit();
std::string xmlScene = scene->GetSceneXMLString();
std::cout << xmlScene << std::endl;

// Load the saved scene
vtkNew<vtkMRMLScene> scene2;

scene2->SetLoadFromXMLString(1);
scene2->SetSceneXMLString(xmlScene);
scene2->Import();

// Check transform node IDs
vtkMRMLNode* transformNode =
scene2->GetNthNodeByClass(0, "vtkMRMLLinearTransformNode");
if (!transformNode || strcmp(transformNode->GetID(), "vtkMRMLLinearTransformNode1") != 0)
{
std::cerr << __LINE__ << ": import failed." << std::endl
<< " transform node ID is " << transformNode->GetID()
<< " instead of vtkMRMLLinearTransformNode1." << std::endl;

return EXIT_FAILURE;
}

// Check references
vtkMRMLTransformableNode* trnsformableNode =
vtkMRMLTransformableNode::SafeDownCast(scene2->GetNthNodeByClass(0, "vtkMRMLTransformableNode"));

if (strcmp(trnsformableNode->GetTransformNodeID(),
transformNode->GetID()) != 0)
{
std::cerr << __LINE__ << ": import failed." << std::endl
<< " Transformable node references are not updated. "
<< "Transform node ID reference is "
<< trnsformableNode->GetTransformNodeID()
<< " instead of " << transformNode->GetID() << std::endl;
return EXIT_FAILURE;
}

// Test vtkMRMLTransformableNode::OnNodeReferenceAdded()
vtkMRMLLinearTransformNode* linearTransformNode = vtkMRMLLinearTransformNode::SafeDownCast(scene2->GetNthNodeByClass(0, "vtkMRMLLinearTransformNode"));
vtkMRMLScalarVolumeNode* volumeNode = vtkMRMLScalarVolumeNode::SafeDownCast(scene2->GetNthNodeByClass(0, "vtkMRMLScalarVolumeNode"));
vtkNew<vtkMRMLNodeCallback> callback;
volumeNode->AddObserver(vtkCommand::AnyEvent, callback.GetPointer());

linearTransformNode->GetMatrixTransformToParent()->Modified();
if (!callback->GetErrorString().empty() ||
callback->GetNumberOfModified() != 0 ||
callback->GetNumberOfEvents(vtkMRMLTransformNode::TransformModifiedEvent) != 1)
{
std::cerr << "vtkMRMLTransformableNode::OnNodeReferenceAdded failed."
<< callback->GetErrorString().c_str() << " "
<< "Number of ModifiedEvent: " << callback->GetNumberOfModified() << " "
<< "Number of TransformModifiedEvent: "
<< callback->GetNumberOfEvents(vtkMRMLTransformNode::TransformModifiedEvent)
<< std::endl;
return EXIT_FAILURE;
}
callback->ResetNumberOfEvents();
return EXIT_SUCCESS;
}

namespace
{

//---------------------------------------------------------------------------
void populateScene(vtkMRMLScene* scene)
{

vtkNew<vtkMRMLScalarVolumeNode> transformableableNode;
scene->AddNode(transformableableNode.GetPointer());

vtkNew<vtkMRMLLinearTransformNode> transformNode;
scene->AddNode(transformNode.GetPointer());

transformableableNode->SetAndObserveTransformNodeID(transformNode->GetID());

}


}
17 changes: 17 additions & 0 deletions Libs/MRML/Core/vtkMRMLTransformableNode.cxx
Expand Up @@ -13,6 +13,7 @@ Version: $Revision: 1.14 $
=========================================================================auto=*/

// MRML includes
#include "vtkEventBroker.h"
#include "vtkMRMLLinearTransformNode.h"
#include "vtkMRMLScene.h"

Expand Down Expand Up @@ -137,6 +138,22 @@ void vtkMRMLTransformableNode::SetAndObserveTransformNodeID(const char *transfor
this->InvokeEvent(vtkMRMLTransformableNode::TransformModifiedEvent, NULL);
}

//----------------------------------------------------------------------------
void vtkMRMLTransformableNode::OnNodeReferenceAdded(vtkMRMLNodeReference *reference)
{
Superclass::OnNodeReferenceAdded(reference);

// When a scene is loaded, vtkMRMLScene::UpdateNodeReferences doesn't handle
// event registration. Except for vtkCommand::ModifiedEvent, any other events
// need to be registered via OnNodeReferenceAdded API.
if (std::string(reference->GetReferenceRole()) == this->GetTransformNodeReferenceRole()
&& reference->ReferencedNode && reference->ReferencingNode)
{
vtkEventBroker::GetInstance()->AddObservation(reference->ReferencedNode,
vtkMRMLTransformableNode::TransformModifiedEvent, reference->ReferencingNode, this->MRMLCallbackCommand);
}
}

//---------------------------------------------------------------------------
void vtkMRMLTransformableNode::ProcessMRMLEvents ( vtkObject *caller,
unsigned long event,
Expand Down
3 changes: 3 additions & 0 deletions Libs/MRML/Core/vtkMRMLTransformableNode.h
Expand Up @@ -105,6 +105,9 @@ class VTK_MRML_EXPORT vtkMRMLTransformableNode : public vtkMRMLNode
virtual const char* GetTransformNodeReferenceRole();
virtual const char* GetTransformNodeReferenceMRMLAttributeName();

/// Called when a node reference ID is added (list size increased).
virtual void OnNodeReferenceAdded(vtkMRMLNodeReference *reference);

private:
char* TransformNodeIDInternal;
vtkSetStringMacro(TransformNodeIDInternal);
Expand Down

0 comments on commit deb391f

Please sign in to comment.