mitk::PlaneGeometry *
  mitk::SlicedGeometry3D::GetPlaneGeometry( int s ) const
{
  mitk::PlaneGeometry::Pointer geometry2D = nullptr;

  if ( this->IsValidSlice(s) )
  {
    geometry2D = m_PlaneGeometries[s];

    // If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored
    // for the requested slice, and (c) the first slice (s=0)
    // is a PlaneGeometry instance, then we calculate the geometry of the
    // requested as the plane of the first slice shifted by m_Spacing[2]*s
    // in the direction of m_DirectionVector.
    if ( (m_EvenlySpaced) && (geometry2D.IsNull()) )
    {
      PlaneGeometry *firstSlice = m_PlaneGeometries[0];

      if ( firstSlice != nullptr && dynamic_cast<AbstractTransformGeometry*>(m_PlaneGeometries[0].GetPointer() )==nullptr)
      {
        if ( (m_DirectionVector[0] == 0.0)
          && (m_DirectionVector[1] == 0.0)
          && (m_DirectionVector[2] == 0.0) )
        {
          m_DirectionVector = firstSlice->GetNormal();
          m_DirectionVector.Normalize();
        }

        Vector3D direction;
        direction = m_DirectionVector * this->GetSpacing()[2];

        mitk::PlaneGeometry::Pointer requestedslice;
        requestedslice = static_cast< mitk::PlaneGeometry * >(
          firstSlice->Clone().GetPointer() );

        requestedslice->SetOrigin(
          requestedslice->GetOrigin() + direction * s );

        geometry2D = requestedslice;
        m_PlaneGeometries[s] = geometry2D;
      }
    }
    return geometry2D;
  }
  else
  {
    return nullptr;
  }
}
void
  mitk::SlicedGeometry3D
  ::ReinitializePlanes( const Point3D &center, const Point3D &referencePoint )
{
  // Need a reference frame to align the rotated planes
  if ( !m_ReferenceGeometry )
  {
    return;
  }

  // Get first plane of plane stack
  PlaneGeometry *firstPlane = m_PlaneGeometries[0];

  // If plane stack is empty, exit
  if ( !firstPlane || dynamic_cast<AbstractTransformGeometry*>(firstPlane) )
  {
    return;
  }

  // Calculate the "directed" spacing when taking the plane (defined by its axes
  // vectors and normal) as the reference coordinate frame.
  //
  // This is done by calculating the radius of the ellipsoid defined by the
  // original volume spacing axes, in the direction of the respective axis of the
  // reference frame.
  mitk::Vector3D axis0 = firstPlane->GetAxisVector(0);
  mitk::Vector3D axis1 = firstPlane->GetAxisVector(1);
  mitk::Vector3D normal = firstPlane->GetNormal();
  normal.Normalize();

  Vector3D spacing;
  spacing[0] = this->CalculateSpacing( axis0 );
  spacing[1] = this->CalculateSpacing( axis1 );
  spacing[2] = this->CalculateSpacing( normal );

  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 ) * normal[0] )
    + std::abs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] )
    + std::abs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] );

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

  // The origin of our "first plane" needs to be adapted to this new extent.
  // To achieve this, we first calculate the current distance to the volume's
  // center, and then shift the origin in the direction of the normal by the
  // difference between this distance and half of the new extent.
  double centerOfRotationDistance =
    firstPlane->SignedDistanceFromPlane( center );

  if ( centerOfRotationDistance > 0 )
  {
    firstPlane->SetOrigin( firstPlane->GetOrigin()
      + normal * (centerOfRotationDistance - directedExtent / 2.0)
      );
    m_DirectionVector = normal;
  }
  else
  {
    firstPlane->SetOrigin( firstPlane->GetOrigin()
      + normal * (directedExtent / 2.0 + centerOfRotationDistance)
      );
    m_DirectionVector = -normal;
  }

  // Now we adjust this distance according with respect to the given reference
  // point: we need to make sure that the point is touched by one slice of the
  // new slice stack.
  double referencePointDistance =
    firstPlane->SignedDistanceFromPlane( referencePoint );

  int referencePointSlice = static_cast< int >(
    referencePointDistance / spacing[2]);

  double alignmentValue =
    referencePointDistance / spacing[2] - referencePointSlice;

  firstPlane->SetOrigin(
    firstPlane->GetOrigin() + normal * alignmentValue * spacing[2] );

  // Finally, we can clear the previous geometry stack and initialize it with
  // our re-initialized "first plane".
  m_PlaneGeometries.assign( m_Slices, PlaneGeometry::Pointer( nullptr ) );

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

  // Reinitialize SNC with new number of slices
  m_SliceNavigationController->GetSlice()->SetSteps( m_Slices );

  this->Modified();
}