void
  mitk::SlicedGeometry3D::ExecuteOperation(Operation* operation)
{
  switch ( operation->GetOperationType() )
  {
  case OpNOTHING:
    break;

  case OpROTATE:
    if ( m_EvenlySpaced )
    {
      // Need a reference frame to align the rotation
      if ( m_ReferenceGeometry )
      {
        // Clear all generated geometries and then rotate only the first slice.
        // The other slices will be re-generated on demand

        // Save first slice
        PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0];

        RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation );

        // Generate a RotationOperation using the dataset center instead of
        // the supplied rotation center. This is necessary so that the rotated
        // zero-plane does not shift away. The supplied center is instead used
        // to adjust the slice stack afterwards.
        Point3D center = m_ReferenceGeometry->GetCenter();

        RotationOperation centeredRotation(
          rotOp->GetOperationType(),
          center,
          rotOp->GetVectorOfRotation(),
          rotOp->GetAngleOfRotation()
          );

        // Rotate first slice
        geometry2D->ExecuteOperation( &centeredRotation );

        // Clear the slice stack and adjust it according to the center of
        // the dataset and the supplied rotation center (see documentation of
        // ReinitializePlanes)
        this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() );

        geometry2D->SetSpacing(this->GetSpacing());

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint(
            rotOp->GetCenterOfRotation() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }

        BaseGeometry::ExecuteOperation( &centeredRotation );
      }
      else
      {
        // we also have to consider the case, that there is no reference geometry available.
        if ( m_PlaneGeometries.size() > 0 )
        {
          // Reach through to all slices in my container
          for (auto iter = m_PlaneGeometries.begin();
            iter != m_PlaneGeometries.end();
            ++iter)
          {
            // Test for empty slices, which can happen if evenly spaced geometry
            if ((*iter).IsNotNull())
            {
              (*iter)->ExecuteOperation(operation);
            }
          }

          // rotate overall geometry
          RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation );
          BaseGeometry::ExecuteOperation( rotOp);
        }
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpORIENT:
    if ( m_EvenlySpaced )
    {
      // get operation data
      PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation );

      // Get first slice
      PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0];

      // Need a PlaneGeometry, a PlaneOperation and a reference frame to
      // carry out the re-orientation. If not all avaialble, stop here
      if ( !m_ReferenceGeometry                                                                       ||
           ( !planeGeometry || dynamic_cast<AbstractTransformGeometry*>(planeGeometry.GetPointer()) ) ||
           !planeOp )
      {
        break;
      }

      // General Behavior:
      // Clear all generated geometries and then rotate only the first slice.
      // The other slices will be re-generated on demand

      //
      // 1st Step: Reorient Normal Vector of first plane
      //
      Point3D center = planeOp->GetPoint(); //m_ReferenceGeometry->GetCenter();
      mitk::Vector3D currentNormal = planeGeometry->GetNormal();
      mitk::Vector3D newNormal;
      if (planeOp->AreAxisDefined())
      {
        // If planeOp was defined by one centerpoint and two axis vectors
        newNormal = CrossProduct(planeOp->GetAxisVec0(), planeOp->GetAxisVec1());
      }
      else
      {
        // If planeOp was defined by one centerpoint and one normal vector
        newNormal = planeOp->GetNormal();
      }

      // Get Rotation axis und angle
      currentNormal.Normalize();
      newNormal.Normalize();
      ScalarType rotationAngle = angle(currentNormal.GetVnlVector(),newNormal.GetVnlVector());

      rotationAngle *= 180.0 / vnl_math::pi; // from rad to deg
      Vector3D rotationAxis = itk::CrossProduct( currentNormal, newNormal );
      if (std::abs(rotationAngle-180) < mitk::eps )
      {
        // current Normal and desired normal are not linear independent!!(e.g 1,0,0 and -1,0,0).
        // Rotation Axis should be ANY vector that is 90� to current Normal
        mitk::Vector3D helpNormal;
        helpNormal = currentNormal;
        helpNormal[0] += 1;
        helpNormal[1] -= 1;
        helpNormal[2] += 1;
        helpNormal.Normalize();
        rotationAxis = itk::CrossProduct( helpNormal, currentNormal );
      }

      RotationOperation centeredRotation(
        mitk::OpROTATE,
        center,
        rotationAxis,
        rotationAngle
        );

      // Rotate first slice
      planeGeometry->ExecuteOperation( &centeredRotation );

      // Reinitialize planes and select slice, if my rotations are all done.
      if (!planeOp->AreAxisDefined())
      {
        // Clear the slice stack and adjust it according to the center of
        // rotation and plane position (see documentation of ReinitializePlanes)
        this->ReinitializePlanes( center, planeOp->GetPoint() );

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }
      }

      // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry)
      BaseGeometry::ExecuteOperation( &centeredRotation );

      //
      // 2nd step. If axis vectors were defined, rotate the plane around its normal to fit these
      //

      if (planeOp->AreAxisDefined())
      {
        mitk::Vector3D vecAxixNew = planeOp->GetAxisVec0();
        vecAxixNew.Normalize();
        mitk::Vector3D VecAxisCurr = planeGeometry->GetAxisVector(0);
        VecAxisCurr.Normalize();

        ScalarType rotationAngle = angle(VecAxisCurr.GetVnlVector(),vecAxixNew.GetVnlVector());
        rotationAngle = rotationAngle * 180 / PI; // Rad to Deg

        // we rotate around the normal of the plane, but we do not know, if we need to rotate clockwise
        // or anti-clockwise. So we rotate around the crossproduct of old and new Axisvector.
        // Since both axis vectors lie in the plane, the crossproduct is the planes normal or the negative planes normal

        rotationAxis = itk::CrossProduct( VecAxisCurr, vecAxixNew  );
        if (std::abs(rotationAngle-180) < mitk::eps )
        {
          // current axisVec and desired axisVec are not linear independent!!(e.g 1,0,0 and -1,0,0).
          // Rotation Axis can be just plane Normal. (have to rotate by 180�)
          rotationAxis = newNormal;
        }

        // Perfom Rotation
        mitk::RotationOperation op(mitk::OpROTATE, center, rotationAxis, rotationAngle);
        planeGeometry->ExecuteOperation( &op );

        // Apply changes on first slice to whole slice stack
        this->ReinitializePlanes( center, planeOp->GetPoint() );

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }

        // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry)
        BaseGeometry::ExecuteOperation( &op );
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpRESTOREPLANEPOSITION:
    if ( m_EvenlySpaced )
    {
      // Save first slice
      PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0];

      RestorePlanePositionOperation *restorePlaneOp = dynamic_cast< RestorePlanePositionOperation* >( operation );

      // Need a PlaneGeometry, a PlaneOperation and a reference frame to
      // carry out the re-orientation
      if ( m_ReferenceGeometry && (planeGeometry && dynamic_cast<AbstractTransformGeometry*>(planeGeometry.GetPointer()) == nullptr) && restorePlaneOp )
      {
        // Clear all generated geometries and then rotate only the first slice.
        // The other slices will be re-generated on demand

        // Rotate first slice
        planeGeometry->ExecuteOperation( restorePlaneOp );

        m_DirectionVector = restorePlaneOp->GetDirectionVector();

        double centerOfRotationDistance =
          planeGeometry->SignedDistanceFromPlane( m_ReferenceGeometry->GetCenter() );

        if ( centerOfRotationDistance > 0 )
        {
          m_DirectionVector = m_DirectionVector;
        }
        else
        {
          m_DirectionVector = -m_DirectionVector;
        }

        Vector3D spacing = restorePlaneOp->GetSpacing();

        Superclass::SetSpacing( spacing );

        // /*Now we need to calculate the number of slices in the plane's normal
        // direction, so that the entire volume is covered. This is done by first
        // calculating the dot product between the volume diagonal (the maximum
        // distance inside the volume) and the normal, and dividing this value by
        // the directed spacing calculated above.*/
        ScalarType directedExtent =
          std::abs( m_ReferenceGeometry->GetExtentInMM( 0 ) * m_DirectionVector[0] )
          + std::abs( m_ReferenceGeometry->GetExtentInMM( 1 ) * m_DirectionVector[1] )
          + std::abs( m_ReferenceGeometry->GetExtentInMM( 2 ) * m_DirectionVector[2] );

        if ( directedExtent >= spacing[2] )
        {
          m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5);
        }
        else
        {
          m_Slices = 1;
        }

        m_PlaneGeometries.assign( m_Slices, PlaneGeometry::Pointer( nullptr ) );

        if ( m_Slices > 0 )
        {
          m_PlaneGeometries[0] = planeGeometry;
        }

        m_SliceNavigationController->GetSlice()->SetSteps( m_Slices );

        this->Modified();

        //End Reinitialization

        if ( m_SliceNavigationController )
        {
          m_SliceNavigationController->GetSlice()->SetPos( restorePlaneOp->GetPos() );
          m_SliceNavigationController->AdjustSliceStepperRange();
        }
        BaseGeometry::ExecuteOperation(restorePlaneOp);
      }
    }
    else
    {
      // Reach through to all slices
      for (auto iter = m_PlaneGeometries.begin();
        iter != m_PlaneGeometries.end();
        ++iter)
      {
        (*iter)->ExecuteOperation(operation);
      }
    }
    break;

  case OpAPPLYTRANSFORMMATRIX:

    // Clear all generated geometries and then transform only the first slice.
    // The other slices will be re-generated on demand

    // Save first slice
    PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0];

    ApplyTransformMatrixOperation *applyMatrixOp = dynamic_cast< ApplyTransformMatrixOperation* >( operation );

    // Apply transformation to first plane
    geometry2D->ExecuteOperation( applyMatrixOp );

    // Generate a ApplyTransformMatrixOperation using the dataset center instead of
    // the supplied rotation center. The supplied center is instead used to adjust the
    // slice stack afterwards (see OpROTATE).
    Point3D center = m_ReferenceGeometry->GetCenter();

    // Clear the slice stack and adjust it according to the center of
    // the dataset and the supplied rotation center (see documentation of
    // ReinitializePlanes)
    this->ReinitializePlanes( center, applyMatrixOp->GetReferencePoint() );

    BaseGeometry::ExecuteOperation( applyMatrixOp );
    break;
  }

  this->Modified();
}
void
  mitk::SlicedGeometry3D::InitializePlanes(
  const mitk::BaseGeometry *geometry3D,
  mitk::PlaneGeometry::PlaneOrientation planeorientation,
  bool top, bool frontside, bool rotated )
{
  m_ReferenceGeometry = const_cast< BaseGeometry * >( geometry3D );

  PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New();
  planeGeometry->InitializeStandardPlane(
    geometry3D, top, planeorientation, frontside, rotated );

  ScalarType viewSpacing = 1;
  unsigned int slices = 1;

  switch ( planeorientation )
  {
  case PlaneGeometry::Axial:
    viewSpacing = geometry3D->GetSpacing()[2];
    slices = (unsigned int) geometry3D->GetExtent( 2 );
    break;

  case PlaneGeometry::Frontal:
    viewSpacing = geometry3D->GetSpacing()[1];
    slices = (unsigned int) geometry3D->GetExtent( 1 );
    break;

  case PlaneGeometry::Sagittal:
    viewSpacing = geometry3D->GetSpacing()[0];
    slices = (unsigned int) geometry3D->GetExtent( 0 );
    break;

  default:
    itkExceptionMacro("unknown PlaneOrientation");
  }

  mitk::Vector3D normal = this->AdjustNormal( planeGeometry->GetNormal() );

  ScalarType directedExtent =
    std::abs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] )
    + std::abs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] )
    + std::abs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] );

  if ( directedExtent >= viewSpacing )
  {
    slices = static_cast< int >(directedExtent / viewSpacing + 0.5);
  }
  else
  {
    slices = 1;
  }

  bool flipped = (top == false);

  if ( frontside == false )
  {
    flipped = !flipped;
  }
  if ( planeorientation == PlaneGeometry::Frontal )
  {
    flipped = !flipped;
  }

  this->InitializeEvenlySpaced( planeGeometry, viewSpacing, slices, flipped );
}