double
mitk::SortByImagePositionPatient
::InternalNumericDistance(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right, bool& possible) const
{
  // sort by distance to world origin, assuming (almost) equal orientation
  static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
  static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

  Vector3D leftRight; leftRight.Fill(0.0);
  Vector3D leftUp; leftUp.Fill(0.0);
  bool leftHasOrientation(false);
  DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ).value,
                                   leftRight, leftUp, leftHasOrientation );

  Vector3D rightRight; rightRight.Fill(0.0);
  Vector3D rightUp; rightUp.Fill(0.0);
  bool rightHasOrientation(false);
  DICOMStringToOrientationVectors(right->GetTagValueAsString(tagImageOrientation).value,
                                   rightRight, rightUp, rightHasOrientation );

  Point3D leftOrigin; leftOrigin.Fill(0.0f);
  bool leftHasOrigin(false);
  leftOrigin = DICOMStringToPoint3D(left->GetTagValueAsString(tagImagePositionPatient).value, leftHasOrigin);

  Point3D rightOrigin; rightOrigin.Fill(0.0f);
  bool rightHasOrigin(false);
  rightOrigin = DICOMStringToPoint3D(right->GetTagValueAsString(tagImagePositionPatient).value, rightHasOrigin);

  //   we tolerate very small differences in image orientation, since we got to know about
  //   acquisitions where these values change across a single series (7th decimal digit)
  //   (http://bugs.mitk.org/show_bug.cgi?id=12263)
  //   still, we want to check if our assumption of 'almost equal' orientations is valid
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    if (   fabs(leftRight[dim] - rightRight[dim]) > 0.0001
        || fabs(leftUp[dim] - rightUp[dim]) > 0.0001)
    {
      MITK_ERROR << "Dicom images have different orientations.";
      throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images.");
    }
  }

  Vector3D normal;
  normal[0] = leftRight[1] * leftUp[2] - leftRight[2] * leftUp[1];
  normal[1] = leftRight[2] * leftUp[0] - leftRight[0] * leftUp[2];
  normal[2] = leftRight[0] * leftUp[1] - leftRight[1] * leftUp[0];

  double leftDistance = 0.0;
  double rightDistance = 0.0;

  // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    leftDistance += normal[dim] * leftOrigin[dim];
    rightDistance += normal[dim] * rightOrigin[dim];
  }

  // if we can sort by just comparing the distance, we do exactly that
  if ( fabs(leftDistance - rightDistance) >= mitk::eps)
  {
    possible = true;
    // default: compare position
    return rightDistance - leftDistance; // if (left < right> ==> diff > 0
  }
  else
  {
    possible = false;
    return 0.0;
  }
}
void
mitk::NormalDirectionConsistencySorter
::Sort()
{
  DICOMDatasetList datasets = GetInput();

  if (datasets.size() > 1)
  {
    // at some point in the code, there is the expectation that
    // the direction of the slice normals is the same as the direction between
    // first and last slice origin. We need to make this sure here, because
    // we want to feed the files into itk::ImageSeriesReader with the consistent
    // setting of ReverseOrderOff.

    static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
    static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

    DICOMDatasetAccess* firstDS = datasets.front();
    DICOMDatasetAccess*  lastDS = datasets.back();

    // make sure here that the direction from slice to slice is the direction of
    // image normals...
    std::string imageOrientationString = firstDS->GetTagValueAsString( tagImageOrientation );
    std::string imagePositionPatientFirst = firstDS->GetTagValueAsString( tagImagePositionPatient );
    std::string imagePositionPatientLast = lastDS->GetTagValueAsString( tagImagePositionPatient );

    Vector3D right; right.Fill(0.0);
    Vector3D up; up.Fill(0.0);
    bool hasOrientation(false);
    DICOMStringToOrientationVectors( imageOrientationString,
        right, up, hasOrientation );

    Point3D firstOrigin; firstOrigin.Fill(0.0f);
    bool firstHasOrigin(false);
    firstOrigin = DICOMStringToPoint3D( imagePositionPatientFirst, firstHasOrigin );

    Point3D lastOrigin; lastOrigin.Fill(0.0f);
    bool lastHasOrigin(false);
    lastOrigin = DICOMStringToPoint3D( imagePositionPatientLast, lastHasOrigin );

    Vector3D normal;
    normal[0] = right[1] * up[2] - right[2] * up[1];
    normal[1] = right[2] * up[0] - right[0] * up[2];
    normal[2] = right[0] * up[1] - right[1] * up[0];
    normal.Normalize();

    Vector3D directionOfSlices;
    directionOfSlices = lastOrigin - firstOrigin;
    directionOfSlices.Normalize();

    double projection = normal * directionOfSlices;

    MITK_DEBUG << "Making sense of \norientation '" << imageOrientationString
               << "'\nfirst position '" << imagePositionPatientFirst
               << "'\nlast position '" << imagePositionPatientLast << "'";
    MITK_DEBUG << "Normal: " << normal;
    MITK_DEBUG << "Direction of slices: " << directionOfSlices;
    MITK_DEBUG << "Projection of direction onto slice normal: " << projection;

    if ( projection < 0.0 )
    {
      MITK_DEBUG << "Need to reverse filenames";
      std::reverse( datasets.begin(), datasets.end() );

      m_TiltInfo = GantryTiltInformation::MakeFromTagValues(
          imagePositionPatientLast,
          imagePositionPatientFirst,
          imageOrientationString,
          datasets.size() - 1
          );
    }
    else
    {
      m_TiltInfo = GantryTiltInformation::MakeFromTagValues(
          imagePositionPatientFirst,
          imagePositionPatientLast,
          imageOrientationString,
          datasets.size() - 1
          );
    }
  }
  else // just ONE dataset, do not forget to reset tilt information
  {
    m_TiltInfo = GantryTiltInformation(); // empty info
  }

  this->SetNumberOfOutputs(1);
  this->SetOutput(0, datasets);
}