Index: mitk/Modules/SceneSerialization/mitkSceneIO.h =================================================================== --- mitk/Modules/SceneSerialization/mitkSceneIO.h (revision 17976) +++ mitk/Modules/SceneSerialization/mitkSceneIO.h (working copy) @@ -24,9 +24,14 @@ #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" +class TiXmlElement; + namespace mitk { +class BaseData; +class PropertyList; + class SceneSerialization_EXPORT SceneIO : public itk::Object { public: @@ -66,6 +71,8 @@ protected: + TiXmlElement* SaveBaseData( BaseData* data, const std::string& filenamehint ); + TiXmlElement* SavePropertyList( PropertyList* propertyList, const std::string& filenamehint ); }; } Index: mitk/Modules/SceneSerialization/mitkSceneIO.cpp =================================================================== --- mitk/Modules/SceneSerialization/mitkSceneIO.cpp (revision 17976) +++ mitk/Modules/SceneSerialization/mitkSceneIO.cpp (working copy) @@ -18,6 +18,12 @@ #include "mitkSceneIO.h" +#include "mitkProgressBar.h" +#include "mitkBaseRenderer.h" +#include "mitkRenderingManager.h" + +#include + mitk::DataStorage::Pointer mitk::SceneIO::LoadScene( const std::string& filename, DataStorage* storage, bool clearStorageFirst ) @@ -29,17 +35,200 @@ const std::string& filename, NodePredicateBase* predicate ) { - if (!storage) return false; + if (!storage) + { + LOG_ERROR << "No data storage given. Not possible to save scene."; + return false; + } - if (predicate) + if ( filename.empty() ) { - LOG_INFO << "Storing scene with " << storage->GetSubset(predicate)->size() << " objects to " << filename; + LOG_ERROR << "No filename given. Not possible to save scene."; + return false; } + + TiXmlDocument document; + TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); // TODO what to write here? encoding? etc.... + document.LinkEndChild( decl ); + + TiXmlElement* version = new TiXmlElement("Version"); + version->SetAttribute("Writer", __FILE__ ); + version->SetAttribute("Revision", "$Revision: 17055 $" ); + version->SetAttribute("FileVersion", 1 ); + document.LinkEndChild(version); + + typedef std::map< DataTreeNode*, std::string > UIDMapType; + typedef std::map< DataTreeNode*, std::list > SourcesMapType; + + UIDMapType nodeUIDs; // for dependencies: ID of each node + SourcesMapType sourceUIDs; // for dependencies: IDs of a node's parent nodes + + DataStorage::SetOfObjects::ConstPointer storedObjects = storage->GetSubset( predicate ); + + if ( storedObjects.IsNull() ) + { + LOG_WARN << "Saving empty scene to " << filename; + } else { - LOG_INFO << "Storing scene with " << storage->GetAll()->size() << " objects to " << filename; + if ( storedObjects->size() == 0 ) + { + LOG_WARN << "Saving empty scene to " << filename; + } + + LOG_INFO << "Storing scene with " << storedObjects->size() << " objects to " << filename; + + ProgressBar::GetInstance()->AddStepsToDo( storedObjects->size() ); + + // find out about dependencies + UIDGenerator nodeUIDGen("OBJECT_"); + + for (DataStorage::SetOfObjects::const_iterator iter = storedObjects->begin(); + iter != storedObjects->end(); + ++iter) + { + DataTreeNode* node = iter->GetPointer(); + if (!node) continue; // unlikely event that we get a NULL pointer as an object for saving. just ignore + + // generate UIDs for all source objects + DataStorage::SetOfObjects::ConstPointer sourceObjects = storage->GetSources( node ); + for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = sourceObjects->begin(); + sourceIter != sourceObjects->end(); + ++sourceIter ) + { + if ( std::find( storedObjects->begin(), storedObjects->end(), *sourceIter ) == storedObjects->end() ) continue; // source is not saved, so don't generate a UID for this source + + // create a uid for the parent object + if ( nodeUIDs[ *sourceIter ].empty() ) + { + nodeUIDs[ *sourceIter ] = nodeUIDGen.GetUID(); + } + + // store this dependency for writing + sourceUIDs[ node ].push_back( nodeUIDs[*sourceIter] ); + } + } + + // write out objects, dependencies and properties + for (DataStorage::SetOfObjects::const_iterator iter = storedObjects->begin(); + iter != storedObjects->end(); + ++iter) + { + DataTreeNode* node = iter->GetPointer(); + + if (node) + { + TiXmlElement* nodeElement = new TiXmlElement("node"); + std::string filenameHint( node->GetName() ); + + // store dependencies + UIDMapType::iterator searchUIDIter = nodeUIDs.find(node); + if ( searchUIDIter != nodeUIDs.end() ) + { + // store this node's ID + nodeElement->SetAttribute("UID", searchUIDIter->second.c_str() ); + } + + SourcesMapType::iterator searchSourcesIter = sourceUIDs.find(node); + if ( searchSourcesIter != sourceUIDs.end() ) + { + // store all source IDs + for ( std::list::iterator sourceUIDIter = searchSourcesIter->second.begin(); + sourceUIDIter != searchSourcesIter->second.end(); + ++sourceUIDIter ) + { + TiXmlElement* uidElement = new TiXmlElement("source"); + uidElement->SetAttribute("UID", sourceUIDIter->c_str() ); + nodeElement->LinkEndChild( uidElement ); + } + } + + // serialize basedata + if ( BaseData* data = node->GetData() ) + { + std::string filenameHint( node->GetName() ); + TiXmlElement* dataElement( SaveBaseData( data, filenameHint ) ); // returns a reference to a file + + // serialize basedata properties + PropertyList* propertyList = data->GetPropertyList(); + if (propertyList && !propertyList->IsEmpty() ) + { + TiXmlElement* baseDataPropertiesElement( SavePropertyList( propertyList, filenameHint + "-data" ) ); // returns a reference to a file + dataElement->LinkEndChild( baseDataPropertiesElement ); + } + + nodeElement->LinkEndChild( dataElement ); + } + + // serialize all renderwindow specific propertylists + const RenderingManager::RenderWindowVector& allRenderWindows( RenderingManager::GetInstance()->GetAllRegisteredRenderWindows() ); + for ( RenderingManager::RenderWindowVector::const_iterator rw = allRenderWindows.begin(); + rw != allRenderWindows.end(); + ++rw) + { + if (vtkRenderWindow* renderWindow = *rw) + { + std::string renderWindowName( mitk::BaseRenderer::GetInstance(renderWindow)->GetName() ); + BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(renderWindow); + PropertyList* propertyList = node->GetPropertyList(renderer); + if ( propertyList && !propertyList->IsEmpty() ) + { + TiXmlElement* renderWindowPropertiesElement( SavePropertyList( propertyList, filenameHint + "-" + renderWindowName ) ); // returns a reference to a file + renderWindowPropertiesElement->SetAttribute("render window", renderWindowName); + nodeElement->LinkEndChild( renderWindowPropertiesElement ); + } + } + } + + // don't forget the renderwindow independent list + PropertyList* propertyList = node->GetPropertyList(); + if ( propertyList && !propertyList->IsEmpty() ) + { + TiXmlElement* propertiesElement( SavePropertyList( propertyList, filenameHint + "-node") ); // returns a reference to a file + nodeElement->LinkEndChild( propertiesElement ); + } + + + document.LinkEndChild( nodeElement ); + } + else + { + LOG_WARN << "Ignoring NULL node during scene serialization."; + } + + ProgressBar::GetInstance()->Progress(); + } // end for all nodes + + } // end if storedObjects + + if ( !document.SaveFile( filename.c_str() ) ) + { + LOG_ERROR << "Could not write scene to " << filename << "\nTinyXML reports '" << document.ErrorDesc() << "'"; + return false; } + else + { + return true; + } +} - return true; +TiXmlElement* mitk::SceneIO::SaveBaseData( BaseData* data, const std::string& filenamehint ) +{ + assert(data); + + TiXmlElement* element = new TiXmlElement("data"); + element->SetAttribute("file", filenamehint); + + return element; } +TiXmlElement* mitk::SceneIO::SavePropertyList( PropertyList* propertyList, const std::string& filenamehint ) +{ + assert(propertyList); + + TiXmlElement* element = new TiXmlElement("properties"); + element->SetAttribute("file", filenamehint); + + return element; +} + Index: mitk/Modules/SceneSerialization/CMakeLists.txt =================================================================== --- mitk/Modules/SceneSerialization/CMakeLists.txt (revision 17976) +++ mitk/Modules/SceneSerialization/CMakeLists.txt (working copy) @@ -2,3 +2,5 @@ INCLUDE_DIRS BaseData Properties DEPENDS Mitk ) + +ADD_SUBDIRECTORY(Testing) Index: mitk/Modules/SceneSerialization/Testing/files.cmake =================================================================== --- mitk/Modules/SceneSerialization/Testing/files.cmake (revision 0) +++ mitk/Modules/SceneSerialization/Testing/files.cmake (revision 0) @@ -0,0 +1,5 @@ + +SET(MODULE_TESTS + mitkSceneIOTest.cpp +) + Property changes on: mitk/Modules/SceneSerialization/Testing/files.cmake ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision" Added: svn:eol-style + native Index: mitk/Modules/SceneSerialization/Testing/mitkSceneIOTest.cpp =================================================================== --- mitk/Modules/SceneSerialization/Testing/mitkSceneIOTest.cpp (revision 0) +++ mitk/Modules/SceneSerialization/Testing/mitkSceneIOTest.cpp (revision 0) @@ -0,0 +1,130 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Module: $RCSfile: mitkPropertyManager.cpp,v $ +Language: C++ +Date: $Date$ +Version: $Revision: 1.12 $ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "mitkTestingMacros.h" + +#include "mitkSceneIO.h" + +#include "mitkStandaloneDataStorage.h" +#include "mitkStandardFileLocations.h" +#include "mitkDataTreeNodeFactory.h" +#include "mitkBaseData.h" +#include "mitkImage.h" +#include "mitkSurface.h" + +class SceneIOTestClass +{ + public: + +/// returns full path to a test file +static std::string LocateFile(const std::string& filename) +{ + mitk::StandardFileLocations::Pointer locator = mitk::StandardFileLocations::GetInstance(); + MITK_TEST_CONDITION_REQUIRED(locator.IsNotNull(),"Instantiating StandardFileLocations") + return locator->FindFile(filename.c_str(), "Core/Testing/Data"); +} + +static mitk::BaseData::Pointer LoadBaseData(const std::string& filename) +{ + mitk::DataTreeNodeFactory::Pointer factory = mitk::DataTreeNodeFactory::New(); + try + { + factory->SetFileName( filename ); + factory->Update(); + + if(factory->GetNumberOfOutputs()<1) + { + MITK_TEST_FAILED_MSG(<< "Could not find test data '" << filename << "'"); + } + + mitk::DataTreeNode::Pointer node = factory->GetOutput( 0 ); + return node->GetData(); + } + catch ( itk::ExceptionObject & ex ) + { + MITK_TEST_FAILED_MSG(<< "Failed loading test data '" << filename << "'"); + } +} + +static mitk::Image::Pointer LoadImage(const std::string& filename) +{ + mitk::BaseData::Pointer basedata = LoadBaseData( filename ); + mitk::Image::Pointer image = dynamic_cast(basedata.GetPointer()); + if(image.IsNull()) + { + MITK_TEST_FAILED_MSG(<< "Test image '" << filename << "' was not loaded as an mitk::Image"); + } + return image; +} + +static mitk::Surface::Pointer LoadSurface(const std::string& filename) +{ + mitk::BaseData::Pointer basedata = LoadBaseData( filename ); + mitk::Surface::Pointer surface = dynamic_cast(basedata.GetPointer()); + if(surface.IsNull()) + { + MITK_TEST_FAILED_MSG(<< "Test surface '" << filename << "' was not loaded as an mitk::Surface"); + } + return surface; +} + +static void FillStorage(mitk::DataStorage* storage) +{ + mitk::Image::Pointer image = LoadImage( LocateFile("Pic3D.pic.gz") ); + MITK_TEST_CONDITION_REQUIRED(image.IsNotNull(),"Loading test image Pic3D.pic.gz"); + + image->SetProperty("image type", mitk::StringProperty::New("test image") ); + image->SetProperty("greetings", mitk::StringProperty::New("to mom") ); + + mitk::DataTreeNode::Pointer imagenode = mitk::DataTreeNode::New(); + imagenode->SetData( image ); + imagenode->SetName( "Pic3D" ); + storage->Add( imagenode ); + + mitk::Surface::Pointer surface = LoadSurface( LocateFile("binary.stl") ); + MITK_TEST_CONDITION_REQUIRED(surface.IsNotNull(),"Loading test surface binary.stl"); + + surface->SetProperty("surface type", mitk::StringProperty::New("test surface") ); + surface->SetProperty("greetings", mitk::StringProperty::New("to dad") ); + + mitk::DataTreeNode::Pointer surfacenode = mitk::DataTreeNode::New(); + surfacenode->SetData( surface ); + surfacenode->SetName( "binary" ); + storage->Add( surfacenode ); +} + +}; // end test helper class + +int mitkSceneIOTest(int /* argc */, char* /*argv*/[]) +{ + MITK_TEST_BEGIN("DataTreeNode") + + mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); + MITK_TEST_CONDITION_REQUIRED(sceneIO.IsNotNull(),"SceneIO instantiation") + + mitk::DataStorage::Pointer storage = mitk::StandaloneDataStorage::New().GetPointer(); + MITK_TEST_CONDITION_REQUIRED(storage.IsNotNull(),"StandaloneDataStorage instantiation"); + + SceneIOTestClass::FillStorage(storage); + + MITK_TEST_CONDITION_REQUIRED( sceneIO->SaveScene( storage, "scene.zip" ), + "Saving scene file" ); + + MITK_TEST_END() +} + Property changes on: mitk/Modules/SceneSerialization/Testing/mitkSceneIOTest.cpp ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision" Added: svn:eol-style + native Index: mitk/Modules/SceneSerialization/Testing/CMakeLists.txt =================================================================== --- mitk/Modules/SceneSerialization/Testing/CMakeLists.txt (revision 0) +++ mitk/Modules/SceneSerialization/Testing/CMakeLists.txt (revision 0) @@ -0,0 +1,3 @@ + +MITK_CREATE_MODULE_TESTS() + Property changes on: mitk/Modules/SceneSerialization/Testing/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Index: mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationViewControls.ui =================================================================== --- mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationViewControls.ui (revision 17976) +++ mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationViewControls.ui (working copy) @@ -39,7 +39,7 @@ true - QAbstractItemView::ExtendedSelection + QAbstractItemView::NoSelection Index: mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationView.cpp =================================================================== --- mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationView.cpp (revision 17976) +++ mitk/Modules/Bundles/org.mitk.gui.qt.sceneserialization/src/internal/QmitkSceneSerializationView.cpp (working copy) @@ -86,7 +86,7 @@ { mitk::SceneIO::Pointer sceneio = mitk::SceneIO::New(); - /* + /* TODO respect user selection in list view * intermediate step: create new data storage, add all selected nodes * OR: create a predicate ORing all selected nodes */