diff --git a/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp b/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp
index b01a3e70b7..2e375d4131 100644
--- a/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp
+++ b/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp
@@ -1,744 +1,610 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <mitkSurfaceInterpolationController.h>
 #include <mitkTestFixture.h>
 #include <mitkTestingMacros.h>
 
 #include "mitkImageAccessByItk.h"
 #include <mitkImageTimeSelector.h>
 #include <mitkLabelSetImage.h>
 
 #include <vtkDebugLeaks.h>
 #include <vtkDoubleArray.h>
 #include <vtkFieldData.h>
 #include <vtkPolygon.h>
 #include <vtkRegularPolygonSource.h>
 
 template <typename ImageType>
 void ClearBufferProcessing(ImageType* itkImage)
 {
   itkImage->FillBuffer(0);
 }
 
 class mitkSurfaceInterpolationControllerTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkSurfaceInterpolationControllerTestSuite);
   MITK_TEST(TestSingleton);
   MITK_TEST(TestSetCurrentInterpolationSession);
   MITK_TEST(TestRemoveAllInterpolationSessions);
   MITK_TEST(TestRemoveInterpolationSession);
   MITK_TEST(TestOnSegmentationDeleted);
 
   MITK_TEST(TestSetCurrentInterpolationSession4D);
   MITK_TEST(TestRemoveAllInterpolationSessions4D);
   MITK_TEST(TestRemoveInterpolationSession4D);
   MITK_TEST(TestOnSegmentationDeleted4D);
 
   /// \todo Workaround for memory leak in TestAddNewContour. Bug 18096.
   vtkDebugLeaks::SetExitError(0);
 
   MITK_TEST(TestAddNewContours);
   MITK_TEST(TestRemoveContours);
   CPPUNIT_TEST_SUITE_END();
 
 private:
   mitk::SurfaceInterpolationController::Pointer m_Controller;
 
 public:
   mitk::Image::Pointer createImage(unsigned int *dimensions)
   {
     mitk::Image::Pointer newImage = mitk::Image::New();
     // mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New();
     mitk::PixelType p_type = mitk::MakeScalarPixelType<unsigned char>();
     newImage->Initialize(p_type, 3, dimensions);
     AccessFixedDimensionByItk(newImage, ClearBufferProcessing, 3);
     return newImage;
   }
 
   mitk::LabelSetImage::Pointer createLabelSetImage(unsigned int *dimensions)
   {
     mitk::Image::Pointer image = createImage(dimensions);
     mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New();
     newImage->InitializeByLabeledImage(image);
     return newImage;
   }
 
   mitk::Image::Pointer createImage4D(unsigned int *dimensions)
   {
     mitk::Image::Pointer newImage = mitk::Image::New();
     mitk::PixelType p_type = mitk::MakeScalarPixelType<unsigned char>();
     newImage->Initialize(p_type, 4, dimensions);
     return newImage;
   }
 
   mitk::LabelSetImage::Pointer createLabelSetImage4D(unsigned int *dimensions)
   {
     mitk::Image::Pointer image = createImage4D(dimensions);
     mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New();
     newImage->InitializeByLabeledImage(image);
     return newImage;
   }
 
   void setUp() override
   {
     m_Controller = mitk::SurfaceInterpolationController::GetInstance();
     m_Controller->RemoveAllInterpolationSessions();
     m_Controller->SetCurrentTimePoint(0);
 
     vtkSmartPointer<vtkRegularPolygonSource> polygonSource = vtkSmartPointer<vtkRegularPolygonSource>::New();
     polygonSource->SetRadius(100);
     polygonSource->SetNumberOfSides(7);
     polygonSource->Update();
     mitk::Surface::Pointer surface = mitk::Surface::New();
     surface->SetVtkPolyData(polygonSource->GetOutput());
   }
 
   void TestSingleton()
   {
     mitk::SurfaceInterpolationController::Pointer controller2 = mitk::SurfaceInterpolationController::GetInstance();
     CPPUNIT_ASSERT_MESSAGE("SurfaceInterpolationController pointers are not equal!",
                            m_Controller.GetPointer() == controller2.GetPointer());
   }
 
   void TestSetCurrentInterpolationSession()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage(dimensions1);
 
     unsigned int dimensions2[] = {20, 10, 30};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
 
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
 
     // Test 2
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_2.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test 3
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test 4
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // // Test 5
     m_Controller->SetCurrentInterpolationSession(nullptr);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation() == nullptr);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
   }
 
-  mitk::PlaneGeometry::Pointer GetPlaneGeometry()
+  mitk::PlaneGeometry::Pointer CreatePlaneGeometry(mitk::ScalarType zIndex)
   {
     mitk::Point3D origin;
-    mitk::Vector3D right, bottom, normal, spacing;
-    mitk::ScalarType width, height;
+    mitk::Vector3D right, bottom, spacing;
     mitk::ScalarType widthInMM, heightInMM, thicknessInMM;
 
     auto planegeometry = mitk::PlaneGeometry::New();
-    width = 100;
-    widthInMM = width;
-    height = 200;
-    heightInMM = height;
+    widthInMM = 100;
+    heightInMM = 200;
     thicknessInMM = 1.0;
-    mitk::FillVector3D(origin, 4.5, 7.3, 11.2);
+    mitk::FillVector3D(origin, 4.5, 7.3, zIndex*thicknessInMM);
     mitk::FillVector3D(right, widthInMM, 0, 0);
     mitk::FillVector3D(bottom, 0, heightInMM, 0);
-    mitk::FillVector3D(normal, 0, 0, thicknessInMM);
     mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM);
 
     planegeometry->InitializeStandardPlane(right, bottom);
     planegeometry->SetOrigin(origin);
     planegeometry->SetSpacing(spacing);
     return planegeometry;
   }
 
+  mitk::Surface::Pointer CreateContour(int numOfSides)
+  {
+    double center_1[3] = { 1.25f, 3.43f, 4.44f };
+    double normal_1[3] = { 0.25f, 1.76f, 0.93f };
+    vtkSmartPointer<vtkRegularPolygonSource> p_source = vtkSmartPointer<vtkRegularPolygonSource>::New();
+    p_source->SetNumberOfSides(numOfSides*10);
+    p_source->SetCenter(center_1);
+    p_source->SetRadius(4);
+    p_source->SetNormal(normal_1);
+    p_source->Update();
+    vtkPolyData* poly_1 = p_source->GetOutput();
+    mitk::Surface::Pointer surf_1 = mitk::Surface::New();
+    surf_1->SetVtkPolyData(poly_1);
+    return surf_1;
+  }
+
   void TestRemoveAllInterpolationSessions()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10};
     auto segmentation_1 = createLabelSetImage(dimensions1);
 
     unsigned int dimensions2[] = {20, 10, 30};
     auto segmentation_2 = createLabelSetImage(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     m_Controller->RemoveAllInterpolationSessions();
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0",
                            m_Controller->GetNumberOfInterpolationSessions() == 0);
   }
 
   void TestRemoveInterpolationSession()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage(dimensions1);
 
     unsigned int dimensions2[] = {20, 10, 30};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test current segmentation should not be null if another one was removed
     m_Controller->RemoveInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_2.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Current segmentation is null after another one was removed",
                            m_Controller->GetCurrentSegmentation() != nullptr);
 
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test current segmentation should not be null if another one was removed
     m_Controller->RemoveInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
     CPPUNIT_ASSERT_MESSAGE("Current segmentation is not null after session was removed",
                            m_Controller->GetCurrentSegmentation() == nullptr);
   }
 
   void TestOnSegmentationDeleted()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10};
     auto segmentation_1 = createLabelSetImage(dimensions1);
 
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
 
     segmentation_1 = nullptr;
 
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0",
                            m_Controller->GetNumberOfInterpolationSessions() == 0);
   }
 
   void TestAddNewContours()
   {
     // Create segmentation image
     unsigned int dimensions1[] = {10, 10, 10};
     auto segmentation_1 = createLabelSetImage(dimensions1);
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
 
-    // Create some contours
-    double center_1[3] = {1.25f, 3.43f, 4.44f};
-    double normal_1[3] = {0.25f, 1.76f, 0.93f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source->SetNumberOfSides(20);
-    p_source->SetCenter(center_1);
-    p_source->SetRadius(4);
-    p_source->SetNormal(normal_1);
-    p_source->Update();
-    vtkPolyData *poly_1 = p_source->GetOutput();
-    mitk::Surface::Pointer surf_1 = mitk::Surface::New();
-    surf_1->SetVtkPolyData(poly_1);
-    vtkSmartPointer<vtkIntArray> int1Array = vtkSmartPointer<vtkIntArray>::New();
-    int1Array->InsertNextValue(1);
-    int1Array->InsertNextValue(0);
-    int1Array->InsertNextValue(0);
-    surf_1->GetVtkPolyData()->GetFieldData()->AddArray(int1Array);
-    vtkSmartPointer<vtkDoubleArray> double1Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double1Array->InsertNextValue(center_1[0]);
-    double1Array->InsertNextValue(center_1[1]);
-    double1Array->InsertNextValue(center_1[2]);
-    surf_1->GetVtkPolyData()->GetFieldData()->AddArray(double1Array);
-
-    double center_2[3] = {4.0f, 4.0f, 4.0f};
-    double normal_2[3] = {1.0f, 0.0f, 0.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_2 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_2->SetNumberOfSides(80);
-    p_source_2->SetCenter(center_2);
-    p_source_2->SetRadius(4);
-    p_source_2->SetNormal(normal_2);
-    p_source_2->Update();
-    vtkPolyData *poly_2 = p_source_2->GetOutput();
-    mitk::Surface::Pointer surf_2 = mitk::Surface::New();
-    surf_2->SetVtkPolyData(poly_2);
-    vtkSmartPointer<vtkIntArray> int2Array = vtkSmartPointer<vtkIntArray>::New();
-    int2Array->InsertNextValue(1);
-    int2Array->InsertNextValue(0);
-    int2Array->InsertNextValue(0);
-    surf_2->GetVtkPolyData()->GetFieldData()->AddArray(int2Array);
-    vtkSmartPointer<vtkDoubleArray> double2Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double2Array->InsertNextValue(center_2[0]);
-    double2Array->InsertNextValue(center_2[1]);
-    double2Array->InsertNextValue(center_2[2]);
-    surf_2->GetVtkPolyData()->GetFieldData()->AddArray(double2Array);
-
-    double center_3[3] = {4.0f, 4.0f, 3.0f};
-    double normal_3[3] = {0.0f, 0.0f, 1.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_3 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_3->SetNumberOfSides(10);
-    p_source_3->SetCenter(center_3);
-    p_source_3->SetRadius(4);
-    p_source_3->SetNormal(normal_3);
-    p_source_3->Update();
-    vtkPolyData *poly_3 = p_source_3->GetOutput();
-    mitk::Surface::Pointer surf_3 = mitk::Surface::New();
-    surf_3->SetVtkPolyData(poly_3);
-    vtkSmartPointer<vtkIntArray> int3Array = vtkSmartPointer<vtkIntArray>::New();
-    int3Array->InsertNextValue(1);
-    int3Array->InsertNextValue(0);
-    int3Array->InsertNextValue(0);
-    surf_3->GetVtkPolyData()->GetFieldData()->AddArray(int3Array);
-    vtkSmartPointer<vtkDoubleArray> double3Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double3Array->InsertNextValue(center_3[0]);
-    double3Array->InsertNextValue(center_3[1]);
-    double3Array->InsertNextValue(center_3[2]);
-    surf_3->GetVtkPolyData()->GetFieldData()->AddArray(double3Array);
-
-    std::vector<mitk::Surface::Pointer> surfaces;
-    surfaces.push_back(surf_1);
-    surfaces.push_back(surf_2);
-    surfaces.push_back(surf_3);
-
-    auto planeGeometry1 = GetPlaneGeometry();
-    auto planeGeometry2 = GetPlaneGeometry();
-    auto planeGeometry3 = GetPlaneGeometry();
-
-    std::vector<const mitk::PlaneGeometry*> planeGeometries;
-    planeGeometries.push_back(planeGeometry1);
-    planeGeometries.push_back(planeGeometry2);
-    planeGeometries.push_back(planeGeometry3);
+    auto surf_1 = CreateContour(3);
+    auto surf_2 = CreateContour(3);
+    auto surf_3 = CreateContour(3);
+    auto surf_3New = CreateContour(3);
+
+    auto planeGeometry1 = CreatePlaneGeometry(1);
+    auto planeGeometry2 = CreatePlaneGeometry(2);
+    auto planeGeometry3 = CreatePlaneGeometry(3);
 
+    mitk::SurfaceInterpolationController::CPIVector cpis= { {surf_1, planeGeometry1, 1, 0},
+      {surf_2, planeGeometry2, 1, 0}, {surf_3, planeGeometry3, 1, 0}, {surf_3New, planeGeometry3, 1, 0},
+      {surf_1, planeGeometry1, 1, 1}, {surf_1, planeGeometry1, 2, 0}, {surf_2, planeGeometry3, 2, 0}
+    };
     // Add contours
-    m_Controller->AddNewContours(surfaces, planeGeometries, true);
+    m_Controller->AddNewContours(cpis, true);
 
     // Check if all contours are there
-    auto contours = m_Controller->GetContours(0, 1);
+    auto contours = m_Controller->GetContours(1, 0);
     CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 3);
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
                            mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
                            mitk::Equal(*(surf_2->GetVtkPolyData()), *((*contours)[1].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_3->GetVtkPolyData()), *((*contours)[2].Contour->GetVtkPolyData()), 0.000001, true));
+                           mitk::Equal(*(surf_3New->GetVtkPolyData()), *((*contours)[2].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(1, 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 2);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_2->GetVtkPolyData()), *((*contours)[1].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 1);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
+    contours = m_Controller->GetContours(3, 0);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
 
     // Create another segmentation image
     unsigned int dimensions2[] = {20, 20, 20};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage(dimensions2);
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
 
-    // Create some contours
-    double center_4[3] = {10.0f, 10.0f, 10.0f};
-    double normal_4[3] = {0.0f, 1.0f, 0.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_4 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_4->SetNumberOfSides(8);
-    p_source_4->SetCenter(center_4);
-    p_source_4->SetRadius(5);
-    p_source_4->SetNormal(normal_4);
-    p_source_4->Update();
-    vtkPolyData *poly_4 = p_source_4->GetOutput();
-    mitk::Surface::Pointer surf_4 = mitk::Surface::New();
-    surf_4->SetVtkPolyData(poly_4);
-    vtkSmartPointer<vtkIntArray> int4Array = vtkSmartPointer<vtkIntArray>::New();
-    int4Array->InsertNextValue(2);
-    int4Array->InsertNextValue(0);
-    int4Array->InsertNextValue(0);
-    surf_4->GetVtkPolyData()->GetFieldData()->AddArray(int4Array);
-    vtkSmartPointer<vtkDoubleArray> double4Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double4Array->InsertNextValue(center_4[0]);
-    double4Array->InsertNextValue(center_4[1]);
-    double4Array->InsertNextValue(center_4[2]);
-    surf_4->GetVtkPolyData()->GetFieldData()->AddArray(double4Array);
-
-    double center_5[3] = {3.0f, 10.0f, 10.0f};
-    double normal_5[3] = {1.0f, 0.0f, 0.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_5 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_5->SetNumberOfSides(16);
-    p_source_5->SetCenter(center_5);
-    p_source_5->SetRadius(8);
-    p_source_5->SetNormal(normal_5);
-    p_source_5->Update();
-    vtkPolyData *poly_5 = p_source_5->GetOutput();
-    mitk::Surface::Pointer surf_5 = mitk::Surface::New();
-    surf_5->SetVtkPolyData(poly_5);
-    vtkSmartPointer<vtkIntArray> int5Array = vtkSmartPointer<vtkIntArray>::New();
-    int5Array->InsertNextValue(2);
-    int5Array->InsertNextValue(0);
-    int5Array->InsertNextValue(0);
-    surf_5->GetVtkPolyData()->GetFieldData()->AddArray(int5Array);
-    vtkSmartPointer<vtkDoubleArray> double5Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double5Array->InsertNextValue(center_5[0]);
-    double5Array->InsertNextValue(center_5[1]);
-    double5Array->InsertNextValue(center_5[2]);
-    surf_5->GetVtkPolyData()->GetFieldData()->AddArray(double5Array);
-
-    double center_6[3] = {10.0f, 10.0f, 3.0f};
-    double normal_6[3] = {0.0f, 0.0f, 1.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_6 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_6->SetNumberOfSides(100);
-    p_source_6->SetCenter(center_6);
-    p_source_6->SetRadius(5);
-    p_source_6->SetNormal(normal_6);
-    p_source_6->Update();
-    vtkPolyData *poly_6 = p_source_6->GetOutput();
-    mitk::Surface::Pointer surf_6 = mitk::Surface::New();
-    surf_6->SetVtkPolyData(poly_6);
-    vtkSmartPointer<vtkIntArray> int6Array = vtkSmartPointer<vtkIntArray>::New();
-    int6Array->InsertNextValue(2);
-    int6Array->InsertNextValue(0);
-    int6Array->InsertNextValue(0);
-    surf_6->GetVtkPolyData()->GetFieldData()->AddArray(int6Array);
-    vtkSmartPointer<vtkDoubleArray> double6Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double6Array->InsertNextValue(center_6[0]);
-    double6Array->InsertNextValue(center_6[1]);
-    double6Array->InsertNextValue(center_6[2]);
-    surf_6->GetVtkPolyData()->GetFieldData()->AddArray(double6Array);
-
-    auto planeGeometry4 = GetPlaneGeometry();
-    auto planeGeometry5 = GetPlaneGeometry();
-    auto planeGeometry6 = GetPlaneGeometry();
-
-    std::vector<mitk::Surface::Pointer> surfaces2;
-    surfaces2.push_back(surf_4);
-    surfaces2.push_back(surf_5);
-    surfaces2.push_back(surf_6);
-
-    std::vector<const mitk::PlaneGeometry*> planeGeometries2;
-    planeGeometries2.push_back(planeGeometry4);
-    planeGeometries2.push_back(planeGeometry5);
-    planeGeometries2.push_back(planeGeometry6);
-
-    m_Controller->AddNewContours(surfaces2, planeGeometries2, true);
+    auto planeGeometry4 = CreatePlaneGeometry(4);
+    auto planeGeometry5 = CreatePlaneGeometry(5);
+    auto planeGeometry6 = CreatePlaneGeometry(6);
 
-    // Check if all contours are there
+    auto surf_4 = CreateContour(4);
+    auto surf_5 = CreateContour(5);
+    auto surf_6 = CreateContour(6);
 
-    CPPUNIT_ASSERT_MESSAGE("Wrong contours stored!", m_Controller->GetContours(0, 1) == nullptr);
+    mitk::SurfaceInterpolationController::CPIVector cpis2 = { {surf_1, planeGeometry1, 1, 0},
+      {surf_2, planeGeometry2, 1, 0}, {surf_4, planeGeometry4, 1, 0},
+      {surf_5, planeGeometry5, 1, 1}, {surf_6, planeGeometry6, 2, 0}
+    };
 
-    auto contours2 = m_Controller->GetContours(0, 2);
+    contours = m_Controller->GetContours(1, 0);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
 
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 2)->size() == 3);
+    m_Controller->AddNewContours(cpis2);
+    // Check if all contours are there
+    contours = m_Controller->GetContours(1, 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 3);
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_4->GetVtkPolyData()), *((*contours2)[0].Contour->GetVtkPolyData()), 0.000001, true));
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_5->GetVtkPolyData()), *((*contours2)[1].Contour->GetVtkPolyData()), 0.000001, true));
+      mitk::Equal(*(surf_2->GetVtkPolyData()), *((*contours)[1].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_6->GetVtkPolyData()), *((*contours2)[2].Contour->GetVtkPolyData()), 0.000001, true));
-
-    // Modify some contours
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_7 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_7->SetNumberOfSides(200);
-    p_source_7->SetCenter(3.0, 10.0, 10.0);
-    p_source_7->SetRadius(5);
-    p_source_7->SetNormal(1, 0, 0);
-    p_source_7->Update();
-    vtkPolyData *poly_7 = p_source_7->GetOutput();
-    mitk::Surface::Pointer surf_7 = mitk::Surface::New();
-    surf_7->SetVtkPolyData(poly_7);
-    vtkSmartPointer<vtkIntArray> int7Array = vtkSmartPointer<vtkIntArray>::New();
-    int7Array->InsertNextValue(2);
-    int7Array->InsertNextValue(0);
-    int7Array->InsertNextValue(0);
-    surf_7->GetVtkPolyData()->GetFieldData()->AddArray(int7Array);
-    vtkSmartPointer<vtkDoubleArray> double7Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double7Array->InsertNextValue(3.0);
-    double7Array->InsertNextValue(10.0);
-    double7Array->InsertNextValue(10.0);
-    surf_7->GetVtkPolyData()->GetFieldData()->AddArray(double7Array);
-
-
-    std::vector<mitk::Surface::Pointer> surfaces3;
-    surfaces3.push_back(surf_7);
-
-    auto planeGeometry7 = GetPlaneGeometry();
-    std::vector<const mitk::PlaneGeometry*> planeGeometries3;
-    planeGeometries3.push_back(planeGeometry7);
-
-    m_Controller->AddNewContours(surfaces3, planeGeometries3, true);
-
-    CPPUNIT_ASSERT_MESSAGE("Wrong contours stored!", m_Controller->GetContours(0, 1) == nullptr);
-    contours2 = m_Controller->GetContours(0, 2);
-    //CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-    //                       mitk::Equal(*(surf_7->GetVtkPolyData()), *(contour_7->GetVtkPolyData()), 0.000001, true));
-
-    // Change session and test if all contours are available
+      mitk::Equal(*(surf_4->GetVtkPolyData()), *((*contours)[2].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(1, 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_5->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_6->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 1);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
+    contours = m_Controller->GetContours(3, 0);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
+
+    // Check if all contours of segmentation_1 are still there
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
-    /*auto contour_8 = m_Controller->GetContour(contourInfo1);
-    auto contour_9 = m_Controller->GetContour(contourInfo2);
-    auto contour_10 = m_Controller->GetContour(contourInfo3);
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 2)->size() == 3);
+    contours = m_Controller->GetContours(1, 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 3);
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_1->GetVtkPolyData()), *(contour_8->GetVtkPolyData()), 0.000001, true));
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_2->GetVtkPolyData()), *(contour_9->GetVtkPolyData()), 0.000001, true));
+      mitk::Equal(*(surf_2->GetVtkPolyData()), *((*contours)[1].Contour->GetVtkPolyData()), 0.000001, true));
     CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
-                           mitk::Equal(*(surf_3->GetVtkPolyData()), *(contour_10->GetVtkPolyData()), 0.000001, true));*/
+      mitk::Equal(*(surf_3New->GetVtkPolyData()), *((*contours)[2].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(1, 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", contours->size() == 2);
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_1->GetVtkPolyData()), *((*contours)[0].Contour->GetVtkPolyData()), 0.000001, true));
+    CPPUNIT_ASSERT_MESSAGE("Contours not equal!",
+      mitk::Equal(*(surf_2->GetVtkPolyData()), *((*contours)[1].Contour->GetVtkPolyData()), 0.000001, true));
+
+    contours = m_Controller->GetContours(2, 1);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
+    contours = m_Controller->GetContours(3, 0);
+    CPPUNIT_ASSERT_MESSAGE("Invalid CPIs exists!", contours == nullptr);
   }
 
   void TestRemoveContours()
   {
     // Create segmentation image
     unsigned int dimensions1[] = {12, 12, 12};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage(dimensions1);
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
 
-    // Create some contours
-    double center_1[3] = {4.0f, 4.0f, 4.0f};
-    double normal_1[3] = {0.0f, 1.0f, 0.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source->SetNumberOfSides(20);
-    p_source->SetCenter(center_1);
-    p_source->SetRadius(4);
-    p_source->SetNormal(normal_1);
-    p_source->Update();
-    vtkPolyData *poly_1 = p_source->GetOutput();
-    mitk::Surface::Pointer surf_1 = mitk::Surface::New();
-    surf_1->SetVtkPolyData(poly_1);
-    vtkSmartPointer<vtkIntArray> int1Array = vtkSmartPointer<vtkIntArray>::New();
-    int1Array->InsertNextValue(1);
-    int1Array->InsertNextValue(0);
-    int1Array->InsertNextValue(0);
-    surf_1->GetVtkPolyData()->GetFieldData()->AddArray(int1Array);
-    vtkSmartPointer<vtkDoubleArray> double1Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double1Array->InsertNextValue(center_1[0]);
-    double1Array->InsertNextValue(center_1[1]);
-    double1Array->InsertNextValue(center_1[2]);
-    surf_1->GetVtkPolyData()->GetFieldData()->AddArray(double1Array);
-
-    double center_2[3] = {4.0f, 4.0f, 4.0f};
-    double normal_2[3] = {1.0f, 0.0f, 0.0f};
-    vtkSmartPointer<vtkRegularPolygonSource> p_source_2 = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    p_source_2->SetNumberOfSides(80);
-    p_source_2->SetCenter(center_2);
-    p_source_2->SetRadius(4);
-    p_source_2->SetNormal(normal_2);
-    p_source_2->Update();
-    vtkPolyData *poly_2 = p_source_2->GetOutput();
-    mitk::Surface::Pointer surf_2 = mitk::Surface::New();
-    surf_2->SetVtkPolyData(poly_2);
-    vtkSmartPointer<vtkIntArray> int2Array = vtkSmartPointer<vtkIntArray>::New();
-    int2Array->InsertNextValue(1);
-    int2Array->InsertNextValue(0);
-    int2Array->InsertNextValue(0);
-    surf_2->GetVtkPolyData()->GetFieldData()->AddArray(int2Array);
-    vtkSmartPointer<vtkDoubleArray> double2Array = vtkSmartPointer<vtkDoubleArray>::New();
-    double2Array->InsertNextValue(center_2[0]);
-    double2Array->InsertNextValue(center_2[1]);
-    double2Array->InsertNextValue(center_2[2]);
-    surf_2->GetVtkPolyData()->GetFieldData()->AddArray(double2Array);
-
-    std::vector<mitk::Surface::Pointer> surfaces;
-    surfaces.push_back(surf_1);
-    surfaces.push_back(surf_2);
-
-    auto planeGeometry1 = GetPlaneGeometry();
-    auto planeGeometry2 = GetPlaneGeometry();
-    std::vector<const mitk::PlaneGeometry*> planeGeometries;
-    planeGeometries.push_back(planeGeometry1);
-    planeGeometries.push_back(planeGeometry2);
-
-    m_Controller->AddNewContours(surfaces, planeGeometries, true);
-    // // Add contours
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 1)->size() == 2);
 
+    auto surf_1 = CreateContour(3);
+    auto surf_2 = CreateContour(3);
+    auto surf_3 = CreateContour(3);
+
+    auto planeGeometry1 = CreatePlaneGeometry(1);
+    auto planeGeometry2 = CreatePlaneGeometry(2);
+    auto planeGeometry3 = CreatePlaneGeometry(3);
+
+    mitk::SurfaceInterpolationController::CPIVector cpis = { {surf_1, planeGeometry1, 1, 0},
+      {surf_2, planeGeometry2, 1, 1}, {surf_3, planeGeometry3, 1, 2},
+      {surf_1, planeGeometry1, 2, 0}, {surf_2, planeGeometry3, 2, 0}
+    };
+    m_Controller->AddNewContours(cpis);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 0)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 1)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 2)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0)->size() == 2);
+
+    //Remove unkown label
     m_Controller->RemoveContours(9);
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 1)->size() == 2);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 0)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 1)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 2)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0)->size() == 2);
 
-    m_Controller->RemoveContours(1, 9);
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 1)->size() == 2);
+    //Remove unkown time step
+    m_Controller->RemoveContours(1,3);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 0)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 1)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 2)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0)->size() == 2);
+
+
+    m_Controller->RemoveContours(1, 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 0)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 1) == nullptr);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 2)->size() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0)->size() == 2);
 
     m_Controller->RemoveContours(1);
-    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(0, 1) == nullptr);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 0) == nullptr);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 1) == nullptr);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(1, 2) == nullptr);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0)->size() == 2);
+
+    m_Controller->RemoveContours(2);
+    CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetContours(2, 0) == nullptr);
   }
 
   bool AssertImagesEqual4D(mitk::LabelSetImage *img1, mitk::LabelSetImage *img2)
   {
     auto selector1 = mitk::ImageTimeSelector::New();
     selector1->SetInput(img1);
     selector1->SetChannelNr(0);
     auto selector2 = mitk::ImageTimeSelector::New();
     selector2->SetInput(img2);
     selector2->SetChannelNr(0);
 
     int numTs1 = img1->GetTimeSteps();
     int numTs2 = img2->GetTimeSteps();
     if (numTs1 != numTs2)
     {
       return false;
     }
 
     /*mitk::ImagePixelWriteAccessor<unsigned char,4> accessor( img1 );
     itk::Index<4> ind;
     ind[0] = 5;
     ind[1] = 5;
     ind[2] = 5;
     ind[3] = 2;
     accessor.SetPixelByIndex( ind, 7 );*/
 
     for (int ts = 0; ts < numTs1; ++ts)
     {
       selector1->SetTimeNr(ts);
       selector2->SetTimeNr(ts);
 
       selector1->Update();
       selector2->Update();
 
       mitk::Image::Pointer imgSel1 = selector1->GetOutput();
       mitk::Image::Pointer imgSel2 = selector2->GetOutput();
 
       MITK_ASSERT_EQUAL(imgSel1, imgSel2, "Segmentation images are not equal");
     }
 
     return true;
   }
 
   void TestSetCurrentInterpolationSession4D()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10, 5};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage4D(dimensions1);
     // mitk::Image * segmentationImage_1 = dynamic_cast<mitk::Image *>(segmentation_1.GetPointer());
 
     unsigned int dimensions2[] = {20, 10, 30, 4};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage4D(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     auto currentSegmentation = dynamic_cast<mitk::LabelSetImage *>(m_Controller->GetCurrentSegmentation());
     AssertImagesEqual4D(currentSegmentation, segmentation_1->Clone());
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
 
     // Test 2
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     // MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_2->Clone(), "Segmentation images are not
     // equal");
     currentSegmentation = dynamic_cast<mitk::LabelSetImage *>(m_Controller->GetCurrentSegmentation());
     // AssertImagesEqual4D(currentSegmentation, segmentation_2->Clone());
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            currentSegmentation == segmentation_2.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test 3
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     // MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not
     // equal");
     currentSegmentation = dynamic_cast<mitk::LabelSetImage *>(m_Controller->GetCurrentSegmentation());
     AssertImagesEqual4D(currentSegmentation, segmentation_1->Clone());
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test 4
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     // MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not
     // equal");
     currentSegmentation = dynamic_cast<mitk::LabelSetImage *>(m_Controller->GetCurrentSegmentation());
     AssertImagesEqual4D(currentSegmentation, segmentation_1->Clone());
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_1.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test 5
     m_Controller->SetCurrentInterpolationSession(nullptr);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation()==nullptr);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
   }
 
   void TestRemoveAllInterpolationSessions4D()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10, 4};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage4D(dimensions1);
 
     unsigned int dimensions2[] = {20, 10, 30, 5};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage4D(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     m_Controller->RemoveAllInterpolationSessions();
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0",
                            m_Controller->GetNumberOfInterpolationSessions() == 0);
   }
 
   void TestRemoveInterpolationSession4D()
   {
     // Create image for testing
     unsigned int dimensions1[] = {10, 10, 10, 3};
     mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage4D(dimensions1);
 
     unsigned int dimensions2[] = {20, 10, 30, 6};
     mitk::LabelSetImage::Pointer segmentation_2 = createLabelSetImage4D(dimensions2);
 
     // Test 1
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     m_Controller->SetCurrentInterpolationSession(segmentation_2);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test current segmentation should not be null if another one was removed
     m_Controller->RemoveInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
     CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal",
                            m_Controller->GetCurrentSegmentation() == segmentation_2.GetPointer());
     CPPUNIT_ASSERT_MESSAGE("Current segmentation is null after another one was removed",
                            m_Controller->GetCurrentSegmentation()!=nullptr);
 
     m_Controller->SetCurrentInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2",
                            m_Controller->GetNumberOfInterpolationSessions() == 2);
 
     // Test current segmentation should not be null if another one was removed
     m_Controller->RemoveInterpolationSession(segmentation_1);
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1",
                            m_Controller->GetNumberOfInterpolationSessions() == 1);
     CPPUNIT_ASSERT_MESSAGE("Current segmentation is not null after session was removed",
                            m_Controller->GetCurrentSegmentation()==nullptr);
   }
 
   void TestOnSegmentationDeleted4D()
   {
     {
       // Create image for testing
       unsigned int dimensions1[] = {10, 10, 10, 7};
       mitk::LabelSetImage::Pointer segmentation_1 = createLabelSetImage4D(dimensions1);
       m_Controller->SetCurrentInterpolationSession(segmentation_1);
       m_Controller->SetCurrentTimePoint(3);
     }
     CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0",
                            m_Controller->GetNumberOfInterpolationSessions() == 0);
   }
 };
 MITK_TEST_SUITE_REGISTRATION(mitkSurfaceInterpolationController)
diff --git a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
index f936786a5a..182a833f89 100644
--- a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
+++ b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp
@@ -1,1005 +1,813 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <mitkSurfaceInterpolationController.h>
 
+#include <shared_mutex>
+
 #include <mitkCreateDistanceImageFromSurfaceFilter.h>
 #include <mitkComputeContourSetNormalsFilter.h>
 #include <mitkImageAccessByItk.h>
 #include <mitkImagePixelReadAccessor.h>
 #include <mitkImageTimeSelector.h>
 #include <mitkImageToSurfaceFilter.h>
 #include <mitkLabelSetImage.h>
 #include <mitkMemoryUtilities.h>
 #include <mitkNodePredicateDataUID.h>
 #include <mitkNodePredicateProperty.h>
+#include <mitkNodePredicateAnd.h>
 #include <mitkPlanarCircle.h>
 #include <mitkPlaneGeometry.h>
 #include <mitkReduceContourSetFilter.h>
 
 #include <vtkFieldData.h>
 #include <vtkMath.h>
 #include <vtkPolygon.h>
 
-// Check whether the given contours are coplanar
-bool ContoursCoplanar(mitk::SurfaceInterpolationController::ContourPositionInformation leftHandSide,
-                      mitk::SurfaceInterpolationController::ContourPositionInformation rightHandSide)
-{
-  // Here we check two things:
-  // 1. Whether the normals of both contours are at least parallel
-  // 2. Whether both contours lie in the same plane
-
-  // Check for coplanarity:
-  // a. Span a vector between two points one from each contour
-  // b. Calculate dot product for the vector and one of the normals
-  // c. If the dot is zero the two vectors are orthogonal and the contours are coplanar
-
-  double vec[3];
-  vec[0] = leftHandSide.ContourPoint[0] - rightHandSide.ContourPoint[0];
-  vec[1] = leftHandSide.ContourPoint[1] - rightHandSide.ContourPoint[1];
-  vec[2] = leftHandSide.ContourPoint[2] - rightHandSide.ContourPoint[2];
-  double n[3];
-  n[0] = rightHandSide.ContourNormal[0];
-  n[1] = rightHandSide.ContourNormal[1];
-  n[2] = rightHandSide.ContourNormal[2];
-  double dot = vtkMath::Dot(n, vec);
-
-  double n2[3];
-  n2[0] = leftHandSide.ContourNormal[0];
-  n2[1] = leftHandSide.ContourNormal[1];
-  n2[2] = leftHandSide.ContourNormal[2];
-
-  // The normals of both contours have to be parallel but not of the same orientation
-  double lengthLHS = leftHandSide.ContourNormal.GetNorm();
-  double lengthRHS = rightHandSide.ContourNormal.GetNorm();
-  double dot2 = vtkMath::Dot(n, n2);
-  bool contoursParallel = mitk::Equal(fabs(lengthLHS * lengthRHS), fabs(dot2), 0.001);
-
-  if (mitk::Equal(dot, 0.0, 0.001) && contoursParallel)
-    return true;
-  else
-    return false;
-}
-
-mitk::SurfaceInterpolationController::ContourPositionInformation CreateContourPositionInformation(
-  const mitk::Surface* contour, const mitk::PlaneGeometry* planeGeometry)
-{
-  mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo;
-  contourInfo.Contour = contour;
-  mitk::ScalarType n[3];
-  vtkPolygon::ComputeNormal(contour->GetVtkPolyData()->GetPoints(), n);
-  contourInfo.ContourNormal = n;
-  contourInfo.Pos = -1;
-  contourInfo.TimeStep = std::numeric_limits<long unsigned int>::max();
-  contourInfo.Plane = planeGeometry;
 
-  auto contourIntArray = vtkIntArray::SafeDownCast( contour->GetVtkPolyData()->GetFieldData()->GetAbstractArray(0) );
+typedef std::map<mitk::TimeStepType, mitk::SurfaceInterpolationController::CPIVector> CPITimeStepMap;
+typedef std::map<mitk::LabelSetImage::LabelValueType, CPITimeStepMap> CPITimeStepLabelMap;
 
-  if (contourIntArray->GetSize() < 2)
-  {
-    MITK_ERROR << "In CreateContourPositionInformation. The contourIntArray is empty.";
-  }
-  contourInfo.LabelValue = contourIntArray->GetValue(0);
+typedef std::map<const mitk::LabelSetImage*, CPITimeStepLabelMap> CPITimeStepLabelSegMap;
 
-  if (contourIntArray->GetSize() >= 3)
-  {
-    contourInfo.TimeStep = contourIntArray->GetValue(2);
-  }
+CPITimeStepLabelSegMap cpiMap;
+std::shared_mutex cpiMutex;
 
-  return contourInfo;
-};
+std::map<mitk::LabelSetImage*, unsigned long> segmentationObserverTags;
 
 mitk::SurfaceInterpolationController::SurfaceInterpolationController()
   : m_SelectedSegmentation(nullptr),
     m_CurrentTimePoint(0.)
 {
   m_DistanceImageSpacing = 0.0;
   m_ReduceFilter = ReduceContourSetFilter::New();
   m_NormalsFilter = ComputeContourSetNormalsFilter::New();
   m_InterpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New();
 
   m_ReduceFilter->SetUseProgressBar(false);
-  //  m_ReduceFilter->SetProgressStepSize(1);
   m_NormalsFilter->SetUseProgressBar(true);
   m_NormalsFilter->SetProgressStepSize(1);
   m_InterpolateSurfaceFilter->SetUseProgressBar(true);
   m_InterpolateSurfaceFilter->SetProgressStepSize(7);
 
-  m_Contours = Surface::New();
-
   m_InterpolationResult = nullptr;
   m_CurrentNumberOfReducedContours = 0;
 }
 
 mitk::SurfaceInterpolationController::~SurfaceInterpolationController()
 {
   this->RemoveObservers();
 }
 
 void mitk::SurfaceInterpolationController::RemoveObservers()
 {
   // Removing all observers
-  for (auto& [segmentation, tag] : m_SegmentationObserverTags)
+  while (segmentationObserverTags.size())
   {
-    this->RemoveObserversInternal(segmentation);
+    this->RemoveObserversInternal(segmentationObserverTags.begin()->first);
   }
-  m_SegmentationObserverTags.clear();
 }
 
 mitk::SurfaceInterpolationController *mitk::SurfaceInterpolationController::GetInstance()
 {
   static mitk::SurfaceInterpolationController::Pointer m_Instance;
 
   if (m_Instance.IsNull())
   {
     m_Instance = SurfaceInterpolationController::New();
   }
   return m_Instance;
 }
 
-void mitk::SurfaceInterpolationController::AddNewContours(const std::vector<mitk::Surface::Pointer>& newContours,
-                                                          std::vector<const mitk::PlaneGeometry*>& contourPlanes,
-                                                          bool reinitializationAction)
+void mitk::SurfaceInterpolationController::AddNewContours(const std::vector<ContourPositionInformation>& newCPIs,
+  bool reinitializationAction)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull()) return;
 
-  if (newContours.size() != contourPlanes.size())
+  for (auto cpi : newCPIs)
   {
-    MITK_ERROR << "SurfaceInterpolationController::AddNewContours. contourPlanes and newContours are not of the same size.";
-  }
-
-  for (size_t i = 0; i < newContours.size(); ++i)
-  {
-    const auto &newContour = newContours[i];
-
-    const mitk::PlaneGeometry * planeGeometry = contourPlanes[i];
-    if (newContour->GetVtkPolyData()->GetNumberOfPoints() > 0)
+    if (cpi.Contour->GetVtkPolyData()->GetNumberOfPoints() > 0)
     {
-      auto contourInfo = CreateContourPositionInformation(newContour, planeGeometry);
-      if (!reinitializationAction)
-      {
-        contourInfo.ContourPoint = this->ComputeInteriorPointOfContour(contourInfo, selectedSegmentation);
-      }
-      else
-      {
-        auto vtkPolyData = contourInfo.Contour->GetVtkPolyData();
-        auto pointVtkArray = vtkDoubleArray::SafeDownCast(vtkPolyData->GetFieldData()->GetAbstractArray(1));
-        mitk::ScalarType *ptArr = new mitk::ScalarType[3];
-        for (int i = 0; i < pointVtkArray->GetSize(); ++i)
-          ptArr[i] = pointVtkArray->GetValue(i);
-
-        mitk::Point3D pt3D;
-        pt3D.FillPoint(ptArr);
-        contourInfo.ContourPoint = pt3D;
-      }
-
-      this->AddToInterpolationPipeline(contourInfo, reinitializationAction);
+      this->AddToInterpolationPipeline(cpi, reinitializationAction);
     }
   }
   this->Modified();
 }
 
-mitk::DataNode* mitk::SurfaceInterpolationController::GetSegmentationImageNode()
+
+mitk::DataNode* GetSegmentationImageNodeInternal(mitk::DataStorage* ds, mitk::LabelSetImage* seg)
 {
-  if (m_DataStorage.IsNull()) return nullptr;
-  auto selectedSegmentation = m_SelectedSegmentation.Lock();
-  if (selectedSegmentation.IsNull()) return nullptr;
+  if (nullptr == ds) return nullptr;
+  if (nullptr == seg) return nullptr;
 
-  DataNode* segmentationNode = nullptr;
-  mitk::NodePredicateDataUID::Pointer dataUIDPredicate = mitk::NodePredicateDataUID::New(selectedSegmentation->GetUID());
-  auto dataNodeObjects = m_DataStorage->GetSubset(dataUIDPredicate);
+  mitk::DataNode* segmentationNode = nullptr;
+  mitk::NodePredicateDataUID::Pointer dataUIDPredicate = mitk::NodePredicateDataUID::New(seg->GetUID());
+  auto dataNodeObjects = ds->GetSubset(dataUIDPredicate);
 
   if (dataNodeObjects->Size() != 0)
   {
     for (auto it = dataNodeObjects->Begin(); it != dataNodeObjects->End(); ++it)
     {
       segmentationNode = it->Value();
     }
   }
   else
   {
     MITK_ERROR << "Unable to find the labelSetImage with the desired UID.";
   }
   return segmentationNode;
 }
 
-void mitk::SurfaceInterpolationController::AddPlaneGeometryNodeToDataStorage(const ContourPositionInformation& contourInfo)
+mitk::DataNode* mitk::SurfaceInterpolationController::GetSegmentationImageNode() const
+{
+  if (m_DataStorage.IsNull()) return nullptr;
+  auto selectedSegmentation = m_SelectedSegmentation.Lock();
+  if (selectedSegmentation.IsNull()) return nullptr;
+  return GetSegmentationImageNodeInternal(this->m_DataStorage, selectedSegmentation);
+}
+
+mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep) const
+{
+  DataStorage::SetOfObjects::Pointer relevantNodes = DataStorage::SetOfObjects::New();
+
+  if (m_DataStorage.IsNotNull())
+  {
+    //remove relevant plane nodes
+    auto nodes = this->GetPlaneGeometryNodeFromDataStorage(segNode, labelValue);
+
+    for (auto it = nodes->Begin(); it != nodes->End(); ++it)
+    {
+      auto aTS = dynamic_cast<mitk::IntProperty*>(it->Value()->GetProperty("timeStep"))->GetValue();
+      bool sameTS = (timeStep == aTS);
+
+      if (sameTS)
+      {
+        relevantNodes->push_back(it->Value());
+      }
+    }
+  }
+  return relevantNodes;
+}
+
+mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue) const
+{
+  auto isContourPlaneGeometry = NodePredicateProperty::New("isContourPlaneGeometry", mitk::BoolProperty::New(true));
+  auto isCorrectLabel = NodePredicateProperty::New("labelID", mitk::UShortProperty::New(labelValue));
+  auto searchPredicate = NodePredicateAnd::New(isContourPlaneGeometry, isCorrectLabel);
+
+  mitk::DataStorage::SetOfObjects::ConstPointer result;
+  if (m_DataStorage.IsNotNull()) result = m_DataStorage->GetDerivations(segNode, searchPredicate);
+  return result;
+}
+
+mitk::DataStorage::SetOfObjects::ConstPointer mitk::SurfaceInterpolationController::GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode) const
+{
+  auto isContourPlaneGeometry = NodePredicateProperty::New("isContourPlaneGeometry", mitk::BoolProperty::New(true));
+
+  mitk::DataStorage::SetOfObjects::ConstPointer result;
+  if (m_DataStorage.IsNotNull()) result = m_DataStorage->GetDerivations(segNode, isContourPlaneGeometry);
+  return result;
+}
+void mitk::SurfaceInterpolationController::AddPlaneGeometryNodeToDataStorage(const ContourPositionInformation& contourInfo) const
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow()<< "Cannot add plane geometries. No valid segmentation selected.";
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     MITK_ERROR << "Invalid time point requested in AddPlaneGeometryNodeToDataStorage.";
     return;
   }
 
+  if (m_DataStorage.IsNull())
+  {
+    MITK_DEBUG << "Cannot add plane geometry nodes. No data storage is set.";
+    return;
+  }
+
   auto planeGeometry = contourInfo.Plane;
   if (planeGeometry)
   {
-    auto planeGeometryData = mitk::PlanarCircle::New();
-    planeGeometryData->SetPlaneGeometry(planeGeometry->Clone());
-    mitk::Point2D p1;
-    planeGeometry->Map(planeGeometry->GetCenter(), p1);
-    planeGeometryData->PlaceFigure(p1);
-    planeGeometryData->SetCurrentControlPoint(p1);
-    planeGeometryData->SetProperty("initiallyplaced", mitk::BoolProperty::New(true));
-
     auto segmentationNode = this->GetSegmentationImageNode();
-    auto isContourPlaneGeometry = mitk::NodePredicateProperty::New("isContourPlaneGeometry", mitk::BoolProperty::New(true));
-
-    mitk::DataStorage::SetOfObjects::ConstPointer contourNodes =
-      m_DataStorage->GetDerivations(segmentationNode, isContourPlaneGeometry);
+    mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = this->GetPlaneGeometryNodeFromDataStorage(segmentationNode, contourInfo.LabelValue, contourInfo.TimeStep);
 
     mitk::DataNode::Pointer contourPlaneGeometryDataNode;
 
     //  Go through the pre-existing contours and check if the contour position matches them.
     for (auto it = contourNodes->Begin(); it != contourNodes->End(); ++it)
     {
-      auto labelID = dynamic_cast<mitk::UShortProperty *>(it->Value()->GetProperty("labelID"))->GetValue();
-      auto posID = dynamic_cast<mitk::IntProperty *>(it->Value()->GetProperty("position"))->GetValue();
-      bool sameLabel = (labelID == contourInfo.LabelValue);
-      bool samePos = (posID == contourInfo.Pos);
+      auto planeData = dynamic_cast<mitk::PlanarFigure*>(it->Value()->GetData());
+      if (nullptr == planeData) mitkThrow() << "Invalid ContourPlaneGeometry data node. Does not contion a planar figure as data.";
 
-      if (samePos && sameLabel)
+      bool samePlane = contourInfo.Plane->IsOnPlane(planeData->GetPlaneGeometry());
+
+      if (samePlane)
       {
         contourPlaneGeometryDataNode = it->Value();
         break;
       }
     }
 
     //  Go through the contourPlaneGeometry Data and add the segmentationNode to it.
     if (contourPlaneGeometryDataNode.IsNull())
     {
-      const auto currentTimeStep = selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
+      auto planeGeometryData = mitk::PlanarCircle::New();
+      planeGeometryData->SetPlaneGeometry(planeGeometry->Clone());
+      mitk::Point2D p1;
+      planeGeometry->Map(planeGeometry->GetCenter(), p1);
+      planeGeometryData->PlaceFigure(p1);
+      planeGeometryData->SetCurrentControlPoint(p1);
+      planeGeometryData->SetProperty("initiallyplaced", mitk::BoolProperty::New(true));
 
-      std::string contourName = "contourPlane T " + std::to_string(currentTimeStep) + " L " + std::to_string(contourInfo.LabelValue) + "P " + std::to_string(contourInfo.Pos);
+      std::string contourName = "contourPlane L " + std::to_string(contourInfo.LabelValue) + " T " + std::to_string(contourInfo.TimeStep);
 
       contourPlaneGeometryDataNode = mitk::DataNode::New();
       contourPlaneGeometryDataNode->SetData(planeGeometryData);
 
       //  No need to change properties
       contourPlaneGeometryDataNode->SetProperty("helper object", mitk::BoolProperty::New(false));
       contourPlaneGeometryDataNode->SetProperty("hidden object", mitk::BoolProperty::New(true));
       contourPlaneGeometryDataNode->SetProperty("isContourPlaneGeometry", mitk::BoolProperty::New(true));
       contourPlaneGeometryDataNode->SetVisibility(false);
 
       //  Need to change properties
       contourPlaneGeometryDataNode->SetProperty("name", mitk::StringProperty::New(contourName) );
       contourPlaneGeometryDataNode->SetProperty("labelID", mitk::UShortProperty::New(contourInfo.LabelValue));
-      contourPlaneGeometryDataNode->SetProperty("position", mitk::IntProperty::New(contourInfo.Pos));
-      contourPlaneGeometryDataNode->SetProperty("timeStep", mitk::IntProperty::New(currentTimeStep));
+      contourPlaneGeometryDataNode->SetProperty("timeStep", mitk::IntProperty::New(contourInfo.TimeStep));
 
-      contourPlaneGeometryDataNode->SetProperty("px", mitk::DoubleProperty::New(contourInfo.ContourPoint[0]));
-      contourPlaneGeometryDataNode->SetProperty("py", mitk::DoubleProperty::New(contourInfo.ContourPoint[1]));
-      contourPlaneGeometryDataNode->SetProperty("pz", mitk::DoubleProperty::New(contourInfo.ContourPoint[2]));
+      contourPlaneGeometryDataNode->SetData(planeGeometryData);
 
       m_DataStorage->Add(contourPlaneGeometryDataNode, segmentationNode);
     }
-
-    contourPlaneGeometryDataNode->SetData(planeGeometryData);
-
   }
 }
 
 void mitk::SurfaceInterpolationController::AddToInterpolationPipeline(ContourPositionInformation& contourInfo, bool reinitializationAction)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
     return;
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     MITK_ERROR << "Invalid time point requested for interpolation pipeline.";
     return;
   }
 
   if (contourInfo.Plane == nullptr)
   {
     MITK_ERROR << "contourInfo plane is null.";
     return;
   }
 
   if (contourInfo.Contour->GetVtkPolyData()->GetNumberOfPoints() == 0)
   {
     this->RemoveContour(contourInfo);
     MITK_DEBUG << "contourInfo contour is empty.";
     return;
   }
 
   {
-    std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-    const auto currentTimeStep = reinitializationAction ? contourInfo.TimeStep : selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
-
-    const auto currentLabelValue = reinitializationAction ? contourInfo.LabelValue : selectedSegmentation->GetActiveLabel()->GetValue();
+    std::lock_guard<std::shared_mutex> guard(cpiMutex);
+    const auto& currentTimeStep = contourInfo.TimeStep;
+    const auto& currentLabelValue = contourInfo.LabelValue;
 
-    auto& currentImageContours = m_CPIMap[selectedSegmentation];
+    auto& currentImageContours = cpiMap[selectedSegmentation];
     auto& currentLabelContours = currentImageContours[currentLabelValue];
     auto& currentContourList = currentLabelContours[currentTimeStep];
 
-    auto finding = std::find_if(currentContourList.begin(), currentContourList.end(), [contourInfo](const ContourPositionInformation& element) {return ContoursCoplanar(contourInfo, element); });
+    auto finding = std::find_if(currentContourList.begin(), currentContourList.end(), [contourInfo](const ContourPositionInformation& element) {return contourInfo.Plane->IsOnPlane(element.Plane); });
 
     if (finding != currentContourList.end())
     {
-      contourInfo.Pos = finding->Pos;
+      MITK_DEBUG << "CPI already exists. CPI is updated. Label: "<< currentLabelValue << "; Time Step: " << currentTimeStep;
       *finding = contourInfo;
     }
     else
     {
-      contourInfo.Pos = currentContourList.size();
       currentContourList.push_back(contourInfo);
     }
   }
 
   if (!reinitializationAction)
   {
     this->AddPlaneGeometryNodeToDataStorage(contourInfo);
   }
 }
 
 bool mitk::SurfaceInterpolationController::RemoveContour(ContourPositionInformation contourInfo)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     return false;
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     return false;
   }
 
   bool removedIt = false;
 
   {
-    std::lock_guard<std::shared_mutex> cpiGuard(m_CPIMutex);
+    std::lock_guard<std::shared_mutex> cpiGuard(cpiMutex);
 
-    const auto currentTimeStep = selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
-    const auto currentLabel = selectedSegmentation->GetActiveLabel()->GetValue();
-    auto it = m_CPIMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).begin();
+    const auto currentTimeStep = contourInfo.TimeStep;
+    const auto currentLabel = contourInfo.LabelValue;
+    auto it = cpiMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).begin();
 
 
-    while (it != m_CPIMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).end())
+    while (it != cpiMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).end())
     {
       const ContourPositionInformation& currentContour = (*it);
-      if (ContoursCoplanar(currentContour, contourInfo))
+      if (currentContour.Plane->IsOnPlane(contourInfo.Plane))
       {
-        m_CPIMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).erase(it);
+        cpiMap.at(selectedSegmentation).at(currentLabel).at(currentTimeStep).erase(it);
         removedIt = true;
+
+        if (m_DataStorage.IsNotNull())
+        {
+          mitk::DataNode::Pointer contourPlaneGeometryDataNode;
+
+          auto contourNodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(m_DataStorage, selectedSegmentation), currentLabel, currentTimeStep);
+
+          //  Go through the nodes and check if the contour position matches them.
+          for (auto it = contourNodes->Begin(); it != contourNodes->End(); ++it)
+          {
+            auto planeData = dynamic_cast<mitk::PlanarFigure*>(it->Value()->GetData());
+            if (nullptr == planeData) mitkThrow() << "Invalid ContourPlaneGeometry data node. Does not contion a planar figure as data.";
+
+            bool samePlane = contourInfo.Plane->IsOnPlane(planeData->GetPlaneGeometry());
+
+            if (samePlane)
+            {
+              m_DataStorage->Remove(it->Value());
+              break;
+            }
+          }
+        }
         break;
       }
       ++it;
     }
   }
 
   if (removedIt)
   {
     this->ReinitializeInterpolation();
   }
 
   return removedIt;
 }
 
 void mitk::SurfaceInterpolationController::AddActiveLabelContoursForInterpolation(mitk::Label::PixelType activeLabel)
 {
   this->ReinitializeInterpolation();
 
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow() << "Cannot add active label contours. No valid segmentation selected.";
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     MITK_ERROR << "Invalid time point requested for interpolation pipeline.";
     return;
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     MITK_ERROR << "Invalid time point requested for interpolation pipeline.";
     return;
   }
   const auto currentTimeStep = selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
 
-  std::shared_lock<std::shared_mutex> guard(m_CPIMutex);
+  std::shared_lock<std::shared_mutex> guard(cpiMutex);
 
-  auto& currentImageContours = m_CPIMap.at(selectedSegmentation);
+  auto& currentImageContours = cpiMap.at(selectedSegmentation);
 
   auto finding = currentImageContours.find(activeLabel);
   if (finding == currentImageContours.end())
   {
     MITK_INFO << "Contours for label don't exist. Label value: " << activeLabel;
     return;
   }
 
   auto currentLabelContoursMap = finding->second;
 
   auto tsfinding = currentLabelContoursMap.find(currentTimeStep);
   if (tsfinding == currentLabelContoursMap.end())
   {
     MITK_INFO << "Contours for current time step don't exist.";
     return;
   }
 
   CPIVector& currentContours = tsfinding->second;
 
   unsigned int index = 0;
   m_ReduceFilter->Reset();
   for (const auto&  cpi : currentContours)
   {
     m_ReduceFilter->SetInput(index, cpi.Contour);
     ++index;
   }
 }
 
 void mitk::SurfaceInterpolationController::Interpolate()
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow() << "Cannot interpolate. No valid segmentation selected.";
   }
 
   if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
   {
     MITK_WARN << "No interpolation possible, currently selected timepoint is not in the time bounds of currently selected segmentation. Time point: " << m_CurrentTimePoint;
     m_InterpolationResult = nullptr;
     return;
   }
   const auto currentTimeStep = selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
   m_ReduceFilter->Update();
   m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs();
 
   if (m_CurrentNumberOfReducedContours == 1)
   {
     vtkPolyData *tmp = m_ReduceFilter->GetOutput(0)->GetVtkPolyData();
     if (tmp == nullptr)
     {
       m_CurrentNumberOfReducedContours = 0;
     }
   }
 
   //  We use the timeSelector to get the segmentation image for the current segmentation.
   mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
   timeSelector->SetInput(selectedSegmentation);
   timeSelector->SetTimeNr(currentTimeStep);
   timeSelector->SetChannelNr(0);
   timeSelector->Update();
 
   mitk::Image::Pointer refSegImage = timeSelector->GetOutput();
-  itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New();
-  AccessFixedDimensionByItk_1(refSegImage, GetImageBase, 3, itkImage);
 
   m_NormalsFilter->SetSegmentationBinaryImage(refSegImage);
 
   for (size_t i = 0; i < m_CurrentNumberOfReducedContours; ++i)
   {
     mitk::Surface::Pointer reducedContour = m_ReduceFilter->GetOutput(i);
     reducedContour->DisconnectPipeline();
     m_NormalsFilter->SetInput(i, reducedContour);
     m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i));
   }
 
   if (m_CurrentNumberOfReducedContours < 2)
   {
     // If no interpolation is possible reset the interpolation result
     MITK_INFO << "Interpolation impossible: not enough contours.";
     m_InterpolationResult = nullptr;
     return;
   }
 
   // Setting up progress bar
   mitk::ProgressBar::GetInstance()->AddStepsToDo(10);
 
   // create a surface from the distance-image
   mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New();
   imageToSurfaceFilter->SetInput(m_InterpolateSurfaceFilter->GetOutput());
   imageToSurfaceFilter->SetThreshold(0);
   imageToSurfaceFilter->SetSmooth(true);
   imageToSurfaceFilter->SetSmoothIteration(1);
   imageToSurfaceFilter->Update();
 
   mitk::Surface::Pointer interpolationResult = mitk::Surface::New();
   interpolationResult->Expand(selectedSegmentation->GetTimeSteps());
 
   auto geometry = selectedSegmentation->GetTimeGeometry()->Clone();
   geometry->ReplaceTimeStepGeometries(mitk::Geometry3D::New());
   interpolationResult->SetTimeGeometry(geometry);
 
   interpolationResult->SetVtkPolyData(imageToSurfaceFilter->GetOutput()->GetVtkPolyData(), currentTimeStep);
   m_InterpolationResult = interpolationResult;
 
   m_DistanceImageSpacing = m_InterpolateSurfaceFilter->GetDistanceImageSpacing();
 
-  auto* contoursGeometry = static_cast<mitk::ProportionalTimeGeometry*>(m_Contours->GetTimeGeometry());
-  auto timeBounds = geometry->GetTimeBounds(currentTimeStep);
-  contoursGeometry->SetFirstTimePoint(timeBounds[0]);
-  contoursGeometry->SetStepDuration(timeBounds[1] - timeBounds[0]);
-
   // Last progress step
   mitk::ProgressBar::GetInstance()->Progress(20);
   m_InterpolationResult->DisconnectPipeline();
 }
 
 mitk::Surface::Pointer mitk::SurfaceInterpolationController::GetInterpolationResult()
 {
   return m_InterpolationResult;
 }
 
-mitk::Surface *mitk::SurfaceInterpolationController::GetContoursAsSurface()
-{
-  return m_Contours;
-}
-
-
 void mitk::SurfaceInterpolationController::SetDataStorage(DataStorage::Pointer ds)
 {
   m_DataStorage = ds;
 }
 
 void mitk::SurfaceInterpolationController::SetMinSpacing(double minSpacing)
 {
   m_ReduceFilter->SetMinSpacing(minSpacing);
 }
 
 void mitk::SurfaceInterpolationController::SetMaxSpacing(double maxSpacing)
 {
   m_ReduceFilter->SetMaxSpacing(maxSpacing);
   m_NormalsFilter->SetMaxSpacing(maxSpacing);
 }
 
 void mitk::SurfaceInterpolationController::SetDistanceImageVolume(unsigned int distImgVolume)
 {
   m_InterpolateSurfaceFilter->SetDistanceImageVolume(distImgVolume);
 }
 
 mitk::LabelSetImage* mitk::SurfaceInterpolationController::GetCurrentSegmentation()
 {
   return m_SelectedSegmentation.Lock();
 }
 
 mitk::Image *mitk::SurfaceInterpolationController::GetInterpolationImage()
 {
   return m_InterpolateSurfaceFilter->GetOutput();
 }
 
-double mitk::SurfaceInterpolationController::EstimatePortionOfNeededMemory()
-{
-  double numberOfPointsAfterReduction = m_ReduceFilter->GetNumberOfPointsAfterReduction() * 3;
-  double sizeOfPoints = pow(numberOfPointsAfterReduction, 2) * sizeof(double);
-  double totalMem = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam();
-  double percentage = sizeOfPoints / totalMem;
-  return percentage;
-}
-
 unsigned int mitk::SurfaceInterpolationController::GetNumberOfInterpolationSessions()
 {
-  return m_CPIMap.size();
+  return cpiMap.size();
 }
 
 template <typename TPixel, unsigned int VImageDimension>
 void mitk::SurfaceInterpolationController::GetImageBase(itk::Image<TPixel, VImageDimension> *input,
                                                         itk::ImageBase<3>::Pointer &result)
 {
   result->Graft(input);
 }
 
 void mitk::SurfaceInterpolationController::SetCurrentInterpolationSession(mitk::LabelSetImage* currentSegmentationImage)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (currentSegmentationImage == selectedSegmentation)
   {
     return;
   }
 
   m_SelectedSegmentation = currentSegmentationImage;
   selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation.IsNotNull())
   {
-    std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
+    std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
-    auto it = m_CPIMap.find(selectedSegmentation);
-    if (it == m_CPIMap.end())
+    auto it = cpiMap.find(selectedSegmentation);
+    if (it == cpiMap.end())
     {
-      m_CPIMap[selectedSegmentation] = CPITimeStepLabelMap();
+      cpiMap[selectedSegmentation] = CPITimeStepLabelMap();
 
       auto command = itk::MemberCommand<SurfaceInterpolationController>::New();
       command->SetCallbackFunction(this, &SurfaceInterpolationController::OnSegmentationDeleted);
-      m_SegmentationObserverTags[selectedSegmentation] = selectedSegmentation->AddObserver(itk::DeleteEvent(), command);
+      segmentationObserverTags[selectedSegmentation] = selectedSegmentation->AddObserver(itk::DeleteEvent(), command);
       selectedSegmentation->AddLabelRemovedListener(mitk::MessageDelegate1<SurfaceInterpolationController, mitk::LabelSetImage::LabelValueType>(
         this, &SurfaceInterpolationController::OnRemoveLabel));
     }
 
   }
 
   m_InterpolationResult = nullptr;
   m_CurrentNumberOfReducedContours = 0;
   m_NormalsFilter->SetSegmentationBinaryImage(nullptr);
   this->ReinitializeInterpolation();
 }
 
 void mitk::SurfaceInterpolationController::RemoveInterpolationSession(mitk::LabelSetImage* segmentationImage)
 {
-  auto selectedSegmentation = m_SelectedSegmentation.Lock();
-
   if (nullptr != segmentationImage)
   {
+    auto selectedSegmentation = m_SelectedSegmentation.Lock();
     if (selectedSegmentation == segmentationImage)
     {
-      selectedSegmentation->RemoveLabelRemovedListener(mitk::MessageDelegate1<SurfaceInterpolationController, mitk::LabelSetImage::LabelValueType>(
-        this, &SurfaceInterpolationController::OnRemoveLabel));
-      m_NormalsFilter->SetSegmentationBinaryImage(nullptr);
-      m_SelectedSegmentation = nullptr;
+      this->SetCurrentInterpolationSession(nullptr);
     }
 
     {
-      std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-      RemoveObserversInternal(segmentationImage);
-      m_CPIMap.erase(segmentationImage);
+      std::lock_guard<std::shared_mutex> guard(cpiMutex);
+      this->RemoveObserversInternal(segmentationImage);
+      cpiMap.erase(segmentationImage);
+      if (m_DataStorage.IsNotNull())
+      {
+        auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, segmentationImage));
+        this->m_DataStorage->Remove(nodes);
+      }
     }
 
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveObserversInternal(mitk::LabelSetImage* segmentationImage)
 {
-  auto pos = m_SegmentationObserverTags.find(segmentationImage);
-  if (pos != m_SegmentationObserverTags.end())
+  auto pos = segmentationObserverTags.find(segmentationImage);
+  if (pos != segmentationObserverTags.end())
   {
     segmentationImage->RemoveObserver((*pos).second);
     segmentationImage->RemoveLabelRemovedListener(mitk::MessageDelegate1<SurfaceInterpolationController, mitk::LabelSetImage::LabelValueType>(
       this, &SurfaceInterpolationController::OnRemoveLabel));
+    segmentationObserverTags.erase(segmentationImage);
   }
 }
 
 void mitk::SurfaceInterpolationController::RemoveAllInterpolationSessions()
 {
   this->RemoveObservers();
   m_NormalsFilter->SetSegmentationBinaryImage(nullptr);
   m_SelectedSegmentation = nullptr;
 
-  std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-  m_CPIMap.clear();
+  std::lock_guard<std::shared_mutex> guard(cpiMutex);
+  cpiMap.clear();
 }
 
 void mitk::SurfaceInterpolationController::RemoveContours(mitk::Label::PixelType label,
   TimeStepType timeStep)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow() << "Cannot remove contours. No valid segmentation selected.";
   }
 
-  std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
+  std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
-  auto cpiLabelMap = m_CPIMap[selectedSegmentation];
+  auto& cpiLabelMap = cpiMap[selectedSegmentation];
   auto finding = cpiLabelMap.find(label);
 
   if (finding != cpiLabelMap.end())
   {
     finding->second.erase(timeStep);
   }
+
+  if (m_DataStorage.IsNotNull())
+  {
+    //remove relevant plane nodes
+    auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, selectedSegmentation), label, timeStep);
+
+    this->m_DataStorage->Remove(nodes);
+  }
 }
 
 void mitk::SurfaceInterpolationController::RemoveContours(mitk::Label::PixelType label)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
   if (selectedSegmentation.IsNull())
   {
     mitkThrow() << "Cannot remove contours. No valid segmentation selected.";
   }
 
-  std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-  m_CPIMap[selectedSegmentation].erase(label);
+  std::lock_guard<std::shared_mutex> guard(cpiMutex);
+  cpiMap[selectedSegmentation].erase(label);
+
+  if (m_DataStorage.IsNotNull())
+  {
+    //remove relevant plane nodes
+    auto nodes = this->GetPlaneGeometryNodeFromDataStorage(GetSegmentationImageNodeInternal(this->m_DataStorage, selectedSegmentation), label);
+    this->m_DataStorage->Remove(nodes);
+  }
 }
 
 
 void mitk::SurfaceInterpolationController::OnSegmentationDeleted(const itk::Object *caller,
                                                                  const itk::EventObject & /*event*/)
 {
-  auto *tempImage = dynamic_cast<mitk::LabelSetImage *>(const_cast<itk::Object *>(caller));
+  auto tempImage = dynamic_cast<mitk::LabelSetImage *>(const_cast<itk::Object *>(caller));
   if (tempImage)
   {
-    std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-
-    auto selectedSegmentation = m_SelectedSegmentation.Lock();
-
-    if (selectedSegmentation == tempImage)
-    {
-      this->SetCurrentInterpolationSession(nullptr);
-    }
-    m_SegmentationObserverTags.erase(tempImage);
-    m_CPIMap.erase(tempImage);
+    this->RemoveInterpolationSession(tempImage);
   }
 }
 
 void mitk::SurfaceInterpolationController::ReinitializeInterpolation()
 {
   // If session has changed reset the pipeline
   m_ReduceFilter->Reset();
   m_NormalsFilter->Reset();
   m_InterpolateSurfaceFilter->Reset();
 
   itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New();
 
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation.IsNotNull())
   {
     if (!selectedSegmentation->GetTimeGeometry()->IsValidTimePoint(m_CurrentTimePoint))
     {
       MITK_WARN << "Interpolation cannot be reinitialized. Currently selected timepoint is not in the time bounds of the currently selected segmentation. Time point: " << m_CurrentTimePoint;
       return;
     }
 
     const auto currentTimeStep = selectedSegmentation->GetTimeGeometry()->TimePointToTimeStep(m_CurrentTimePoint);
 
     //  Set reference image for interpolation surface filter
     mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
     timeSelector->SetInput(selectedSegmentation);
     timeSelector->SetTimeNr(currentTimeStep);
     timeSelector->SetChannelNr(0);
     timeSelector->Update();
     mitk::Image::Pointer refSegImage = timeSelector->GetOutput();
     AccessFixedDimensionByItk_1(refSegImage, GetImageBase, 3, itkImage);
     m_InterpolateSurfaceFilter->SetReferenceImage(itkImage.GetPointer());
   }
 }
 
 void mitk::SurfaceInterpolationController::OnRemoveLabel(mitk::Label::PixelType removedLabelValue)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation.IsNotNull())
   {
     this->RemoveContours(removedLabelValue);
   }
 }
 
-mitk::SurfaceInterpolationController::CPIVector* mitk::SurfaceInterpolationController::GetContours(TimeStepType timeStep, LabelSetImage::LabelValueType labelValue)
+mitk::SurfaceInterpolationController::CPIVector* mitk::SurfaceInterpolationController::GetContours(LabelSetImage::LabelValueType labelValue, TimeStepType timeStep)
 {
   auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
   if (selectedSegmentation == nullptr)
     return nullptr;
 
-  std::shared_lock<std::shared_mutex> guard(m_CPIMutex);
+  std::shared_lock<std::shared_mutex> guard(cpiMutex);
 
-  auto labelFinding = m_CPIMap[selectedSegmentation].find(labelValue);
+  auto labelFinding = cpiMap[selectedSegmentation].find(labelValue);
 
-  if (labelFinding != m_CPIMap[selectedSegmentation].end())
+  if (labelFinding != cpiMap[selectedSegmentation].end())
   {
     auto tsFinding = labelFinding->second.find(timeStep);
 
     if (tsFinding != labelFinding->second.end())
     {
       return &(tsFinding->second);
     }
   }
 
   return nullptr;
 }
 
-void mitk::SurfaceInterpolationController::CompleteReinitialization(const std::vector<mitk::Surface::Pointer>& contourList,
-                                                                    std::vector<const mitk::PlaneGeometry *>& contourPlanes)
+std::vector<mitk::LabelSetImage::LabelValueType> mitk::SurfaceInterpolationController::GetAffectedLabels(const LabelSetImage* seg, TimeStepType timeStep, const PlaneGeometry* plane) const
 {
-  this->ClearInterpolationSession();
+  std::lock_guard<std::shared_mutex> guard(cpiMutex);
 
-  //  Now the layers should be empty and the new layers can be added.
-  this->AddNewContours(contourList, contourPlanes, true);
-}
-
-void mitk::SurfaceInterpolationController::ClearInterpolationSession()
-{
-  auto selectedSegmentation = m_SelectedSegmentation.Lock();
+  std::vector<mitk::LabelSetImage::LabelValueType> result;
 
-  if (selectedSegmentation != nullptr)
-  {
-    std::lock_guard<std::shared_mutex> guard(m_CPIMutex);
-    m_CPIMap[selectedSegmentation].clear();
-  }
-}
+  auto finding = cpiMap.find(seg);
+  if (finding == cpiMap.end()) return result;
+  auto currentImageContours = finding->second;
 
-std::vector< mitk::Point3D > mitk::ContourExt::GetBoundingBoxGridPoints(
-                                              size_t planeDimension,
-                                              double startDim1,
-                                              size_t numPointsToSampleDim1,
-                                              double deltaDim1,
-                                              double startDim2,
-                                              size_t numPointsToSampleDim2,
-                                              double deltaDim2,
-                                              double valuePlaneDim)
-{
-  std::vector< mitk::Point3D > gridPoints;
-  for (size_t i = 0; i < numPointsToSampleDim1; ++i)
+  for (auto [label, contours] : currentImageContours)
   {
-    for (size_t j = 0; j < numPointsToSampleDim2; ++j)
+    auto tsFinding = contours.find(timeStep);
+    if (tsFinding != contours.end())
     {
-      mitk::ScalarType *ptVec = new mitk::ScalarType[3];
-
-      if (planeDimension == 0)
-      {
-        ptVec[0] = valuePlaneDim;
-        ptVec[1] = startDim1 + deltaDim1 * i;
-        ptVec[2] = startDim2 + deltaDim2 * j;
-      }
-      else if (planeDimension == 1)
-      {
-        ptVec[0] = startDim1 + deltaDim1 * i;
-        ptVec[1] = valuePlaneDim;
-        ptVec[2] = startDim2 + deltaDim2 * j;
+      auto cpis = tsFinding->second;
+      auto finding = std::find_if(cpis.begin(), cpis.end(), [plane](const ContourPositionInformation& element) {return plane->IsOnPlane(element.Plane); });
 
-      }
-      else if (planeDimension == 2)
+      if (finding != cpis.end())
       {
-        ptVec[0] = startDim1 + deltaDim1 * i;
-        ptVec[1] = startDim2 + deltaDim2 * j;
-        ptVec[2] = valuePlaneDim;
+        result.push_back(label);
       }
-
-      mitk::Point3D pt3D;
-      pt3D.FillPoint(ptVec);
-      gridPoints.push_back(pt3D);
     }
   }
-
-  return gridPoints;
+  return result;
 }
 
-mitk::Point3D mitk::SurfaceInterpolationController::ComputeInteriorPointOfContour(
-                                    const mitk::SurfaceInterpolationController::ContourPositionInformation& contour,
-                                    mitk::LabelSetImage * labelSetImage)
-{
-  if (labelSetImage->GetDimension() == 4)
-  {
-    return mitk::ContourExt::ComputeInteriorPointOfContour<4>(contour, labelSetImage, m_CurrentTimePoint);
-  }
-  else
-  {
-    return mitk::ContourExt::ComputeInteriorPointOfContour<3>(contour, labelSetImage, m_CurrentTimePoint);
-  }
-}
 
-template<unsigned int VImageDimension>
-mitk::Point3D mitk::ContourExt::ComputeInteriorPointOfContour(
-                                    const mitk::SurfaceInterpolationController::ContourPositionInformation& contour,
-                                    mitk::LabelSetImage * labelSetImage,
-                                    mitk::TimePointType currentTimePoint)
+void mitk::SurfaceInterpolationController::CompleteReinitialization(const std::vector<ContourPositionInformation>& newCPIs)
 {
-  mitk::ImagePixelReadAccessor<mitk::Label::PixelType, VImageDimension> readAccessor(labelSetImage);
-
-  if (!labelSetImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint))
-  {
-    MITK_ERROR << "Invalid time point requested for interpolation pipeline.";
-    mitk::Point3D pt;
-    return pt;
-  }
-
-  std::vector<mitk::Label::PixelType> pixelsPresent;
-  const auto currentTimeStep = labelSetImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint);
-
-  auto polyData = contour.Contour->GetVtkPolyData();
-
-  polyData->ComputeCellsBounds();
-  mitk::ScalarType cellBounds[6];
-  polyData->GetCellsBounds(cellBounds);
-
-  size_t numPointsToSample = 10;
-  mitk::ScalarType StartX = cellBounds[0];
-  mitk::ScalarType StartY = cellBounds[2];
-  mitk::ScalarType StartZ = cellBounds[4];
-
-  size_t deltaX = (cellBounds[1] - cellBounds[0]) / numPointsToSample;
-  size_t deltaY = (cellBounds[3] - cellBounds[2]) / numPointsToSample;
-  size_t deltaZ = (cellBounds[5] - cellBounds[4]) / numPointsToSample;
-
-  auto planeOrientation = mitk::ContourExt::GetContourOrientation(contour.ContourNormal);
-
-  std::vector<mitk::Point3D> points;
-  if (planeOrientation == 0)
-  {
-    points = mitk::ContourExt::GetBoundingBoxGridPoints(planeOrientation,
-                                      StartY, numPointsToSample, deltaY,
-                                      StartZ, numPointsToSample, deltaZ,
-                                      StartX);
-  }
-  else if (planeOrientation == 1)
-  {
-    points = mitk::ContourExt::GetBoundingBoxGridPoints(planeOrientation,
-                                      StartX, numPointsToSample, deltaX,
-                                      StartZ, numPointsToSample, deltaZ,
-                                      StartY);
-  }
-  else if (planeOrientation == 2)
-  {
-    points = mitk::ContourExt::GetBoundingBoxGridPoints(planeOrientation,
-                                      StartX, numPointsToSample, deltaX,
-                                      StartY, numPointsToSample, deltaY,
-                                      StartZ);
-  }
-  mitk::Label::PixelType pixelVal;
-  mitk::Point3D pt3D;
-  std::vector<mitk::Label::PixelType> pixelVals;
-  for (size_t i = 0; i < points.size(); ++i)
-  {
-    pt3D = points[i];
-    itk::Index<3> itkIndex;
-    labelSetImage->GetGeometry()->WorldToIndex(pt3D, itkIndex);
-
-    if (VImageDimension == 4)
-    {
-      itk::Index<VImageDimension> time3DIndex;
-      for (size_t i = 0; i < itkIndex.size(); ++i)
-        time3DIndex[i] = itkIndex[i];
-      time3DIndex[3] = currentTimeStep;
-
-      pixelVal = readAccessor.GetPixelByIndexSafe(time3DIndex);
-    }
-    else if (VImageDimension == 3)
-    {
-      itk::Index<VImageDimension> geomIndex;
-      for (size_t i=0;i<itkIndex.size();++i)
-        geomIndex[i] = itkIndex[i];
-
-      pixelVal = readAccessor.GetPixelByIndexSafe(geomIndex);
-    }
+  this->ClearInterpolationSession();
 
-    if (pixelVal == contour.LabelValue)
-      break;
-  }
-  return pt3D;
+  //  Now the layers should be empty and the new layers can be added.
+  this->AddNewContours(newCPIs, true);
 }
 
-size_t mitk::ContourExt::GetContourOrientation(const mitk::Vector3D& ContourNormal)
+void mitk::SurfaceInterpolationController::ClearInterpolationSession()
 {
-  double n[3];
-  n[0] = ContourNormal[0];
-  n[1] = ContourNormal[1];
-  n[2] = ContourNormal[2];
-
-  double XVec[3];
-  XVec[0] = 1.0;  XVec[1] = 0.0;  XVec[2] = 0.0;
-  double dotX = vtkMath::Dot(n, XVec);
-
-  double YVec[3];
-  YVec[0] = 0.0;  YVec[1] = 1.0;  YVec[2] = 0.0;
-  double dotY = vtkMath::Dot(n, YVec);
-
-  double ZVec[3];
-  ZVec[0] = 0.0;  ZVec[1] = 0.0;  ZVec[2] = 1.0;
-  double dotZ = vtkMath::Dot(n, ZVec);
+  auto selectedSegmentation = m_SelectedSegmentation.Lock();
 
-  size_t planeOrientation = 0;
-  if (fabs(dotZ) > mitk::eps)
-  {
-    planeOrientation = 2;
-  }
-  else if (fabs(dotY) > mitk::eps)
-  {
-    planeOrientation = 1;
-  }
-  else if(fabs(dotX) > mitk::eps)
+  if (selectedSegmentation != nullptr)
   {
-    planeOrientation = 0;
+    std::lock_guard<std::shared_mutex> guard(cpiMutex);
+    cpiMap[selectedSegmentation].clear();
   }
-  return planeOrientation;
 }
diff --git a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h
index 3656e9cac9..4f09448856 100644
--- a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h
+++ b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h
@@ -1,359 +1,289 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkSurfaceInterpolationController_h
 #define mitkSurfaceInterpolationController_h
 
-#include <shared_mutex>
-
 #include <mitkDataStorage.h>
 #include <mitkLabelSetImage.h>
 #include <mitkLabel.h>
 #include <mitkSurface.h>
 
 #include <MitkSurfaceInterpolationExports.h>
 
 namespace mitk
 {
   class ComputeContourSetNormalsFilter;
   class CreateDistanceImageFromSurfaceFilter;
   class LabelSetImage;
   class ReduceContourSetFilter;
 
   class MITKSURFACEINTERPOLATION_EXPORT SurfaceInterpolationController : public itk::Object
   {
   public:
     mitkClassMacroItkParent(SurfaceInterpolationController, itk::Object);
     itkFactorylessNewMacro(Self);
     itkCloneMacro(Self);
     itkGetMacro(DistanceImageSpacing, double);
 
     struct MITKSURFACEINTERPOLATION_EXPORT ContourPositionInformation
     {
-      int Pos;
       Surface::ConstPointer Contour;
-      Vector3D ContourNormal;
-      Point3D ContourPoint;
       PlaneGeometry::ConstPointer Plane;
       Label::PixelType LabelValue;
       TimeStepType TimeStep;
 
       ContourPositionInformation()
-        : Pos(-1),
-          Plane(nullptr),
+        : Plane(nullptr),
           LabelValue(std::numeric_limits<Label::PixelType>::max()),
           TimeStep(std::numeric_limits<TimeStepType>::max())
       {
       }
+      ContourPositionInformation(Surface::ConstPointer contour,
+        PlaneGeometry::ConstPointer plane,
+        Label::PixelType labelValue,
+        TimeStepType timeStep)
+        :
+        Contour(contour),
+        Plane(plane),
+        LabelValue(labelValue),
+        TimeStep(timeStep)
+      {
+      }
     };
 
     typedef std::vector<ContourPositionInformation> CPIVector;
-    typedef std::map<TimeStepType, CPIVector> CPITimeStepMap;
-    typedef std::map<LabelSetImage::LabelValueType, CPITimeStepMap> CPITimeStepLabelMap;
-
-    typedef std::map<LabelSetImage*, CPITimeStepLabelMap> CPITimeStepLabelSegMap;
 
     static SurfaceInterpolationController *GetInstance();
 
     void SetCurrentTimePoint(TimePointType tp)
     {
       if (m_CurrentTimePoint != tp)
       {
         m_CurrentTimePoint = tp;
 
         if (m_SelectedSegmentation)
         {
           this->ReinitializeInterpolation();
         }
       }
     };
 
     TimePointType GetCurrentTimePoint() const { return m_CurrentTimePoint; };
 
     /**
      * @brief Adds new extracted contours to the list. If one or more contours at a given position
      *        already exist they will be updated respectively
      */
-    void AddNewContours(const std::vector<Surface::Pointer>& newContours, std::vector<const mitk::PlaneGeometry*>& contourPlanes, bool reinitializeAction = false);
+    void AddNewContours(const std::vector<ContourPositionInformation>& newCPIs, bool reinitializeAction = false);
 
     /**
      * @brief Removes the contour for a given plane for the current selected segmenation
      * @param contourInfo the contour which should be removed
      * @return true if a contour was found and removed, false if no contour was found
      */
     bool RemoveContour(ContourPositionInformation contourInfo);
 
-    /**
-     * @brief Computes an interior point of the input contour. It's used to detect merge and erase operations.
-     *
-     * @param contour Contour for which to compute the contour
-     * @param labelSetImage LabelSetImage used input to check contour Label.
-     * @return mitk::Point3D 3D Interior point of the contour returned.
-     */
-    mitk::Point3D ComputeInteriorPointOfContour(const ContourPositionInformation& contour,
-                                                 mitk::LabelSetImage * labelSetImage);
-
-
     /**
      * @brief Resets the pipeline for interpolation. The various filters used are reset.
      *
      */
     void ReinitializeInterpolation();
 
     void RemoveObservers();
 
     /**
      * @brief Performs the interpolation.
      *
      */
     void Interpolate();
 
     /**
      * @brief Get the Result of the interpolation operation.
      *
      * @return mitk::Surface::Pointer
      */
     mitk::Surface::Pointer GetInterpolationResult();
 
     /**
      * @brief Sets the minimum spacing of the current selected segmentation
      * This is needed since the contour points we reduced before they are used to interpolate the surface.
      *
      * @param minSpacing Paramter to set
      */
     void SetMinSpacing(double minSpacing);
 
     /**
      * @brief Sets the minimum spacing of the current selected segmentation
      * This is needed since the contour points we reduced before they are used to interpolate the surface
      * @param maxSpacing Set the max Spacing for interpolation
      */
     void SetMaxSpacing(double maxSpacing);
 
     /**
      * Sets the volume i.e. the number of pixels that the distance image should have
      * By evaluation we found out that 50.000 pixel delivers a good result
      */
     void SetDistanceImageVolume(unsigned int distImageVolume);
 
     /**
      * @brief Get the current selected segmentation for which the interpolation is performed
      * @return the current segmentation image
      */
     mitk::LabelSetImage* GetCurrentSegmentation();
 
-    Surface *GetContoursAsSurface();
-
     void SetDataStorage(DataStorage::Pointer ds);
 
     /**
      * Sets the current list of contourpoints which is used for the surface interpolation
      * @param currentSegmentationImage The current selected segmentation
      */
     void SetCurrentInterpolationSession(LabelSetImage* currentSegmentationImage);
 
     /**
      * @brief Remove interpolation session
      * @param segmentationImage the session to be removed
      */
     void RemoveInterpolationSession(LabelSetImage* segmentationImage);
 
     /**
      * @brief Removes all sessions
      */
     void RemoveAllInterpolationSessions();
 
     mitk::Image *GetInterpolationImage();
 
     /**
      * @brief Get the Contours at a certain timeStep and layerID.
      *
      * @param timeStep Time Step from which to get the contours.
-     * @param layerID Layer from which to get the contours.
+     * @param labelValue label from which to get the contours.
      * @return std::vector<ContourPositionInformation> Returns contours.
      */
-    CPIVector* GetContours(TimeStepType timeStep, LabelSetImage::LabelValueType labelValue);
+    CPIVector* GetContours(LabelSetImage::LabelValueType labelValue, TimeStepType timeStep);
+
+    std::vector<LabelSetImage::LabelValueType> GetAffectedLabels(const LabelSetImage* seg, TimeStepType timeStep, const PlaneGeometry* plane) const;
 
     /**
      * @brief Trigerred with the "Reinit Interpolation" action. The contours are used to repopulate the
      *        surfaceInterpolator data structures so that interpolation can be performed after reloading data.
      *
      * @param contourList List of contours extracted
      * @param contourPlanes List of planes at which the contours were extracted
      */
-    void CompleteReinitialization(const std::vector<mitk::Surface::Pointer>& contourList,
-                                           std::vector<const mitk::PlaneGeometry *>& contourPlanes);
+    void CompleteReinitialization(const std::vector<ContourPositionInformation>& newCPIs);
 
     /**
      * @brief Removes contours of a particular label and at a given time step for the current session/segmentation.
      *
      * @param label Label of contour to remove.
      * @param timeStep Time step in which to remove the contours.
      * @remark if the label or time step does not exist, nothing happens.
      */
     void RemoveContours(mitk::Label::PixelType label, TimeStepType timeStep);
 
     /**
      * @brief Removes contours of a particular label and at a given time step for the current session/segmentation.
      *
      * @param label Label of contour to remove.
      * @param timeStep Time step in which to remove the contours.
      * @remark if the label or time step does not exist, nothing happens.
      */
     void RemoveContours(mitk::Label::PixelType label);
 
-    /**
-     * Estimates the memory which is needed to build up the equationsystem for the interpolation.
-     * \returns The percentage of the real memory which will be used by the interpolation
-     */
-    double EstimatePortionOfNeededMemory();
-
     /**
      * Adds Contours from the active Label to the interpolation pipeline
      */
     void AddActiveLabelContoursForInterpolation(mitk::Label::PixelType activeLabel);
 
     unsigned int GetNumberOfInterpolationSessions();
 
     /**
      * @brief Get the Segmentation Image Node object
      *
      * @return DataNode* returns the DataNode containing the segmentation image.
      */
-    mitk::DataNode* GetSegmentationImageNode();
+    mitk::DataNode* GetSegmentationImageNode() const;
 
   protected:
     SurfaceInterpolationController();
 
     ~SurfaceInterpolationController() override;
 
     template <typename TPixel, unsigned int VImageDimension>
     void GetImageBase(itk::Image<TPixel, VImageDimension> *input, itk::ImageBase<3>::Pointer &result);
 
   private:
 
     /**
      * @brief
      *
      * @param caller
      * @param event
      */
     void OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &event);
 
     /**
      * @brief Function that removes contours of a particular label when the "Remove Label" event is trigerred in the labelSetImage.
      *
      */
     void OnRemoveLabel(mitk::Label::PixelType removedLabelValue);
 
     /**
      * @brief When a new contour is added to the pipeline or an existing contour is replaced,
      *        the plane geometry information of that contour is added as a child node to the
      *        current node of the segmentation image. This is useful in the retrieval of contour information
      *        when data is reloaded after saving.
      *
      * @param contourInfo contourInfo struct to add to data storage.
      */
-    void AddPlaneGeometryNodeToDataStorage(const ContourPositionInformation& contourInfo);
+    void AddPlaneGeometryNodeToDataStorage(const ContourPositionInformation& contourInfo) const;
+
+    DataStorage::SetOfObjects::ConstPointer GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode) const;
+    DataStorage::SetOfObjects::ConstPointer GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue) const;
+    DataStorage::SetOfObjects::ConstPointer GetPlaneGeometryNodeFromDataStorage(const DataNode* segNode, LabelSetImage::LabelValueType labelValue, TimeStepType timeStep) const;
 
     /**
      * @brief Clears the interpolation data structures. Called from CompleteReinitialization().
      *
      */
     void ClearInterpolationSession();
 
     void RemoveObserversInternal(mitk::LabelSetImage* segmentationImage);
 
     /**
      * @brief Add contour to the interpolation pipeline
      *
      * @param contourInfo Contour information to be added
      * @param reinitializationAction If the contour is coming from a reinitialization process or not
      */
     void AddToInterpolationPipeline(ContourPositionInformation& contourInfo, bool reinitializationAction = false);
 
     itk::SmartPointer<ReduceContourSetFilter> m_ReduceFilter;
     itk::SmartPointer<ComputeContourSetNormalsFilter> m_NormalsFilter;
     itk::SmartPointer<CreateDistanceImageFromSurfaceFilter> m_InterpolateSurfaceFilter;
 
-    mitk::Surface::Pointer m_Contours;
-
     double m_DistanceImageSpacing;
 
     mitk::DataStorage::Pointer m_DataStorage;
 
-    CPITimeStepLabelSegMap m_CPIMap;
-
     mitk::Surface::Pointer m_InterpolationResult;
 
     unsigned int m_CurrentNumberOfReducedContours;
 
     WeakPointer<LabelSetImage> m_SelectedSegmentation;
 
-    std::map<mitk::LabelSetImage*, unsigned long> m_SegmentationObserverTags;
-
     mitk::TimePointType m_CurrentTimePoint;
-
-    std::shared_mutex m_CPIMutex;
   };
-
-  namespace ContourExt
-  {
-    /**
-     * @brief Returns the plane the contour belongs to.
-     *
-     * @param ContourNormal
-     * @return size_t
-     */
-    size_t GetContourOrientation(const mitk::Vector3D& ContourNormal);
-
-    /**
-     * @brief Function used to compute an interior point of the contour.
-     *        Used to react to the merge label and erase label actions.
-     *
-     *
-     * @tparam VImageDimension Dimension of the image
-     * @param contour Contour for which to compute the interior point
-     * @param labelSetImage Label Set Image For which to find the contour
-     * @param currentTimePoint Current Time Point of the Image
-     * @return mitk::Point3D The returned point in the interior of the contour.s
-     */
-    template<unsigned int VImageDimension>
-    mitk::Point3D ComputeInteriorPointOfContour(const mitk::SurfaceInterpolationController::ContourPositionInformation& contour,
-                                                 mitk::LabelSetImage * labelSetImage,
-                                                 mitk::TimePointType currentTimePoint);
-    /**
-     * @brief Get a Grid points within the bounding box of the contour at a certain spacing.
-     *
-     * @param planeDimension  Plane orientation (Sagittal, Coronal, Axial)
-     * @param startDim1 Starting coordinate along dimension 1 to start the grid point sampling from
-     * @param numPointsToSampleDim1 Number of points to sample along dimension 1
-     * @param deltaDim1 Spacing for dimension 1 at which points should be sampled
-     * @param startDim2 Starting coordinate along dimension 2 to start the grid point sampling from
-     * @param numPointsToSampleDim2 Number of points to sample along dimension 2
-     * @param deltaDim2 Spacing for dimension 1 at which points should be sampled
-     * @param valuePlaneDim Slice index of the plane in the volume
-     * @return std::vector< mitk::Point3D > The computed grid points are returned by the function.
-     */
-    std::vector< mitk::Point3D > GetBoundingBoxGridPoints(size_t planeDimension,
-                                            double startDim1,
-                                            size_t numPointsToSampleDim1,
-                                            double deltaDim1,
-                                            double startDim2,
-                                            size_t numPointsToSampleDim2,
-                                            double deltaDim2,
-                                            double valuePlaneDim);
-  };
-
 }
 
 #endif
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp
index 6e84f979e1..3cd4345e95 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp
@@ -1,1091 +1,1094 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "QmitkSegmentationView.h"
 #include "mitkPluginActivator.h"
 
 // blueberry
 #include <berryIWorkbenchPage.h>
 
 // mitk
 #include <mitkApplicationCursor.h>
 #include <mitkBaseApplication.h>
 #include <mitkBaseRendererHelper.h>
 #include <mitkCameraController.h>
 #include <mitkLabelSetImage.h>
 #include <mitkLabelSetImageHelper.h>
 #include <mitkMultiLabelIOHelper.h>
 #include <mitkManualPlacementAnnotationRenderer.h>
 #include <mitkNodePredicateSubGeometry.h>
 #include <mitkSegmentationObjectFactory.h>
 #include <mitkSegTool2D.h>
 #include <mitkStatusBar.h>
 #include <mitkToolManagerProvider.h>
 #include <mitkVtkResliceInterpolationProperty.h>
 #include <mitkWorkbenchUtil.h>
 #include <mitkIPreferences.h>
 
 // Qmitk
 #include <QmitkRenderWindow.h>
 #include <QmitkStaticDynamicSegmentationDialog.h>
 #include <QmitkNewSegmentationDialog.h>
 #include <QmitkMultiLabelManager.h>
 
 // us
 #include <usModuleResource.h>
 #include <usModuleResourceStream.h>
 
 // Qt
 #include <QMessageBox>
 #include <QShortcut>
 #include <QDir>
 
 // vtk
 #include <vtkQImageToImageSource.h>
 
 #include <regex>
 
 namespace
 {
   QList<QmitkRenderWindow*> Get2DWindows(const QList<QmitkRenderWindow*> allWindows)
   {
     QList<QmitkRenderWindow*> all2DWindows;
     for (auto* window : allWindows)
     {
       if (window->GetRenderer()->GetMapperID() == mitk::BaseRenderer::Standard2D)
       {
         all2DWindows.append(window);
       }
     }
     return all2DWindows;
   }
 }
 
 const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation";
 
 QmitkSegmentationView::QmitkSegmentationView()
   : m_Parent(nullptr)
   , m_Controls(nullptr)
   , m_RenderWindowPart(nullptr)
   , m_ToolManager(nullptr)
   , m_ReferenceNode(nullptr)
   , m_WorkingNode(nullptr)
   , m_DrawOutline(true)
   , m_SelectionMode(false)
   , m_MouseCursorSet(false)
   , m_DefaultLabelNaming(true)
   , m_SelectionChangeIsAlreadyBeingHandled(false)
 {
   auto isImage = mitk::TNodePredicateDataType<mitk::Image>::New();
   auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage");
   auto isDti = mitk::NodePredicateDataType::New("TensorImage");
   auto isOdf = mitk::NodePredicateDataType::New("OdfImage");
   auto isSegment = mitk::NodePredicateDataType::New("Segment");
 
   auto validImages = mitk::NodePredicateOr::New();
   validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment)));
   validImages->AddPredicate(isDwi);
   validImages->AddPredicate(isDti);
   validImages->AddPredicate(isOdf);
 
   m_SegmentationPredicate = mitk::NodePredicateAnd::New();
   m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType<mitk::LabelSetImage>::New());
   m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")));
   m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object")));
 
   m_ReferencePredicate = mitk::NodePredicateAnd::New();
   m_ReferencePredicate->AddPredicate(validImages);
   m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate));
   m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")));
   m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object")));
 }
 
 QmitkSegmentationView::~QmitkSegmentationView()
 {
   if (nullptr != m_Controls)
   {
     // deactivate all tools
     m_ToolManager->ActivateTool(-1);
 
     // removing all observers from working data
     for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter)
     {
       (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second);
     }
     m_WorkingDataObserverTags.clear();
 
     this->RemoveObserversFromWorkingImage();
 
     // removing all observers from reference data
     for (NodeTagMapType::iterator dataIter = m_ReferenceDataObserverTags.begin(); dataIter != m_ReferenceDataObserverTags.end(); ++dataIter)
     {
       (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second);
     }
     m_ReferenceDataObserverTags.clear();
 
     mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag);
 
     ctkPluginContext* context = mitk::PluginActivator::getContext();
     ctkServiceReference ppmRef = context->getServiceReference<mitk::PlanePositionManagerService>();
     mitk::PlanePositionManagerService* service = context->getService<mitk::PlanePositionManagerService>(ppmRef);
     service->RemoveAllPlanePositions();
     context->ungetService(ppmRef);
 
     m_ToolManager->SetReferenceData(nullptr);
     m_ToolManager->SetWorkingData(nullptr);
   }
 
   m_ToolManager->ActiveToolChanged -=
     mitk::MessageDelegate<Self>(this, &Self::ActiveToolChanged);
 
   delete m_Controls;
 }
 
 /**********************************************************************/
 /* private Q_SLOTS                                                    */
 /**********************************************************************/
 void QmitkSegmentationView::OnReferenceSelectionChanged(QList<mitk::DataNode::Pointer>)
 {
   this->OnAnySelectionChanged();
 }
 
 void QmitkSegmentationView::OnSegmentationSelectionChanged(QList<mitk::DataNode::Pointer>)
 {
   this->OnAnySelectionChanged();
 }
 
 void QmitkSegmentationView::OnAnySelectionChanged()
 {
   // When only a segmentation has been selected and the method is then called by a reference image selection,
   // the already selected segmentation may not match the geometry predicate of the new reference image anymore.
   // This will trigger a recursive call of this method further below. While it would be resolved gracefully, we
   // can spare the extra call with an early-out. The original call of this method will handle the segmentation
   // selection change afterwards anyway.
 
   if (m_SelectionChangeIsAlreadyBeingHandled)
     return;
 
   auto selectedReferenceNode = m_Controls->referenceNodeSelector->GetSelectedNode();
   bool referenceNodeChanged = false;
 
   m_ToolManager->ActivateTool(-1);
 
   if (m_ReferenceNode != selectedReferenceNode)
   {
     referenceNodeChanged = true;
 
     // Remove visibility observer for the current reference node
     if (m_ReferenceDataObserverTags.find(m_ReferenceNode) != m_ReferenceDataObserverTags.end())
     {
       m_ReferenceNode->GetProperty("visible")->RemoveObserver(m_ReferenceDataObserverTags[m_ReferenceNode]);
       m_ReferenceDataObserverTags.erase(m_ReferenceNode);
     }
 
     // Set new reference node
     m_ReferenceNode = selectedReferenceNode;
     m_ToolManager->SetReferenceData(m_ReferenceNode);
 
     // Prepare for a potential recursive call when changing node predicates of the working node selector
     m_SelectionChangeIsAlreadyBeingHandled = true;
 
     if (m_ReferenceNode.IsNull())
     {
       // Without a reference image, allow all segmentations to be selected
       m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate);
       m_SelectionChangeIsAlreadyBeingHandled = false;
     }
     else
     {
       // With a reference image, only allow segmentations that fit the geometry of the reference image to be selected.
       m_Controls->workingNodeSelector->SetNodePredicate(mitk::NodePredicateAnd::New(
         mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry()),
         m_SegmentationPredicate.GetPointer()));
 
       m_SelectionChangeIsAlreadyBeingHandled = false;
 
       this->ApplySelectionModeOnReferenceNode();
 
       // Add visibility observer for the new reference node
       auto command = itk::SimpleMemberCommand<Self>::New();
       command->SetCallbackFunction(this, &Self::ValidateSelectionInput);
 
       m_ReferenceDataObserverTags[m_ReferenceNode] =
         m_ReferenceNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command);
     }
   }
 
   auto selectedWorkingNode = m_Controls->workingNodeSelector->GetSelectedNode();
   bool workingNodeChanged = false;
 
   if (m_WorkingNode != selectedWorkingNode)
   {
     workingNodeChanged = true;
 
     this->RemoveObserversFromWorkingImage();
 
     // Remove visibility observer for the current working node
     if (m_WorkingDataObserverTags.find(m_WorkingNode) != m_WorkingDataObserverTags.end())
     {
       m_WorkingNode->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[m_WorkingNode]);
       m_WorkingDataObserverTags.erase(m_WorkingNode);
     }
 
     // Set new working node
     m_WorkingNode = selectedWorkingNode;
     m_ToolManager->SetWorkingData(m_WorkingNode);
 
     if (m_WorkingNode.IsNotNull())
     {
       this->ApplySelectionModeOnWorkingNode();
 
       // Add visibility observer for the new segmentation node
       auto command = itk::SimpleMemberCommand<Self>::New();
       command->SetCallbackFunction(this, &Self::ValidateSelectionInput);
 
       m_WorkingDataObserverTags[m_WorkingNode] =
         m_WorkingNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command);
 
       this->AddObserversToWorkingImage();
     }
   }
 
   // Reset camera if any selection changed but only if both reference node and working node are set
   if ((referenceNodeChanged || workingNodeChanged) && (m_ReferenceNode.IsNotNull() && m_WorkingNode.IsNotNull()))
   {
     if (nullptr != m_RenderWindowPart)
     {
       m_RenderWindowPart->InitializeViews(m_ReferenceNode->GetData()->GetTimeGeometry(), false);
     }
   }
 
   this->UpdateGUI();
 }
 
 void QmitkSegmentationView::OnLabelAdded(mitk::LabelSetImage::LabelValueType)
 {
   this->ValidateSelectionInput();
 }
 
 void QmitkSegmentationView::OnLabelRemoved(mitk::LabelSetImage::LabelValueType)
 {
   this->ValidateSelectionInput();
 }
 
 void QmitkSegmentationView::OnGroupRemoved(mitk::LabelSetImage::GroupIndexType)
 {
   this->ValidateSelectionInput();
 }
 
 mitk::LabelSetImage* QmitkSegmentationView::GetWorkingImage()
 {
   if (m_WorkingNode.IsNull())
     return nullptr;
 
   return dynamic_cast<mitk::LabelSetImage*>(m_WorkingNode->GetData());
 }
 
 void QmitkSegmentationView::AddObserversToWorkingImage()
 {
   auto* workingImage = this->GetWorkingImage();
 
   if (workingImage != nullptr)
   {
     workingImage->AddLabelAddedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::LabelValueType>(this, &Self::OnLabelAdded));
     workingImage->AddLabelRemovedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::LabelValueType>(this, &Self::OnLabelRemoved));
     workingImage->AddGroupRemovedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::GroupIndexType>(this, &Self::OnGroupRemoved));
   }
 }
 
 void QmitkSegmentationView::RemoveObserversFromWorkingImage()
 {
   auto* workingImage = this->GetWorkingImage();
 
   if (workingImage != nullptr)
   {
     workingImage->RemoveLabelAddedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::LabelValueType>(this, &Self::OnLabelAdded));
     workingImage->RemoveLabelRemovedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::LabelValueType>(this, &Self::OnLabelRemoved));
     workingImage->RemoveGroupRemovedListener(mitk::MessageDelegate1<Self, mitk::LabelSetImage::GroupIndexType>(this, &Self::OnGroupRemoved));
   }
 }
 
 void QmitkSegmentationView::OnVisibilityShortcutActivated()
 {
   if (m_WorkingNode.IsNull())
   {
     return;
   }
 
   bool isVisible = false;
   m_WorkingNode->GetBoolProperty("visible", isVisible);
   m_WorkingNode->SetVisibility(!isVisible);
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkSegmentationView::OnLabelToggleShortcutActivated()
 {
   if (m_WorkingNode.IsNull())
   {
     return;
   }
 
   auto workingImage = dynamic_cast<mitk::LabelSetImage*>(m_WorkingNode->GetData());
   if (nullptr == workingImage)
   {
     return;
   }
 
   this->WaitCursorOn();
   auto labels = workingImage->GetLabelValuesByGroup(workingImage->GetActiveLayer());
   auto it = std::find(labels.begin(), labels.end(), workingImage->GetActiveLabel()->GetValue());
 
   if (it != labels.end())
     ++it;
 
   if (it == labels.end())
   {
     it = labels.begin();
   }
 
   workingImage->SetActiveLabel(*it);
   this->WaitCursorOff();
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkSegmentationView::OnNewSegmentation()
 {
   m_ToolManager->ActivateTool(-1);
 
   if (m_ReferenceNode.IsNull())
   {
     MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected.";
     return;
   }
 
   mitk::Image::ConstPointer referenceImage = dynamic_cast<mitk::Image*>(m_ReferenceNode->GetData());
   if (referenceImage.IsNull())
   {
     QMessageBox::information(
       m_Parent, "New segmentation", "Please load and select an image before starting some action.");
     return;
   }
 
   if (referenceImage->GetDimension() <= 1)
   {
     QMessageBox::information(
       m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images");
     return;
   }
 
   auto segTemplateImage = referenceImage;
   if (referenceImage->GetDimension() > 3)
   {
     QmitkStaticDynamicSegmentationDialog dialog(m_Parent);
     dialog.SetReferenceImage(referenceImage.GetPointer());
     dialog.exec();
     segTemplateImage = dialog.GetSegmentationTemplate();
   }
 
   mitk::DataNode::Pointer newSegmentationNode;
   try
   {
     this->WaitCursorOn();
     newSegmentationNode = mitk::LabelSetImageHelper::CreateNewSegmentationNode(m_ReferenceNode, segTemplateImage);
     this->WaitCursorOff();
   }
   catch (mitk::Exception& e)
   {
     this->WaitCursorOff();
     MITK_ERROR << "Exception caught: " << e.GetDescription();
     QMessageBox::warning(m_Parent, "New segmentation", "Could not create a new segmentation.");
     return;
   }
 
   auto newLabelSetImage = dynamic_cast<mitk::LabelSetImage*>(newSegmentationNode->GetData());
   if (nullptr == newLabelSetImage)
   {
     // something went wrong
     return;
   }
 
   const auto labelSetPreset = this->GetDefaultLabelSetPreset();
 
   if (labelSetPreset.empty() || !mitk::MultiLabelIOHelper::LoadLabelSetImagePreset(labelSetPreset, newLabelSetImage))
   {
     auto newLabel = mitk::LabelSetImageHelper::CreateNewLabel(newLabelSetImage);
 
     if (!m_DefaultLabelNaming)
       QmitkNewSegmentationDialog::DoRenameLabel(newLabel, nullptr, m_Parent);
 
     newLabelSetImage->AddLabel(newLabel, newLabelSetImage->GetActiveLayer());
   }
 
   if (!this->GetDataStorage()->Exists(newSegmentationNode))
   {
     this->GetDataStorage()->Add(newSegmentationNode, m_ReferenceNode);
   }
 
   if (m_ToolManager->GetWorkingData(0))
   {
     m_ToolManager->GetWorkingData(0)->SetSelected(false);
   }
 
   newSegmentationNode->SetSelected(true);
   m_Controls->workingNodeSelector->SetCurrentSelectedNode(newSegmentationNode);
 }
 
 std::string QmitkSegmentationView::GetDefaultLabelSetPreset() const
 {
   auto labelSetPreset = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABELSET_PRESET.toStdString(), "");
 
   if (labelSetPreset.empty())
     labelSetPreset = m_LabelSetPresetPreference.toStdString();
 
   return labelSetPreset;
 }
 
 void QmitkSegmentationView::OnManualTool2DSelected(int id)
 {
   this->ResetMouseCursor();
   mitk::StatusBar::GetInstance()->DisplayText("");
 
   if (id >= 0)
   {
     std::string text = "Active Tool: \"";
     text += m_ToolManager->GetToolById(id)->GetName();
     text += "\"";
     mitk::StatusBar::GetInstance()->DisplayText(text.c_str());
 
     us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource();
     this->SetMouseCursor(resource, 0, 0);
   }
 }
 
 void QmitkSegmentationView::OnShowMarkerNodes(bool state)
 {
   mitk::SegTool2D::Pointer manualSegmentationTool;
 
   unsigned int numberOfExistingTools = m_ToolManager->GetTools().size();
 
   for (unsigned int i = 0; i < numberOfExistingTools; i++)
   {
     manualSegmentationTool = dynamic_cast<mitk::SegTool2D*>(m_ToolManager->GetToolById(i));
     if (nullptr == manualSegmentationTool)
     {
       continue;
     }
 
     manualSegmentationTool->SetShowMarkerNodes(state);
   }
 }
 
 void QmitkSegmentationView::OnCurrentLabelSelectionChanged(QmitkMultiLabelManager::LabelValueVectorType labels)
 {
   auto segmentation = this->GetCurrentSegmentation();
 
   const auto labelValue = labels.front();
-  if (labelValue != segmentation->GetActiveLabel()->GetValue()) segmentation->SetActiveLabel(labelValue);
+  if (nullptr == segmentation->GetActiveLabel() || labelValue != segmentation->GetActiveLabel()->GetValue())
+  {
+    segmentation->SetActiveLabel(labelValue);
+    m_Controls->slicesInterpolator->SetActiveLabelValue(labelValue);
 
-  segmentation->Modified();
-  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
+    mitk::RenderingManager::GetInstance()->RequestUpdateAll();
+  }
 }
 
 void QmitkSegmentationView::OnGoToLabel(mitk::LabelSetImage::LabelValueType /*label*/, const mitk::Point3D& pos)
 {
   if (m_RenderWindowPart)
   {
     m_RenderWindowPart->SetSelectedPosition(pos);
   }
 }
 
 void QmitkSegmentationView::OnLabelRenameRequested(mitk::Label* label, bool rename) const
 {
   auto segmentation = this->GetCurrentSegmentation();
 
   if (rename)
   {
     QmitkNewSegmentationDialog::DoRenameLabel(label, segmentation, this->m_Parent, QmitkNewSegmentationDialog::Mode::RenameLabel);
     return;
   }
 
   QmitkNewSegmentationDialog::DoRenameLabel(label, nullptr, this->m_Parent, QmitkNewSegmentationDialog::Mode::NewLabel);
 }
 
 mitk::LabelSetImage* QmitkSegmentationView::GetCurrentSegmentation() const
 {
   auto workingNode = m_Controls->workingNodeSelector->GetSelectedNode();
   if (workingNode.IsNull()) mitkThrow() << "Segmentation view is in an invalid state. Working node is null, but a label selection change has been triggered.";
 
   auto segmentation = dynamic_cast<mitk::LabelSetImage*>(workingNode->GetData());
   if (nullptr == segmentation) mitkThrow() << "Segmentation view is in an invalid state. Working node contains no segmentation, but a label selection change has been triggered.";
 
   return segmentation;
 }
 
 /**********************************************************************/
 /* private                                                            */
 /**********************************************************************/
 void QmitkSegmentationView::CreateQtPartControl(QWidget* parent)
 {
    m_Parent = parent;
 
    m_Controls = new Ui::QmitkSegmentationViewControls;
    m_Controls->setupUi(parent);
 
    // *------------------------
    // * SHORTCUTS
    // *------------------------
    QShortcut* visibilityShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_H), parent);
    connect(visibilityShortcut, &QShortcut::activated, this, &Self::OnVisibilityShortcutActivated);
    QShortcut* labelToggleShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_L, Qt::CTRL | Qt::Key::Key_I), parent);
    connect(labelToggleShortcut, &QShortcut::activated, this, &Self::OnLabelToggleShortcutActivated);
 
    // *------------------------
    // * DATA SELECTION WIDGETS
    // *------------------------
    m_Controls->referenceNodeSelector->SetDataStorage(GetDataStorage());
    m_Controls->referenceNodeSelector->SetNodePredicate(m_ReferencePredicate);
    m_Controls->referenceNodeSelector->SetInvalidInfo("Select an image");
    m_Controls->referenceNodeSelector->SetPopUpTitel("Select an image");
    m_Controls->referenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation.");
 
    m_Controls->workingNodeSelector->SetDataStorage(GetDataStorage());
    m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate);
    m_Controls->workingNodeSelector->SetInvalidInfo("Select a segmentation");
    m_Controls->workingNodeSelector->SetPopUpTitel("Select a segmentation");
    m_Controls->workingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected.");
 
    connect(m_Controls->referenceNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged,
            this, &Self::OnReferenceSelectionChanged);
    connect(m_Controls->workingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged,
            this, &Self::OnSegmentationSelectionChanged);
 
    // *------------------------
    // * TOOLMANAGER
    // *------------------------
    m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager();
    m_ToolManager->SetDataStorage(*(this->GetDataStorage()));
    m_ToolManager->InitializeTools();
 
    QString segTools2D = tr("Add Subtract Lasso Fill Erase Close Paint Wipe 'Region Growing' 'Live Wire' 'Segment Anything'");
    QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Region Growing 3D' Picking GrowCut TotalSegmentator");
 
 #ifdef __linux__
    segTools3D.append(" nnUNet"); // plugin not enabled for MacOS / Windows
 #endif
    std::regex extSegTool2DRegEx("SegTool2D$");
    std::regex extSegTool3DRegEx("SegTool3D$");
 
    auto tools = m_ToolManager->GetTools();
    for (const auto &tool : tools)
    {
      if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx))
      {
        segTools2D.append(QString(" '%1'").arg(tool->GetName()));
      }
      else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx))
      {
        segTools3D.append(QString(" '%1'").arg(tool->GetName()));
      }
    }
 
    // setup 2D tools
    m_Controls->toolSelectionBox2D->SetToolManager(*m_ToolManager);
    m_Controls->toolSelectionBox2D->SetGenerateAccelerators(true);
    m_Controls->toolSelectionBox2D->SetToolGUIArea(m_Controls->toolGUIArea2D);
    m_Controls->toolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString());
    connect(m_Controls->toolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected,
            this, &Self::OnManualTool2DSelected);
 
    // setup 3D Tools
    m_Controls->toolSelectionBox3D->SetToolManager(*m_ToolManager);
    m_Controls->toolSelectionBox3D->SetGenerateAccelerators(true);
    m_Controls->toolSelectionBox3D->SetToolGUIArea(m_Controls->toolGUIArea3D);
    m_Controls->toolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString());
 
    m_Controls->slicesInterpolator->SetDataStorage(this->GetDataStorage());
 
    // create general signal / slot connections
    connect(m_Controls->newSegmentationButton, &QToolButton::clicked, this, &Self::OnNewSegmentation);
 
    connect(m_Controls->slicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &Self::OnShowMarkerNodes);
 
    connect(m_Controls->multiLabelWidget, &QmitkMultiLabelManager::CurrentSelectionChanged, this, &Self::OnCurrentLabelSelectionChanged);
    connect(m_Controls->multiLabelWidget, &QmitkMultiLabelManager::GoToLabel, this, &Self::OnGoToLabel);
    connect(m_Controls->multiLabelWidget, &QmitkMultiLabelManager::LabelRenameRequested, this, &Self::OnLabelRenameRequested);
 
    auto command = itk::SimpleMemberCommand<Self>::New();
    command->SetCallbackFunction(this, &Self::ValidateSelectionInput);
    m_RenderingManagerObserverTag =
      mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command);
 
    m_RenderWindowPart = this->GetRenderWindowPart();
    if (nullptr != m_RenderWindowPart)
    {
      this->RenderWindowPartActivated(m_RenderWindowPart);
    }
 
    // Make sure the GUI notices if appropriate data is already present on creation.
    // Should be done last, if everything else is configured because it triggers the autoselection of data.
    m_Controls->referenceNodeSelector->SetAutoSelectNewNodes(true);
    m_Controls->workingNodeSelector->SetAutoSelectNewNodes(true);
 
    this->UpdateGUI();
 }
 
 void QmitkSegmentationView::ActiveToolChanged()
 {
   if (nullptr == m_RenderWindowPart)
   {
     return;
   }
 
   mitk::TimeGeometry* interactionReferenceGeometry = nullptr;
   auto activeTool = m_ToolManager->GetActiveTool();
   if (nullptr != activeTool && m_ReferenceNode.IsNotNull())
   {
     mitk::Image::ConstPointer referenceImage = dynamic_cast<mitk::Image *>(m_ReferenceNode->GetData());
     if (referenceImage.IsNotNull())
     {
       // tool activated, reference image available: set reference geometry
       interactionReferenceGeometry = m_ReferenceNode->GetData()->GetTimeGeometry();
     }
   }
 
   // set the interaction reference geometry for the render window part (might be nullptr)
   m_RenderWindowPart->SetInteractionReferenceGeometry(interactionReferenceGeometry);
 }
 
 void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart)
 {
   if (m_RenderWindowPart != renderWindowPart)
   {
     m_RenderWindowPart = renderWindowPart;
   }
 
   if (nullptr != m_Parent)
   {
     m_Parent->setEnabled(true);
   }
 
   if (nullptr == m_Controls)
   {
     return;
   }
 
   if (nullptr != m_RenderWindowPart)
   {
     auto all2DWindows = Get2DWindows(m_RenderWindowPart->GetQmitkRenderWindows().values());
     m_Controls->slicesInterpolator->Initialize(m_ToolManager, all2DWindows);
 
     if (!m_RenderWindowPart->HasCoupledRenderWindows())
     {
       // react if the active tool changed, only if a render window part with decoupled render windows is used
       m_ToolManager->ActiveToolChanged +=
         mitk::MessageDelegate<Self>(this, &Self::ActiveToolChanged);
     }
   }
 }
 
 void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/)
 {
   m_RenderWindowPart = nullptr;
   if (nullptr != m_Parent)
   {
     m_Parent->setEnabled(false);
   }
 
   // remove message-connection to make sure no message is processed if no render window part is available
   m_ToolManager->ActiveToolChanged -=
     mitk::MessageDelegate<Self>(this, &Self::ActiveToolChanged);
 
   m_Controls->slicesInterpolator->Uninitialize();
 }
 
 void QmitkSegmentationView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* /*renderWindowPart*/)
 {
   if (nullptr == m_RenderWindowPart)
   {
     return;
   }
 
   m_Controls->slicesInterpolator->Uninitialize();
   auto all2DWindows = Get2DWindows(m_RenderWindowPart->GetQmitkRenderWindows().values());
   m_Controls->slicesInterpolator->Initialize(m_ToolManager, all2DWindows);
 }
 
 void QmitkSegmentationView::OnPreferencesChanged(const mitk::IPreferences* prefs)
 {
   auto labelSuggestions = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString(), "");
 
   m_DefaultLabelNaming = labelSuggestions.empty()
     ? prefs->GetBool("default label naming", true)
     : false; // No default label naming when label suggestions are enforced via command-line argument
 
   if (nullptr != m_Controls)
   {
     m_Controls->multiLabelWidget->SetDefaultLabelNaming(m_DefaultLabelNaming);
 
     bool compactView = prefs->GetBool("compact view", false);
     int numberOfColumns = compactView ? 6 : 4;
 
     m_Controls->toolSelectionBox2D->SetLayoutColumns(numberOfColumns);
     m_Controls->toolSelectionBox2D->SetShowNames(!compactView);
 
     m_Controls->toolSelectionBox3D->SetLayoutColumns(numberOfColumns);
     m_Controls->toolSelectionBox3D->SetShowNames(!compactView);
   }
 
   m_DrawOutline = prefs->GetBool("draw outline", true);
   m_SelectionMode = prefs->GetBool("selection mode", false);
 
   m_LabelSetPresetPreference = QString::fromStdString(prefs->Get("label set preset", ""));
 
   this->ApplyDisplayOptions();
   this->ApplySelectionMode();
 }
 
 void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node)
 {
   if (m_SegmentationPredicate->CheckNode(node))
     this->ApplyDisplayOptions(const_cast<mitk::DataNode*>(node));
 
   this->ApplySelectionMode();
 }
 
 void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node)
 {
   if (!m_SegmentationPredicate->CheckNode(node))
   {
     return;
   }
 
   // remove all possible contour markers of the segmentation
   mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(
     node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)));
 
   ctkPluginContext* context = mitk::PluginActivator::getContext();
   ctkServiceReference ppmRef = context->getServiceReference<mitk::PlanePositionManagerService>();
   mitk::PlanePositionManagerService* service = context->getService<mitk::PlanePositionManagerService>(ppmRef);
 
   for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it)
   {
     std::string nodeName = node->GetName();
     unsigned int t = nodeName.find_last_of(" ");
     unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1;
 
     service->RemovePlanePosition(id);
 
     this->GetDataStorage()->Remove(it->Value());
   }
 
   context->ungetService(ppmRef);
   service = nullptr;
 
   auto image = dynamic_cast<mitk::LabelSetImage*>(node->GetData());
   mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image);
 }
 
 void QmitkSegmentationView::ApplyDisplayOptions()
 {
   if (nullptr == m_Parent)
   {
     return;
   }
 
   if (nullptr == m_Controls)
   {
     return; // might happen on initialization (preferences loaded)
   }
 
   mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate);
   for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter)
   {
     this->ApplyDisplayOptions(*iter);
   }
 
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node)
 {
   if (nullptr == node)
   {
     return;
   }
 
   auto labelSetImage = dynamic_cast<mitk::LabelSetImage*>(node->GetData());
   if (nullptr == labelSetImage)
   {
     return;
   }
 
   // the outline property can be set in the segmentation preference page
   node->SetProperty("labelset.contour.active", mitk::BoolProperty::New(m_DrawOutline));
 
   // force render window update to show outline
   mitk::RenderingManager::GetInstance()->RequestUpdateAll();
 }
 
 void QmitkSegmentationView::ApplySelectionMode()
 {
   if (!m_SelectionMode)
     return;
 
   this->ApplySelectionModeOnReferenceNode();
   this->ApplySelectionModeOnWorkingNode();
 }
 
 void QmitkSegmentationView::ApplySelectionModeOnReferenceNode()
 {
   this->ApplySelectionMode(m_ReferenceNode, m_ReferencePredicate);
 }
 
 void QmitkSegmentationView::ApplySelectionModeOnWorkingNode()
 {
   this->ApplySelectionMode(m_WorkingNode, m_SegmentationPredicate);
 }
 
 void QmitkSegmentationView::ApplySelectionMode(mitk::DataNode* node, mitk::NodePredicateBase* predicate)
 {
   if (!m_SelectionMode || node == nullptr || predicate == nullptr)
     return;
 
   auto nodes = this->GetDataStorage()->GetSubset(predicate);
 
   for (auto iter = nodes->begin(); iter != nodes->end(); ++iter)
     (*iter)->SetVisibility(*iter == node);
 }
 
 void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node)
 {
   QmitkRenderWindow* selectedRenderWindow = nullptr;
   auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN);
   auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial");
   auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal");
   auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal");
   auto* threeDRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d");
   bool PlanarFigureInitializedWindow = false;
 
   // find initialized renderwindow
   if (node->GetBoolProperty("PlanarFigureInitializedWindow",
     PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer()))
   {
     selectedRenderWindow = axialRenderWindow;
   }
   if (!selectedRenderWindow && node->GetBoolProperty(
     "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow,
     sagittalRenderWindow->GetRenderer()))
   {
     selectedRenderWindow = sagittalRenderWindow;
   }
   if (!selectedRenderWindow && node->GetBoolProperty(
     "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow,
     coronalRenderWindow->GetRenderer()))
   {
     selectedRenderWindow = coronalRenderWindow;
   }
   if (!selectedRenderWindow && node->GetBoolProperty(
     "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow,
     threeDRenderWindow->GetRenderer()))
   {
     selectedRenderWindow = threeDRenderWindow;
   }
 
   // make node visible
   if (nullptr != selectedRenderWindow)
   {
     std::string nodeName = node->GetName();
     unsigned int t = nodeName.find_last_of(" ");
     unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1;
 
     ctkPluginContext* context = mitk::PluginActivator::getContext();
     ctkServiceReference ppmRef = context->getServiceReference<mitk::PlanePositionManagerService>();
     mitk::PlanePositionManagerService* service = context->getService<mitk::PlanePositionManagerService>(ppmRef);
     selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id));
     context->ungetService(ppmRef);
 
     selectedRenderWindow->GetRenderer()->GetCameraController()->Fit();
     mitk::RenderingManager::GetInstance()->RequestUpdateAll();
   }
 }
 
 void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList<mitk::DataNode::Pointer>& nodes)
 {
   if (0 == nodes.size())
   {
     return;
   }
 
   std::string markerName = "Position";
   unsigned int numberOfNodes = nodes.size();
   std::string nodeName = nodes.at(0)->GetName();
   if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0))
   {
     this->OnContourMarkerSelected(nodes.at(0));
     return;
   }
 }
 
 void QmitkSegmentationView::ResetMouseCursor()
 {
   if (m_MouseCursorSet)
   {
     mitk::ApplicationCursor::GetInstance()->PopCursor();
     m_MouseCursorSet = false;
   }
 }
 
 void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY)
 {
   // Remove previously set mouse cursor
   if (m_MouseCursorSet)
   {
     this->ResetMouseCursor();
   }
 
   if (resource)
   {
     us::ModuleResourceStream cursor(resource, std::ios::binary);
     mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY);
     m_MouseCursorSet = true;
   }
 }
 
 void QmitkSegmentationView::UpdateGUI()
 {
   mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0);
   bool hasReferenceNode = referenceNode != nullptr;
 
   mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0);
   bool hasWorkingNode = workingNode != nullptr;
 
   m_Controls->newSegmentationButton->setEnabled(false);
 
   if (hasReferenceNode)
   {
     m_Controls->newSegmentationButton->setEnabled(true);
   }
 
   if (hasWorkingNode && hasReferenceNode)
   {
     int layer = -1;
     referenceNode->GetIntProperty("layer", layer);
     workingNode->SetIntProperty("layer", layer + 1);
   }
 
   this->ValidateSelectionInput();
 }
 
 void QmitkSegmentationView::ValidateSelectionInput()
 {
   auto referenceNode = m_Controls->referenceNodeSelector->GetSelectedNode();
   auto workingNode = m_Controls->workingNodeSelector->GetSelectedNode();
 
   bool hasReferenceNode = referenceNode.IsNotNull();
   bool hasWorkingNode = workingNode.IsNotNull();
   bool hasBothNodes = hasReferenceNode && hasWorkingNode;
 
   QString warning;
   bool toolSelectionBoxesEnabled = hasReferenceNode && hasWorkingNode;
   unsigned int numberOfLabels = 0;
 
   m_Controls->multiLabelWidget->setEnabled(hasWorkingNode);
 
   m_Controls->toolSelectionBox2D->setEnabled(hasBothNodes);
   m_Controls->toolSelectionBox3D->setEnabled(hasBothNodes);
 
   m_Controls->slicesInterpolator->setEnabled(false);
   m_Controls->interpolatorWarningLabel->hide();
 
   if (hasReferenceNode)
   {
     if (nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows() && !referenceNode->IsVisible(nullptr))
     {
       warning += tr("The selected reference image is currently not visible!");
       toolSelectionBoxesEnabled = false;
     }
   }
 
   if (hasWorkingNode)
   {
     if (nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows() && !workingNode->IsVisible(nullptr))
     {
       warning += (!warning.isEmpty() ? "<br>" : "") + tr("The selected segmentation is currently not visible!");
       toolSelectionBoxesEnabled = false;
     }
 
     m_ToolManager->SetReferenceData(referenceNode);
     m_ToolManager->SetWorkingData(workingNode);
     m_Controls->multiLabelWidget->setEnabled(true);
     m_Controls->toolSelectionBox2D->setEnabled(true);
     m_Controls->toolSelectionBox3D->setEnabled(true);
 
     auto labelSetImage = dynamic_cast<mitk::LabelSetImage *>(workingNode->GetData());
     numberOfLabels = labelSetImage->GetTotalNumberOfLabels();
 
     if (numberOfLabels > 0)
       m_Controls->slicesInterpolator->setEnabled(true);
 
     m_Controls->multiLabelWidget->SetMultiLabelSegmentation(dynamic_cast<mitk::LabelSetImage*>(workingNode->GetData()));
   }
   else
   {
     m_Controls->multiLabelWidget->SetMultiLabelSegmentation(nullptr);
   }
 
   toolSelectionBoxesEnabled &= numberOfLabels > 0;
 
   // Here we need to check whether the geometry of the selected segmentation image (working image geometry)
   // is aligned with the geometry of the 3D render window.
   // It is not allowed to use a geometry different from the working image geometry for segmenting.
   // We only need to this if the tool selection box would be enabled without this check.
   // Additionally this check only has to be performed for render window parts with coupled render windows.
   // For different render window parts the user is given the option to reinitialize each render window individually
   // (see QmitkRenderWindow::ShowOverlayMessage).
   if (toolSelectionBoxesEnabled && nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows())
   {
     const mitk::BaseGeometry* workingNodeGeometry = workingNode->GetData()->GetGeometry();
     const mitk::BaseGeometry* renderWindowGeometry =
       m_RenderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D();
     if (nullptr != workingNodeGeometry && nullptr != renderWindowGeometry)
     {
       if (!mitk::Equal(*workingNodeGeometry->GetBoundingBox(), *renderWindowGeometry->GetBoundingBox(), mitk::eps, true))
       {
         warning += (!warning.isEmpty() ? "<br>" : "") + tr("Please reinitialize the selected segmentation image!");
         toolSelectionBoxesEnabled = false;
       }
     }
   }
 
   m_Controls->toolSelectionBox2D->setEnabled(toolSelectionBoxesEnabled);
   m_Controls->toolSelectionBox3D->setEnabled(toolSelectionBoxesEnabled);
 
   this->UpdateWarningLabel(warning);
 
   m_ToolManager->SetReferenceData(referenceNode);
   m_ToolManager->SetWorkingData(workingNode);
 }
 
 void QmitkSegmentationView::UpdateWarningLabel(QString text)
 {
   if (text.isEmpty())
   {
     m_Controls->selectionWarningLabel->hide();
   }
   else
   {
     m_Controls->selectionWarningLabel->setText("<font color=\"red\">" + text + "</font>");
     m_Controls->selectionWarningLabel->show();
   }
 }