Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes

mitk::SceneIO Class Reference

#include <mitkSceneIO.h>

List of all members.

Public Types

typedef SceneIO Self
typedef itk::Object Superclass
typedef itk::SmartPointer< SelfPointer
typedef itk::SmartPointer
< const Self
ConstPointer
typedef DataStorage::SetOfObjects FailedBaseDataListType

Public Member Functions

virtual const char * GetClassName () const
virtual DataStorage::Pointer LoadScene (const std::string &filename, DataStorage *storage=NULL, bool clearStorageFirst=false)
 Load a scene of objects from file.
virtual bool SaveScene (DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage *storage, const std::string &filename)
 Save a scene of objects to file.
const FailedBaseDataListTypeGetFailedNodes ()
 Get a list of nodes (BaseData containers) that failed to be read/written.
const PropertyListGetFailedProperties ()
 Get a list of properties that failed to be read/written.

Static Public Member Functions

static Pointer New ()

Protected Member Functions

 SceneIO ()
virtual ~SceneIO ()
std::string CreateEmptyTempDirectory ()
TiXmlElementSaveBaseData (BaseData *data, const std::string &filenamehint, bool &error)
TiXmlElementSavePropertyList (PropertyList *propertyList, const std::string &filenamehint)
void OnUnzipError (const void *pSender, std::pair< const Poco::Zip::ZipLocalFileHeader, const std::string > &info)
void OnUnzipOk (const void *pSender, std::pair< const Poco::Zip::ZipLocalFileHeader, const Poco::Path > &info)

Protected Attributes

FailedBaseDataListType::Pointer m_FailedNodes
PropertyList::Pointer m_FailedProperties
std::string m_WorkingDirectory
unsigned int m_UnzipErrors

Detailed Description

Definition at line 36 of file mitkSceneIO.h.


Member Typedef Documentation

typedef itk::SmartPointer<const Self> mitk::SceneIO::ConstPointer

Definition at line 40 of file mitkSceneIO.h.

Definition at line 41 of file mitkSceneIO.h.

typedef itk::SmartPointer<Self> mitk::SceneIO::Pointer

Definition at line 40 of file mitkSceneIO.h.

Definition at line 40 of file mitkSceneIO.h.

typedef itk::Object mitk::SceneIO::Superclass

Definition at line 40 of file mitkSceneIO.h.


Constructor & Destructor Documentation

mitk::SceneIO::SceneIO (  ) [protected]

Definition at line 43 of file mitkSceneIO.cpp.

mitk::SceneIO::~SceneIO (  ) [protected, virtual]

Definition at line 49 of file mitkSceneIO.cpp.

{
}

Member Function Documentation

std::string mitk::SceneIO::CreateEmptyTempDirectory (  ) [protected]

Definition at line 53 of file mitkSceneIO.cpp.

References MITK_ERROR.

{
  std::string uniquename = Poco::TemporaryFile::tempName();
  Poco::File tempdir( uniquename );
  try
  {
    if (!tempdir.createDirectory())
    {
      MITK_ERROR << "Could not create temporary directory " << uniquename;
      return "";
    }
  }
  catch( std::exception& e )
  {
      MITK_ERROR << "Could not create temporary directory " << uniquename << ":" << e.what();
      return "";
  }
      
  return uniquename;
}
virtual const char* mitk::SceneIO::GetClassName (  ) const [virtual]
const mitk::SceneIO::FailedBaseDataListType * mitk::SceneIO::GetFailedNodes (  )

Get a list of nodes (BaseData containers) that failed to be read/written.

FailedBaseDataListType hold all those nodes that contain BaseData objects which could not be read or written during the last call to LoadScene or SaveScene.

Definition at line 500 of file mitkSceneIO.cpp.

{ 
  return m_FailedNodes.GetPointer(); 
}
const mitk::PropertyList * mitk::SceneIO::GetFailedProperties (  )

Get a list of properties that failed to be read/written.

Each entry corresponds to a property which could not be (de)serialized. The properties may come from either of

Definition at line 505 of file mitkSceneIO.cpp.

{ 
  return m_FailedProperties; 
}
mitk::DataStorage::Pointer mitk::SceneIO::LoadScene ( const std::string &  filename,
DataStorage storage = NULL,
bool  clearStorageFirst = false 
) [virtual]

Load a scene of objects from file.

Returns:
DataStorage with all scene objects and their relations. If loading failed, query GetFailedNodes() and GetFailedProperties() for more detail.

Attempts to read the provided file and create objects with parent/child relations into a DataStorage.

Parameters:
filenamefull filename of the scene file
storageIf given, this DataStorage is used instead of a newly created one
clearStorageFirstIf set, the provided DataStorage will be cleared before populating it with the loaded objects

Definition at line 74 of file mitkSceneIO.cpp.

References TiXmlDocument::ErrorDesc(), TiXmlDocument::LoadFile(), MITK_ERROR, mitk::SceneReader::New(), mitk::StandaloneDataStorage::New(), OnUnzipError(), and OnUnzipOk().

{
  // prepare data storage
  DataStorage::Pointer storage = pStorage;
  if ( storage.IsNull() )
  {
    storage = StandaloneDataStorage::New().GetPointer();
  }

  if ( clearStorageFirst )
  {
    try
    {
      storage->Remove( storage->GetAll() );
    }
    catch(...)
    {
      MITK_ERROR << "DataStorage cannot be cleared properly.";
    }
  }

  // test input filename
  if ( filename.empty() )
  {
    MITK_ERROR << "No filename given. Not possible to load scene.";
    return NULL;
  }
  
  // test if filename can be read
  std::ifstream file( filename.c_str(), std::ios::binary );
  if (!file.good())
  {
    MITK_ERROR << "Cannot open '" << filename << "' for reading";
    return NULL;
  }
  
  // get new temporary directory
  m_WorkingDirectory = CreateEmptyTempDirectory();
  if (m_WorkingDirectory.empty())
  {
    MITK_ERROR << "Could not create temporary directory. Cannot open scene files.";
    return NULL;
  }

  // unzip all filenames contents to temp dir
  m_UnzipErrors = 0;
  Poco::Zip::Decompress unzipper( file, Poco::Path( m_WorkingDirectory ) );
  unzipper.EError += Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &SceneIO::OnUnzipError);
  unzipper.EOk    += Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const Poco::Path> >(this, &SceneIO::OnUnzipOk);
  unzipper.decompressAllFiles();
  unzipper.EError -= Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &SceneIO::OnUnzipError);
  unzipper.EOk    -= Poco::Delegate<SceneIO, std::pair<const Poco::Zip::ZipLocalFileHeader, const Poco::Path> >(this, &SceneIO::OnUnzipOk);

  if ( m_UnzipErrors )
  {
    MITK_ERROR << "There were " << m_UnzipErrors << " errors unzipping '" << filename << "'. Will attempt to read whatever could be unzipped.";
  }

  // test if index.xml exists
  // parse index.xml with TinyXML
  TiXmlDocument document( m_WorkingDirectory + Poco::Path::separator() + "index.xml" );
  if (!document.LoadFile())
  {
    MITK_ERROR << "Could not open/read/parse " << m_WorkingDirectory << "/index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl;
    return NULL;
  }
      
  SceneReader::Pointer reader = SceneReader::New();
  if ( !reader->LoadScene( document, m_WorkingDirectory, storage ) )
  {
    MITK_ERROR << "There were errors while loding scene file " << filename << ". Your data may be corrupted";
  }

  // delete temp directory
  try
  {
    Poco::File deleteDir( m_WorkingDirectory );
    deleteDir.remove(true); // recursive
  }
  catch(...)
  {
    MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory;
  }

  // return new data storage, even if empty or uncomplete (return as much as possible but notify calling method)
  return storage;

}
static Pointer mitk::SceneIO::New (  ) [static]
void mitk::SceneIO::OnUnzipError ( const void *  pSender,
std::pair< const Poco::Zip::ZipLocalFileHeader, const std::string > &  info 
) [protected]

Definition at line 510 of file mitkSceneIO.cpp.

References MITK_ERROR.

Referenced by LoadScene().

{
  ++m_UnzipErrors;
  MITK_ERROR << "Error while unzipping: " << info.second;
}
void mitk::SceneIO::OnUnzipOk ( const void *  pSender,
std::pair< const Poco::Zip::ZipLocalFileHeader, const Poco::Path > &  info 
) [protected]

Definition at line 516 of file mitkSceneIO.cpp.

Referenced by LoadScene().

{
  // MITK_INFO << "Unzipped ok: " << info.second.toString();
}
TiXmlElement * mitk::SceneIO::SaveBaseData ( BaseData data,
const std::string &  filenamehint,
bool &  error 
) [protected]

Definition at line 419 of file mitkSceneIO.cpp.

References MITK_ERROR, and TiXmlElement::SetAttribute().

{
  assert(data);
  error = true;

  // find correct serializer
  // the serializer must
  //  - create a file containing all information to recreate the BaseData object --> needs to know where to put this file (and a filename?)
  //  - TODO what to do about writers that creates one file per timestep?
  TiXmlElement* element = new TiXmlElement("data");
  element->SetAttribute( "type", data->GetNameOfClass() );
 
  // construct name of serializer class
  std::string serializername(data->GetNameOfClass());
  serializername += "Serializer";
  
  std::list<itk::LightObject::Pointer> thingsThatCanSerializeThis = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str());
  if (thingsThatCanSerializeThis.size() < 1)
  {
    MITK_ERROR << "No serializer found for " << data->GetNameOfClass() << ". Skipping object";
  }

  for ( std::list<itk::LightObject::Pointer>::iterator iter = thingsThatCanSerializeThis.begin();
        iter != thingsThatCanSerializeThis.end();
        ++iter )
  {
    if (BaseDataSerializer* serializer = dynamic_cast<BaseDataSerializer*>( iter->GetPointer() ) )
    {
      serializer->SetData(data);
      serializer->SetFilenameHint(filenamehint);
      serializer->SetWorkingDirectory( m_WorkingDirectory );
      try
      {
        std::string writtenfilename = serializer->Serialize();
        element->SetAttribute("file", writtenfilename);
        error = false;
      }
      catch (std::exception& e)
      {
        MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
      }
      break;
    }
  }

  return element;
}
TiXmlElement * mitk::SceneIO::SavePropertyList ( PropertyList propertyList,
const std::string &  filenamehint 
) [protected]

Definition at line 467 of file mitkSceneIO.cpp.

References MITK_ERROR, mitk::PropertyListSerializer::New(), and TiXmlElement::SetAttribute().

{
  assert(propertyList);
  
  //  - TODO what to do about shared properties (same object in two lists or behind several keys)?
  TiXmlElement* element = new TiXmlElement("properties");
 
  // construct name of serializer class
  PropertyListSerializer::Pointer serializer = PropertyListSerializer::New();
  
  serializer->SetPropertyList(propertyList);
  serializer->SetFilenameHint(filenamehint);
  serializer->SetWorkingDirectory( m_WorkingDirectory );
  try
  {
    std::string writtenfilename = serializer->Serialize();
    element->SetAttribute("file", writtenfilename);
    PropertyList::Pointer failedProperties = serializer->GetFailedProperties();
    if (failedProperties.IsNotNull())
    {
      // move failed properties to global list
      m_FailedProperties->ConcatenatePropertyList( failedProperties, true );
    }
  }
  catch (std::exception& e)
  {
    MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
  }
    
  return element;
}
bool mitk::SceneIO::SaveScene ( DataStorage::SetOfObjects::ConstPointer  sceneNodes,
const DataStorage storage,
const std::string &  filename 
) [virtual]

Save a scene of objects to file.

Returns:
True if complete success, false if any problem occurred. Note that a scene file might still be written if false is returned, it just will not contain every node/property. If writing failed, query GetFailedNodes() and GetFailedProperties() for more detail.

Attempts to write a scene file, which contains the nodes of the provided DataStorage, their parent/child relations, and properties.

Parameters:
storagea DataStorage containing all nodes that should be saved
filenamefull filename of the scene file
predicatedefining which items of the datastorage to use and which not

Definition at line 165 of file mitkSceneIO.cpp.

References mitk::ProgressBar::AddStepsToDo(), TiXmlDocument::ErrorDesc(), mitk::DataNode::GetData(), mitk::BaseRenderer::GetInstance(), mitk::RenderingManager::GetInstance(), mitk::ProgressBar::GetInstance(), mitk::DataNode::GetName(), mitk::DataNode::GetPropertyList(), mitk::DataStorage::GetSources(), mitk::UIDGenerator::GetUID(), mitk::PropertyList::IsEmpty(), TiXmlNode::LinkEndChild(), MITK_ERROR, MITK_INFO, MITK_WARN, mitk::PropertyList::New(), mitk::ProgressBar::Progress(), CommonFunctionality::SaveBaseData(), TiXmlDocument::SaveFile(), and TiXmlElement::SetAttribute().

{
  if (!sceneNodes) 
  {
    MITK_ERROR << "No set of nodes given. Not possible to save scene.";
    return false;
  }
  if (!storage) 
  {
    MITK_ERROR << "No data storage given. Not possible to save scene.";  // \TODO: Technically, it would be possible to save the nodes without their relation
    return false;
  }

  if ( filename.empty() )
  {
    MITK_ERROR << "No filename given. Not possible to save scene.";
    return false;
  }

  try
  {

    m_FailedNodes = DataStorage::SetOfObjects::New();
    m_FailedProperties = PropertyList::New();

    // start XML DOM
    TiXmlDocument document;
    TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" ); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere...
    document.LinkEndChild( decl );

    TiXmlElement* version = new TiXmlElement("Version");
    version->SetAttribute("Writer",  __FILE__ );
    version->SetAttribute("Revision",  "$Revision: 17055 $" );
    version->SetAttribute("FileVersion",  1 );
    document.LinkEndChild(version);

    //DataStorage::SetOfObjects::ConstPointer sceneNodes = storage->GetSubset( predicate );

    if ( sceneNodes.IsNull() )
    {
      MITK_WARN << "Saving empty scene to " << filename;
    }
    else
    {
      if ( sceneNodes->size() == 0 )
      {
        MITK_WARN << "Saving empty scene to " << filename;
      }

    MITK_INFO << "Storing scene with " << sceneNodes->size() << " objects to " << filename;

      m_WorkingDirectory = CreateEmptyTempDirectory();
      if (m_WorkingDirectory.empty())
      {
        MITK_ERROR << "Could not create temporary directory. Cannot create scene files.";
        return false;
      }

      ProgressBar::GetInstance()->AddStepsToDo( sceneNodes->size() );

      // find out about dependencies
      typedef std::map< DataNode*, std::string > UIDMapType;
      typedef std::map< DataNode*, std::list<std::string> > SourcesMapType;

      UIDMapType nodeUIDs;              // for dependencies: ID of each node
      SourcesMapType sourceUIDs; // for dependencies: IDs of a node's parent nodes

      UIDGenerator nodeUIDGen("OBJECT_");

      for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin();
           iter != sceneNodes->end();
           ++iter)
      {
        DataNode* 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( sceneNodes->begin(), sceneNodes->end(), *sourceIter ) == sceneNodes->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] );
        }

        if ( nodeUIDs[ node ].empty() )
        {
          nodeUIDs[ node ] = nodeUIDGen.GetUID();
        }
      }

      // write out objects, dependencies and properties
      for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin();
           iter != sceneNodes->end();
           ++iter)
      {
        DataNode* node = iter->GetPointer();

        if (node)
        {
          TiXmlElement* nodeElement = new TiXmlElement("node");
          std::string filenameHint( node->GetName() );
          filenameHint = itksys::SystemTools::MakeCindentifier(filenameHint.c_str()); // escape filename <-- only allow [A-Za-z0-9_], replace everything else with _

          // 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<std::string>::iterator sourceUIDIter = searchSourcesIter->second.begin();
                  sourceUIDIter != searchSourcesIter->second.end();
                  ++sourceUIDIter )
            {
              TiXmlElement* uidElement = new TiXmlElement("source");
              uidElement->SetAttribute("UID", sourceUIDIter->c_str() );
              nodeElement->LinkEndChild( uidElement );
            }
          }

          // store basedata
          if ( BaseData* data = node->GetData() )
          {
            //std::string filenameHint( node->GetName() );
            bool error(false);
            TiXmlElement* dataElement( SaveBaseData( data, filenameHint, error ) ); // returns a reference to a file
            if (error)
            {
              m_FailedNodes->push_back( node );
            }

            // store 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 );
          }

          // store 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("renderwindow", 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
        {
          MITK_WARN << "Ignoring NULL node during scene serialization.";
        }

        ProgressBar::GetInstance()->Progress();
      } // end for all nodes

    } // end if sceneNodes

    if ( !document.SaveFile( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ) )
    {
      MITK_ERROR << "Could not write scene to " << m_WorkingDirectory << Poco::Path::separator() << "index.xml" << "\nTinyXML reports '" << document.ErrorDesc() << "'";
      return false;
    }
    else
    {
      try
      {
        Poco::File deleteFile( filename.c_str() );
        if (deleteFile.exists())
        {
          deleteFile.remove();
        }

        // create zip at filename
        std::ofstream file( filename.c_str(), std::ios::binary | std::ios::out);
        if (!file.good())
        {
          MITK_ERROR << "Could not open a zip file for writing: '" << filename << "'";
        }
        else
        {
          Poco::Zip::Compress zipper( file, true );
          Poco::Path tmpdir( m_WorkingDirectory );
          zipper.addRecursive( tmpdir );
          zipper.close();
        }
        try
        {
          Poco::File deleteDir( m_WorkingDirectory );
          deleteDir.remove(true); // recursive
        }
        catch(...)
        {
          MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory;
          return false; // ok?
        }
      }
      catch(std::exception& e)
      {
        MITK_ERROR << "Could not create ZIP file from " << m_WorkingDirectory << "\nReason: " << e.what();
        return false;
      }
      return true;
    }
  }
  catch(std::exception& e)
  {
    MITK_ERROR << "Caught exception during saving temporary files to disk. Error description: '" << e.what() << "'";
    return false;
  }
}

Member Data Documentation

FailedBaseDataListType::Pointer mitk::SceneIO::m_FailedNodes [protected]

Definition at line 109 of file mitkSceneIO.h.

Definition at line 110 of file mitkSceneIO.h.

unsigned int mitk::SceneIO::m_UnzipErrors [protected]

Definition at line 113 of file mitkSceneIO.h.

std::string mitk::SceneIO::m_WorkingDirectory [protected]

Definition at line 112 of file mitkSceneIO.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines