Commit 9adee893 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[MERGE]

parents d21321d1 06f47a83
Alois Schloegl
André Reichenbach
Anne Berres
Christian Heine
......
......@@ -24,5 +24,12 @@ export LD_PRELOAD=$Preloads
# Force C locale. This fixes an issue with newer boost versions. See ticket #130.
export LC_ALL=C
# Check if the user has set $OPENWALNUT_USEOPTIMUS to an executable
runner=
if [ -x "$OPENWALNUT_USEOPTIMUS" ]; then
echo "Optimus implementation found. Using "$OPENWALNUT_USEOPTIMUS""
runner=/$OPENWALNUT_USEOPTIMUS
fi
# Run OpenWalnut
$BINDIR/openwalnut-qt4 $@
$runner $BINDIR/openwalnut-qt4 $@
#! /path/to/openwalnut/bin/openwalnut-script -f
# 1. Introduction
#
# This is an example on how to use the script interpreter that comes with OpenWalnut.
# We will be loading all NIfTI datasets in a directory given via script parameter, apply a
# gaussian blur and then save the data to another directory also given via script parameter.
#
# However, before we start, let's have a look at OpenWalnut's script interpreter.
# 2. Script interpreter
#
# The script interpreter can be started via
#
# openwalnut-script -i language-name ,
#
# Where 'language-name' is the name of the language to use (currently "lua" and/or "python", depending on which
# prerequisite libraries were available when compiling).
# Start in python mode:
#
# openwalnut-script -i python
#
# You can use this python interpreter just as you would use the normal one. For example, type
#
# print i
#
# This yields an error, as 'i' was not defined. Try
#
# i = 1
# print i
#
# This yields the correct answer. You can also use all modules available to your python installation:
#
# import datetime
# print datetime.datetime.now().strftime( "%A %Y-%m-%d %H:%M" )
#
# This will print the current day and time. You can also define and use functions and classes. Feel free to experiment a bit.
# You can quit by typing 'quit'.
# 3. Executing script files
#
# To execute a script, switch to your OpenWalnut installation and execute:
#
# openwalnut-script -f script-name
#
# Where 'script-name' is the path to and name of your script file. For example, to execute this script, type
#
# openwalnut-script -f template.py
#
# Depending on whether you installed OpenWalnut or built it yourself, you might need to change the path to
# something like:
#
# openwalnut-script -f ../resources/scripting/template.py
#
# The script will tell you that no input and output directories were found and OpenWalnut will quit afterwards.
# The directories can be set via script parameters:
#
# openwalnut-script -f ../resources/scripting/template.py ./inDir ./outDir
#
# or
#
# ../resources/scripting/template.py ./inDir ./outDir (this requires the script to be executable and the path to your
# OpenWalnut installation/build-directory set correctly in the
# first line of the script)
# 4. Implementing a batch processing pipeline for OpenWalnut
#
# Now that we know how to execute the script, let's have a look at what it actually does.
# The first part is importing what we need:
import sys
import os
import signal
import time
# This makes the interpreter react to Ctrl+C.
signal.signal( signal.SIGINT, signal.SIG_DFL )
# Now we can proceed by checking the parameters:
if len( sys.argv ) < 3:
print "Too few parameters, quitting."
exit( 1 )
# This checks the input dir:
inputDir = sys.argv[ 1 ]
print "Input dir was set to", inputDir
if not os.path.exists( inputDir ):
print "The directory", inputDir, "does not exist!"
exit( 1 )
if not os.path.isdir( inputDir ):
print inputDir, "is not a directory!"
exit( 1 )
# Now the same for our output directory:
outputDir = sys.argv[ 2 ]
print "Output dir was set to", outputDir
if not os.path.exists( outputDir ):
print "The directory", outputDir, "does not exist!"
exit( 1 )
if not os.path.isdir( outputDir ):
print outputDir, "is not a directory!"
exit( 1 )
# The next step is to find all the files that we want to process:
niftiList = list()
filesList = os.listdir( inputDir )
for f in filesList:
if not os.path.isdir( os.path.join( inputDir, f ) ):
filename, extension = os.path.splitext( f )
if extension is not None and extension == '.nii':
niftiList.append( f )
if extension is not None and extension == '.gz':
filename, extension = os.path.splitext( filename )
if extension is not None and extension == '.nii':
niftiList.append( f )
print "List of nifti files in input directory:", niftiList
if len( niftiList ) == 0:
print "No nifti files found!"
exit( 1 )
# Now that we have found all the datasets, we can proceed by initializing the
# OpenWalnut module pipeline that will do the gauss filter on our datasets. The
# pipeline will look like this:
#
# 'Data Module' -> 'Gauss Filtering' -> 'Write NIfTI'
#
# We start by creating the 'Gauss Filtering' and 'Write NIfTI' modules using the
# 'rootContainer' global:
gauss = rootContainer.create( "Gauss Filtering" )
writer = rootContainer.create( "Write NIfTI" )
# We can now change some properties of the modules we just created. We get access
# to a module's properties with the 'getProperties()' and 'getInformationProperties()' funtions.
# These return the respective property groups.
# The groups can then be asked for properties or nested property groups via the 'getProperty()'
# and 'getGroup()' functions, both taking a string parameter denoting the name of the property
# or group to get.
iterProp = gauss.getProperties().getProperty( "Iterations" )
# Let's increase the width of the kernel:
iterProp.setInt( 2 )
# The properties provide various functions for getting and setting, for example the
# 'setInt()' function we just used. There are more such functions, such as
#
# 'setBool()'
# 'setDouble()'
# 'setFilename()' - the parameter is a string denoting a path/filename
# 'setSelection()' - the parameter is an integer denoting which element of a selection to select
# 0 is the first one, 1 the second one etc....
#
# There are also the respective getters.
# We now need to connect the modules. To be more precise, we need to connect
# the writer's input connector 'in' to the gauss filter's output connector 'out'.
# The names of the connectors can be looked up in the GUI version of OpenWalnut.
# (The names of the properties too.)
writer.getInputConnector( "in" ).connect( gauss.getOutputConnector( "out" ) )
# The modules can be disconnected again using the 'disconnect()' function of either
# the input- or the output connectors. We'll see this in action later.
# Now that we have done the setup, let's start working on the datasets.
for dataset in niftiList:
fileToLoad = os.path.join( inputDir, dataset )
# We start with loading the dataset, which is done by creating a data module:
data = rootContainer.createDataModule( fileToLoad )
# Now we check if the data we loaded is a scalar dataset:
if not data.getInformationProperties().getProperty( "Dataset type" ).getString( True ) == "WDataSetScalar":
print fileToLoad, "does not contain scalar data! Skipping."
continue
# If the dataset is a scalar dataset, we proceed by setting the output filename in the writer:
fileToSave = os.path.join( outputDir, dataset )
writer.getProperties().getProperty( "Filename" ).setFilename( fileToSave )
# Now we connect the data module, this will start the pipeline:
gauss.getInputConnector( "in" ).connect( data.getOutputConnector( "out" ) )
# The tricky part is waiting for the correct events, as all OpenWalnut modules run
# in their own threads. We cannot just keep on loading data and passing them to the gauss
# module, as it would just ignore the new inputs until it has finished calculating. By the time
# this happens, we might already be done loading the datasets, so OpenWalnut would just
# close because we reached the end of the script without waiting for the calculations to finish.
#
# So what we need to do now is wait for the input of the writer to update:
writer.getInputConnector( "in" ).waitForInput()
# We can now issue the saving of the result by pushing the 'Save' button.
writer.getProperties().getProperty( "Do save" ).click()
# We could now wait for the button to be reset. (Which means the saving is done.)
#
# writer.getProperties().getProperty( "Do save" ).waitForUpdate()
#
# You can wait for any property to be changed via its 'waitForUpdate()' function.
#
# However, for really small datasets, the saving might be done really fast, so
# the update may happen before we actually start waiting for it, resulting in us waiting
# forever. And we most certainly do not have that much time. So we just wait a few seconds.
time.sleep( 3 )
# Now our data should be written to disk, so we can now delete the dataset from the pipeline
# by removing the data module. This is done via the 'remove()' function of the 'rootContainer'
# global. We might also want to disconnect the data- and gauss modules beforehand.
data.getOutputConnector( "out" ).disconnect()
rootContainer.remove( data )
# Now we are ready for the next dataset.
# Well, and that's it for this simple batch processing example.
time.sleep( 3 )
print "Everything done, bye!"
# As python provides quite a lot of functionality, you can write lots of cool scripts to control
# your pipelines. For example, using sockets, you could control multiple OpenWalnut instances on
# remote computers. Have an entire army of OpenWalnuts do as you command!
#
# Have fun!
......@@ -141,13 +141,19 @@ ADD_SUBDIRECTORY( core )
OPTION( OW_GUI_QT4 "Enable this to build the QT4-based OpenWalnut GUI." ON )
IF( OW_GUI_QT4 )
SET( OWQt4GuiName "qt4gui" )
SET( OWBinaryName "openwalnut-qt4" )
# build
ADD_SUBDIRECTORY( qt4gui )
ENDIF()
# -----------------------------------------------------------------------------------------------------------------------------------------------
# Scripting GUI
OPTION( OW_GUI_SCRIPT "Enable this to build the script-based OpenWalnut interface for commandline-only use." ON )
IF( OW_GUI_SCRIPT )
# build
ADD_SUBDIRECTORY( scriptgui )
ENDIF()
# -----------------------------------------------------------------------------------------------------------------------------------------------
# Modules
......
......@@ -37,6 +37,21 @@ ADD_DEFINITIONS( '-DW_LIB_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}"' )
OPTION( OW_STATIC_BUILD "Enable this to build the core library as static library." OFF )
# the files to link against if we found the necessary libs for a script interpreter
SET( INTERPRETER_LINK_LIBRARIES )
IF( BUILD_PYTHON_INTERPRETER )
# Python
FIND_PACKAGE( PythonLibs REQUIRED )
# Python found?
IF( PYTHONLIBS_FOUND AND Boost_FOUND )
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} )
ADD_DEFINITIONS( -DPYTHON_FOUND )
SET( INTERPRETER_LINK_LIBRARIES ${INTERPRETER_LINK_LIBRARIES} ${PYTHON_LIBRARIES} )
ENDIF()
ENDIF() # BUILD_SCRIPTENGINE
# ---------------------------------------------------------------------------------------------------------------------------------------------------
# Add sources as target
# ---------------------------------------------------------------------------------------------------------------------------------------------------
......@@ -51,7 +66,7 @@ ELSE()
ADD_LIBRARY( ${LibName} SHARED ${TARGET_CPP_FILES} ${TARGET_H_FILES} ${OW_VERSION_HEADER} )
ENDIF()
TARGET_LINK_LIBRARIES( ${LibName} ${Boost_LIBRARIES} ${CMAKE_STANDARD_LIBRARIES} ${CMAKE_DL_LIBS} ${OPENGL_gl_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES}
TARGET_LINK_LIBRARIES( ${LibName} ${Boost_LIBRARIES} ${CMAKE_STANDARD_LIBRARIES} ${CMAKE_DL_LIBS} ${OPENGL_gl_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES} ${INTERPRETER_LINK_LIBRARIES}
)
# Tell CMake that someone creates this file for us. See doc of SETUP_VERSION_HEADER for details why this is needed.
......@@ -156,4 +171,3 @@ SETUP_SHADERS( "${TARGET_GLSL_FILES}" "${OW_SHARE_DIR_RELATIVE}/shaders" "CORE"
SETUP_STYLECHECKER( "${LibName}"
"${TARGET_CPP_FILES};${TARGET_H_FILES};${TARGET_TEST_FILES};${TARGET_GLSL_FILES}" # add all these files to the stylechecker
"" ) # exlude some ugly files
......@@ -168,6 +168,17 @@ public:
protected:
private:
/**
* Checks if the two given intervals intersect and computes the distance between them.
*
* \param a0 lower bound of the first interval
* \param a1 upper bound of the first interval
* \param b0 lower bound of the second interval
* \param b1 upper bound if the second interval
*
* \return The distance between those intervals if they don't overlap, zero otherwise
*/
double intervalDistance( double a0, double a1, double b0, double b1 ) const;
};
template< class VT >
......@@ -223,33 +234,18 @@ inline bool WBoundingBoxImpl< VT >::intersects( const WBoundingBoxImpl< VT > &bb
return osg::BoundingBoxImpl< VT >::intersects( bb );
}
/**
* Anonymous namespace, just to be DRY in minDistance.
*/
namespace
template< class VT >
inline double WBoundingBoxImpl< VT >::intervalDistance( double a0, double a1, double b0, double b1 ) const
{
/**
* Checks if the two given intervals intersect and computes the distance between them.
*
* \param a0 lower bound of the first interval
* \param a1 upper bound of the first interval
* \param b0 lower bound of the second interval
* \param b1 upper bound if the second interval
*
* \return The distance between those intervals if they don't overlap, zero otherwise
*/
inline double intervalDistance( double a0, double a1, double b0, double b1 )
if( a1 < b0 )
{
if( a1 < b0 )
{
return b0 - a1;
}
else if( b1 < a0 )
{
return a0 - b1;
}
return 0.0;
return b0 - a1;
}
else if( b1 < a0 )
{
return a0 - b1;
}
return 0.0;
}
template< class VT >
......
......@@ -55,9 +55,25 @@ const std::vector< std::string >& WProjectFileIO::getErrors() const
return m_errors;
}
bool WProjectFileIO::hadWarnings() const
{
return m_warnings.size();
}
const std::vector< std::string >& WProjectFileIO::getWarnings() const
{
return m_warnings;
}
void WProjectFileIO::addError( std::string description )
{
wlog::error( "Project Loader" ) << description;
m_errors.push_back( description );
}
void WProjectFileIO::addWarning( std::string description )
{
wlog::warn( "Project Loader" ) << description;
m_warnings.push_back( description );
}
......@@ -86,6 +86,20 @@ public:
*/
const std::vector< std::string >& getErrors() const;
/**
* Checks whether there where warnings during load or save.
*
* \return true if there where.
*/
bool hadWarnings() const;
/**
* Get warnings list.
*
* \return the list
*/
const std::vector< std::string >& getWarnings() const;
protected:
/**
* Add an error. Use this when you encounter some difficulties during parsing or applying settings. Provide useful errors. They will be
......@@ -95,11 +109,24 @@ protected:
*/
void addError( std::string description );
/**
* Add an warning. Use this when you encounter some difficulties during parsing or applying settings. Provide useful warnings. They will be
* presented to the user.
*
* \param description the error description
*/
void addWarning( std::string description );
private:
/**
* List of errors if any.
*/
std::vector< std::string > m_errors;
/**
* List of warnings if any.
*/
std::vector< std::string > m_warnings;
};
#endif // WPROJECTFILEIO_H
......
......@@ -183,3 +183,8 @@ boost::shared_ptr< WCondition > WPropertyBase::getUpdateCondition() const
return m_updateCondition;
}
WPropInterval WPropertyBase::toPropInterval()
{
return boost::shared_static_cast< WPVInterval >( shared_from_this() );
}
......@@ -265,7 +265,7 @@ public:
/**
* Helper converts this instance to its native type.
*
* \return the property as matrix4x4 property
* \return the property as transfer function property
*/
WPropTransferFunction toPropTransferFunction();
......@@ -276,6 +276,13 @@ public:
*/
WPropGroup toPropGroup();
/**
* Helper converts this instance to its native type.
*
* \return the property as interval property
*/
WPropInterval toPropInterval();
/**
* Convert the property to a WPropertyGroupBase. This can be done with property structs and groups-
*
......
......@@ -37,6 +37,7 @@
#include "math/linearAlgebra/WLinearAlgebra.h"
#include "math/linearAlgebra/WMatrixFixed.h"
#include "math/linearAlgebra/WVectorFixed.h"
#include "math/WInterval.h"
#include "WAssert.h"
#include "WColor.h"
#include "WItemSelector.h"
......@@ -74,7 +75,8 @@ typedef enum
PV_MATRIX4X4, //!< for 4x4 matrices
PV_TRANSFERFUNCTION, //!< for transfer function textures
PV_STRUCT, //!< for complex, structured properties (used by \ref WPropertyStruct)
PV_LIST //!< for a dynamic list of properties of the same type (see \ref WPropertyList)
PV_LIST, //!< for a dynamic list of properties of the same type (see \ref WPropertyList)
PV_INTERVAL //!< for defining intervals (min and max values)
}
PROPERTY_TYPE;
......@@ -109,6 +111,7 @@ namespace WPVBaseTypes
typedef WColor PV_COLOR; //!< base type used for every WPVColor
typedef WMatrix4d PV_MATRIX4X4; //!< base type used for every WPVMatrix4X4
typedef WTransferFunction PV_TRANSFERFUNCTION; //!< base type for every transfer function
typedef WIntervalDouble PV_INTERVAL; //!< base type used for every PV_INTERVAL
/**
* Enum denoting the possible trigger states. It is used for trigger properties.
......@@ -216,6 +219,11 @@ typedef WPropertyVariable< WPVBaseTypes::PV_MATRIX4X4 > WPVMatrix4X4;
*/
typedef WPropertyVariable< WPVBaseTypes::PV_TRANSFERFUNCTION > WPVTransferFunction;
/**
* Interval properties
*/
typedef WPropertyVariable< WPVBaseTypes::PV_INTERVAL > WPVInterval;
/**
* Some convenience type alias for a even more easy usage of WPropertyVariable.
* These typdefs define some pointer alias.
......@@ -281,6 +289,11 @@ typedef boost::shared_ptr< WPVMatrix4X4 > WPropMatrix4X4;
*/
typedef boost::shared_ptr< WPVTransferFunction > WPropTransferFunction;
/**
* Alias for the interval properties
*/
typedef boost::shared_ptr< WPVInterval > WPropInterval;
/**
* This namespace contains several helper classes which translate their template type to an enum.
*/
......@@ -552,6 +565,24 @@ namespace PROPERTY_TYPE_HELPER
}
};
/**
* Class helping to adapt types specified as template parameter into an enum.
*/
template<>
class WTypeIdentifier< WPVBaseTypes::PV_INTERVAL >
{
public:
/**
* Get type identifier of the template type T.
*
* \return type identifier-
*/
PROPERTY_TYPE getType()
{
return PV_INTERVAL;
}
};
/**
* Class helping to create a new instance of the property content from an old one. Selections need this special care since they contain not
* serializable content which needs to be acquired from its predecessor instance.
......@@ -701,6 +732,48 @@ namespace PROPERTY_TYPE_HELPER
return out.str();
}
};
/**
* Class helping to create a new instance of the property content from an old one. Selections need this special care since they contain not
* serializable content which needs to be acquired from its predecessor instance.
*/
template<>
class WStringConversion< WPVBaseTypes::PV_INTERVAL >
{
public:
/**
* Creates a new instance of the type from a given string. Some classes need a predecessor which is also specified here.
*
* \param str the new value as string
*
* \return the new instance
*/
WPVBaseTypes::PV_INTERVAL create( const WPVBaseTypes::PV_INTERVAL& /*old*/, const std::string str )
{
std::vector< std::string > tokens;
tokens = string_utils::tokenize( str, ";" );
WAssert( tokens.size() >= 2, "There weren't 2 values for an interval" );
WPVBaseTypes::PV_INTERVAL c( string_utils::fromString< double >( tokens[ 0 ] ),
string_utils::fromString< double >( tokens[ 1 ] ) );
return c;
}
/**
* Creates a string from the specified value.
*
* \param v the value to convert
*
* \return the string representation
*/
std::string asString( const WPVBaseTypes::PV_INTERVAL& v )
{
std::ostringstream out;
out << v.getLower() << ";" << v.getUpper();
return out.str();
}
};
}
#endif // WPROPERTYTYPES_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of<