瀏覽代碼

Merge remote branch 'remotepieper/master'

Michi Onken 16 年之前
父節點
當前提交
eee564357f

+ 9 - 5
Applications/ctkDICOM/ctkDICOM.cpp

@@ -38,7 +38,7 @@ int main(int argc, char** argv)
 
   // set up the database 
   const char *datbaseFileName = "/tmp/test.db";
-  const char *datbaseScriptFileName = "/Users/pieper/ctk/latest/CTK/Libs/DICOM/Core/Resources/dicom-sample.sql";
+  const char *datbaseScriptFileName = "/home/nolden/CTK/Libs/DICOM/Core/Resources/dicom-sample.sql";
   if (argc > 1)
     {
     datbaseFileName = argv[1];
@@ -49,12 +49,16 @@ int main(int argc, char** argv)
     }
 
   ctkDICOM myCTK;
-  if (!myCTK.openDatabase( datbaseFileName ))
-    {
+  try
+  {
+    myCTK.openDatabase( datbaseFileName );
+  }
+  catch (std::exception e)
+  {
     std::cerr << "Error when opening the data base file: " << datbaseFileName
-              << " error: " << myCTK.GetLastError().toStdString();
+              << " error: " << e.what();
     return EXIT_FAILURE;
-    }
+  }
   if (!myCTK.initializeDatabase(datbaseScriptFileName))
     {
     std::cerr << "Error when initializing the data base: " << datbaseScriptFileName

+ 62 - 24
Applications/ctkDICOMIndexer/ctkDICOMIndexer.cpp

@@ -32,45 +32,83 @@
 #include <iostream>
 #include <fstream>
 
+void print_usage()
+{
+  std::cerr << "Usage:\n";
+  std::cerr << "  1. ctkDICOMIndexer --add <database.db> <sourceDir> [destDir]\n";
+  std::cerr << "     Adds (or refreshes) sourceDir to the index of the database.\n";
+  std::cerr << "     Creates the database if it is not valid..\n";
+  std::cerr << "     If destDir is provided, images are copied there after import.\n";
+  std::cerr << "  2. ctkDICOMIndexer --init <database.db> [sqlScript]\n";
+  std::cerr << "     Reinitialize the database. Uses default schema or the provided sqlScript file.\n";
+  std::cerr << "  3. ctkDICOMIndexer --cleanup <database.db>\n";
+  std::cerr << "     Remove non-existent files from the database.\n";
+  return;
+}
+
+
+/**
+  *
+*/
 int main(int argc, char** argv)
 {
 
-  if (argc < 2)
-    {
-    std::cerr << "Usage: ctkDICOMIndexer <database.db> <sourceDir> [destDir]\n";
+  if (argc < 3)
+  {
+    print_usage();
     return EXIT_FAILURE;
-    }
+  }
 
   QApplication app(argc, argv);
   QTextStream out(stdout);
 
   ctkDICOMIndexer idx;
-
   ctkDICOM myCTK;
-  if ( myCTK.openDatabase( argv[1]) )
+
+
+  try
+  {
+    if (std::string("--add") == argv[1])
+    {
+      {
+        myCTK.openDatabase( argv[2] );
+        if (argc > 4)
+        {
+          idx.addDirectory(myCTK.database(),argv[3],argv[4]);
+        }
+        else
+        {
+          idx.addDirectory(myCTK.database(),argv[3]);
+        }
+      }
+    }
+    else if (std::string("--init") == argv[1])
     {
-    out << "open db success\n";
-    /// make sure it is empty and properly initialized
-    myCTK.initializeDatabase();
-    out << "init db done\n";
-    if (argc > 3)
+      myCTK.openDatabase( argv[2] );
+      if (argc > 2)
       {
-      idx.addDirectory(myCTK.database(),argv[2],argv[3]);
-      } 
-      else 
+        myCTK.initializeDatabase(argv[2]);
+      }
+      else
       {
-      idx.addDirectory(myCTK.database(),argv[2]);
+        myCTK.initializeDatabase();
       }
-    out << "add db done\n";
-    idx.refreshDatabase(myCTK.database(),argv[2]);
-    out << "refresh db done\n";
-    myCTK.closeDatabase();
     }
-  else
-    { 
-    out << "ERROR: " ;
-    out << myCTK.GetLastError();
-    out << "\n" ;
+    else if (std::string("--cleanup") == argv[1])
+    {
+      // TODO
+    }
+    else
+    {
+      print_usage();
+      return EXIT_FAILURE;
     }
+  }
+  catch (std::exception e)
+  {
+    std::cerr << "Database error:" << qPrintable(myCTK.GetLastError());
+    myCTK.closeDatabase();
+    return EXIT_FAILURE;
+  }
   return EXIT_SUCCESS;
 }

+ 20 - 17
CMakeExternals/ZMQ.cmake

@@ -1,18 +1,21 @@
-#
-# ZMQ
-#
-SET(ZMQ_DEPENDS)
-ctkMacroShouldAddExternalProject(ZMQ_LIBRARIES add_project)
-IF(${add_project})
-  SET(proj ZMQ)
-#   MESSAGE(STATUS "Adding project:${proj}")
-  SET(ZMQ_DEPENDS ${proj})
-  ExternalProject_Add(${proj}
-      DOWNLOAD_COMMAND ""
-      INSTALL_COMMAND ""
-      CMAKE_GENERATOR ${gen}
-      SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ZMQ
-      CMAKE_ARGS
-        ${ep_common_args}
-      )
+#
+# ZMQ
+#
+SET(ZMQ_DEPENDS)
+ctkMacroShouldAddExternalProject(ZMQ_LIBRARIES add_project)
+IF(${add_project})
+  SET(proj ZMQ)
+#   MESSAGE(STATUS "Adding project:${proj}")
+  SET(ZMQ_DEPENDS ${proj})
+  ExternalProject_Add(${proj}
+      GIT_REPOSITORY git://github.com/PatrickCheng/zeromq2.git
+      INSTALL_COMMAND ""
+      CMAKE_GENERATOR ${gen}
+      CMAKE_ARGS
+        ${ep_common_args}
+		-DBUILD_SHARED_LIBS:BOOL=ON 
+		-DZMQ_BUILD_DEVICES:BOOL=ON
+		-DZMQ_BUILD_PERFORMANCE_TESTS:BOOL=ON
+      )
+	  SET(ZMQ_DIR ${ep_build_dir}/${proj})
 ENDIF()

+ 10 - 9
CMakeLists.txt

@@ -50,6 +50,7 @@ ENDFOREACH()
 PROJECT(CTK)
 #-----------------------------------------------------------------------------
 
+#-----------------------------------------------------------------------------
 # Default to shared library
 SET(CTK_LIBRARY_MODE "SHARED")
 SET(CTK_BUILD_SHARED_LIBS TRUE)
@@ -57,15 +58,13 @@ SET(CTK_BUILD_SHARED_LIBS TRUE)
 #-----------------------------------------------------------------------------
 # Output directories.
 #
-IF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
-  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CTK_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all libraries.")
-ENDIF()
-IF(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
-  SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CTK_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all libraries.")
-ENDIF()
-IF(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
-  SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CTK_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all libraries.")
-ENDIF()
+FOREACH(type LIBRARY RUNTIME ARCHIVE)
+  IF(NOT CTK_CMAKE_${type}_OUTPUT_DIRECTORY)
+    SET(CMAKE_${type}_OUTPUT_DIRECTORY ${${PROJECT_NAME}_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all libraries.")
+  ELSE()
+    SET(CMAKE_${type}_OUTPUT_DIRECTORY ${CTK_CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Single output directory for building all libraries.")
+  ENDIF()
+ENDFOREACH()
 
 #-----------------------------------------------------------------------------
 # Install directories, used for install rules.
@@ -234,6 +233,7 @@ SET(CTK_LIBS
   Widgets:OFF
   DICOM/Core:OFF
   DICOM/Widgets:OFF
+  Messaging/Core:OFF
   Scripting/Python/Core:OFF
   Scripting/Python/Widgets:OFF
   Visualization/VTK/Core:OFF
@@ -484,3 +484,4 @@ INCLUDE(Utilities/KWStyle/KWStyle.cmake)
 # the end of the whole configuration process, as a "last step".
 # This directory is typically the last SUBDIRS in the main CMakeLists.txt.
 ADD_SUBDIRECTORY(Utilities/LastConfigureStep)
+

+ 8 - 4
Libs/DICOM/Core/Testing/Cpp/ctkDICOMModelTest1.cpp

@@ -31,12 +31,16 @@ int ctkDICOMModelTest1( int argc, char * argv [] )
     }
   
   ctkDICOM myCTK;
-  if (!myCTK.openDatabase( argv[1] ))
-    {
+  try
+  {
+    myCTK.openDatabase( argv[1] );
+  }
+  catch (std::exception e)
+  {
     std::cerr << "Error when opening the data base file: " << argv[1] 
-              << " error: " << myCTK.GetLastError().toStdString();
+              << " error: " << e.what();
     return EXIT_FAILURE;
-    }
+  }
   if (!myCTK.initializeDatabase(argv[2]))
     {
     std::cerr << "Error when initializing the data base: " << argv[2] 

+ 8 - 7
Libs/DICOM/Core/Testing/Cpp/ctkDICOMTest1.cpp

@@ -15,8 +15,9 @@ int ctkDICOMTest1(int argc, char * argv []) {
   QApplication app(argc, argv);
   QTextStream out(stdout);
   ctkDICOM myCTK;
-  if ( myCTK.openDatabase( argv[1]) )
-    {
+  try
+  {
+    myCTK.openDatabase( argv[1]);
     out << "open db success\n";
     /// make sure it is empty and properly initialized
     if (! myCTK.initializeDatabase() ) {
@@ -30,11 +31,11 @@ int ctkDICOMTest1(int argc, char * argv []) {
     };
     myCTK.closeDatabase(); 
     }
-  else
-    { 
-    out << "ERROR: " ;
-    out << myCTK.GetLastError();
-    }
+  catch (std::exception e)
+  {
+    out << "ERROR: " << e.what();
+    return EXIT_FAILURE;
+  }
   return EXIT_SUCCESS;
 }
 

+ 3 - 3
Libs/DICOM/Core/ctkDICOM.cpp

@@ -31,6 +31,7 @@
 
 // STD includes
 #include <iostream>
+#include <stdexcept>
 
 //----------------------------------------------------------------------------
 class ctkDICOMPrivate: public ctkPrivate<ctkDICOM>
@@ -67,7 +68,7 @@ ctkDICOM::~ctkDICOM()
 }
 
 //----------------------------------------------------------------------------
-bool ctkDICOM::openDatabase(const QString& databaseFileName)
+void ctkDICOM::openDatabase(const QString& databaseFileName)
 {
   CTK_D(ctkDICOM);
   d->Database = QSqlDatabase::addDatabase("QSQLITE","DICOM-DB");
@@ -75,13 +76,12 @@ bool ctkDICOM::openDatabase(const QString& databaseFileName)
   if ( ! (d->Database.open()) )
     {
     d->LastError = d->Database.lastError().text();
-    return false;
+    throw std::runtime_error(qPrintable(d->LastError));
     }
   if ( d->Database.tables().empty() ) 
     {
     initializeDatabase();
     }
-  return true;
 }
 
 //------------------------------------------------------------------------------

+ 1 - 1
Libs/DICOM/Core/ctkDICOM.h

@@ -43,7 +43,7 @@ public:
   /// open the SQLite database in @param file. If the file does not
   /// exist, a new database is created and initialized with the
   /// default schema
-  virtual bool openDatabase(const QString& file);
+  virtual void openDatabase(const QString& file);
 
   const QSqlDatabase& database() const;
   const QString& GetLastError() const; 

+ 1 - 1
Libs/DICOM/Core/ctkDICOMModel.cpp

@@ -285,7 +285,7 @@ void ctkDICOMModelPrivate::updateQueries(Node* node)const
       break;
     case ctkDICOMModelPrivate::SeriesType:
       //query = QString("SELECT Filename as UID, Filename as Name, SeriesInstanceUID as Date FROM Images WHERE SeriesInstanceUID='%1'").arg(node->UID);
-      query = this->generateQuery("Filename as UID, Filename as Name, SeriesInstanceUID as Date", "Images", QString("SeriesInstanceUID='%1'").arg(node->UID));
+      // query = this->generateQuery("Filename as UID, Filename as Name, SeriesInstanceUID as Date", "Images", QString("SeriesInstanceUID='%1'").arg(node->UID));
       break;
     case ctkDICOMModelPrivate::ImageType:
       break;

+ 81 - 0
Libs/Messaging/Core/CMakeLists.txt

@@ -0,0 +1,81 @@
+PROJECT(CTKMessagingCore)
+
+#
+# 3rd party dependencies
+#
+
+FIND_PACKAGE(ZMQ)
+# TODO In case ZMQ is passed directly using ZMQ_DIR, check expected options
+IF(NOT ZMQ_FOUND)
+  MESSAGE(FATAL_ERROR "error: ZMQ package is required to build ${PROJECT_NAME}")
+ENDIF()
+INCLUDE(${ZMQ_USE_FILE})
+
+
+#FIND_PACKAGE(OpenIGTLink)
+# TODO In case OpenIGTLink is passed directly using OpenIGTLink_DIR, check expected options
+#IF(NOT OpenIGTLink_FOUND)
+#  MESSAGE(FATAL_ERROR "error: OpenIGTLink package is required to build ${PROJECT_NAME}")
+#ENDIF()
+#INCLUDE(${OpenIGTLink_USE_FILE})
+
+
+#
+# See CTK/CMake/ctkMacroBuildLib.cmake for details
+#
+
+SET(KIT_export_directive "CTK_MESSAGING_CORE_EXPORT")
+
+# Additional directories to include
+SET(KIT_include_directories
+  )
+  
+# Source files
+SET(KIT_SRCS
+  ctkMessagingServer.h
+  ctkMessagingServer.cpp
+  ctkMessagingClient.h
+  ctkMessagingClient.cpp
+  )
+
+# Headers that should run through moc
+SET(KIT_MOC_SRCS
+  )
+
+# UI files
+SET(KIT_UI_FORMS
+  )
+
+# Resources
+SET(KIT_resources
+  )
+
+# Set VTK_LIBRARIES variable
+#SET(ZMQ_LIBRARIES
+#  vtkCommon
+#  vtkFiltering
+#  )
+
+# Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
+# The following macro will read the target libraries from the file 'target_libraries.cmake'
+ctkMacroGetTargetLibraries(KIT_target_libraries)
+
+ctkMacroBuildLib(
+  NAME ${PROJECT_NAME}
+  EXPORT_DIRECTIVE ${KIT_export_directive}
+  INCLUDE_DIRECTORIES ${KIT_include_directories}
+  SRCS ${KIT_SRCS}
+  MOC_SRCS ${KIT_MOC_SRCS}
+  UI_FORMS ${KIT_UI_FORMS}
+  TARGET_LIBRARIES ${KIT_target_libraries}
+  RESOURCES ${KIT_resources}
+  LIBRARY_TYPE ${CTK_LIBRARY_MODE}
+  )
+
+# Plugins
+#ADD_SUBDIRECTORY(Plugins)
+
+# Testing
+IF(BUILD_TESTING)
+  ADD_SUBDIRECTORY(Testing)
+ENDIF(BUILD_TESTING)

+ 30 - 0
Libs/Messaging/Core/Testing/CMakeLists.txt

@@ -0,0 +1,30 @@
+SET(KIT ${PROJECT_NAME})
+
+CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cpp
+  ctkMessagingServerTest1.cpp
+  #EXTRA_INCLUDE TestingMacros.h
+  )
+
+SET (TestsToRun ${Tests})
+REMOVE (TestsToRun ${KIT}CppTests.cpp)
+
+SET(LIBRARY_NAME ${PROJECT_NAME})
+
+ADD_EXECUTABLE(${KIT}CppTests ${Tests})
+TARGET_LINK_LIBRARIES(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES})
+
+SET( KIT_TESTS ${CPP_TEST_PATH}/${KIT}CppTests)
+IF(WIN32)
+  SET(KIT_TESTS ${CPP_TEST_PATH}/${CMAKE_BUILD_TYPE}/${KIT}CppTests)
+ENDIF(WIN32)
+
+MACRO( SIMPLE_TEST  TESTNAME )
+  ADD_TEST( ${TESTNAME} ${KIT_TESTS} ${TESTNAME} )
+  SET_PROPERTY(TEST ${TESTNAME} PROPERTY LABELS ${PROJECT_NAME})
+ENDMACRO( SIMPLE_TEST  )
+
+#
+# Add Tests
+#
+
+SIMPLE_TEST( ctkMessagingServerTest1 )

+ 37 - 0
Libs/Messaging/Core/Testing/ctkMessagingServerTest1.cpp

@@ -0,0 +1,37 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+// CTK includes
+#include "ctkMessagingServer.h"
+#include "ctkModelTester.h"
+
+// STD includes
+#include <stdlib.h>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+int ctkMessagingServerTest1(int argc, char * argv [] )
+{
+  
+  ctkMessagingServer * server = new ctkMessagingServer;
+
+  return EXIT_SUCCESS;
+}
+

+ 39 - 0
Libs/Messaging/Core/ctkMessagingClient.cpp

@@ -0,0 +1,39 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+// ZMQ includes
+
+// ctkDICOM includes
+#include "ctkMessagingClient.h"
+
+// STD includes
+#include <iostream>
+
+
+//------------------------------------------------------------------------------
+ctkMessagingClient::ctkMessagingClient()
+{
+}
+
+//----------------------------------------------------------------------------
+ctkMessagingClient::~ctkMessagingClient()
+{
+}
+

+ 43 - 0
Libs/Messaging/Core/ctkMessagingClient.h

@@ -0,0 +1,43 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+#ifndef __ctkMessagingClient_h
+#define __ctkMessagingClient_h
+
+// ZMQ includes 
+#include <zmq.hpp>
+#include "CTKMessagingCoreExport.h"
+
+//class ctkMessagingClientPrivate;
+
+class CTK_MESSAGING_CORE_EXPORT ctkMessagingClient
+{
+public:
+  //typedef QObject Superclass;
+  explicit ctkMessagingClient();
+  virtual ~ctkMessagingClient();
+  
+
+private:
+//  CTK_DECLARE_PRIVATE(ctkMessagingClient);
+
+};
+
+#endif

+ 44 - 0
Libs/Messaging/Core/ctkMessagingServer.cpp

@@ -0,0 +1,44 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+// ZMQ includes
+
+// ctkDICOM includes
+#include "ctkMessagingServer.h"
+
+// STD includes
+#include <iostream>
+
+
+//------------------------------------------------------------------------------
+ctkMessagingServer::ctkMessagingServer()
+{
+  zmq::context_t ctx (1, 1);
+
+  // Create a PUB socket for port 5555 on the lo interface
+  zmq::socket_t s(ctx, ZMQ_PUB);
+  //s.bind ("tcp://lo0:5555");
+}
+
+//----------------------------------------------------------------------------
+ctkMessagingServer::~ctkMessagingServer()
+{
+}
+

+ 43 - 0
Libs/Messaging/Core/ctkMessagingServer.h

@@ -0,0 +1,43 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  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.
+ 
+=========================================================================*/
+
+#ifndef __ctkMessagingServer_h
+#define __ctkMessagingServer_h
+
+// ZMQ includes 
+#include <zmq.hpp>
+#include "CTKMessagingCoreExport.h"
+
+//class ctkMessagingServerPrivate;
+
+class CTK_MESSAGING_CORE_EXPORT ctkMessagingServer
+{
+public:
+  //typedef QObject Superclass;
+  explicit ctkMessagingServer();
+  virtual ~ctkMessagingServer();
+  
+
+private:
+//  CTK_DECLARE_PRIVATE(ctkMessagingServer);
+
+};
+
+#endif

+ 11 - 0
Libs/Messaging/Core/target_libraries.cmake

@@ -0,0 +1,11 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK libraries
+#
+
+SET(target_libraries
+  #OpenIGTLink_LIBRARIES
+  ZMQ_LIBRARIES
+  CTKCore
+  )

+ 20 - 12
Libs/Visualization/VTK/Core/ctkVTKColorTransferFunction.cpp

@@ -177,23 +177,31 @@ ctkControlPoint* ctkVTKColorTransferFunction::controlPoint(int index)const
   ctkNonLinearControlPoint* cp = new ctkNonLinearControlPoint();
   cp->P.X = values[0];
   cp->P.Value = rgb;
-  d->ColorTransferFunction->GetNodeValue(index + 1, values);
-  Q_ASSERT(values[0] >= d->ColorTransferFunction->GetRange()[0] &&
-           values[0] <= d->ColorTransferFunction->GetRange()[1] &&
-           values[1] >= 0. && values[1] <= 1. &&  // Red
-           values[2] >= 0. && values[2] <= 1. &&  // Green
-           values[3] >= 0. && values[3] <= 1. &&  // Blue
-           values[4] >= 0. && values[4] <= 1. &&  // MidPoint
-           values[5] >= 0. && values[5] <= 1.);   // Sharpness
+  double nextValues[6];
+  d->ColorTransferFunction->GetNodeValue(index + 1, nextValues);
+  Q_ASSERT(nextValues[0] >= d->ColorTransferFunction->GetRange()[0] &&
+           nextValues[0] <= d->ColorTransferFunction->GetRange()[1] &&
+           nextValues[1] >= 0. && nextValues[1] <= 1. &&  // Red
+           nextValues[2] >= 0. && nextValues[2] <= 1. &&  // Green
+           nextValues[3] >= 0. && nextValues[3] <= 1. &&  // Blue
+           nextValues[4] >= 0. && nextValues[4] <= 1. &&  // MidPoint
+           nextValues[5] >= 0. && nextValues[5] <= 1.);   // Sharpness
+  // Optimization: don't use SubPoints when the sharpness is 0.
+  if (values[5] == 0.)
+    {
+    cp->SubPoints << ctkPoint(values[0], rgb);
+    rgb = QColor::fromRgbF(nextValues[1], nextValues[2], nextValues[3]);
+    cp->SubPoints << ctkPoint(nextValues[0], rgb);
+    return cp;
+    } 
   double subPoints[30];
   d->ColorTransferFunction->GetTable(cp->x(), values[0], 10, subPoints);
   qreal interval = (values[0] - cp->x()) / 9.;
   for(int i = 0; i < 10; ++i)
     {
-    
-    QColor rgb = QColor::fromRgbF(subPoints[3*i], 
-                                  subPoints[3*i+1],
-                                  subPoints[3*i+2]);
+    rgb = QColor::fromRgbF(subPoints[3*i], 
+                           subPoints[3*i+1],
+                           subPoints[3*i+2]);
     cp->SubPoints << ctkPoint(cp->x() + interval*i, rgb);
     }
   return cp;

+ 7 - 3
Libs/Visualization/VTK/Core/ctkVTKLookupTable.cpp

@@ -162,10 +162,13 @@ ctkControlPoint* ctkVTKLookupTable::controlPoint(int index)const
 QVariant ctkVTKLookupTable::value(qreal pos)const
 {
   CTK_D(const ctkVTKLookupTable);
-  QSharedPointer<ctkControlPoint> point = 
-    QSharedPointer<ctkControlPoint>(this->controlPoint(this->posToIndex(pos)));
-  return point->P.Value;
+  Q_ASSERT(d->LookupTable.GetPointer());
+  double rgb[3];
+  d->LookupTable->GetColor(pos, rgb);
+  double alpha = d->LookupTable->GetOpacity(pos);
+  return QColor::fromRgbF(rgb[0], rgb[1], rgb[2], alpha);
 }
+
 //-----------------------------------------------------------------------------
 int ctkVTKLookupTable::insertControlPoint(const ctkControlPoint& cp)
 {
@@ -173,6 +176,7 @@ int ctkVTKLookupTable::insertControlPoint(const ctkControlPoint& cp)
   qDebug() << "ctkVTKLookupTable doesn't support insertControlPoint";
   return -1;
 }
+
 //-----------------------------------------------------------------------------
 // insert point with value = 0
 int ctkVTKLookupTable::insertControlPoint(qreal pos)

+ 20 - 10
Libs/Visualization/VTK/Core/ctkVTKPiecewiseFunction.cpp

@@ -163,17 +163,27 @@ ctkControlPoint* ctkVTKPiecewiseFunction::controlPoint(int index)const
   ctkNonLinearControlPoint* cp = new ctkNonLinearControlPoint();
   cp->P.X = values[0];
   cp->P.Value = values[1];
-  d->PiecewiseFunction->GetNodeValue(index + 1, values);
-
-
-  Q_ASSERT(values[0] >= range[0] && values[0] <= range[1]  &&  // X
-           values[1] >= rangeY[0].toDouble() && values[1] <= rangeY[1].toDouble()  &&  // Y
-           values[2] >= 0. && values[2] <= 1. &&                // Midpoint
-           values[3] >= 0. && values[3] <= 1. );                // Sharpness
-
+  // Optimization: don't use Subpoints if sharpness == 0
+  if (values[3] == 0.)
+    {
+    cp->SubPoints << ctkPoint(values[0], values[1]);
+    } 
+  double nextValues[4];
+  d->PiecewiseFunction->GetNodeValue(index + 1, nextValues);
+
+  Q_ASSERT(nextValues[0] >= range[0] && nextValues[0] <= range[1]  &&  // X
+           nextValues[1] >= rangeY[0].toDouble() && nextValues[1] <= rangeY[1].toDouble()  &&  // Y
+           nextValues[2] >= 0. && nextValues[2] <= 1. &&                // Midpoint
+           nextValues[3] >= 0. && nextValues[3] <= 1. );                // Sharpness
+  // Optimization: Don't use Subpoints if sharpness == 0
+  if (values[3] == 0.)
+    {
+    cp->SubPoints << ctkPoint(nextValues[0], nextValues[1]);
+    return cp;
+    }
   double subPoints[100];
-  d->PiecewiseFunction->GetTable(cp->x(), values[0], 100, subPoints);
-  qreal interval = (values[0] - cp->x()) / 99.;
+  d->PiecewiseFunction->GetTable(cp->x(), nextValues[0], 100, subPoints);
+  qreal interval = (nextValues[0] - cp->x()) / 99.;
 
   // subPoints[i] since value varies (not like in color transfer function widget)
   for(int i = 0; i < 100; ++i)

+ 3 - 3
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkTransferFunctionWidgetTest3.cpp

@@ -55,8 +55,8 @@ int ctkTransferFunctionWidgetTest3(int argc, char * argv [] )
   // the widget is not really shown here, only when app.exec() is called
   transferFunctionWidget.show();
 
-//  QTimer autoExit;
-//  QObject::connect(&autoExit, SIGNAL(timeout()), &app, SLOT(quit()));
-//  autoExit.start(1000);
+  QTimer autoExit;
+  QObject::connect(&autoExit, SIGNAL(timeout()), &app, SLOT(quit()));
+  autoExit.start(1000);
   return app.exec();
 }

+ 38 - 26
Libs/Widgets/ctkTransferFunctionControlPointsItem.cpp

@@ -30,6 +30,7 @@
 /// CTK includes
 #include "ctkTransferFunctionControlPointsItem.h"
 #include "ctkTransferFunctionScene.h"
+#include "ctkTransferFunctionWidget.h"
 
 //-----------------------------------------------------------------------------
 class ctkTransferFunctionControlPointsItemPrivate: 
@@ -39,14 +40,14 @@ public:
   ctkTransferFunctionControlPointsItemPrivate();
   void init();
   QList<QPointF> ControlPoints;
-  QSizeF         PointSize;
+  QSize          PointSize;
   int            SelectedPoint;
 };
 
 //-----------------------------------------------------------------------------
 ctkTransferFunctionControlPointsItemPrivate::ctkTransferFunctionControlPointsItemPrivate()
 {
-  this->PointSize = QSizeF(0.01,0.01);
+  this->PointSize = QSize(12,12);
   this->SelectedPoint = -1;
 }
 
@@ -94,21 +95,25 @@ void ctkTransferFunctionControlPointsItem::paint(
   Q_ASSERT(tfScene);
   
   const QPainterPath& curve = tfScene->curve();
-  painter->setRenderHint(QPainter::Antialiasing);
   QPen pen(QColor(255, 255, 255, 191), 1);
   pen.setCosmetic(true);
   painter->setPen(pen);
   painter->drawPath(curve);
 
   d->ControlPoints = tfScene->points();
-  QPainterPath points;
-  points.setFillRule(Qt::WindingFill);
+  painter->setBrush(QBrush(QColor(191, 191, 191, 127)));
+  painter->save();
+  QTransform transform = painter->transform();
+  painter->setTransform(QTransform());
   foreach(const QPointF& point, d->ControlPoints)
     {
-    points.addEllipse(point, d->PointSize.width(), d->PointSize.height());
+    QPointF pos = transform.map(point);
+    painter->drawEllipse(pos.x() - d->PointSize.width() / 2, 
+                         pos.y() - d->PointSize.height() / 2, 
+                         d->PointSize.width(), d->PointSize.width());
+    //points.addEllipse(point, d->PointSize.width(), d->PointSize.height());
     }
-  painter->setBrush(QBrush(QColor(191, 191, 191, 127)));
-  painter->drawPath(points);
+  painter->restore();
 }
 
 //-----------------------------------------------------------------------------
@@ -116,31 +121,35 @@ void ctkTransferFunctionControlPointsItem::mousePressEvent(QGraphicsSceneMouseEv
 {
   qDebug() << "mouse press caught";
   CTK_D(ctkTransferFunctionControlPointsItem);
-  QRectF pointArea(QPointF(0,0), d->PointSize*2.);
+  QWidget* w = e->widget();
+  ctkTransferFunctionWidget* view = qobject_cast<ctkTransferFunctionWidget*>(e->widget()->parentWidget());
+  Q_ASSERT(view);
+  // e->pos() is ok, pointArea should be in the world coordiate
+  QRect pointViewArea(QPoint(-d->PointSize.width() / 2, -d->PointSize.height() / 2), d->PointSize);
+  QPolygonF pointItemArea = this->mapFromScene(view->mapToScene(pointViewArea));
   d->SelectedPoint = -1;
   for(int i = 0; i < d->ControlPoints.count(); ++i)
     {
-    pointArea.moveCenter(d->ControlPoints[i]);
-    if (pointArea.contains(e->pos()))
+    if (pointItemArea.translated(d->ControlPoints[i]).containsPoint(e->pos(), Qt::OddEvenFill))
       {
       d->SelectedPoint = i;
       break;
       }
     }
-  if (d->SelectedPoint < 0)
+  if (d->SelectedPoint >= 0)
     {
-    //QPointF currentPoint( e->pos() );
-  //  e->pos()->x();
-    //this->transferFunction()->insertControlPoint( e->pos().x() );
-
+    return;
+    }
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
+  
   // convert coordinates
-  QPointF functionCoordinates = screen2TransferFunctionCoordinates( e->pos().x(), e->pos().y());
+  QPointF tfPos = tfScene->mapPointFromScene(e->pos());
   // add point to transfer function
   // returns index
-  int index = this->transferFunction()->insertControlPoint( functionCoordinates.x());
+  int index = this->transferFunction()->insertControlPoint( tfPos.x());
   // update value of the point
-  this->transferFunction()->setControlPointValue( index, functionCoordinates.y());
-    }
+  this->transferFunction()->setControlPointValue( index, tfPos.y());
 }
 
 //-----------------------------------------------------------------------------
@@ -153,12 +162,15 @@ void ctkTransferFunctionControlPointsItem::mouseMoveEvent(QGraphicsSceneMouseEve
     e->ignore();
     return;
     }
-  qreal range[2];
-  this->transferFunction()->range(range);
-  qreal newPos = range[0] + e->pos().x() / (this->rect().width() / (range[1] - range[0]));
-  newPos = qBound(range[0], newPos, range[1]);
-  this->transferFunction()->setControlPointPos(d->SelectedPoint, newPos);
-  //this->transferFunction()->setControlPointValue(d->SelectedPoint, e->y());
+  //qreal range[2];
+  //this->transferFunction()->range(range);
+  //qreal newPos = range[0] + e->pos().x() / (this->rect().width() / (range[1] - range[0]));
+  //newPos = qBound(range[0], newPos, range[1]);
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
+  QPointF newPos = tfScene->mapPointFromScene(e->pos());
+  this->transferFunction()->setControlPointPos(d->SelectedPoint, newPos.x());
+  this->transferFunction()->setControlPointValue(d->SelectedPoint, newPos.y());
 }
 
 //-----------------------------------------------------------------------------

+ 5 - 99
Libs/Widgets/ctkTransferFunctionGradientItem.cpp

@@ -30,6 +30,7 @@
 /// CTK includes
 #include "ctkTransferFunction.h"
 #include "ctkTransferFunctionGradientItem.h"
+#include "ctkTransferFunctionScene.h"
 
 //-----------------------------------------------------------------------------
 ctkTransferFunctionGradientItem::ctkTransferFunctionGradientItem(QGraphicsItem* parentGraphicsItem)
@@ -53,105 +54,10 @@ ctkTransferFunctionGradientItem::~ctkTransferFunctionGradientItem()
 void ctkTransferFunctionGradientItem::paint(
   QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
 {
-  int count = this->transferFunction() ? this->transferFunction()->count() : 0;
-  if (count <= 0)
-    {
-    painter->fillRect(this->rect(),Qt::black);
-    return;
-    }
-  qreal range[2];
-  this->transferFunction()->range(range);
-  qreal rangeDiff = this->rect().width() / (range[1] - range[0]);
-  qreal rangeOffset = range[0];
-  ctkControlPoint* startCP = this->transferFunction()->controlPoint(0);
-  ctkControlPoint* endCP = 0;
+  ctkTransferFunctionScene* tfScene = dynamic_cast<ctkTransferFunctionScene*>(this->scene());
+  Q_ASSERT(tfScene);
   
-  qreal start = (startCP->x() - rangeOffset) * rangeDiff;
-  qreal end = 0;
-  for(int i = 1; i < count; ++i)
-    {
-    endCP = this->transferFunction()->controlPoint(i);
-    // TODO, handle Bezier points for a finer gradient
-    // TODO, handle nonlinear points
-    if (this->transferFunction()->isDiscrete())
-      {
-      // pos
-      end = ((startCP->x() + endCP->x()) /2. -rangeOffset) * rangeDiff;
-      QRectF itemRect = QRectF(start, 0, end - start, 
-                               this->rect().height());
-      if (i==1)
-        {
-        itemRect.setLeft(0.);
-        }
-      QColor valueColor = this->color(startCP->value());
-      // paint
-      painter->fillRect(itemRect, valueColor);
-      // draw the last item
-      if (i == count -1)
-        {
-        //pos
-        itemRect = QRectF(end, 0, this->rect().width(), 
-                          this->rect().height());
-        // color
-        valueColor = this->color(endCP->value());
-        // paint
-        painter->fillRect(itemRect, valueColor);
-        }
-      }
-    else if (dynamic_cast<ctkNonLinearControlPoint*>(startCP) != 0)
-      {
-      QList<ctkPoint> points = this->nonLinearPoints(startCP, endCP);
-      for (int j = 1; j < points.count(); ++j)
-        {
-        // pos
-        end = (points[j].X - rangeOffset) * rangeDiff;
-        QRectF itemRect = QRectF(start, 0, end - start, 
-                                 this->rect().height());
-        if (i==1 && j == 1)
-          {
-          itemRect.setLeft(0.);
-          }
-        if ((i == count -1) && (j == points.count() -1))
-          {
-          itemRect.setRight(this->rect().width());
-          }
-        // color
-        QLinearGradient gradient(start, 0, end, 0);
-        gradient.setColorAt(0, this->color(points[j-1]));
-        gradient.setColorAt(1, this->color(points[j]));
-        // paint
-        painter->fillRect(itemRect, gradient);
-        start = end;
-        }
-      }
-    else
-      {
-      // pos
-      end = (endCP->x() - rangeOffset) * rangeDiff;
-      QRectF itemRect = QRectF(start, 0, end - start, 
-                               this->rect().height());
-      if (i==1)
-        {
-        itemRect.setLeft(0.);
-        }
-      if (i == count -1)
-        {
-        itemRect.setRight(this->rect().width());
-        }
-      // color
-      QLinearGradient gradient(start, 0, end, 0);
-      gradient.setColorAt(0, this->color(startCP->value()));
-      gradient.setColorAt(1, this->color(endCP->value()));
-      // paint
-      painter->fillRect(itemRect, gradient);
-      }
-    delete startCP;
-    startCP = endCP;
-    start = end;
-    }
-  if (startCP)
-    {
-    delete startCP;
-    }
+  const QGradient& gradient = tfScene->gradient();
+  painter->fillRect(this->rect(), gradient);
 }
 

+ 109 - 30
Libs/Widgets/ctkTransferFunctionScene.cpp

@@ -19,6 +19,7 @@
 =========================================================================*/
 /// Qt includes
 #include <QGraphicsScene>
+#include <QLinearGradient>
 #include <QResizeEvent>
 #include <QDebug>
 
@@ -26,6 +27,9 @@
 #include "ctkTransferFunction.h"
 #include "ctkTransferFunctionScene.h"
 
+/// STL includes
+#include <limits>
+
 //-----------------------------------------------------------------------------
 class ctkTransferFunctionScenePrivate: public ctkPrivate<ctkTransferFunctionScene>
 {
@@ -35,6 +39,7 @@ public:
   QRectF               OldRect;
   ctkTransferFunction* TransferFunction;
   QPainterPath   Path;
+  QLinearGradient Gradient;
   QList<QPointF> Points;
   qreal        WorldRangeX[2];
   QVariant     WorldRangeY[2];
@@ -106,6 +111,7 @@ const QPainterPath& ctkTransferFunctionScene::curve()const
   if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
     {
     const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
     }
   return d->Path;
 }
@@ -117,11 +123,24 @@ const QList<QPointF>& ctkTransferFunctionScene::points()const
   if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
     {
     const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
     }
   return d->Points;
 }
 
 //-----------------------------------------------------------------------------
+const QGradient& ctkTransferFunctionScene::gradient()const
+{
+  CTK_D(const ctkTransferFunctionScene);
+  if (d->Path.isEmpty())// || this->sceneRect() != d->OldRect)
+    {
+    const_cast<ctkTransferFunctionScene*>(this)->computeCurve();
+    const_cast<ctkTransferFunctionScene*>(this)->computeGradient();
+    }
+  return d->Gradient;
+}
+
+//-----------------------------------------------------------------------------
 void ctkTransferFunctionScene::computeCurve()
 {
   CTK_D(ctkTransferFunctionScene);
@@ -133,8 +152,8 @@ void ctkTransferFunctionScene::computeCurve()
     }
   qDebug() << "computeCurve" << this->sceneRect();
   d->TransferFunction->range(d->WorldRangeX[0], d->WorldRangeX[1]);
-  d->WorldRangeY[0] = this->y(d->TransferFunction->minValue());
-  d->WorldRangeY[1] = this->y(d->TransferFunction->maxValue());
+  d->WorldRangeY[0] = this->posY(d->TransferFunction->minValue());
+  d->WorldRangeY[1] = this->posY(d->TransferFunction->maxValue());
 
   d->RangeXDiff   = this->computeRangeXDiff(this->sceneRect(), d->WorldRangeX);
   d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
@@ -145,7 +164,7 @@ void ctkTransferFunctionScene::computeCurve()
   ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
   ctkControlPoint* nextCP = 0;
 
-  QPointF startPos = this->mapPointToScreen(startCP);
+  QPointF startPos = this->mapPointToScene(startCP);
   
   d->Points.clear();
   d->Points << startPos;
@@ -161,10 +180,10 @@ void ctkTransferFunctionScene::computeCurve()
       int j;
       for (j = 1; j < points.count(); ++j)
         {
-        d->Path.lineTo(this->mapPointToScreen(points[j]));
+        d->Path.lineTo(this->mapPointToScene(points[j]));
         }
       j = points.count() - 1;
-      d->Points << this->mapPointToScreen(points[j]);
+      d->Points << this->mapPointToScene(points[j]);
       }
     else //dynamic_cast<ctkBezierControlPoint*>(startCP))
       {
@@ -173,7 +192,7 @@ void ctkTransferFunctionScene::computeCurve()
       QList<QPointF> bezierPoints;
       foreach(const ctkPoint& p, points)
         {
-        bezierPoints << this->mapPointToScreen(p);
+        bezierPoints << this->mapPointToScene(p);
         }
       d->Path.cubicTo(bezierPoints[1], bezierPoints[2], bezierPoints[3]);
       d->Points << bezierPoints[3];
@@ -189,6 +208,78 @@ void ctkTransferFunctionScene::computeCurve()
 }
 
 //-----------------------------------------------------------------------------
+void ctkTransferFunctionScene::computeGradient()
+{
+  CTK_D(ctkTransferFunctionScene);
+
+  int count = d->TransferFunction ? d->TransferFunction->count() : 0;
+  if (count <= 0)
+    {
+    return;
+    }
+  qDebug() << "computeCurve" << this->sceneRect();
+  d->TransferFunction->range(d->WorldRangeX[0], d->WorldRangeX[1]);
+  d->WorldRangeY[0] = this->posY(d->TransferFunction->minValue());
+  d->WorldRangeY[1] = this->posY(d->TransferFunction->maxValue());
+
+  d->RangeXDiff   = this->computeRangeXDiff(QRectF(0.,0.,1.,1.), d->WorldRangeX);
+  d->RangeXOffSet = this->computeRangeXOffset(d->WorldRangeX);
+
+  d->RangeYDiff   = this->computeRangeYDiff(QRectF(0.,0.,1.,1.), d->WorldRangeY);
+  d->RangeYOffSet = this->computeRangeYOffset(d->WorldRangeY);
+
+  ctkControlPoint* startCP = d->TransferFunction->controlPoint(0);
+  ctkControlPoint* nextCP = 0;
+
+  qreal startPos = this->mapXToScene(this->posX(startCP->x()));
+  qreal nextPos;
+  
+  d->Gradient = QLinearGradient(0., 0., 1., 0.);
+  d->Gradient.setColorAt(startPos, this->color(startCP));
+
+  for(int i = 1; i < count; ++i)
+    {
+    nextCP = d->TransferFunction->controlPoint(i);
+    nextPos = this->mapXToScene(this->posX(nextCP));
+    if (this->transferFunction()->isDiscrete())
+      {
+      qreal midPoint = (startPos + nextPos)  / 2;
+      d->Gradient.setColorAt(midPoint, this->color(startCP));
+      d->Gradient.setColorAt(midPoint + std::numeric_limits<qreal>::epsilon(), this->color(nextCP));
+      }
+    else if (dynamic_cast<ctkNonLinearControlPoint*>(startCP))
+      {
+      QList<ctkPoint> points = this->nonLinearPoints(startCP, nextCP);
+      foreach(const ctkPoint& p, points)
+        {
+        d->Gradient.setColorAt(this->mapXToScene(this->posX(p)), this->color(p));
+        }
+      //no need, d->Gradient.setColorAt(nextPos, this->color(nextCP));
+      }
+    else //dynamic_cast<ctkBezierControlPoint*>(startCP))
+      { // TODO handle bezier points with color
+      QList<ctkPoint> points = this->bezierParams(startCP, nextCP);
+      QList<ctkPoint>::iterator it = points.begin();
+      QList<QPointF> bezierPoints;
+      foreach(const ctkPoint& p, points)
+        {
+        d->Gradient.setColorAt(this->mapXToScene(this->posX(p)), this->color(p));
+        }
+      nextPos = this->mapXToScene(this->posX(points[points.size() - 1])); 
+      }
+    //qDebug() << i << points[0] << points[1] << points[2] << points[3];
+    delete startCP;
+    startCP = nextCP;
+    startPos = nextPos;
+    }
+  d->Gradient.setColorAt(startPos, this->color(startCP));
+  if (startCP)
+    {
+    delete startCP;
+    }
+}
+
+//-----------------------------------------------------------------------------
 QList<ctkPoint> ctkTransferFunctionScene::bezierParams(
   ctkControlPoint* start, ctkControlPoint* end) const
 {
@@ -231,18 +322,6 @@ QList<ctkPoint> ctkTransferFunctionScene::nonLinearPoints(
   return nonLinearCP->SubPoints;
 }
 
-
-//-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::y(const QVariant& v) const
-{ 
-  Q_ASSERT(v.canConvert<qreal>() || v.canConvert<QColor>());
-  if (v.canConvert<QColor>())
-    {
-    return v.value<QColor>().alphaF();
-    }
-  return v.toReal();
-}
-
 //-----------------------------------------------------------------------------
 QColor ctkTransferFunctionScene::color(const QVariant& v) const
 { 
@@ -320,43 +399,43 @@ qreal ctkTransferFunctionScene::posY(const QVariant& value)const
 }
 
 //-----------------------------------------------------------------------------
-QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkControlPoint* cp)const
+QPointF ctkTransferFunctionScene::mapPointToScene(const ctkControlPoint* cp)const
 {
-  return QPointF(this->mapXToScreen(this->posX(cp->x())),
-                 this->mapYToScreen(this->posY(cp->value())));
+  return QPointF(this->mapXToScene(this->posX(cp->x())),
+                 this->mapYToScene(this->posY(cp->value())));
 }
 
 //-----------------------------------------------------------------------------
-QPointF ctkTransferFunctionScene::mapPointToScreen(const ctkPoint& point)const
+QPointF ctkTransferFunctionScene::mapPointToScene(const ctkPoint& point)const
 {
-  return QPointF( this->mapXToScreen(this->posX(point.X)),
-                  this->mapYToScreen(this->posY(point.Value)));
+  return QPointF( this->mapXToScene(this->posX(point.X)),
+                  this->mapYToScene(this->posY(point.Value)));
 }
 
 //-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::mapXToScreen(qreal xPos)const
+qreal ctkTransferFunctionScene::mapXToScene(qreal xPos)const
 {
   CTK_D(const ctkTransferFunctionScene);
   return (xPos - d->RangeXOffSet) * d->RangeXDiff;
 }
 
 //-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::mapYToScreen(qreal yPos)const
+qreal ctkTransferFunctionScene::mapYToScene(qreal yPos)const
 {
   CTK_D(const ctkTransferFunctionScene);
   return this->height() - (yPos - d->RangeYOffSet) * d->RangeYDiff;
 }
 
 //-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::mapXFromScreen(qreal screenPosX)const
+qreal ctkTransferFunctionScene::mapXFromScene(qreal scenePosX)const
 {
   CTK_D(const ctkTransferFunctionScene);
-  return (screenPosX / d->RangeXDiff) + d->RangeXOffSet;
+  return (scenePosX / d->RangeXDiff) + d->RangeXOffSet;
 }
 
 //-----------------------------------------------------------------------------
-qreal ctkTransferFunctionScene::mapYFromScreen(qreal screenPosY)const
+qreal ctkTransferFunctionScene::mapYFromScene(qreal scenePosY)const
 {
   CTK_D(const ctkTransferFunctionScene);
-  return ((this->height() - screenPosY) / d->RangeYDiff) + d->RangeYOffSet ;
+  return ((this->height() - scenePosY) / d->RangeYDiff) + d->RangeYOffSet ;
 }

+ 58 - 14
Libs/Widgets/ctkTransferFunctionScene.h

@@ -25,13 +25,14 @@
 #include <QGraphicsScene>
 
 /// CTK includes
-#include "CTKWidgetsExport.h"
 #include "ctkPimpl.h"
+#include "ctkTransferFunction.h"
+#include "CTKWidgetsExport.h"
 
-class ctkTransferFunction;
+//class ctkTransferFunction;
 class ctkTransferFunctionScenePrivate;
-class ctkControlPoint;
-class ctkPoint;
+//class ctkControlPoint;
+//class ctkPoint;
 
 //-----------------------------------------------------------------------------
 class CTK_WIDGETS_EXPORT ctkTransferFunctionScene: public QGraphicsScene
@@ -45,26 +46,37 @@ public:
   void setTransferFunction(ctkTransferFunction* transferFunction);
   ctkTransferFunction* transferFunction()const;
 
-  qreal y(const QVariant& v) const;
-  QColor color(const QVariant& v) const;
+  inline qreal posX(const ctkControlPoint* cp)const;
+  inline qreal posY(const ctkControlPoint* cp)const;
+  inline QColor color(const ctkControlPoint* cp) const;
 
-  qreal posX(const qreal& x)const;
-  qreal posY(const QVariant& value)const;
+  inline qreal posX(const ctkPoint& point)const;
+  inline qreal posY(const ctkPoint& point)const;
+  inline QColor color(const ctkPoint& point) const;
+
+  qreal posX(const qreal& tfX)const;
+  qreal posY(const QVariant& tfV)const;
+  QColor color(const QVariant& tfV) const;
+  
+  QPointF mapPointToScene(const ctkControlPoint* cp)const;
+  QPointF mapPointToScene(const ctkPoint& point)const;
   
-  QPointF mapPointToScreen(const ctkControlPoint* cp)const;
-  QPointF mapPointToScreen(const ctkPoint& point)const;
  
-  qreal mapXToScreen(qreal posX)const;
-  qreal mapYToScreen(qreal posY)const;
-  qreal mapXFromScreen(qreal screenPosX)const;
-  qreal mapYFromScreen(qreal screenPosY)const;
+  qreal mapXToScene(qreal posX)const;
+  qreal mapYToScene(qreal posY)const;
+  qreal mapXFromScene(qreal ScenePosX)const;
+  qreal mapYFromScene(qreal ScenePosY)const;
+  inline QPointF mapPointFromScene(const QPointF& point)const;
 
   QList<ctkPoint> bezierParams(ctkControlPoint* start, ctkControlPoint* end) const;
   QList<ctkPoint> nonLinearPoints(ctkControlPoint* start, ctkControlPoint* end) const;
 
   const QPainterPath& curve()const;
   const QList<QPointF>& points()const;
+  const QGradient& gradient()const;
+
   void computeCurve();
+  void computeGradient();
 
 protected slots:
   virtual void onTransferFunctionChanged();
@@ -78,4 +90,36 @@ private:
   CTK_DECLARE_PRIVATE(ctkTransferFunctionScene);
 };
 
+qreal ctkTransferFunctionScene::posX(const ctkControlPoint* cp)const
+{
+  return this->posX(cp->x());
+}
+qreal ctkTransferFunctionScene::posY(const ctkControlPoint* cp)const
+{
+  return this->posY(cp->value());
+}
+QColor ctkTransferFunctionScene::color(const ctkControlPoint* cp) const
+{
+  return this->color(cp->value());
+}
+
+qreal ctkTransferFunctionScene::posX(const ctkPoint& point)const
+{
+  return this->posX(point.X);
+}
+qreal ctkTransferFunctionScene::posY(const ctkPoint& point)const
+{
+  return this->posY(point.Value);
+}
+QColor ctkTransferFunctionScene::color(const ctkPoint& point) const
+{
+  return this->color(point.Value);
+}
+
+QPointF ctkTransferFunctionScene::mapPointFromScene(const QPointF& point)const
+{
+  return QPointF(this->mapXFromScene(point.x()),
+                 this->mapYFromScene(point.y()));
+}
+
 #endif

+ 1 - 0
Libs/Widgets/ctkTransferFunctionWidget.cpp

@@ -54,6 +54,7 @@ void ctkTransferFunctionWidgetPrivate::init()
   p->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   p->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   //p->setViewport(new QGLWidget);
+  p->setRenderHint(QPainter::Antialiasing);
 }
 
 //-----------------------------------------------------------------------------

+ 246 - 244
SuperBuild.cmake

@@ -1,244 +1,246 @@
-###########################################################################
-#
-#  Library:   CTK
-# 
-#  Copyright (c) 2010  Kitware Inc.
-#
-#  Licensed under the Apache License, Version 2.0 (the "License");
-#  you may not use this file except in compliance with the License.
-#  You may obtain a copy of the License at
-#
-#      http://www.commontk.org/LICENSE
-#
-#  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.
-# 
-###########################################################################
-
-SET(cmake_version_required "2.8")
-SET(cmake_version_required_dash "2-8")
-
-CMAKE_MINIMUM_REQUIRED(VERSION ${cmake_version_required})
-
-# 
-# CTK_KWSTYLE_EXECUTABLE
-# DCMTK_DIR
-# QT_QMAKE_EXECUTABLE
-# VTK_DIR
-# PYTHONQT_INSTALL_DIR
-# PYTHON_LIBRARY
-# PYTHON_INCLUDE_DIR
-#
-
-#-----------------------------------------------------------------------------
-# Enable and setup External project global properties
-#
-INCLUDE(ExternalProject)
-
-SET(ep_base "${CMAKE_BINARY_DIR}/CMakeExternals")
-SET_PROPERTY(DIRECTORY PROPERTY EP_BASE ${ep_base})
-
-SET(ep_install_dir ${ep_base}/Install)
-SET(ep_build_dir ${ep_base}/Build)
-SET(ep_source_dir ${ep_base}/Source)
-#SET(ep_parallelism_level)
-SET(ep_build_shared_libs ON)
-SET(ep_build_testing OFF)
-
-SET(ep_common_args
-  -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir}
-  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-  -DBUILD_TESTING:BOOL=${ep_build_testing}
-  )
-
-# Compute -G arg for configuring external projects with the same CMake generator:
-IF(CMAKE_EXTRA_GENERATOR)
-  SET(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
-ELSE()
-  SET(gen "${CMAKE_GENERATOR}")
-ENDIF()
-
-# Use this value where semi-colons are needed in ep_add args:
-set(sep "^^")
-
-#-----------------------------------------------------------------------------
-# Update CMake module path
-#
-SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
-
-#-----------------------------------------------------------------------------
-# Collect CTK library target dependencies
-#
-
-ctkMacroCollectAllTargetLibraries("${CTK_LIBS_SUBDIRS}" "Libs" ALL_TARGET_LIBRARIES)
-ctkMacroCollectAllTargetLibraries("${CTK_PLUGINS_SUBDIRS}" "Plugins" ALL_TARGET_LIBRARIES)
-ctkMacroCollectAllTargetLibraries("${CTK_APPLICATIONS_SUBDIRS}" "Applications" ALL_TARGET_LIBRARIES)
-#MESSAGE(STATUS ALL_TARGET_LIBRARIES:${ALL_TARGET_LIBRARIES})
-
-#-----------------------------------------------------------------------------
-# Initialize NON_CTK_DEPENDENCIES variable
-#
-# Using the variable ALL_TARGET_LIBRARIES initialized above with the help
-# of the macro ctkMacroCollectAllTargetLibraries, let's get the list of all Non-CTK dependencies.
-# NON_CTK_DEPENDENCIES is expected by the macro ctkMacroShouldAddExternalProject
-ctkMacroGetAllNonCTKTargetLibraries("${ALL_TARGET_LIBRARIES}" NON_CTK_DEPENDENCIES)
-#MESSAGE(STATUS NON_CTK_DEPENDENCIES:${NON_CTK_DEPENDENCIES})
-
-#-----------------------------------------------------------------------------
-# Qt is expected to be setup by CTK/CMakeLists.txt just before it includes the SuperBuild script
-#
-
-#-----------------------------------------------------------------------------
-# ExternalProjects
-#
-SET(external_projects
-  KWStyle
-  PythonQt
-  DCMTK
-  ZMQ
-  QtMobility
-  OpenIGTLink
-  VTK
-  XIP
-  )
-
-# Include external projects
-FOREACH(p ${external_projects})
-  INCLUDE(CMakeExternals/${p}.cmake)
-ENDFOREACH()
-   
-#-----------------------------------------------------------------------------
-# CTK Utilities
-#
-set(proj CTK-Utilities)
-ExternalProject_Add(${proj}
-  DOWNLOAD_COMMAND ""
-  CONFIGURE_COMMAND ""
-  BUILD_COMMAND ""
-  INSTALL_COMMAND ""
-  DEPENDS
-    # Mandatory dependencies
-    #  - none
-    # Optionnal dependencies
-    ${QtMobility_DEPENDS}
-    ${kwstyle_DEPENDS}
-    ${DCMTK_DEPENDS}
-    ${PythonQt_DEPENDS}
-    ${ZMQ_DEPENDS}
-    ${OpenIGTLink_DEPENDS}
-    ${VTK_DEPENDS}
-    ${XIP_DEPENDS}
-)
-
-#-----------------------------------------------------------------------------
-# Generate cmake variable name corresponding to Libs, Plugins and Applications
-#
-SET(ctk_libs_bool_vars)
-FOREACH(lib ${CTK_LIBS_SUBDIRS})
-  LIST(APPEND ctk_libs_bool_vars CTK_LIB_${lib})
-ENDFOREACH()
-
-SET(ctk_plugins_bool_vars)
-FOREACH(plugin ${CTK_PLUGINS_SUBDIRS})
-  LIST(APPEND ctk_plugins_bool_vars CTK_PLUGIN_${plugin})
-ENDFOREACH()
-
-SET(ctk_applications_bool_vars)
-FOREACH(app ${CTK_APPLICATIONS_SUBDIRS})
-  LIST(APPEND ctk_applications_bool_vars CTK_APP_${app})
-ENDFOREACH()
-
-#-----------------------------------------------------------------------------
-# Convenient macro allowing to define superbuild arg
-#
-MACRO(ctk_set_superbuild_boolean_arg ctk_cmake_var)
-  SET(superbuild_${ctk_cmake_var} ON)
-  IF(DEFINED ${ctk_cmake_var} AND NOT ${ctk_cmake_var})
-    SET(superbuild_${ctk_cmake_var} OFF)
-  ENDIF()
-ENDMACRO()
-
-#-----------------------------------------------------------------------------
-# Set superbuild boolean args
-#
-
-SET(ctk_cmake_boolean_args
-  BUILD_TESTING
-  CTK_USE_KWSTYLE
-  ${ctk_libs_bool_vars}
-  ${ctk_plugins_bool_vars}
-  ${ctk_applications_bool_vars}
-  )
-
-SET(ctk_superbuild_boolean_args)
-FOREACH(ctk_cmake_arg ${ctk_cmake_boolean_args})
-  ctk_set_superbuild_boolean_arg(${ctk_cmake_arg})
-  LIST(APPEND ctk_superbuild_boolean_args -D${ctk_cmake_arg}:BOOL=${superbuild_${ctk_cmake_arg}})
-ENDFOREACH()
-
-# MESSAGE("CMake args:")
-# FOREACH(arg ${ctk_superbuild_boolean_args})
-#   MESSAGE("  ${arg}")
-# ENDFOREACH()
-
-#-----------------------------------------------------------------------------
-# CTK Configure
-#
-SET(proj CTK-Configure)
-
-ExternalProject_Add(${proj}
-  DOWNLOAD_COMMAND ""
-  CMAKE_GENERATOR ${gen}
-  CMAKE_ARGS
-    ${ctk_superbuild_boolean_args}
-    -DCTK_SUPERBUILD:BOOL=OFF
-    -DWITH_COVERAGE:BOOL=${WITH_COVERAGE}
-    -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS}
-    -DCTK_SUPERBUILD_BINARY_DIR:PATH=${CTK_BINARY_DIR}
-    -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir}
-    -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-    -DCTK_CXX_FLAGS:STRING=${CTK_CXX_FLAGS}
-    -DCTK_C_FLAGS:STRING=${CTK_C_FLAGS}
-    -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
-    -DCTK_KWSTYLE_EXECUTABLE:FILEPATH=${CTK_KWSTYLE_EXECUTABLE}
-    -DDCMTK_DIR:PATH=${DCMTK_DIR} # FindDCMTK expects DCMTK_DIR
-    -DVTK_DIR:PATH=${VTK_DIR}     # FindVTK expects VTK_DIR
-    -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR}    # FindPythonQt expects PYTHON_INCLUDE_DIR
-    -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY}        # FindPythonQt expects PYTHON_LIBRARY
-    -DPYTHONQT_INSTALL_DIR:PATH=${PYTHONQT_INSTALL_DIR} # FindPythonQt expects PYTHONQT_INSTALL_DIR
-  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
-  BINARY_DIR ${CMAKE_BINARY_DIR}/CTK-build
-  BUILD_COMMAND ""
-  INSTALL_COMMAND ""
-  DEPENDS
-    "CTK-Utilities"
-  )
-
-
-#-----------------------------------------------------------------------------
-# CTK
-#
-#MESSAGE(STATUS SUPERBUILD_EXCLUDE_CTKBUILD_TARGET:${SUPERBUILD_EXCLUDE_CTKBUILD_TARGET})
-IF(NOT DEFINED SUPERBUILD_EXCLUDE_CTKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_CTKBUILD_TARGET)
-  SET(proj CTK-build)
-  ExternalProject_Add(${proj}
-    DOWNLOAD_COMMAND ""
-    CMAKE_GENERATOR ${gen}
-    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
-    BINARY_DIR CTK-build
-    INSTALL_COMMAND ""
-    DEPENDS
-      "CTK-Configure"
-    )
-ENDIF()
-
-#-----------------------------------------------------------------------------
-# Custom target allowing to drive the build of CTK project itself
-#
-ADD_CUSTOM_TARGET(CTK
-  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/CTK-build
-  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CTK-build
-  )
+###########################################################################
+#
+#  Library:   CTK
+# 
+#  Copyright (c) 2010  Kitware Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.commontk.org/LICENSE
+#
+#  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.
+# 
+###########################################################################
+
+SET(cmake_version_required "2.8")
+SET(cmake_version_required_dash "2-8")
+
+CMAKE_MINIMUM_REQUIRED(VERSION ${cmake_version_required})
+
+# 
+# CTK_KWSTYLE_EXECUTABLE
+# DCMTK_DIR
+# QT_QMAKE_EXECUTABLE
+# VTK_DIR
+# PYTHONQT_INSTALL_DIR
+# PYTHON_LIBRARY
+# PYTHON_INCLUDE_DIR
+#
+
+#-----------------------------------------------------------------------------
+# Enable and setup External project global properties
+#
+INCLUDE(ExternalProject)
+
+SET(ep_base "${CMAKE_BINARY_DIR}/CMakeExternals")
+SET_PROPERTY(DIRECTORY PROPERTY EP_BASE ${ep_base})
+
+SET(ep_install_dir ${ep_base}/Install)
+SET(ep_build_dir ${ep_base}/Build)
+SET(ep_source_dir ${ep_base}/Source)
+#SET(ep_parallelism_level)
+SET(ep_build_shared_libs ON)
+SET(ep_build_testing OFF)
+
+SET(ep_common_args
+  -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir}
+  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+  -DBUILD_TESTING:BOOL=${ep_build_testing}
+  )
+
+# Compute -G arg for configuring external projects with the same CMake generator:
+IF(CMAKE_EXTRA_GENERATOR)
+  SET(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
+ELSE()
+  SET(gen "${CMAKE_GENERATOR}")
+ENDIF()
+
+# Use this value where semi-colons are needed in ep_add args:
+set(sep "^^")
+
+#-----------------------------------------------------------------------------
+# Update CMake module path
+#
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
+
+#-----------------------------------------------------------------------------
+# Collect CTK library target dependencies
+#
+
+ctkMacroCollectAllTargetLibraries("${CTK_LIBS_SUBDIRS}" "Libs" ALL_TARGET_LIBRARIES)
+ctkMacroCollectAllTargetLibraries("${CTK_PLUGINS_SUBDIRS}" "Plugins" ALL_TARGET_LIBRARIES)
+ctkMacroCollectAllTargetLibraries("${CTK_APPLICATIONS_SUBDIRS}" "Applications" ALL_TARGET_LIBRARIES)
+#MESSAGE(STATUS ALL_TARGET_LIBRARIES:${ALL_TARGET_LIBRARIES})
+
+#-----------------------------------------------------------------------------
+# Initialize NON_CTK_DEPENDENCIES variable
+#
+# Using the variable ALL_TARGET_LIBRARIES initialized above with the help
+# of the macro ctkMacroCollectAllTargetLibraries, let's get the list of all Non-CTK dependencies.
+# NON_CTK_DEPENDENCIES is expected by the macro ctkMacroShouldAddExternalProject
+ctkMacroGetAllNonCTKTargetLibraries("${ALL_TARGET_LIBRARIES}" NON_CTK_DEPENDENCIES)
+#MESSAGE(STATUS NON_CTK_DEPENDENCIES:${NON_CTK_DEPENDENCIES})
+
+#-----------------------------------------------------------------------------
+# Qt is expected to be setup by CTK/CMakeLists.txt just before it includes the SuperBuild script
+#
+
+#-----------------------------------------------------------------------------
+# ExternalProjects
+#
+SET(external_projects
+  KWStyle
+  PythonQt
+  DCMTK
+  ZMQ
+  QtMobility
+  OpenIGTLink
+  VTK
+  XIP
+  )
+
+# Include external projects
+FOREACH(p ${external_projects})
+  INCLUDE(CMakeExternals/${p}.cmake)
+ENDFOREACH()
+   
+#-----------------------------------------------------------------------------
+# CTK Utilities
+#
+set(proj CTK-Utilities)
+ExternalProject_Add(${proj}
+  DOWNLOAD_COMMAND ""
+  CONFIGURE_COMMAND ""
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+  DEPENDS
+    # Mandatory dependencies
+    #  - none
+    # Optionnal dependencies
+    ${QtMobility_DEPENDS}
+    ${kwstyle_DEPENDS}
+    ${DCMTK_DEPENDS}
+    ${PythonQt_DEPENDS}
+    ${ZMQ_DEPENDS}
+    ${OpenIGTLink_DEPENDS}
+    ${VTK_DEPENDS}
+    ${XIP_DEPENDS}
+)
+
+#-----------------------------------------------------------------------------
+# Generate cmake variable name corresponding to Libs, Plugins and Applications
+#
+SET(ctk_libs_bool_vars)
+FOREACH(lib ${CTK_LIBS_SUBDIRS})
+  LIST(APPEND ctk_libs_bool_vars CTK_LIB_${lib})
+ENDFOREACH()
+
+SET(ctk_plugins_bool_vars)
+FOREACH(plugin ${CTK_PLUGINS_SUBDIRS})
+  LIST(APPEND ctk_plugins_bool_vars CTK_PLUGIN_${plugin})
+ENDFOREACH()
+
+SET(ctk_applications_bool_vars)
+FOREACH(app ${CTK_APPLICATIONS_SUBDIRS})
+  LIST(APPEND ctk_applications_bool_vars CTK_APP_${app})
+ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# Convenient macro allowing to define superbuild arg
+#
+MACRO(ctk_set_superbuild_boolean_arg ctk_cmake_var)
+  SET(superbuild_${ctk_cmake_var} ON)
+  IF(DEFINED ${ctk_cmake_var} AND NOT ${ctk_cmake_var})
+    SET(superbuild_${ctk_cmake_var} OFF)
+  ENDIF()
+ENDMACRO()
+
+#-----------------------------------------------------------------------------
+# Set superbuild boolean args
+#
+
+SET(ctk_cmake_boolean_args
+  BUILD_TESTING
+  CTK_USE_KWSTYLE
+  ${ctk_libs_bool_vars}
+  ${ctk_plugins_bool_vars}
+  ${ctk_applications_bool_vars}
+  )
+
+SET(ctk_superbuild_boolean_args)
+FOREACH(ctk_cmake_arg ${ctk_cmake_boolean_args})
+  ctk_set_superbuild_boolean_arg(${ctk_cmake_arg})
+  LIST(APPEND ctk_superbuild_boolean_args -D${ctk_cmake_arg}:BOOL=${superbuild_${ctk_cmake_arg}})
+ENDFOREACH()
+
+# MESSAGE("CMake args:")
+# FOREACH(arg ${ctk_superbuild_boolean_args})
+#   MESSAGE("  ${arg}")
+# ENDFOREACH()
+
+#-----------------------------------------------------------------------------
+# CTK Configure
+#
+SET(proj CTK-Configure)
+
+ExternalProject_Add(${proj}
+  DOWNLOAD_COMMAND ""
+  CMAKE_GENERATOR ${gen}
+  CMAKE_ARGS
+    ${ctk_superbuild_boolean_args}
+    -DCTK_SUPERBUILD:BOOL=OFF
+    -DWITH_COVERAGE:BOOL=${WITH_COVERAGE}
+    -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS}
+    -DCTK_SUPERBUILD_BINARY_DIR:PATH=${CTK_BINARY_DIR}
+    -DCMAKE_INSTALL_PREFIX:PATH=${ep_install_dir}
+    -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+    -DCTK_CXX_FLAGS:STRING=${CTK_CXX_FLAGS}
+    -DCTK_C_FLAGS:STRING=${CTK_C_FLAGS}
+    -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
+    -DCTK_KWSTYLE_EXECUTABLE:FILEPATH=${CTK_KWSTYLE_EXECUTABLE}
+    -DDCMTK_DIR:PATH=${DCMTK_DIR} # FindDCMTK expects DCMTK_DIR
+    -DVTK_DIR:PATH=${VTK_DIR}     # FindVTK expects VTK_DIR
+	-DZMQ_DIR:PATH=${ZMQ_DIR}     # FindVTK expects VTK_DIR
+	-DOpenIGTLink_DIR:PATH=${OpenIGTLink_DIR}     # FindVTK expects VTK_DIR
+    -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR}    # FindPythonQt expects PYTHON_INCLUDE_DIR
+    -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY}        # FindPythonQt expects PYTHON_LIBRARY
+    -DPYTHONQT_INSTALL_DIR:PATH=${PYTHONQT_INSTALL_DIR} # FindPythonQt expects PYTHONQT_INSTALL_DIR
+  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+  BINARY_DIR ${CMAKE_BINARY_DIR}/CTK-build
+  BUILD_COMMAND ""
+  INSTALL_COMMAND ""
+  DEPENDS
+    "CTK-Utilities"
+  )
+
+
+#-----------------------------------------------------------------------------
+# CTK
+#
+#MESSAGE(STATUS SUPERBUILD_EXCLUDE_CTKBUILD_TARGET:${SUPERBUILD_EXCLUDE_CTKBUILD_TARGET})
+IF(NOT DEFINED SUPERBUILD_EXCLUDE_CTKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_CTKBUILD_TARGET)
+  SET(proj CTK-build)
+  ExternalProject_Add(${proj}
+    DOWNLOAD_COMMAND ""
+    CMAKE_GENERATOR ${gen}
+    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+    BINARY_DIR CTK-build
+    INSTALL_COMMAND ""
+    DEPENDS
+      "CTK-Configure"
+    )
+ENDIF()
+
+#-----------------------------------------------------------------------------
+# Custom target allowing to drive the build of CTK project itself
+#
+ADD_CUSTOM_TARGET(CTK
+  COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/CTK-build
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CTK-build
+  )