diff --git a/Modules/Core/include/mitkTimeGeometry.h b/Modules/Core/include/mitkTimeGeometry.h
index 42b90c7441..cfbd8c732e 100644
--- a/Modules/Core/include/mitkTimeGeometry.h
+++ b/Modules/Core/include/mitkTimeGeometry.h
@@ -1,351 +1,351 @@
 /*============================================================================
 
 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 mitkTimeGeometry_h
 #define mitkTimeGeometry_h
 
 // ITK
 #include <itkObject.h>
 // MITK
 #include "mitkOperationActor.h"
 #include <MitkCoreExports.h>
 #include <mitkBaseGeometry.h>
 #include <mitkCommon.h>
 
 namespace mitk
 {
   typedef mitk::ScalarType TimePointType;
   typedef std::size_t TimeStepType;
 
-  static const size_t TIMESTEP_INVALID = -1;
+  static const TimeStepType TIMESTEP_INVALID = -1;
 
   /**
   * \brief Manages the geometries of a data object for each time step
   *
   * This class is an abstract class. The concrete implementation
   * depends on the way the different time steps are managed.
   *
   * The time is defined either by a time step or a time point. Time steps
   * are non-negative integers starting from 0. A time point is a ScalarType value
   * which gives the passed time since start in ms. Be aware that the starting
   * point is not fixed so it is possible that the same time point  defines two
   * different time depending on the start time of the used time geometry.
   *
   * \addtogroup geometry
   */
   class MITKCORE_EXPORT TimeGeometry : public itk::Object, public OperationActor
   {
   protected:
     TimeGeometry();
     ~TimeGeometry() override;
 
     /**
     * \brief Contains a bounding box which includes all time steps
     */
     BoundingBox::Pointer m_BoundingBox;
 
     /**
     * \brief Makes a deep copy of the current object
     */
     LightObject::Pointer InternalClone() const override;
 
   public:
     mitkClassMacroItkParent(TimeGeometry, itk::Object);
     itkCloneMacro(Self);
     itkCreateAnotherMacro(Self);
 
       /**
       * \brief Returns the number of time steps.
       *
       * Returns the number of time steps for which
       * geometries are saved. The number of time steps
       * is also the upper bound of the time steps. The
       * minimum time steps is always 0.
       */
       virtual TimeStepType CountTimeSteps() const = 0;
     /**
     * \brief Returns the first time point for which the object is valid.
     *
     * Returns the first valid time point for this geometry. If only one
     * time steps available it usually goes from -max to +max. The time point
     * is given in ms.
     */
     virtual TimePointType GetMinimumTimePoint() const = 0;
     /**
     * \brief Returns the last time point for which the object is valid
     *
     * Gives the last time point for which a valid geometry is saved in
     * this time geometry. The time point is given in ms.
     */
     virtual TimePointType GetMaximumTimePoint() const = 0;
 
     /**
     * \brief Returns the first time point for which the object is valid.
     *
     * Returns the first valid time point for the given TimeStep. The time point
     * is given in ms.
     */
     virtual TimePointType GetMinimumTimePoint(TimeStepType step) const = 0;
     /**
     * \brief Returns the last time point for which the object is valid
     *
     * Gives the last time point for the Geometry specified by the given TimeStep. The time point is given in ms.
     */
     virtual TimePointType GetMaximumTimePoint(TimeStepType step) const = 0;
 
     /**
     * \brief Get the time bounds (in ms)
     */
     virtual TimeBounds GetTimeBounds() const = 0;
 
     /**
     * \brief Get the time bounds for the given TimeStep (in ms)
     */
     virtual TimeBounds GetTimeBounds(TimeStepType step) const = 0;
     /**
     * \brief Tests if a given time point is covered by this object
     *
     * Returns true if a geometry can be returned for the given time
     * point and falls if not. The time point must be given in ms.
     */
     virtual bool IsValidTimePoint(TimePointType timePoint) const = 0;
     /**
     * \brief Test for the given time step if a geometry is available
     *
     * Returns true if a geometry is defined for the given time step.
     * Otherwise false is returned.
     * The time step is defined as positive number.
     */
     virtual bool IsValidTimeStep(TimeStepType timeStep) const = 0;
 
     /**
     * \brief Converts a time step to a time point
     *
     * Converts a time step to a time point in a way that
     * the new time point indicates the same geometry as the time step.
     * If the original time steps does not point to a valid geometry,
     * a time point is calculated that also does not point to a valid
     * geometry, but no exception is raised.
     */
     virtual TimePointType TimeStepToTimePoint(TimeStepType timeStep) const = 0;
     /**
     * \brief Converts a time point to the corresponding time step
     *
     * Converts a time point to a time step in a way that
     * the new time step indicates the same geometry as the time point.
     * If a negative invalid time point is given always time step 0 is
     * returned. If an positive invalid time step is given an invalid
     * time step will be returned.
     */
     virtual TimeStepType TimePointToTimeStep(TimePointType timePoint) const = 0;
 
     /**
     * \brief Returns the geometry of a specific time point
     *
     * Returns the geometry which defines the given time point. If
     * the given time point is invalid an null-pointer is returned.
     *
     * The pointer to the returned geometry may point to the saved
     * geometry but this is not necessarily the case. So a change to
     * the returned geometry may or may not afflict the geometry for the
     * time point or all time points depending on the used implementation
     * of TimeGeometry.
     */
     virtual BaseGeometry::Pointer GetGeometryForTimePoint(TimePointType timePoint) const = 0;
     /**
     * \brief Returns the geometry which corresponds to the given time step
     *
     * Returns the geometry which defines the given time step. If
     * the given time step is invalid an null-pointer is returned.
     *
     * The pointer to the returned geometry may point to the saved
     * geometry but this is not necessarily the case. So a change to
     * the returned geometry may or may not afflict the geometry for the
     * time step or all time steps depending on the used implementation
     * of TimeGeometry.
     */
     virtual BaseGeometry::Pointer GetGeometryForTimeStep(TimeStepType timeStep) const = 0;
 
     /**
     * \brief Returns a clone of the geometry of a specific time point
     *
     * If an invalid time step is given (e.g. no geometry is defined for this time step)
     * a null-pointer will be returned.
     */
     virtual BaseGeometry::Pointer GetGeometryCloneForTimeStep(TimeStepType timeStep) const = 0;
 
     /**
     * \brief Sets the geometry for a given time step
     *
     * Sets the geometry for the given time steps. This may also afflects other
     * time steps, depending on the implementation of TimeGeometry.
     */
     virtual void SetTimeStepGeometry(BaseGeometry *geometry, TimeStepType timeStep) = 0;
 
     /**
     * \brief Expands to the given number of time steps
     *
     * Expands to the given number of time steps. Each new created time
     * step is filled with an empty geometry.
     * Shrinking is not supported!
     */
     virtual void Expand(TimeStepType size) = 0;
 
     /**
     * \brief Replaces the geometry instances with clones ot the passed geometry.
     *
     * Replaces the geometries of all time steps with clones of the passed
     * geometry. Replacement strategy depends on the implementation of TimeGeometry
     * sub class.
     * @remark The time points itself stays untouched. Use this method if you want
     * to change the spatial properties of a TimeGeometry and preserve the time
     * "grid".
     */
     virtual void ReplaceTimeStepGeometries(const BaseGeometry *geometry) = 0;
 
     /**
     * \brief Tests if all necessary information are set and the object is valid
     */
     virtual bool IsValid() const = 0;
     /**
     * \brief Get the position of the corner number \a id (in world coordinates)
     *
     * See SetImageGeometry for how a corner is defined on images.
     */
     Point3D GetCornerPointInWorld(int id) const;
 
     /**
     * \brief Get the position of a corner (in world coordinates)
     *
     * See SetImageGeometry for how a corner is defined on images.
     */
     Point3D GetCornerPointInWorld(bool xFront = true, bool yFront = true, bool zFront = true) const;
 
     /**
     * \brief Get the center of the bounding-box in mm
     */
     Point3D GetCenterInWorld() const;
 
     /**
     * \brief Get the squared length of the diagonal of the bounding-box in mm
     */
     double GetDiagonalLength2InWorld() const;
 
     /**
     * \brief Get the length of the diagonal of the bounding-box in mm
     */
     double GetDiagonalLengthInWorld() const;
 
     /**
     * \brief Test whether the point \a p (world coordinates in mm) is inside the bounding box
     */
     bool IsWorldPointInside(const mitk::Point3D &p) const;
 
     /**
     * \brief Updates the bounding box to cover the area used in all time steps
     *
     * The bounding box is updated by this method. The new bounding box
     * covers an area which includes all bounding boxes during
     * all times steps.
     */
     void UpdateBoundingBox();
 
     /**
     * \brief Returns a bounding box that covers all time steps
     */
     BoundingBox *GetBoundingBoxInWorld() const { return m_BoundingBox; }
     /**
     * \brief Returns the world bounds of the object that cover all time steps
     */
     BoundingBox::BoundsArrayType GetBoundsInWorld() const { return m_BoundingBox->GetBounds(); }
     /**
     * \brief Returns the Extend of the bounding in the given direction
     */
     ScalarType GetExtentInWorld(unsigned int direction) const;
 
     /**
     * \brief Initializes the TimeGeometry
     */
     virtual void Initialize();
 
     /**
     * \brief Updates the geometry
     */
     void Update();
 
     /**
     * \brief Updates everything except the Bounding box
     *
     * This class should be overwritten by child classes.
     * The method is called when Update() is required.
     */
     virtual void UpdateWithoutBoundingBox(){};
 
     /**
     * \brief Executes the given operation on all time steps
     */
     void ExecuteOperation(Operation *op) override;
 
     void PrintSelf(std::ostream &os, itk::Indent indent) const override;
   }; // end class TimeGeometry
 
   /**
   * @brief Equal A function comparing two instances of TimeGeometry for being identical.
   *
   * @ingroup MITKTestingAPI
   *
   * The function compares two instances of TimeGeometries in all their aspects.
   *
   * The parameter eps is a tolerance value for all methods which are internally used for comparison.
   * If you want to use different tolerance values for different parts of the geometry, feel free to use
   * the other comparison methods and write your own implementation of Equal.
   *
   * @param rightHandSide Compare this against leftHandSide.
   * @param leftHandSide Compare this against rightHandSide.
   * @param eps Tolerance for comparison. You can use mitk::eps in most cases.
   * @param verbose Flag indicating if the user wants detailed console output or not.
   *
   * @return True, if all comparison are true. False in any other case.
   */
   MITKCORE_EXPORT bool Equal(const mitk::TimeGeometry &leftHandSide,
                              const mitk::TimeGeometry &rightHandSide,
                              ScalarType eps,
                              bool verbose);
 
   /**
   * @brief Compare two instances of TimeGeometry
   *
   * @ingroup MITKTestingAPI
   *
   * The function compares two instances of TimeGeometries in all their aspects.
   *
   * The parameter eps is a tolerance value for all methods which are internally used for comparison.
   * If you want to use different tolerance values for different parts of the geometry, feel free to use
   * the other comparison methods and write your own implementation of Equal.
   *
   * @param leftHandSide Compare this against rightHandSide.
   * @param rightHandSide Compare this against leftHandSide.
   * @param coordinateEps Tolerance for comparison of all spatial and temporal aspects (spacing, origin and grid alignment, time points).
   * You can use mitk::eps in most cases.
   * @param directionEps Tolerance for comparison of all directional aspects (axis). You can use mitk::eps in most cases.
   * @param verbose Flag indicating if the user wants detailed console output or not.
   *
   * @return True, if all comparisons are true. False in any other case.
   */
   MITKCORE_EXPORT bool Equal(const mitk::TimeGeometry& leftHandSide,
     const mitk::TimeGeometry& rightHandSide,
     ScalarType coordinateEps,
     ScalarType directionEps,
     bool verbose);
 
 } // end namespace MITK
 #endif
diff --git a/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp b/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
index f3165290cc..70893567b1 100644
--- a/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
+++ b/Modules/Multilabel/mitkLabelSetImageVtkMapper2D.cpp
@@ -1,762 +1,764 @@
 /*============================================================================
 
 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 "mitkLabelSetImageVtkMapper2D.h"
 
 // MITK
 #include <mitkAbstractTransformGeometry.h>
 #include <mitkDataNode.h>
 #include <mitkImageSliceSelector.h>
 #include <mitkPlaneGeometry.h>
 #include <mitkProperties.h>
 #include <mitkVectorProperty.h>
 
 // MITK Rendering
 #include "vtkNeverTranslucentTexture.h"
 
 // VTK
 #include <vtkCamera.h>
 #include <vtkImageData.h>
 #include <vtkImageReslice.h>
 #include <vtkLookupTable.h>
 #include <vtkPlaneSource.h>
 #include <vtkPolyData.h>
 #include <vtkPolyDataMapper.h>
 #include <vtkImageMapToColors.h>
 
 namespace
 {
   itk::ModifiedTimeType PropertyTimeStampIsNewer(const mitk::IPropertyProvider* provider, mitk::BaseRenderer* renderer, const std::string& propName, itk::ModifiedTimeType refMT)
   {
     const std::string context = renderer != nullptr ? renderer->GetName() : "";
     auto prop = provider->GetConstProperty(propName, context);
     if (prop != nullptr)
     {
       return prop->GetTimeStamp() > refMT;
     }
     return false;
   }
 }
 
 mitk::LabelSetImageVtkMapper2D::LabelSetImageVtkMapper2D()
 {
 }
 
 mitk::LabelSetImageVtkMapper2D::~LabelSetImageVtkMapper2D()
 {
 }
 
 vtkProp *mitk::LabelSetImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer *renderer)
 {
   // return the actor corresponding to the renderer
   return m_LSH.GetLocalStorage(renderer)->m_Actors;
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage *mitk::LabelSetImageVtkMapper2D::GetLocalStorage(
   mitk::BaseRenderer *renderer)
 {
   return m_LSH.GetLocalStorage(renderer);
 }
 
 void mitk::LabelSetImageVtkMapper2D::GenerateLookupTable(mitk::BaseRenderer* renderer)
 {
   LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer);
   mitk::DataNode* node = this->GetDataNode();
   auto* image = dynamic_cast<mitk::LabelSetImage*>(node->GetData());
   assert(image && image->IsInitialized());
 
   localStorage->m_LabelLookupTable = image->GetLookupTable()->Clone();
   const auto labelValues = image->GetAllLabelValues();
 
   std::string propertyName = "org.mitk.multilabel.labels.highlighted";
 
   mitk::IntVectorProperty::Pointer prop = dynamic_cast<mitk::IntVectorProperty*>(node->GetNonConstProperty(propertyName));
   if (nullptr != prop)
   {
     const auto highlightedLabelValues = prop->GetValue();
 
     if (!highlightedLabelValues.empty())
     {
       auto lookUpTable  = localStorage->m_LabelLookupTable->GetVtkLookupTable();
       auto highlightEnd = highlightedLabelValues.cend();
 
       double rgba[4];
       for (const auto& value : labelValues)
       {
         lookUpTable->GetTableValue(value, rgba);
         if (highlightEnd == std::find(highlightedLabelValues.begin(), highlightedLabelValues.end(), value))
         { //make all none highlighted values more transparent
           rgba[3] *= 0.3;
         }
         else
         {
           if (rgba[3] != 0)
           { //if highlighted values are visible set them to opaque to pop out
             rgba[3] = 1.;
           }
           else
           { //if highlighted values are invisible the opacity is increased a bit
             //to give a visual hint that the are highlighted but also invisible.
             //e.g. needed to see a difference if you change the visibility of
             //a highlighted label in the MultiLabelInspector
             rgba[3] = 0.4;
           }
         }
         lookUpTable->SetTableValue(value, rgba);
       }
       localStorage->m_LabelLookupTable->Modified();
     }
   }
 }
 
 namespace
 {
   std::vector<mitk::LabelSetImage::GroupIndexType> GetOutdatedGroups(const mitk::LabelSetImageVtkMapper2D::LocalStorage* ls, const mitk::LabelSetImage* seg)
   {
     const auto nrOfGroups = seg->GetNumberOfLayers();
     std::vector<mitk::LabelSetImage::GroupIndexType> result;
 
     for (mitk::LabelSetImage::GroupIndexType groupID = 0; groupID < nrOfGroups; ++groupID)
     {
       const auto groupImage = seg->GetGroupImage(groupID);
       if (groupImage->GetMTime() > ls->m_LastDataUpdateTime
         || groupImage->GetPipelineMTime() > ls->m_LastDataUpdateTime
         || ls->m_GroupImageIDs.size() <= groupID
         || groupImage != ls->m_GroupImageIDs[groupID])
       {
         result.push_back(groupID);
       }
     }
     return result;
   }
 }
 
 void mitk::LabelSetImageVtkMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
   mitk::DataNode *node = this->GetDataNode();
   auto *segmentation = dynamic_cast<mitk::LabelSetImage *>(node->GetData());
   assert(segmentation && segmentation->IsInitialized());
 
   bool isLookupModified = localStorage->m_LabelLookupTable.IsNull() ||
     (localStorage->m_LabelLookupTable->GetMTime() < segmentation->GetLookupTable()->GetMTime()) ||
     PropertyTimeStampIsNewer(node, renderer, "org.mitk.multilabel.labels.highlighted", localStorage->m_LabelLookupTable->GetMTime()) ||
     PropertyTimeStampIsNewer(node, renderer, "opacity", localStorage->m_LabelLookupTable->GetMTime());
 
   if (isLookupModified)
   {
     this->GenerateLookupTable(renderer);
   }
 
   bool isGeometryModified = (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) ||
     (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime());
 
   bool rendererGeometryIsValid = true;
 
   // check if there is a valid worldGeometry
   if (isGeometryModified)
   {
     const PlaneGeometry* worldGeometry = renderer->GetCurrentWorldPlaneGeometry();
     rendererGeometryIsValid = worldGeometry != nullptr
       && worldGeometry->IsValid()
       && worldGeometry->HasReferenceGeometry();
 
     isGeometryModified = rendererGeometryIsValid
       && localStorage->m_WorldPlane.IsNotNull() && !Equal(*worldGeometry, *(localStorage->m_WorldPlane.GetPointer()));
 
     localStorage->m_WorldPlane = rendererGeometryIsValid ? worldGeometry->Clone() : nullptr;
   }
 
-  bool hasValidContent = rendererGeometryIsValid && RenderingGeometryIntersectsImage(localStorage->m_WorldPlane, segmentation->GetSlicedGeometry());
+  const bool hasValidContent = rendererGeometryIsValid && RenderingGeometryIntersectsImage(localStorage->m_WorldPlane, segmentation->GetSlicedGeometry());
+  const bool contentBecameValid = hasValidContent && !localStorage->m_HasValidContent;
+  const bool contentBecameInvalid = !hasValidContent && localStorage->m_HasValidContent;
 
-  if (!hasValidContent && localStorage->m_HasValidContent)
+  if (contentBecameInvalid)
   {
     // set image to nullptr, to clear the texture in 3D, because
     // the latest image is used there if the plane is out of the geometry
     // see bug-13275
     for (unsigned int lidx = 0; lidx < localStorage->m_NumberOfLayers; ++lidx)
     {
       localStorage->m_ReslicedImageVector[lidx] = nullptr;
       localStorage->m_LayerMapperVector[lidx]->SetInputData(localStorage->m_EmptyPolyData);
       localStorage->m_OutlineActor->SetVisibility(false);
       localStorage->m_OutlineShadowActor->SetVisibility(false);
     }
     localStorage->m_LastDataUpdateTime.Modified();
   }
 
   localStorage->m_HasValidContent = hasValidContent;
   if (!hasValidContent)
   {
     // early out if there is no intersection of the current rendering geometry
     // and the geometry of the image that is to be rendered.
     return;
   }
 
   std::vector<mitk::LabelSetImage::GroupIndexType> outdatedGroups;
   auto currentTimestep = this->GetTimestep();
-  if (isGeometryModified || (hasValidContent && !localStorage->m_HasValidContent) || localStorage->m_LastTimeStep!= currentTimestep)
+  if (isGeometryModified || contentBecameValid || localStorage->m_LastTimeStep!= currentTimestep)
   {
     //if geometry is outdated or we have valid content again
     // -> all groups need regeneration
     outdatedGroups.resize(segmentation->GetNumberOfLayers());
     std::iota(outdatedGroups.begin(), outdatedGroups.end(), 0);
   }
   else
   {
     outdatedGroups = GetOutdatedGroups(localStorage, segmentation);
   }
 
   if (!outdatedGroups.empty())
   {
     this->GenerateImageSlice(renderer, outdatedGroups);
   }
 
   localStorage->m_LastTimeStep = currentTimestep;
 
 
   float opacity = 1.0f;
   node->GetOpacity(opacity, renderer, "opacity");
 
   if (isLookupModified)
   {
     //if lookup table is modified all groups need a new color mapping
     outdatedGroups.resize(segmentation->GetNumberOfLayers());
     std::iota(outdatedGroups.begin(), outdatedGroups.end(), 0);
   }
 
   for (const auto groupID: outdatedGroups)
   {
     localStorage->m_LayerImageMapToColors[groupID]->SetLookupTable(localStorage->m_LabelLookupTable->GetVtkLookupTable());
     localStorage->m_LayerImageMapToColors[groupID]->SetInputData(localStorage->m_ReslicedImageVector[groupID]);
     localStorage->m_LayerImageMapToColors[groupID]->Update();
 
     // check for texture interpolation property
     bool textureInterpolation = false;
     node->GetBoolProperty("texture interpolation", textureInterpolation, renderer);
 
     // set the interpolation modus according to the property
     localStorage->m_LayerTextureVector[groupID]->SetInterpolate(textureInterpolation);
 
     localStorage->m_LayerTextureVector[groupID]->SetInputConnection(
       localStorage->m_LayerImageMapToColors[groupID]->GetOutputPort());
     this->TransformActor(renderer);
 
     // set the plane as input for the mapper
     localStorage->m_LayerMapperVector[groupID]->SetInputConnection(localStorage->m_Plane->GetOutputPort());
 
     // set the texture for the actor
     localStorage->m_LayerActorVector[groupID]->SetTexture(localStorage->m_LayerTextureVector[groupID]);
     localStorage->m_LayerActorVector[groupID]->GetProperty()->SetOpacity(opacity);
   }
 
   auto activeLayer = segmentation->GetActiveLayer();
   bool activeGroupIsOutdated = std::find(outdatedGroups.begin(), outdatedGroups.end(), activeLayer) != outdatedGroups.end();
 
   if (activeGroupIsOutdated
       || PropertyTimeStampIsNewer(node, renderer, "opacity", localStorage->m_LastActiveLabelUpdateTime.GetMTime())
       || PropertyTimeStampIsNewer(node, renderer, "labelset.contour.active", localStorage->m_LastActiveLabelUpdateTime.GetMTime())
       || PropertyTimeStampIsNewer(node, renderer, "labelset.contour.width", localStorage->m_LastActiveLabelUpdateTime.GetMTime())
     )
   {
     this->GenerateActiveLabelOutline(renderer);
   }
 }
 
 void mitk::LabelSetImageVtkMapper2D::GenerateImageSlice(mitk::BaseRenderer* renderer, const std::vector<mitk::LabelSetImage::GroupIndexType>& outdatedGroupIDs)
 {
   LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer);
   mitk::DataNode* node = this->GetDataNode();
   auto* segmentation = dynamic_cast<mitk::LabelSetImage*>(node->GetData());
   assert(segmentation && segmentation->IsInitialized());
 
   segmentation->Update();
 
   const auto numberOfLayers = segmentation->GetNumberOfLayers();
 
   if (numberOfLayers != localStorage->m_NumberOfLayers)
   {
     if (numberOfLayers > localStorage->m_NumberOfLayers)
     {
       for (unsigned int lidx = localStorage->m_NumberOfLayers; lidx < numberOfLayers; ++lidx)
       {
         localStorage->m_GroupImageIDs.push_back(nullptr);
         localStorage->m_ReslicedImageVector.push_back(vtkSmartPointer<vtkImageData>::New());
         localStorage->m_ReslicerVector.push_back(mitk::ExtractSliceFilter::New());
         localStorage->m_LayerTextureVector.push_back(vtkSmartPointer<vtkNeverTranslucentTexture>::New());
         localStorage->m_LayerMapperVector.push_back(vtkSmartPointer<vtkPolyDataMapper>::New());
         localStorage->m_LayerActorVector.push_back(vtkSmartPointer<vtkActor>::New());
         localStorage->m_LayerImageMapToColors.push_back(vtkSmartPointer<vtkImageMapToColors>::New());
 
         // do not repeat the texture (the image)
         localStorage->m_LayerTextureVector[lidx]->RepeatOff();
         // set corresponding mappers for the actors
         localStorage->m_LayerActorVector[lidx]->SetMapper(localStorage->m_LayerMapperVector[lidx]);
       }
     }
     else
     {
       localStorage->m_GroupImageIDs.resize(numberOfLayers);
       localStorage->m_ReslicedImageVector.resize(numberOfLayers);
       localStorage->m_ReslicerVector.resize(numberOfLayers);
       localStorage->m_LayerTextureVector.resize(numberOfLayers);
       localStorage->m_LayerMapperVector.resize(numberOfLayers);
       localStorage->m_LayerActorVector.resize(numberOfLayers);
       localStorage->m_LayerImageMapToColors.resize(numberOfLayers);
     }
     localStorage->m_NumberOfLayers = numberOfLayers;
 
     localStorage->m_Actors = vtkSmartPointer<vtkPropAssembly>::New();
 
     for (unsigned int lidx = 0; lidx < numberOfLayers; ++lidx)
     {
       localStorage->m_Actors->AddPart(localStorage->m_LayerActorVector[lidx]);
     }
     localStorage->m_Actors->AddPart(localStorage->m_OutlineShadowActor);
     localStorage->m_Actors->AddPart(localStorage->m_OutlineActor);
   }
 
   for (const auto groupID : outdatedGroupIDs)
   {
     const auto groupImage = segmentation->GetGroupImage(groupID);
     localStorage->m_GroupImageIDs[groupID] = groupImage;
 
     localStorage->m_ReslicerVector[groupID]->SetInput(groupImage);
     localStorage->m_ReslicerVector[groupID]->SetWorldGeometry(localStorage->m_WorldPlane);
     localStorage->m_ReslicerVector[groupID]->SetTimeStep(this->GetTimestep());
 
     // set the transformation of the image to adapt reslice axis
     localStorage->m_ReslicerVector[groupID]->SetResliceTransformByGeometry(
       groupImage->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep()));
 
     // is the geometry of the slice based on the image image or the worldgeometry?
     bool inPlaneResampleExtentByGeometry = false;
     node->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer);
     localStorage->m_ReslicerVector[groupID]->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry);
     localStorage->m_ReslicerVector[groupID]->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST);
     localStorage->m_ReslicerVector[groupID]->SetVtkOutputRequest(true);
 
     // this is needed when thick mode was enabled before. These variables have to be reset to default values
     localStorage->m_ReslicerVector[groupID]->SetOutputDimensionality(2);
     localStorage->m_ReslicerVector[groupID]->SetOutputSpacingZDirection(1.0);
     localStorage->m_ReslicerVector[groupID]->SetOutputExtentZDirection(0, 0);
 
     // Bounds information for reslicing (only required if reference geometry is present)
     // this used for generating a vtkPLaneSource with the right size
     double sliceBounds[6];
     sliceBounds[0] = 0.0;
     sliceBounds[1] = 0.0;
     sliceBounds[2] = 0.0;
     sliceBounds[3] = 0.0;
     sliceBounds[4] = 0.0;
     sliceBounds[5] = 0.0;
 
     localStorage->m_ReslicerVector[groupID]->GetClippedPlaneBounds(sliceBounds);
 
     // setup the textured plane
     this->GeneratePlane(renderer, sliceBounds);
 
     // get the spacing of the slice
     localStorage->m_mmPerPixel = localStorage->m_ReslicerVector[groupID]->GetOutputSpacing();
     localStorage->m_ReslicerVector[groupID]->Modified();
     // start the pipeline with updating the largest possible, needed if the geometry of the image has changed
     localStorage->m_ReslicerVector[groupID]->UpdateLargestPossibleRegion();
     localStorage->m_ReslicedImageVector[groupID] = localStorage->m_ReslicerVector[groupID]->GetVtkOutput();
   }
   localStorage->m_LastDataUpdateTime.Modified();
 }
 
 void mitk::LabelSetImageVtkMapper2D::GenerateActiveLabelOutline(mitk::BaseRenderer* renderer)
 {
   LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer);
   mitk::DataNode* node = this->GetDataNode();
   auto* image = dynamic_cast<mitk::LabelSetImage*>(node->GetData());
 
   int activeLayer = image->GetActiveLayer();
 
   float opacity = 1.0f;
   node->GetOpacity(opacity, renderer, "opacity");
 
   mitk::Label* activeLabel = image->GetActiveLabel();
   bool contourActive = false;
   node->GetBoolProperty("labelset.contour.active", contourActive, renderer);
   if (nullptr != activeLabel && contourActive && activeLabel->GetVisible())
   {
     //generate contours/outlines
     localStorage->m_OutlinePolyData =
       this->CreateOutlinePolyData(renderer, localStorage->m_ReslicedImageVector[activeLayer], activeLabel->GetValue());
     localStorage->m_OutlineActor->SetVisibility(true);
     localStorage->m_OutlineShadowActor->SetVisibility(true);
     const mitk::Color& color = activeLabel->GetColor();
     localStorage->m_OutlineActor->GetProperty()->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
     localStorage->m_OutlineShadowActor->GetProperty()->SetColor(0, 0, 0);
 
     float contourWidth(2.0);
     node->GetFloatProperty("labelset.contour.width", contourWidth, renderer);
     localStorage->m_OutlineActor->GetProperty()->SetLineWidth(contourWidth);
     localStorage->m_OutlineShadowActor->GetProperty()->SetLineWidth(contourWidth * 1.5);
 
     localStorage->m_OutlineActor->GetProperty()->SetOpacity(opacity);
     localStorage->m_OutlineShadowActor->GetProperty()->SetOpacity(opacity);
 
     localStorage->m_OutlineMapper->SetInputData(localStorage->m_OutlinePolyData);
   }
   else
   {
     localStorage->m_OutlineActor->SetVisibility(false);
     localStorage->m_OutlineShadowActor->SetVisibility(false);
   }
   localStorage->m_LastActiveLabelUpdateTime.Modified();
 }
 
 
 bool mitk::LabelSetImageVtkMapper2D::RenderingGeometryIntersectsImage(const PlaneGeometry *renderingGeometry,
   const BaseGeometry *imageGeometry) const
 {
   // if either one of the two geometries is nullptr we return true
   // for safety reasons
   if (renderingGeometry == nullptr || imageGeometry == nullptr)
     return true;
 
   // get the distance for the first cornerpoint
   ScalarType initialDistance = renderingGeometry->SignedDistance(imageGeometry->GetCornerPoint(0));
   for (int i = 1; i < 8; i++)
   {
     mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint(i);
 
     // get the distance to the other cornerpoints
     ScalarType distance = renderingGeometry->SignedDistance(cornerPoint);
 
     // if it has not the same signing as the distance of the first point
     if (initialDistance * distance < 0)
     {
       // we have an intersection and return true
       return true;
     }
   }
 
   // all distances have the same sign, no intersection and we return false
   return false;
 }
 
 vtkSmartPointer<vtkPolyData> mitk::LabelSetImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer *renderer,
                                                                                    vtkImageData *image,
                                                                                    int pixelValue)
 {
   LocalStorage *localStorage = this->GetLocalStorage(renderer);
 
   // get the min and max index values of each direction
   int *extent = image->GetExtent();
   int xMin = extent[0];
   int xMax = extent[1];
   int yMin = extent[2];
   int yMax = extent[3];
 
   int *dims = image->GetDimensions(); // dimensions of the image
   int line = dims[0];                 // how many pixels per line?
   int x = xMin;                       // pixel index x
   int y = yMin;                       // pixel index y
 
   // get the depth for each contour
   float depth = this->CalculateLayerDepth(renderer);
 
   vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();      // the points to draw
   vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New(); // the lines to connect the points
 
   // We take the pointer to the first pixel of the image
   auto *currentPixel = static_cast<mitk::Label::PixelType *>(image->GetScalarPointer());
 
   while (y <= yMax)
   {
     // if the current pixel value is set to something
     if ((currentPixel) && (*currentPixel == pixelValue))
     {
       // check in which direction a line is necessary
       // a line is added if the neighbor of the current pixel has the value 0
       // and if the pixel is located at the edge of the image
 
       // if   vvvvv  not the first line vvvvv
       if (y > yMin && *(currentPixel - line) != pixelValue)
       { // x direction - bottom edge of the pixel
         // add the 2 points
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         // add the line between both points
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the last line vvvvv
       if (y < yMax && *(currentPixel + line) != pixelValue)
       { // x direction - top edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the first pixel vvvvv
       if ((x > xMin || y > yMin) && *(currentPixel - 1) != pixelValue)
       { // y direction - left edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  not the last pixel vvvvv
       if ((y < yMax || (x < xMax)) && *(currentPixel + 1) != pixelValue)
       { // y direction - right edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       /*  now consider pixels at the edge of the image  */
 
       // if   vvvvv  left edge of image vvvvv
       if (x == xMin)
       { // draw left edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  right edge of image vvvvv
       if (x == xMax)
       { // draw right edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  bottom edge of image vvvvv
       if (y == yMin)
       { // draw bottom edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 =
           points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
 
       // if   vvvvv  top edge of image vvvvv
       if (y == yMax)
       { // draw top edge of the pixel
         vtkIdType p1 =
           points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         vtkIdType p2 = points->InsertNextPoint(
           (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth);
         lines->InsertNextCell(2);
         lines->InsertCellPoint(p1);
         lines->InsertCellPoint(p2);
       }
     } // end if currentpixel is set
 
     x++;
 
     if (x > xMax)
     { // reached end of line
       x = xMin;
       y++;
     }
 
     // Increase the pointer-position to the next pixel.
     // This is safe, as the while-loop and the x-reset logic above makes
     // sure we do not exceed the bounds of the image
     currentPixel++;
   } // end of while
 
   // Create a polydata to store everything in
   vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
   // Add the points to the dataset
   polyData->SetPoints(points);
   // Add the lines to the dataset
   polyData->SetLines(lines);
   return polyData;
 }
 
 void mitk::LabelSetImageVtkMapper2D::Update(mitk::BaseRenderer *renderer)
 {
   bool visible = true;
   const DataNode *node = this->GetDataNode();
   node->GetVisibility(visible, renderer, "visible");
 
   if (!visible)
     return;
 
   auto *image = dynamic_cast<mitk::LabelSetImage *>(node->GetData());
 
   if (image == nullptr || image->IsInitialized() == false)
     return;
 
   // Calculate time step of the image data for the specified renderer (integer value)
   this->CalculateTimeStep(renderer);
 
   // Check if time step is valid
   const TimeGeometry *dataTimeGeometry = image->GetTimeGeometry();
   if ((dataTimeGeometry == nullptr) || (dataTimeGeometry->CountTimeSteps() == 0) ||
       (!dataTimeGeometry->IsValidTimeStep(this->GetTimestep())))
   {
     return;
   }
 
   image->UpdateOutputInformation();
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
 
   // check if something important has changed and we need to re-render
 
   if (localStorage->m_LabelLookupTable.IsNull() ||
       (localStorage->m_LabelLookupTable->GetMTime() < image->GetLookupTable()->GetMTime()) ||
       (localStorage->m_LastDataUpdateTime < image->GetMTime()) ||
       (localStorage->m_LastDataUpdateTime < image->GetPipelineMTime()) ||
       (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) ||
       (localStorage->m_LastDataUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) ||
       (localStorage->m_LastPropertyUpdateTime < node->GetPropertyList()->GetMTime()) ||
       (localStorage->m_LastPropertyUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ||
       (localStorage->m_LastPropertyUpdateTime < image->GetPropertyList()->GetMTime()))
   {
     this->GenerateDataForRenderer(renderer);
     localStorage->m_LastPropertyUpdateTime.Modified();
   }
   else if ((localStorage->m_LastPropertyUpdateTime < node->GetPropertyList()->GetMTime()) ||
            (localStorage->m_LastPropertyUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ||
            (localStorage->m_LastPropertyUpdateTime < image->GetPropertyList()->GetMTime()))
   {
     this->GenerateDataForRenderer(renderer);
     localStorage->m_LastPropertyUpdateTime.Modified();
   }
 }
 
 // set the two points defining the textured plane according to the dimension and spacing
 void mitk::LabelSetImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer *renderer, double planeBounds[6])
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
 
   float depth = this->CalculateLayerDepth(renderer);
   // Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct
   // plane size in crosshair rotation and swivel mode.
   localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth);
   // These two points define the axes of the plane in combination with the origin.
   // Point 1 is the x-axis and point 2 the y-axis.
   // Each plane is transformed according to the view (axial, coronal and sagittal) afterwards.
   localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depth); // P1: (xMax, yMin, depth)
   localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); // P2: (xMin, yMax, depth)
 }
 
 float mitk::LabelSetImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer *renderer)
 {
   // get the clipping range to check how deep into z direction we can render images
   double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1];
 
   // Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined
   float depth = -maxRange * 0.01; // divide by 100
   int layer = 0;
   GetDataNode()->GetIntProperty("layer", layer, renderer);
   // add the layer property for each image to render images with a higher layer on top of the others
   depth += layer * 10; //*10: keep some room for each image (e.g. for ODFs in between)
   if (depth > 0.0f)
   {
     depth = 0.0f;
     MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead.";
   }
   return depth;
 }
 
 void mitk::LabelSetImageVtkMapper2D::TransformActor(mitk::BaseRenderer *renderer)
 {
   LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer);
   // get the transformation matrix of the reslicer in order to render the slice as axial, coronal or sagittal
   vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
   vtkSmartPointer<vtkMatrix4x4> matrix = localStorage->m_ReslicerVector[0]->GetResliceAxes(); // same for all layers
   trans->SetMatrix(matrix);
 
   for (unsigned int lidx = 0; lidx < localStorage->m_NumberOfLayers; ++lidx)
   {
     // transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or sagittal)
     localStorage->m_LayerActorVector[lidx]->SetUserTransform(trans);
     // transform the origin to center based coordinates, because MITK is center based.
     localStorage->m_LayerActorVector[lidx]->SetPosition(
       -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
   }
   // same for outline actor
   localStorage->m_OutlineActor->SetUserTransform(trans);
   localStorage->m_OutlineActor->SetPosition(
     -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
   // same for outline shadow actor
   localStorage->m_OutlineShadowActor->SetUserTransform(trans);
   localStorage->m_OutlineShadowActor->SetPosition(
     -0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0);
 }
 
 void mitk::LabelSetImageVtkMapper2D::SetDefaultProperties(mitk::DataNode *node,
                                                           mitk::BaseRenderer *renderer,
                                                           bool overwrite)
 {
   // add/replace the following properties
   node->SetProperty("opacity", FloatProperty::New(1.0f), renderer);
   node->SetProperty("binary", BoolProperty::New(false), renderer);
 
   node->SetProperty("labelset.contour.active", BoolProperty::New(true), renderer);
   node->SetProperty("labelset.contour.width", FloatProperty::New(2.0), renderer);
 
   Superclass::SetDefaultProperties(node, renderer, overwrite);
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage::~LocalStorage()
 {
 }
 
 mitk::LabelSetImageVtkMapper2D::LocalStorage::LocalStorage()
 {
   // Do as much actions as possible in here to avoid double executions.
   m_Plane = vtkSmartPointer<vtkPlaneSource>::New();
   m_Actors = vtkSmartPointer<vtkPropAssembly>::New();
   m_OutlinePolyData = vtkSmartPointer<vtkPolyData>::New();
   m_EmptyPolyData = vtkSmartPointer<vtkPolyData>::New();
   m_OutlineActor = vtkSmartPointer<vtkActor>::New();
   m_OutlineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
   m_OutlineShadowActor = vtkSmartPointer<vtkActor>::New();
 
   m_HasValidContent = false;
   m_NumberOfLayers = 0;
   m_mmPerPixel = nullptr;
   m_LastTimeStep = 0;
 
   m_OutlineActor->SetMapper(m_OutlineMapper);
   m_OutlineShadowActor->SetMapper(m_OutlineMapper);
 
   m_OutlineActor->SetVisibility(false);
   m_OutlineShadowActor->SetVisibility(false);
 }