Commit 42d2cb21 authored by Floris Berendsen's avatar Floris Berendsen
Browse files

Merge branch 'develop' into ELASTIX-12-implement-componentdatabase

Conflicts:
	CMakeLists.txt
	Modules/Core/elxModuleCore.cmake
	SuperBuild/CMakeLists.txt
	Testing/Unit/CMakeLists.txt
parents 2ccb4dda 27392ab4
[submodule "Testing/GoogleTest"]
path = Testing/GoogleTest
url = https://github.com/kaspermarstal/GoogleTest
tag = release-1.7.0
sudo: false
sudo: required
dist: trusty
language: cpp
......@@ -26,8 +27,8 @@ before_script:
script:
- cmake ../SuperElastix/SuperBuild
- make --jobs=2 | grep -v '^--' | grep -v '^Installing'
- make --jobs=2 | grep -v '^--' | grep -v '^Installing' | grep -v '^common'
after_sucess:
after_success:
- cd Elastix-build
- ctest
macro( ElastixComponent COMPONENT )
ElastixModuleCheckName( ${COMPONENT} )
set( ELASTIX_COMPONENT_{$COMPONENT}_DEFINED TRUE )
endmacro()
macro( ElastixComponentCheckName COMPONENT )
if( NOT "${_name}" MATCHES "^[a-zA-Z][a-zA-Z0-9]*$" )
message( FATAL_ERROR "Invalid component name: ${COMPONENT}" )
endif()
endmacro()
\ No newline at end of file
......@@ -6,7 +6,7 @@ macro( _elxmodule_check_name MODULE )
message( FATAL_ERROR "Invalid module name: ${MODULE}" )
endif()
list( FIND ELXMODULE_ALL "${MODULE}" MODULE_FOUND )
list( FIND ELASTIX_MODULES "${MODULE}" MODULE_FOUND )
if( ${MODULE_FOUND} EQUAL -1 )
message( FATAL_ERROR "Module not found: ${MODULE}")
endif()
......@@ -16,7 +16,7 @@ macro( _elxmodule_enable MODULE )
_elxmodule_check_name( ${MODULE} )
if( NOT ${MODULE}_ENABLED )
set( USE_${MODULE} ON )
set( ELASTIX_USE_${MODULE} ON )
include( ${${MODULE}_FILE} )
......@@ -24,14 +24,9 @@ macro( _elxmodule_enable MODULE )
include_directories( ${${MODULE}_INCLUDE_DIRS} )
endif()
add_subdirectory( ${${MODULE}_SOURCE_DIR} )
if( ${MODULE}_LIBRARIES )
link_directories( ${${MODULE}_LIBRARY_DIRS} )
list( APPEND ELASTIX_LIBRARIES
${${MODULE}_LIBRARIES}
)
list( APPEND ELASTIX_LIBRARIES ${${MODULE}_LIBRARIES} )
endif()
# TODO: Add recursive dependency walk
......@@ -43,30 +38,32 @@ macro( _elxmodule_disable MODULE )
endmacro()
macro( _elxmodules_initialize )
set( ELXMODULE_ALL )
set( ELASTIX_LIBRARIES )
set( ELASTIX_MODULES )
file( GLOB MODULE_FILES RELATIVE "${CMAKE_SOURCE_DIR}"
file( GLOB_RECURSE MODULE_FILES RELATIVE "${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/Modules/*/elxModule*.cmake"
)
message( STATUS "Found the following elastix modules:")
foreach( MODULE_FILE ${MODULE_FILES})
get_filename_component( MODULE_PATH ${MODULE_FILE} PATH )
get_filename_component( MODULE ${MODULE_FILE} NAME_WE )
message( STATUS " ${MODULE}" )
get_filename_component( MODULE_NAME ${MODULE_FILE} NAME_WE )
get_filename_component( ${MODULE_NAME}_PATH ${MODULE_FILE} PATH )
message( STATUS " ${MODULE_NAME}" )
option( "USE_${MODULE}" OFF )
set( "${MODULE}_FILE" ${CMAKE_SOURCE_DIR}/${MODULE_FILE} )
set( "${MODULE}_ENABLED" OFF )
option( "ELASTIX_USE_${MODULE_NAME}" OFF )
set( "${MODULE_NAME}_FILE" ${CMAKE_SOURCE_DIR}/${MODULE_FILE} )
set( "${MODULE_NAME}_ENABLED" OFF )
set( ${MODULE}_SOURCE_DIR ${CMAKE_SOURCE_DIR}/${MODULE_PATH} )
set( ${MODULE}_BINARY_DIR ${CMAKE_BINARY_DIR}/${MODULE_PATH} )
set( ${MODULE_NAME}_SOURCE_DIR ${CMAKE_SOURCE_DIR}/${${MODULE_NAME}_PATH} )
set( ${MODULE_NAME}_BINARY_DIR ${CMAKE_BINARY_DIR}/${${MODULE_NAME}_PATH} )
set( ${MODULE}_INCLUDE_DIRS )
set( ${MODULE}_LIBRARY_DIRS )
set( ${MODULE}_LIBRARIES )
set( ${MODULE_NAME}_INCLUDE_DIRS )
set( ${MODULE_NAME}_LIBRARY_DIRS )
set( ${MODULE_NAME}_LIBRARIES )
list(APPEND ELXMODULE_ALL ${MODULE} )
list(APPEND ELASTIX_MODULES ${MODULE_NAME} )
endforeach()
endmacro()
......@@ -79,9 +76,3 @@ macro( elxmodule_enable MODULE )
_elxmodule_enable( ${MODULE} )
endmacro()
macro( elxmodule_compile MODULE )
project( "${MODULE}" )
add_library( ${MODULE} STATIC "${${MODULE}_SOURCE_FILES}" )
target_link_libraries( ${MODULE} ${ELASTIX_LIBRARIES} )
list( APPEND ${MODULE}_LIBRARIES ${MODULE} )
endmacro()
# Visual Studio complains if paths are too long
string( LENGTH "${CMAKE_CURRENT_SOURCE_DIR}" n )
if( n GREATER 50 )
message(
FATAL_ERROR
"Source code directory path length is too long for MSVC (${n} > 50)."
"Please move the source code directory to a directory with a shorter path."
)
endif()
if( MSVC )
string( LENGTH "${CMAKE_CURRENT_SOURCE_DIR}" n )
if( n GREATER 50 )
message(
FATAL_ERROR
"Source code directory path length is too long for MSVC (${n} > 50)."
"Please move the source code directory to a directory with a shorter path."
)
endif()
string( LENGTH "${CMAKE_CURRENT_BINARY_DIR}" n )
if( n GREATER 50 )
message(
FATAL_ERROR
"Build directory path length is too long for MSVC (${n} > 50)."
"Please move the build directory to a directory with a shorter path."
)
endif()
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /bigobj" )
string( LENGTH "${CMAKE_CURRENT_BINARY_DIR}" n )
if( n GREATER 50 )
message(
FATAL_ERROR
"Build directory path length is too long for MSVC (${n} > 50)."
"Please move the build directory to a directory with a shorter path."
)
endif()
\ No newline at end of file
# GoogleTest needs static linking
include( elxCompilerFlags.cmake )
foreach( CompilerFlag ${CompilerFlags} )
string( REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}" )
endforeach()
......@@ -2,7 +2,7 @@ cmake_minimum_required( VERSION 2.8 )
# Explicitly add INCREMENTAL linking option to command lines.
# http://www.cmake.org/pipermail/cmake/2010-February/035174.html
set( MSVC_INCREMENTAL_DEFAULT ON )
#set( MSVC_INCREMENTAL_DEFAULT ON )
# ---------------------------------------------------------------------
project( Elastix )
......@@ -13,13 +13,11 @@ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY
)
# Include SuperElastix CMake scripts
set( CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/CMake"
${CMAKE_MODULE_PATH}
)
list( APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake" )
if( ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" )
include( CMake/elxWinConfig.cmake )
if( ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC )
include( elxWinConfig )
endif()
# ---------------------------------------------------------------------
......@@ -31,14 +29,13 @@ include( "${CMAKE_CURRENT_SOURCE_DIR}/CMake/elxITKRequiredModules.cmake" )
# ---------------------------------------------------------------------
# Boost Graph Library
find_package( Boost REQUIRED graph )
find_package( Boost )
include_directories( ${Boost_INCLUDE_DIRS} )
# ---------------------------------------------------------------------
# Build Elastix
# Build SuperElastix
# For now we just enable all modules
include( "${CMAKE_CURRENT_SOURCE_DIR}/CMake/elxModules.cmake" )
include( elxModules )
elxmodule_enable( elxModuleCore )
# ---------------------------------------------------------------------
......@@ -46,14 +43,14 @@ elxmodule_enable( elxModuleCore )
# Testing requires CMake version 2.8.11 to download test data
if( CMAKE_VERSION VERSION_LESS 2.8.11 )
set( ELASTIX_BUILD_TESTING_DEFAULT OFF )
set( SUPERELASTIX_BUILD_TESTING_DEFAULT OFF )
message( STATUS "ELASTIX_BUILD_TESTING is set to OFF because CMake version is less than 2.8.11" )
else()
set( ELASTIX BUILD_TESTING_DEFAULT ON )
set( SUPERELASTIX_BUILD_TESTING_DEFAULT ON )
endif()
option( ELASTIX_BUILD_TESTING "Enable building tests." ${ELASTIX_BUILD_TESTING_DEFAULT} )
if( ${ELASTIX_BUILD_TESTING} )
option( SUPERELASTIX_BUILD_TESTING "Enable building tests." ${SUPERELASTIX_BUILD_TESTING_DEFAULT} )
if( ${SUPERELASTIX_BUILD_TESTING} )
enable_testing()
add_subdirectory( Testing )
endif()
......@@ -61,9 +58,9 @@ endif()
# ---------------------------------------------------------------------
# Build Documentation
mark_as_advanced( ELASTIX_BUILD_DOXYGEN )
option( ELASTIX_BUILD_DOXYGEN "Enable building Doxygen documentation." OFF )
mark_as_advanced( SUPERELASTIX_BUILD_DOXYGEN )
option( SUPERELASTIX_BUILD_DOXYGEN "Enable building Doxygen documentation." OFF )
mark_as_advanced( ELASTIX_BUILD_READTHEDOCS )
option( ELASTIX_BUILD_READTHEDOCS "Enable building readthedocs.org documentation." OFF )
mark_as_advanced( SUPERELASTIX_BUILD_READTHEDOCS )
option( SUPERELASTIX_BUILD_READTHEDOCS "Enable building readthedocs.org documentation." OFF )
#ifndef __Blueprint_h
#define __Blueprint_h
#include "boost/graph/graph_traits.hpp"
#include "boost/graph/directed_graph.hpp"
#include "itkObjectFactory.h"
#include "itkDataObject.h"
#include "elxMacro.h"
#include "elxComponentDescriptor.h"
#include "boost/graph/graph_traits.hpp"
#include "boost/graph/directed_graph.hpp"
namespace elx {
template< class TComponentDescriptor >
class Blueprint : public itk::DataObject
{
public:
elxNewMacro( Blueprint, itk::DataObject );
typedef TComponentDescriptor ComponentDescriptorType;
typedef typename TComponentDescriptor::ComponentNameType ComponentNameType;
typedef std::string ParameterKeyType;
typedef std::vector< std::string > ParameterValueType;
typedef std::map< ParameterKeyType, ParameterValueType > ParameterMapType;
// Component parameter map that sits on a node in the graph
// and holds component configuration settings
struct ComponentPropertyType {
ParameterMapType parameterMap;
};
// Component parameter map that sits on an edge in the graph
// and holds component configuration settings
struct ConnectionPropertyType {
ParameterMapType parameterMap;
};
typedef boost::adjacency_list< boost::vecS,
boost::vecS,
boost::directedS,
ComponentDescriptorType > GraphType;
typedef typename boost::graph_traits< GraphType >::vertex_descriptor ComponentType;
typedef typename boost::graph_traits< GraphType >::vertex_iterator ComponentIterator, ComponentIteratorEnd;
typedef boost::vertex_index_t ComponentIndexType;
typedef typename boost::property_map< GraphType, ComponentIndexType >::type ComponentIndexMapType;
typedef typename boost::graph_traits< GraphType >::edge_descriptor ConnectionDescriptorType;
typedef typename boost::graph_traits< GraphType >::edge_iterator ConnectionIterator, ConnectionIteratorEnd;
typedef typename boost::graph_traits< GraphType >::in_edge_iterator InputIterator, InputIteratorEnd;
typedef typename boost::graph_traits< GraphType >::out_edge_iterator OutputIterator, OutputIteratorEnd;
int TestFunction( void );
bool AddComponent( ComponentDescriptorType component );
bool SetComponent( ComponentIndexType componentIndex, ComponentDescriptorType component );
ComponentDescriptorType GetComponent( ComponentIndexType componentIndex );
bool RemoveComponent( ComponentDescriptorType component );
bool SetConnection( ComponentIndexType upstream, ComponentIndexType downstream );
ConnectionDescriptorType GetConnection( ConnectionDescriptorType Connection );
bool RemoveConnection( ConnectionDescriptorType connection );
void PrintGraph( void );
ComponentPropertyType,
ConnectionPropertyType > GraphType;
typedef boost::graph_traits< GraphType >::vertex_descriptor ComponentIndexType;
typedef boost::graph_traits< GraphType >::vertex_iterator ComponentIteratorType;
typedef std::pair< ComponentIteratorType, ComponentIteratorType > ComponentIteratorPairType;
typedef boost::graph_traits< GraphType >::edge_descriptor ConnectionIndexType;
typedef boost::graph_traits< GraphType >::edge_iterator ConnectionIteratorType;
typedef std::pair< ConnectionIteratorType, ConnectionIteratorType > ConnectionIteratorPairType;
typedef boost::graph_traits< GraphType >::in_edge_iterator InputIteratorType;
typedef std::pair< InputIteratorType, InputIteratorType > InputIteratorPairType;
typedef boost::graph_traits< GraphType >::out_edge_iterator OutputIteratorType;
typedef std::pair< OutputIteratorType, OutputIteratorType > OutputIteratorPairType;
// Interface for managing components
ComponentIndexType AddComponent( void );
ComponentIndexType AddComponent( ParameterMapType parameterMap );
ParameterMapType GetComponent( ComponentIndexType index );
void SetComponent( ComponentIndexType, ParameterMapType parameterMap );
// TODO: Let user delete component. Before we do this, we need a proper way of
// checking that a vertex exist. Otherwise a call to GetComponent() on
// a deleted vertex will result in segfault. It is not really a in issue
// _before_ release since typically we (the developers) will use blueprint
// interface procedurally.
// void DeleteComponent( ComponentIndexType );
ComponentIteratorPairType GetComponentIterator( void ) {
return boost::vertices( this->m_Graph );
}
// Interface for managing connections between components in which we
// deliberately avoid using connection indexes, but instead force
// the user to think in terms of components (which is conceptually simpler)
bool AddConnection( ComponentIndexType upstream, ComponentIndexType downstream );
bool AddConnection( ComponentIndexType upstream, ComponentIndexType downstream, ParameterMapType parameterMap );
ParameterMapType GetConnection( ComponentIndexType upstream, ComponentIndexType downstream );
bool SetConnection( ComponentIndexType upstream, ComponentIndexType downstream, ParameterMapType parameterMap );
bool DeleteConnection( ComponentIndexType upstream, ComponentIndexType downstream );
bool ConnectionExists( ComponentIndexType upstream, ComponentIndexType downstream );
// Returns iterator for all connections in the graph
ConnectionIteratorPairType GetConnectionIterator( void ) {
return boost::edges(this->m_Graph);
}
// Returns the outgoing connections from a component in the graph,
// i.e. all components that reads data from given component
OutputIteratorPairType GetOutputIterator( const ComponentIndexType index ) {
return boost::out_edges( index, this->m_Graph );
}
void WriteBlueprint( const std::string filename );
private:
ConnectionIndexType GetConnectionIndex( ComponentIndexType upsteam, ComponentIndexType downstream );
GraphType m_Graph;
......
#ifndef __ComponentDescriptor_h
#define __ComponentDescriptor_h
#include "elxMacro.h"
#include "itkObjectFactory.h"
#include "itkDataObject.h"
namespace elx {
class ComponentDescriptor : public itk::DataObject
{
public:
elxNewMacro( ComponentDescriptor, itk::DataObject );
// Identifier to find component in the component database
typedef std::string ComponentNameType;
ComponentDescriptor( void ) { this->SetComponentName( ComponentNameType() ); }
ComponentDescriptor( const ComponentNameType componentName );
// TODO: Setter should validate ComponentName exists in ComponentDatabase
itkSetMacro( ComponentName, ComponentNameType );
itkGetMacro( ComponentName, ComponentNameType );
private:
ComponentNameType m_ComponentName;
};
}
#endif // __ComponentDescriptor_h
#ifndef __Blueprint_hxx
#define __Blueprint_hxx
#ifndef __Blueprint_cxx
#define __Blueprint_cxx
#include <boost/graph/graphviz.hpp>
#include "boost/graph/graphviz.hpp"
#include "elxBlueprint.h"
namespace elx {
/*
Blueprint< ComponentDescriptor >::ComponentDescriptorType
Blueprint< ComponentDescriptor >
::AddComponent( ComponentDescriptorType component )
Blueprint::ComponentIndexType
Blueprint
::AddComponent( void )
{
// TODO: Check that the component is in the ComponentDatabase
this->Modified();
return this->m_Graph->add_vertex( component );
ComponentIndexType index = boost::add_vertex( this->m_Graph );
// Return component index so component can retrieved at a later time
return index;
}
bool
Blueprint< ComponentDescriptor >
::SetComponent( ComponentDescriptorType component )
Blueprint::ComponentIndexType
Blueprint
::AddComponent( ParameterMapType parameterMap )
{
this->Modified();
ComponentIndexType index = boost::add_vertex( this->m_Graph );
this->m_Graph[index].parameterMap = parameterMap;
// Return component index so component can retrieved at a later time
return index;
}
Blueprint::ParameterMapType
Blueprint
::GetComponent( ComponentIndexType index )
{
this->Modified();
return this->m_Graph->remove_vertex( connection );
return this->m_Graph[ index ].parameterMap;
}
void
Blueprint
::SetComponent( ComponentIndexType index, ParameterMapType parameterMap )
{
this->Modified();
this->m_Graph[ index ].parameterMap = parameterMap;
}
// TODO: See explanation in elxBlueprint.h
// void
// Blueprint
// ::DeleteComponent( const ComponentIndexType index )
// {
// this->Modified();
//
// clear_vertex( index, this->m_Graph );
// remove_vertex( index, this->m_Graph );
// }
bool
Blueprint< ComponentDescriptor >
::RemoveComponent( ComponentDescriptorType component )
Blueprint
::AddConnection( ComponentIndexType upstream, ComponentIndexType downstream )
{
this->Modified();
return this->m_Graph->remove_vertex( connection );
if( this->ConnectionExists( upstream, downstream) ) {
return false;
}
// Adds directed connection from upstream component to downstream component
return boost::add_edge( upstream, downstream, this->m_Graph ).second;
}
bool
Blueprint< ComponentDescriptor >
::AddConnection( ComponentDescriptorType upsteam, ComponentDescriptorType downstream )
Blueprint
::AddConnection( ComponentIndexType upstream, ComponentIndexType downstream, ParameterMapType parameterMap )
{
this->Modified();
if( !this->ConnectionExists( upstream, downstream ) ) {
ConnectionIndexType index = boost::add_edge( upstream, downstream, this->m_Graph ).first;
this->m_Graph[ index ].parameterMap = parameterMap;
return true;
}
// If the connection does not exist don't do anything because previous settings
// will be overwritten. If the user do want to overwrite current settings,
// she should use SetConnection() instead where the intent is explicit.
return false;
}
Blueprint::ParameterMapType
Blueprint
::GetConnection( ComponentIndexType upstream, ComponentIndexType downstream )
{
this->Modified();
return this->m_Graph->add_edge( upstream, downstream );
return this->m_Graph[ this->GetConnectionIndex( upstream, downstream ) ].parameterMap;
}
ConnectionDescriptorType
Blueprint< ComponentDescriptor >
::GetConnection( ConnectionDescriptorType Connection )
bool
Blueprint
::SetConnection( ComponentIndexType upstream, ComponentIndexType downstream, ParameterMapType parameterMap )
{
this->Modified();
if( !this->ConnectionExists( upstream, downstream ) ) {
return this->AddConnection( upstream, downstream, parameterMap );
} else {
this->m_Graph[ this->GetConnectionIndex( upstream, downstream ) ].parameterMap = parameterMap;
return true;
}
}
void
Blueprint< ComponentDescriptor >
::RemoveConnection( ConnectionType connection )
bool
Blueprint
::DeleteConnection( ComponentIndexType upstream, ComponentIndexType downstream )
{
this->Modified();
this->m_Graph->remove_edge( connection );
if( this->ConnectionExists( upstream, downstream ) ) {
this->m_Graph.remove_edge( this->GetConnectionIndex( upstream, downstream ) );
}
return !this->ConnectionExists( upstream, downstream );
}
void
Blueprint< ComponentDescriptor >
::PrintGraph( void )
bool
Blueprint
::ConnectionExists( ComponentIndexType upstream, ComponentIndexType downstream )
{
// TODO: Link to graphviz library
// boost::write_graphviz(std::cout, this->m_Graph);
std::cout << "Printed graph" << std::endl;
return boost::edge( upstream, downstream, this->m_Graph).second;
}
*/
template<>
int
Blueprint< ComponentDescriptor >
::TestFunction( void )
{ return 0; }
Blueprint::ConnectionIndexType
Blueprint
::GetConnectionIndex( ComponentIndexType upstream, ComponentIndexType downstream )
{
// This function is part of the internal API and should fail hard if we use it incorrectly
if( !this->ConnectionExists( upstream, downstream ) ) {
itkExceptionMacro( "Blueprint does not contain connection from component " << upstream << " to " << downstream );
}
return boost::edge( upstream, downstream, this->m_Graph).first;
}
void
Blueprint
::WriteBlueprint( const std::string filename )
{
std::ofstream dotfile( filename.c_str() );
boost::write_graphviz( dotfile, this->m_Graph );
}