<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkPlaneGeometry.h"
#include <vnl/vnl_cross.h>

//##ModelId=3E395F22035A
mitk::PlaneGeometry::PlaneGeometry()
{
  Initialize();
}

//##ModelId=3E395F220382
mitk::PlaneGeometry::~PlaneGeometry()
{
}

void mitk::PlaneGeometry::Initialize()
{
  Superclass::Initialize();
}

void mitk::PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D* transform)
{
  //ensure row(2) of transform to be perpendicular to plane, keep length.
  VnlVector normal = vnl_cross_3d(transform->GetMatrix().GetVnlMatrix().get_column(0),transform->GetMatrix().GetVnlMatrix().get_column(1));
  normal.normalize();
  ScalarType len = transform->GetMatrix().GetVnlMatrix().get_column(2).two_norm();
  if(len==0) len = 1;
  normal*=len;
  mitk::Matrix3D matrix = transform->GetMatrix();
  matrix.GetVnlMatrix().set_column(2, normal);
  transform->SetMatrix(matrix);
}

void mitk::PlaneGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D* transform)
{
  EnsurePerpendicularNormal(transform);

  Superclass::SetIndexToWorldTransform(transform);
}

void mitk::PlaneGeometry::SetBounds(const BoundingBox::BoundsArrayType& bounds)
{
  //currently the unit rectangle must be starting at the origin [0,0]
  assert(bounds[0]==0);
  assert(bounds[2]==0);
  //the unit rectangle must be two-dimensional
  assert(bounds[1]>0);
  assert(bounds[3]>0);

  Superclass::SetBounds(bounds);
}

//##ModelId=3E3B9C730262
void mitk::PlaneGeometry::IndexToWorld(const mitk::Point2D &pt_units, mitk::Point2D &pt_mm) const
{
  pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0];
  pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1];
}

//##ModelId=3E3B9C760112
void mitk::PlaneGeometry::WorldToIndex(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units) const
{
  pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX);
  pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY);
}

//##ModelId=3E3B9C8C0145
void mitk::PlaneGeometry::IndexToWorld(const mitk::Point2D &atPt2d_units, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const
{
  vec_mm[0]=m_ScaleFactorMMPerUnitX*vec_units[0];
  vec_mm[1]=m_ScaleFactorMMPerUnitY*vec_units[1];
}

//##ModelId=3E3B9C8E0152
void mitk::PlaneGeometry::WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const
{
  vec_units[0]=vec_mm[0]*(1.0/m_ScaleFactorMMPerUnitX);
  vec_units[1]=vec_mm[1]*(1.0/m_ScaleFactorMMPerUnitY);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const Vector3D & spacing, mitk::PlaneGeometry::PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  AffineTransform3D::Pointer transform;

  transform = AffineTransform3D::New();
  AffineTransform3D::MatrixType matrix;
  AffineTransform3D::MatrixType::InternalMatrixType & vnlmatrix = matrix.GetVnlMatrix();
  vnlmatrix.set_identity();
  vnlmatrix(0,0) = spacing[0];
  vnlmatrix(1,1) = spacing[1];
  vnlmatrix(2,2) = spacing[2];
  transform->SetIdentity();
  transform->SetMatrix(matrix);

  InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const mitk::AffineTransform3D* transform, mitk::PlaneGeometry::PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  Superclass::Initialize();

  //construct standard view
  mitk::Point3D  origin;
  VnlVector rightDV(3), bottomDV(3);
  origin.Fill(0);
  int normalDirection;
  switch(planeorientation)
  {
    case Transversal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   0,  0, zPosition);
          FillVector3D(rightDV,  1,  0,         0);
          FillVector3D(bottomDV, 0,  1,         0);
        }
        else
        {
          FillVector3D(origin,   width,  height, zPosition);
          FillVector3D(rightDV,     -1,       0,         0);
          FillVector3D(bottomDV,     0,      -1,         0);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,   width,  0, zPosition);
          FillVector3D(rightDV,     -1,  0,         0);
          FillVector3D(bottomDV,     0,  1,         0);
        }
        else
        {
          FillVector3D(origin,   0,  height, zPosition);
          FillVector3D(rightDV,  1,       0,         0);
          FillVector3D(bottomDV, 0,      -1,         0);
        }
      }
      normalDirection = 2;
      break;
    case Frontal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   0, zPosition, 0);
          FillVector3D(rightDV,  1, 0,         0);
          FillVector3D(bottomDV, 0, 0,         1);
        }
        else
        {
          FillVector3D(origin,   width, zPosition, height);
          FillVector3D(rightDV,     -1,         0,      0);
          FillVector3D(bottomDV,     0,         0,     -1);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,    width, zPosition,  0);
          FillVector3D(rightDV,      -1,         0,  0);
          FillVector3D(bottomDV,      0,         0,  1);
        }
        else
        {
          FillVector3D(origin,   0, zPosition,  height);
          FillVector3D(rightDV,  1,         0,       0);
          FillVector3D(bottomDV, 0,         0,      -1);
        }
      }
      normalDirection = 1;
      break;
    case Sagittal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   zPosition, 0, 0);
          FillVector3D(rightDV,  0,         1, 0);
          FillVector3D(bottomDV, 0,         0, 1);
        }
        else
        {
          FillVector3D(origin,   zPosition, width, height);
          FillVector3D(rightDV,          0,    -1,      0);
          FillVector3D(bottomDV,         0,     0,     -1);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,   zPosition,  width, 0);
          FillVector3D(rightDV,          0,     -1, 0);
          FillVector3D(bottomDV,         0,      0, 1);
        }
        else
        {
          FillVector3D(origin,   zPosition,  0, height);
          FillVector3D(rightDV,          0,  1,      0);
          FillVector3D(bottomDV,         0,  0,     -1);
        }
      }
      normalDirection = 0;
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }
  if(transform!=NULL)
  {
    origin   = transform->TransformPoint(origin);
    rightDV  = transform->TransformVector(rightDV);
    bottomDV = transform->TransformVector(bottomDV);
  }

  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);

  if(transform==NULL)
    SetMatrixByVectors(rightDV, bottomDV);
  else
    SetMatrixByVectors(rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix().get_column(normalDirection).magnitude());

  SetOrigin(origin);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const mitk::Geometry3D* geometry3D, PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  mitk::ScalarType width, height;

  const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds();
  mitk::Vector3D  originVector;
  FillVector3D(originVector,  boundsarray[0], boundsarray[2], boundsarray[4]);
  if(geometry3D->GetImageGeometry())
  {
    FillVector3D(originVector, originVector[0]-0.5, originVector[1]-0.5, originVector[2]-0.5);
  }
  switch(planeorientation)
  {
    case Transversal:
      width  = geometry3D->GetExtent(0);
      height = geometry3D->GetExtent(1);
      break;
    case Frontal:
      width  = geometry3D->GetExtent(0);
      height = geometry3D->GetExtent(2);
      break;
    case Sagittal:
      width  = geometry3D->GetExtent(1);
      height = geometry3D->GetExtent(2);
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }

  InitializeStandardPlane(width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated);

  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);

  mitk::Point3D  origin;
  originVector = geometry3D->GetIndexToWorldTransform()->TransformVector(originVector);
  origin = GetOrigin()+originVector;
  SetOrigin(origin);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const mitk::Geometry3D* geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated)
{
  mitk::ScalarType zPosition;

  switch(planeorientation)
  {
    case Transversal:
      zPosition = (top ? 0 : geometry3D->GetExtent(2)-1+0.5);
      break;
    case Frontal:
      zPosition = (top ? 0 : geometry3D->GetExtent(1)-1+0.5);
      break;
    case Sagittal:
      zPosition = (top ? 0 : geometry3D->GetExtent(0)-1+0.5);
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }

  InitializeStandardPlane(geometry3D, planeorientation, zPosition, frontside, rotated);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing)
{
  InitializeStandardPlane(rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing)
{
  mitk::ScalarType width  = rightVector.magnitude();
  mitk::ScalarType height = downVector.magnitude();

  InitializeStandardPlane(width, height, rightVector, downVector, spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing)
{
  InitializeStandardPlane(width, height, rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing)
{
  assert(width > 0);
  assert(height > 0);

  VnlVector rightDV = rightVector; rightDV.normalize();
  VnlVector downDV  = downVector;  downDV.normalize();
  VnlVector normal  = vnl_cross_3d(rightVector, downVector); normal.normalize();

  if(spacing!=NULL)
  {
    rightDV *= (*spacing)[0];
    downDV  *= (*spacing)[1];
    normal  *= (*spacing)[2];
  }

  mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New();
  mitk::Matrix3D matrix;
  matrix.GetVnlMatrix().set_column(0, rightDV);
  matrix.GetVnlMatrix().set_column(1, downDV);
  matrix.GetVnlMatrix().set_column(2, normal);
  transform->SetMatrix(matrix);
  transform->SetOffset(m_IndexToWorldTransform->GetOffset());
  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);
  SetIndexToWorldTransform(transform);
}

void mitk::PlaneGeometry::InitializePlane(const mitk::Point3D& origin, const mitk::Vector3D& normal)
{
  VnlVector rightVectorVnl(3), downVectorVnl;

  if( mitk::Equal( normal[1], 0.0f ) == false )
  {
    FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f );
    rightVectorVnl.normalize();
  }
  else
  {
    FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f );
  }
  downVectorVnl = vnl_cross_3d( normal.Get_vnl_vector(), rightVectorVnl );
  downVectorVnl.normalize();

  InitializeStandardPlane( rightVectorVnl, downVectorVnl );

  SetOrigin(origin);
}

mitk::ScalarType mitk::PlaneGeometry::SignedDistance(const mitk::Point3D& pt3d_mm) const
{
  return SignedDistanceFromPlane(pt3d_mm);
}

bool mitk::PlaneGeometry::IsAbove(const mitk::Point3D& pt3d_mm) const
{
  return SignedDistanceFromPlane(pt3d_mm)>0;
}

mitk::AffineGeometryFrame3D::Pointer mitk::PlaneGeometry::Clone() const
{
  Self::Pointer newGeometry = Self::New();
  newGeometry->Initialize();
  InitializeGeometry(newGeometry);
  return newGeometry.GetPointer();
}

void mitk::PlaneGeometry::InitializeGeometry(Self * newGeometry) const
{
  Superclass::InitializeGeometry(newGeometry);
}

void mitk::PlaneGeometry::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  Superclass::PrintSelf(os,indent);
  os << indent << " Normal: " << GetNormal() << std::endl;
}
<commit_msg>FIX: zPosition of new InitializeStandardPlane variant was incorrect<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkPlaneGeometry.h"
#include <vnl/vnl_cross.h>

//##ModelId=3E395F22035A
mitk::PlaneGeometry::PlaneGeometry()
{
  Initialize();
}

//##ModelId=3E395F220382
mitk::PlaneGeometry::~PlaneGeometry()
{
}

void mitk::PlaneGeometry::Initialize()
{
  Superclass::Initialize();
}

void mitk::PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D* transform)
{
  //ensure row(2) of transform to be perpendicular to plane, keep length.
  VnlVector normal = vnl_cross_3d(transform->GetMatrix().GetVnlMatrix().get_column(0),transform->GetMatrix().GetVnlMatrix().get_column(1));
  normal.normalize();
  ScalarType len = transform->GetMatrix().GetVnlMatrix().get_column(2).two_norm();
  if(len==0) len = 1;
  normal*=len;
  mitk::Matrix3D matrix = transform->GetMatrix();
  matrix.GetVnlMatrix().set_column(2, normal);
  transform->SetMatrix(matrix);
}

void mitk::PlaneGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D* transform)
{
  EnsurePerpendicularNormal(transform);

  Superclass::SetIndexToWorldTransform(transform);
}

void mitk::PlaneGeometry::SetBounds(const BoundingBox::BoundsArrayType& bounds)
{
  //currently the unit rectangle must be starting at the origin [0,0]
  assert(bounds[0]==0);
  assert(bounds[2]==0);
  //the unit rectangle must be two-dimensional
  assert(bounds[1]>0);
  assert(bounds[3]>0);

  Superclass::SetBounds(bounds);
}

//##ModelId=3E3B9C730262
void mitk::PlaneGeometry::IndexToWorld(const mitk::Point2D &pt_units, mitk::Point2D &pt_mm) const
{
  pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0];
  pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1];
}

//##ModelId=3E3B9C760112
void mitk::PlaneGeometry::WorldToIndex(const mitk::Point2D &pt_mm, mitk::Point2D &pt_units) const
{
  pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX);
  pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY);
}

//##ModelId=3E3B9C8C0145
void mitk::PlaneGeometry::IndexToWorld(const mitk::Point2D &atPt2d_units, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const
{
  vec_mm[0]=m_ScaleFactorMMPerUnitX*vec_units[0];
  vec_mm[1]=m_ScaleFactorMMPerUnitY*vec_units[1];
}

//##ModelId=3E3B9C8E0152
void mitk::PlaneGeometry::WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const
{
  vec_units[0]=vec_mm[0]*(1.0/m_ScaleFactorMMPerUnitX);
  vec_units[1]=vec_mm[1]*(1.0/m_ScaleFactorMMPerUnitY);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const Vector3D & spacing, mitk::PlaneGeometry::PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  AffineTransform3D::Pointer transform;

  transform = AffineTransform3D::New();
  AffineTransform3D::MatrixType matrix;
  AffineTransform3D::MatrixType::InternalMatrixType & vnlmatrix = matrix.GetVnlMatrix();
  vnlmatrix.set_identity();
  vnlmatrix(0,0) = spacing[0];
  vnlmatrix(1,1) = spacing[1];
  vnlmatrix(2,2) = spacing[2];
  transform->SetIdentity();
  transform->SetMatrix(matrix);

  InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const mitk::AffineTransform3D* transform, mitk::PlaneGeometry::PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  Superclass::Initialize();

  //construct standard view
  mitk::Point3D  origin;
  VnlVector rightDV(3), bottomDV(3);
  origin.Fill(0);
  int normalDirection;
  switch(planeorientation)
  {
    case Transversal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   0,  0, zPosition);
          FillVector3D(rightDV,  1,  0,         0);
          FillVector3D(bottomDV, 0,  1,         0);
        }
        else
        {
          FillVector3D(origin,   width,  height, zPosition);
          FillVector3D(rightDV,     -1,       0,         0);
          FillVector3D(bottomDV,     0,      -1,         0);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,   width,  0, zPosition);
          FillVector3D(rightDV,     -1,  0,         0);
          FillVector3D(bottomDV,     0,  1,         0);
        }
        else
        {
          FillVector3D(origin,   0,  height, zPosition);
          FillVector3D(rightDV,  1,       0,         0);
          FillVector3D(bottomDV, 0,      -1,         0);
        }
      }
      normalDirection = 2;
      break;
    case Frontal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   0, zPosition, 0);
          FillVector3D(rightDV,  1, 0,         0);
          FillVector3D(bottomDV, 0, 0,         1);
        }
        else
        {
          FillVector3D(origin,   width, zPosition, height);
          FillVector3D(rightDV,     -1,         0,      0);
          FillVector3D(bottomDV,     0,         0,     -1);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,    width, zPosition,  0);
          FillVector3D(rightDV,      -1,         0,  0);
          FillVector3D(bottomDV,      0,         0,  1);
        }
        else
        {
          FillVector3D(origin,   0, zPosition,  height);
          FillVector3D(rightDV,  1,         0,       0);
          FillVector3D(bottomDV, 0,         0,      -1);
        }
      }
      normalDirection = 1;
      break;
    case Sagittal:
      if(frontside)
      {
        if(rotated==false)
        {
          FillVector3D(origin,   zPosition, 0, 0);
          FillVector3D(rightDV,  0,         1, 0);
          FillVector3D(bottomDV, 0,         0, 1);
        }
        else
        {
          FillVector3D(origin,   zPosition, width, height);
          FillVector3D(rightDV,          0,    -1,      0);
          FillVector3D(bottomDV,         0,     0,     -1);
        }
      }
      else
      {
        if(rotated==false)
        {
          FillVector3D(origin,   zPosition,  width, 0);
          FillVector3D(rightDV,          0,     -1, 0);
          FillVector3D(bottomDV,         0,      0, 1);
        }
        else
        {
          FillVector3D(origin,   zPosition,  0, height);
          FillVector3D(rightDV,          0,  1,      0);
          FillVector3D(bottomDV,         0,  0,     -1);
        }
      }
      normalDirection = 0;
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }
  if(transform!=NULL)
  {
    origin   = transform->TransformPoint(origin);
    rightDV  = transform->TransformVector(rightDV);
    bottomDV = transform->TransformVector(bottomDV);
  }

  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);

  if(transform==NULL)
    SetMatrixByVectors(rightDV, bottomDV);
  else
    SetMatrixByVectors(rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix().get_column(normalDirection).magnitude());

  SetOrigin(origin);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const mitk::Geometry3D* geometry3D, PlaneOrientation planeorientation, mitk::ScalarType zPosition, bool frontside, bool rotated)
{
  mitk::ScalarType width, height;

  const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds();
  mitk::Vector3D  originVector;
  FillVector3D(originVector,  boundsarray[0], boundsarray[2], boundsarray[4]);
  if(geometry3D->GetImageGeometry())
  {
    FillVector3D(originVector, originVector[0]-0.5, originVector[1]-0.5, originVector[2]-0.5);
  }
  switch(planeorientation)
  {
    case Transversal:
      width  = geometry3D->GetExtent(0);
      height = geometry3D->GetExtent(1);
      break;
    case Frontal:
      width  = geometry3D->GetExtent(0);
      height = geometry3D->GetExtent(2);
      break;
    case Sagittal:
      width  = geometry3D->GetExtent(1);
      height = geometry3D->GetExtent(2);
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }

  InitializeStandardPlane(width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated);

  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);

  mitk::Point3D  origin;
  originVector = geometry3D->GetIndexToWorldTransform()->TransformVector(originVector);
  origin = GetOrigin()+originVector;
  SetOrigin(origin);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const mitk::Geometry3D* geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated)
{
  mitk::ScalarType zPosition;

  switch(planeorientation)
  {
    case Transversal:
      zPosition = (top ? 0.5 : geometry3D->GetExtent(2)-1+0.5);
      break;
    case Frontal:
      zPosition = (top ? 0.5 : geometry3D->GetExtent(1)-1+0.5);
      break;
    case Sagittal:
      zPosition = (top ? 0.5 : geometry3D->GetExtent(0)-1+0.5);
      break;
    default:
      itkExceptionMacro("unknown PlaneOrientation");
  }

  InitializeStandardPlane(geometry3D, planeorientation, zPosition, frontside, rotated);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing)
{
  InitializeStandardPlane(rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing)
{
  mitk::ScalarType width  = rightVector.magnitude();
  mitk::ScalarType height = downVector.magnitude();

  InitializeStandardPlane(width, height, rightVector, downVector, spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing)
{
  InitializeStandardPlane(width, height, rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing);
}

void mitk::PlaneGeometry::InitializeStandardPlane(mitk::ScalarType width, mitk::ScalarType height, const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing)
{
  assert(width > 0);
  assert(height > 0);

  VnlVector rightDV = rightVector; rightDV.normalize();
  VnlVector downDV  = downVector;  downDV.normalize();
  VnlVector normal  = vnl_cross_3d(rightVector, downVector); normal.normalize();

  if(spacing!=NULL)
  {
    rightDV *= (*spacing)[0];
    downDV  *= (*spacing)[1];
    normal  *= (*spacing)[2];
  }

  mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New();
  mitk::Matrix3D matrix;
  matrix.GetVnlMatrix().set_column(0, rightDV);
  matrix.GetVnlMatrix().set_column(1, downDV);
  matrix.GetVnlMatrix().set_column(2, normal);
  transform->SetMatrix(matrix);
  transform->SetOffset(m_IndexToWorldTransform->GetOffset());
  ScalarType bounds[6]={0, width, 0, height, 0, 1};
  SetBounds(bounds);
  SetIndexToWorldTransform(transform);
}

void mitk::PlaneGeometry::InitializePlane(const mitk::Point3D& origin, const mitk::Vector3D& normal)
{
  VnlVector rightVectorVnl(3), downVectorVnl;

  if( mitk::Equal( normal[1], 0.0f ) == false )
  {
    FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f );
    rightVectorVnl.normalize();
  }
  else
  {
    FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f );
  }
  downVectorVnl = vnl_cross_3d( normal.Get_vnl_vector(), rightVectorVnl );
  downVectorVnl.normalize();

  InitializeStandardPlane( rightVectorVnl, downVectorVnl );

  SetOrigin(origin);
}

mitk::ScalarType mitk::PlaneGeometry::SignedDistance(const mitk::Point3D& pt3d_mm) const
{
  return SignedDistanceFromPlane(pt3d_mm);
}

bool mitk::PlaneGeometry::IsAbove(const mitk::Point3D& pt3d_mm) const
{
  return SignedDistanceFromPlane(pt3d_mm)>0;
}

mitk::AffineGeometryFrame3D::Pointer mitk::PlaneGeometry::Clone() const
{
  Self::Pointer newGeometry = Self::New();
  newGeometry->Initialize();
  InitializeGeometry(newGeometry);
  return newGeometry.GetPointer();
}

void mitk::PlaneGeometry::InitializeGeometry(Self * newGeometry) const
{
  Superclass::InitializeGeometry(newGeometry);
}

void mitk::PlaneGeometry::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  Superclass::PrintSelf(os,indent);
  os << indent << " Normal: " << GetNormal() << std::endl;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    DicomSeriesReadImageWrite.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

//  Software Guide : BeginLatex
//
//  This example illustrates how to read a DICOM series into a volume
//  and then save this volume in another file format.
//
//  Software Guide : EndLatex

#include "itkImageSeriesReader.h"
#include "itkDICOMImageIO2.h"
#include "itkDICOMSeriesFileNames.h"
#include "itkImageFileWriter.h"

int main( int argc, char* argv[] )
{

  if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] << " DicomDirectory  outputFileName  [seriesName]" << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::Image<unsigned short,3>            ImageType;
  typedef itk::ImageSeriesReader< ImageType >     ReaderType;

  itk::DICOMImageIO2::Pointer dicomIO = itk::DICOMImageIO2::New();

  // Get the DICOM filenames from the directory
  itk::DICOMSeriesFileNames::Pointer nameGenerator = itk::DICOMSeriesFileNames::New();
  nameGenerator->SetDirectory( argv[1] );

  try
    {
    typedef std::vector<std::string> seriesIdContainer;
    const seriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();

    seriesIdContainer::const_iterator seriesItr = seriesUID.begin();
    seriesIdContainer::const_iterator seriesEnd = seriesUID.end();

    std::cout << std::endl << "The directory: " << std::endl;
    std::cout << std::endl << argv[1] << std::endl << std::endl;
    std::cout << "Contains the following DICOM Series: ";
    std::cout << std::endl << std::endl;

    while( seriesItr != seriesEnd )
      {
      std::cout << seriesItr->c_str() << std::endl;
      seriesItr++;
      }

    std::cout << std::endl << std::endl;
    std::cout << "Now reading series: " << std::endl << std::endl;

    typedef std::vector<std::string> fileNamesContainer;
    fileNamesContainer fileNames;

    if( argc < 4 ) // If no optional third argument
      {
      std::cout << seriesUID.begin()->c_str() << std::endl;
      fileNames = nameGenerator->GetFileNames();
      }
    else
      {
      std::cout << argv[3] << std::endl;
      fileNames = nameGenerator->GetFileNames( argv[3] );
      }
    std::cout << std::endl << std::endl;

    ReaderType::Pointer reader = ReaderType::New();
    reader->SetFileNames( fileNames );
    reader->SetImageIO( dicomIO );

    try
      {
      reader->Update();
      }
    catch (itk::ExceptionObject &ex)
      {
      std::cout << ex << std::endl;
      return EXIT_FAILURE;
      }

    typedef itk::ImageFileWriter< ImageType > WriterType;
    WriterType::Pointer writer = WriterType::New();

    std::cout  << "Writing the image as " << std::endl << std::endl;
    std::cout  << argv[2] << std::endl << std::endl;

    writer->SetFileName( argv[2] );

    writer->SetInput( reader->GetOutput() );

    try
      {
      writer->Update();
      }
    catch (itk::ExceptionObject &ex)
      {
      std::cout << ex;
      return EXIT_FAILURE;
      }
    }
  catch (itk::ExceptionObject &ex)
    {
    std::cout << ex;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;

}
<commit_msg>STYLE: Added a longer introductory comment. Note however that this example        is the obsolete form of reading DICOM series. Therefore it is not        being included in the text of the Software Guide.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    DicomSeriesReadImageWrite.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

//  Software Guide : BeginLatex
//
//  Probably the most common representation of datasets in clinical
//  applications is the one that uses sets of DICOM slices in order to compose
//  tridimensional images. This is the case for CT, MRI and PET scanners. It is
//  very common therefore for image analysists to have to process volumetric
//  images that are stored in the form of a set of DICOM files belonging to a
//  common DICOM series.
//
//  The following example illustrates how to use ITK functionalities in order
//  to read a DICOM series into a volume and then save this volume in another
//  file format.
//
//  Software Guide : EndLatex

#include "itkImageSeriesReader.h"
#include "itkDICOMImageIO2.h"
#include "itkDICOMSeriesFileNames.h"
#include "itkImageFileWriter.h"

int main( int argc, char* argv[] )
{

  if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] << " DicomDirectory  outputFileName  [seriesName]" << std::endl;
    return EXIT_FAILURE;
    }

  typedef itk::Image<unsigned short,3>            ImageType;
  typedef itk::ImageSeriesReader< ImageType >     ReaderType;

  itk::DICOMImageIO2::Pointer dicomIO = itk::DICOMImageIO2::New();

  // Get the DICOM filenames from the directory
  itk::DICOMSeriesFileNames::Pointer nameGenerator = itk::DICOMSeriesFileNames::New();
  nameGenerator->SetDirectory( argv[1] );

  try
    {
    typedef std::vector<std::string> seriesIdContainer;
    const seriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();

    seriesIdContainer::const_iterator seriesItr = seriesUID.begin();
    seriesIdContainer::const_iterator seriesEnd = seriesUID.end();

    std::cout << std::endl << "The directory: " << std::endl;
    std::cout << std::endl << argv[1] << std::endl << std::endl;
    std::cout << "Contains the following DICOM Series: ";
    std::cout << std::endl << std::endl;

    while( seriesItr != seriesEnd )
      {
      std::cout << seriesItr->c_str() << std::endl;
      seriesItr++;
      }

    std::cout << std::endl << std::endl;
    std::cout << "Now reading series: " << std::endl << std::endl;

    typedef std::vector<std::string> fileNamesContainer;
    fileNamesContainer fileNames;

    if( argc < 4 ) // If no optional third argument
      {
      std::cout << seriesUID.begin()->c_str() << std::endl;
      fileNames = nameGenerator->GetFileNames();
      }
    else
      {
      std::cout << argv[3] << std::endl;
      fileNames = nameGenerator->GetFileNames( argv[3] );
      }
    std::cout << std::endl << std::endl;

    ReaderType::Pointer reader = ReaderType::New();
    reader->SetFileNames( fileNames );
    reader->SetImageIO( dicomIO );

    try
      {
      reader->Update();
      }
    catch (itk::ExceptionObject &ex)
      {
      std::cout << ex << std::endl;
      return EXIT_FAILURE;
      }

    typedef itk::ImageFileWriter< ImageType > WriterType;
    WriterType::Pointer writer = WriterType::New();

    std::cout  << "Writing the image as " << std::endl << std::endl;
    std::cout  << argv[2] << std::endl << std::endl;

    writer->SetFileName( argv[2] );

    writer->SetInput( reader->GetOutput() );

    try
      {
      writer->Update();
      }
    catch (itk::ExceptionObject &ex)
      {
      std::cout << ex;
      return EXIT_FAILURE;
      }
    }
  catch (itk::ExceptionObject &ex)
    {
    std::cout << ex;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>/*
 * Unit tests for TTObject
 * Copyright © 2014, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTObjectTest.h"
#include "TTObjectTemplates.h"

#define thisTTClass			TTObjectTest
#define thisTTClassName		"object.test"
#define thisTTClassTags		"test, foundation"

TT_OBJECT_CONSTRUCTOR
{;}

TTObjectTest::~TTObjectTest()
{;}

void TTObjectTestBasic(int& errorCount, int& testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing basic functionality of TTObject");

	TTObject callback("callback");						// create a callback object
	TTSymbol notificationName;

	callback.set("notification", "foo");				// set a symbol attr
	callback.get("notification", notificationName);		// attr we get back is what we just set?

	TTTestAssertion("symbol attr that we set is returnable to us with correct value",
					notificationName == "foo",
					testAssertionCount,
					errorCount);
/*
    TTObject o1 = callback;

    TTTestAssertion("two object refering to the same object instance are equal",
					o1 == callback,
					testAssertionCount,
					errorCount);
 */
}

void TTObjectTestWithTTValue(int& errorCount, int& testAssertionCount)
{
	TTObject callback("callback");

    TTTestAssertion("after creation the object is valid",
                    callback.valid(),
                    testAssertionCount,
                    errorCount);

	callback.set("notification", "foo");        // set an attr so we can verify that it survives

	{
		TTValue v1(callback);					// assign to value with copy constructor

        TTTestAssertion("after duplication the object is valid",
                        callback.valid(),
                        testAssertionCount,
                        errorCount);

		TTValue v2 = callback;					// assign to value with = operator

		TTTestAssertion("1 object and 2 values -- refcount should be 3",
						callback.instance()->getReferenceCount() == 3,
						testAssertionCount,
						errorCount);

		// could check that v1 and v2 have correct and sane content

		TTObject o1 = v1[0];
		TTObject o2 = v2[0];

		TTTestAssertion("3 objects and 2 values -- refcount should be 5",
						callback.instance()->getReferenceCount() == 5,
						testAssertionCount,
						errorCount);
	}

	TTTestAssertion("1 object, others went out of scope -- refcount should be 1",
					callback.instance()->getReferenceCount() == 1,
					testAssertionCount,
					errorCount);
}

TTErr TTObjectTest::test(TTValue& returnedTestInfo)
{
	int	errorCount = 0;
	int testAssertionCount = 0;

	TTObjectTestBasic(errorCount, testAssertionCount);
	TTObjectTestWithTTValue(errorCount, testAssertionCount);

	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}
<commit_msg>minor<commit_after>/*
 * Unit tests for TTObject
 * Copyright © 2014, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTObjectTest.h"
#include "TTObjectTemplates.h"

#define thisTTClass			TTObjectTest
#define thisTTClassName		"object.test"
#define thisTTClassTags		"test, foundation"

TT_OBJECT_CONSTRUCTOR
{;}

TTObjectTest::~TTObjectTest()
{;}

void TTObjectTestBasic(int& errorCount, int& testAssertionCount)
{
	TTTestLog("\n");
	TTTestLog("Testing basic functionality of TTObject");

	TTObject callback("callback");						// create a callback object
	TTSymbol notificationName;

	callback.set("notification", "foo");				// set a symbol attr
	callback.get("notification", notificationName);		// attr we get back is what we just set?

	TTTestAssertion("symbol attr that we set is returnable to us with correct value",
					notificationName == "foo",
					testAssertionCount,
					errorCount);
/*
    TTObject o1 = callback;

    TTTestAssertion("two object refering to the same object instance are equal",
					o1 == callback,
					testAssertionCount,
					errorCount);
 */
}

void TTObjectTestWithTTValue(int& errorCount, int& testAssertionCount)
{
	TTObject callback("callback");

    TTTestAssertion("after creation the object is valid",
                    callback.valid(),
                    testAssertionCount,
                    errorCount);

	callback.set("notification", "foo");        // set an attr so we can verify that it survives

	{
		TTValue v1(callback);					// assign to value with copy constructor

        TTTestAssertion("after duplication the object is still valid",
                        callback.valid(),
                        testAssertionCount,
                        errorCount);

		TTValue v2 = callback;					// assign to value with = operator

		TTTestAssertion("1 object and 2 values -- refcount should be 3",
						callback.instance()->getReferenceCount() == 3,
						testAssertionCount,
						errorCount);

		// could check that v1 and v2 have correct and sane content

		TTObject o1 = v1[0];
		TTObject o2 = v2[0];

		TTTestAssertion("3 objects and 2 values -- refcount should be 5",
						callback.instance()->getReferenceCount() == 5,
						testAssertionCount,
						errorCount);
	}

	TTTestAssertion("1 object, others went out of scope -- refcount should be 1",
					callback.instance()->getReferenceCount() == 1,
					testAssertionCount,
					errorCount);
}

TTErr TTObjectTest::test(TTValue& returnedTestInfo)
{
	int	errorCount = 0;
	int testAssertionCount = 0;

	TTObjectTestBasic(errorCount, testAssertionCount);
	TTObjectTestWithTTValue(errorCount, testAssertionCount);

	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}
<|endoftext|>


<commit_before>// $Id$

//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/// @file   AliHLTGlobalHistoComponent.cxx
/// @author Matthias Richter
/// @date   2010-09-16
/// @brief  A histogramming component for global ESD properties based
///         on the AliHLTTTreeProcessor

#include "AliHLTGlobalHistoComponent.h"
#include "AliESDEvent.h"
#include "AliESDv0.h"
#include "AliKFParticle.h"
#include "AliKFVertex.h"

#include "TTree.h"
#include "TString.h"
#include <cassert>

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTGlobalHistoComponent)

AliHLTGlobalHistoComponent::AliHLTGlobalHistoComponent()
  : AliHLTTTreeProcessor()
  , fEvent(0)
  , fNofTracks(0)
  , fNofV0s(0)
  , fNofContributors(0)
  , fVertexX(-99)
  , fVertexY(-99)
  , fVertexZ(-99)
  , fVertexStatus(kFALSE)
  , fMaxTrackCount(20000)
  , fMaxV0Count(1000)
  , fFillV0(kFALSE)
  , fTrackVariables()
  , fTrackVariablesInt()
  , fV0Variables()
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTGlobalHistoComponent::~AliHLTGlobalHistoComponent(){
  // see header file for class documentation
  fTrackVariables.Reset();
  fTrackVariablesInt.Reset();
  fV0Variables.Reset();
}

void AliHLTGlobalHistoComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list){
  // see header file for class documentation
  list.push_back(kAliHLTAllDataTypes);
}

AliHLTComponentDataType AliHLTGlobalHistoComponent::GetOutputDataType(){
  // see header file for class documentation
  return kAliHLTDataTypeHistogram|kAliHLTDataOriginOut;
}

TTree* AliHLTGlobalHistoComponent::CreateTree(int /*argc*/, const char** /*argv*/){
// create the tree and branches

  int iResult=0;
  TTree* pTree = new TTree("ESDproperties", "HLT ESD properties");
  if (!pTree) return NULL;

  const char* trackVariableNames = {
    // Note the black at the end of each name!
    "Track_pt "
    "Track_phi "
    "Track_eta "
    "Track_p "
    "Track_theta "
    "Track_TPCclus "
    "Track_ITSclus "
    "Track_status "
    "Track_charge "
    "Track_DCAr "
    "Track_DCAz "
    "Track_dEdx "
  };

  const char* trackIntVariableNames = {
    // Note the black at the end of each name!
    "Track_status "
  };

  const char* V0VariableNames = {
    // Note the black at the end of each name!
    "V0_AP "
    "V0_pt "
    "clust1 "
    "clust2 "
    "dev1 "
    "dev2 "
    "devPrim "
    "length "
    "sigmaLength "
    "r "
  };

  if((iResult=fTrackVariables.Init(fMaxTrackCount, trackVariableNames))<0){
    HLTError("failed to initialize internal structure for track properties (float)");
  }
  if((iResult=fTrackVariablesInt.Init(fMaxTrackCount, trackIntVariableNames))<0){
    HLTError("failed to initialize internal structure for track properties (int)");
  }
  if((iResult=fV0Variables.Init(fMaxV0Count, V0VariableNames))<0){
      HLTError("failed to initialize internal structure for V0 properties (float)");
  }

  if(iResult>=0){
     pTree->Branch("event",	   &fEvent,	      "event/I");
     pTree->Branch("trackcount",   &fNofTracks,       "trackcount/I");
     pTree->Branch("vertexX",	   &fVertexX,	      "vertexX/F");
     pTree->Branch("vertexY",	   &fVertexY,	      "vertexY/F");
     pTree->Branch("vertexZ",	   &fVertexZ,	      "vertexZ/F");
     pTree->Branch("nContributors",&fNofContributors, "nContributors/I");
     pTree->Branch("vertexStatus", &fVertexStatus,    "vertexStatus/I");
     if(fFillV0==kTRUE) pTree->Branch("V0", &fNofV0s, "V0/I");

     int i=0;
     // FIXME: this is a bit ugly since type 'f' and 'i' are specified
     // explicitely. Would be better to use a function like
     // AliHLTGlobalHistoVariables::GetType but could not get this working

     for(i=0; i<fTrackVariables.Variables(); i++){
         TString specifier=fTrackVariables.GetKey(i);
         float* pArray=fTrackVariables.GetArray(specifier);
         specifier+="[trackcount]/f";
         pTree->Branch(fTrackVariables.GetKey(i), pArray, specifier.Data());
     }
     for(i=0; i<fTrackVariablesInt.Variables(); i++){
         TString specifier=fTrackVariablesInt.GetKey(i);
         int* pArray=fTrackVariablesInt.GetArray(specifier);
         specifier+="[trackcount]/i";
         pTree->Branch(fTrackVariablesInt.GetKey(i), pArray, specifier.Data());
     }
     if(fFillV0==kTRUE){
        for(i=0; i<fV0Variables.Variables(); i++){
            TString specifier=fV0Variables.GetKey(i);
            float* pArray=fV0Variables.GetArray(specifier);
            specifier+="[V0]/f";
            pTree->Branch(fV0Variables.GetKey(i), pArray, specifier.Data());
        }
     }
  } else {
    delete pTree;
    pTree = NULL;
  }

  return pTree;
}

void AliHLTGlobalHistoComponent::FillHistogramDefinitions(){
  /// default histogram definitions
}

int AliHLTGlobalHistoComponent::FillTree(TTree* pTree, const AliHLTComponentEventData& /*evtData*/, AliHLTComponentTriggerData& /*trigData*/ ){

  /// fill the tree from the ESD
  int iResult=0;
  if (!IsDataEvent()) return 0;

  ResetVariables();

  // fetch ESD from input stream
  const TObject *obj = GetFirstInputObject(kAliHLTAllDataTypes, "AliESDEvent");
  AliESDEvent *esd = dynamic_cast<AliESDEvent*>(const_cast<TObject*>(obj));
  esd->GetStdContent();

  // fill track variables
  fNofTracks       = esd->GetNumberOfTracks();
  fVertexX         = esd->GetPrimaryVertexTracks()->GetX();
  fVertexY         = esd->GetPrimaryVertexTracks()->GetY();
  fVertexZ         = esd->GetPrimaryVertexTracks()->GetZ();
  fNofContributors = esd->GetPrimaryVertexTracks()->GetNContributors();
  fVertexStatus    = esd->GetPrimaryVertexTracks()->GetStatus();
  fNofV0s          = esd->GetNumberOfV0s();

  if(fFillV0==kTRUE && (fNofV0s > fMaxV0Count)){
     HLTWarning("Found V0s are %d, while component argument is %d, the respective TTree branch is not filled properly. Need to reconfigure.\n", fNofV0s, fMaxV0Count);
  }

  for(int i=0; i<fNofTracks; i++){
      AliESDtrack *esdTrack = esd->GetTrack(i);
      if (!esdTrack) continue;

      Float_t DCAr, DCAz = -99;
      esdTrack->GetImpactParametersTPC(DCAr, DCAz);

      fTrackVariables.Fill("Track_pt"	     , esdTrack->Pt()			   );
      fTrackVariables.Fill("Track_phi"       , esdTrack->Phi()*TMath::RadToDeg()   );
      fTrackVariables.Fill("Track_eta"       , esdTrack->Eta()   		   );
      fTrackVariables.Fill("Track_p"	     , esdTrack->P()			   );
      fTrackVariables.Fill("Track_theta"     , esdTrack->Theta()*TMath::RadToDeg() );
      fTrackVariables.Fill("Track_TPCclus"   , esdTrack->GetTPCNcls()		   );
      fTrackVariables.Fill("Track_ITSclus"   , esdTrack->GetNcls(0)		   );
      fTrackVariables.Fill("Track_status"    , esdTrack->GetStatus()		   );
      fTrackVariables.Fill("Track_charge"    , esdTrack->Charge()		   );
      fTrackVariables.Fill("Track_DCAr"      , DCAr				   );
      fTrackVariables.Fill("Track_DCAz"      , DCAz				   );
      fTrackVariables.Fill("Track_dEdx"      , esdTrack->GetTPCsignal() 	   );
      fTrackVariablesInt.Fill("Track_status" , esdTrack->GetStatus()		   );
  }

  if(fFillV0==kTRUE){
     for(int i=0; i<fNofV0s; i++){
   	 AliESDv0 *esdV0 = esd->GetV0(i);
   	 if(!esdV0) continue;

   	//fV0Variables.Fill("V0_AP", ap);
   	//fV0Variables.Fill("V0_pt", pt);
   	//fV0Variables.Fill("clust1", t1->GetTPCNcls());
   	//fV0Variables.Fill("clust2", t2->GetTPCNcls());
   	//fV0Variables.Fill("dev1", dev1);
   	//fV0Variables.Fill("dev2", dev2);
   	//fV0Variables.Fill("devPrim", devPrim);
   	//fV0Variables.Fill("length", length);
   	//fV0Variables.Fill("sigmaLength", sigmaLength);
   	//fV0Variables.Fill("r", r);

     } // end of loop over V0s
  }

  if(iResult<0){
    // fill an empty event
    ResetVariables();
  }

  fEvent++;
  pTree->Fill();
  return iResult;
}

int AliHLTGlobalHistoComponent::ResetVariables(){
/// reset all filling variables
  fNofTracks=0;
  fNofV0s=0;
  fTrackVariables.ResetCount();
  fTrackVariablesInt.ResetCount();
  fV0Variables.ResetCount();
  return 0;
}

AliHLTComponentDataType AliHLTGlobalHistoComponent::GetOriginDataType() const{
// get the origin of the output data
  return kAliHLTDataTypeHistogram|kAliHLTDataOriginHLT;
}

int AliHLTGlobalHistoComponent::ScanConfigurationArgument(int argc, const char** argv){
/// inherited from AliHLTComponent, scan argument

  if (argv==NULL || argc<1) return 0;

  int i=0;
  TString argument = argv[i];

  // -max-track-count
  if(argument.CompareTo("-max-track-count")==0){
     if (++i>=argc) return -EPROTO; // missing parameter
     argument = argv[i];
     fMaxTrackCount = argument.Atoi();
     HLTInfo("got %s with parameter %s", argument.Data(), argv[i]);
     return ++i;
  }

  // -max-V0-count
  if(argument.CompareTo("-max-V0-count")==0){
     if (++i>=argc) return -EPROTO; // missing parameter
     argument = argv[i];
     fMaxV0Count = argument.Atoi();
     HLTInfo("got %s with parameter %s", argument.Data(), argv[i]);
     return ++i;
  }

  // -fill-V0
  if(argument.CompareTo("-fill-V0")==0){
     fFillV0 = kTRUE;
     HLTInfo("got %s", argument.Data());
     return ++i;
  }
  // no recognized argument, forward to base class
  return AliHLTTTreeProcessor::ScanConfigurationArgument(argc, argv);
}

int AliHLTGlobalHistoComponent::Reconfigure(const char* cdbEntry, const char* /*chainId*/){
// see header file for class documentation

  TString cdbPath;
  if (cdbEntry) {
    cdbPath=cdbEntry;
  } else {
    cdbPath="HLT/ConfigHLT/";
    cdbPath+=GetComponentID();
  }

  return ConfigureFromCDBTObjString(cdbPath.Data());
}

<commit_msg>- coverity fix 10184<commit_after>// $Id$

//**************************************************************************
//* This file is property of and copyright by the ALICE HLT Project        *
//* ALICE Experiment at CERN, All rights reserved.                         *
//*                                                                        *
//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
//*                  for The ALICE HLT Project.                            *
//*                                                                        *
//* Permission to use, copy, modify and distribute this software and its   *
//* documentation strictly for non-commercial purposes is hereby granted   *
//* without fee, provided that the above copyright notice appears in all   *
//* copies and that both the copyright notice and this permission notice   *
//* appear in the supporting documentation. The authors make no claims     *
//* about the suitability of this software for any purpose. It is          *
//* provided "as is" without express or implied warranty.                  *
//**************************************************************************

/// @file   AliHLTGlobalHistoComponent.cxx
/// @author Matthias Richter
/// @date   2010-09-16
/// @brief  A histogramming component for global ESD properties based
///         on the AliHLTTTreeProcessor

#include "AliHLTGlobalHistoComponent.h"
#include "AliESDEvent.h"
#include "AliESDv0.h"
#include "AliKFParticle.h"
#include "AliKFVertex.h"

#include "TTree.h"
#include "TString.h"
#include <cassert>

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTGlobalHistoComponent)

AliHLTGlobalHistoComponent::AliHLTGlobalHistoComponent()
  : AliHLTTTreeProcessor()
  , fEvent(0)
  , fNofTracks(0)
  , fNofV0s(0)
  , fNofContributors(0)
  , fVertexX(-99)
  , fVertexY(-99)
  , fVertexZ(-99)
  , fVertexStatus(kFALSE)
  , fMaxTrackCount(20000)
  , fMaxV0Count(1000)
  , fFillV0(kFALSE)
  , fTrackVariables()
  , fTrackVariablesInt()
  , fV0Variables()
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTGlobalHistoComponent::~AliHLTGlobalHistoComponent(){
  // see header file for class documentation
  fTrackVariables.Reset();
  fTrackVariablesInt.Reset();
  fV0Variables.Reset();
}

void AliHLTGlobalHistoComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list){
  // see header file for class documentation
  list.push_back(kAliHLTAllDataTypes);
}

AliHLTComponentDataType AliHLTGlobalHistoComponent::GetOutputDataType(){
  // see header file for class documentation
  return kAliHLTDataTypeHistogram|kAliHLTDataOriginOut;
}

TTree* AliHLTGlobalHistoComponent::CreateTree(int /*argc*/, const char** /*argv*/){
// create the tree and branches

  int iResult=0;
  TTree* pTree = new TTree("ESDproperties", "HLT ESD properties");
  if (!pTree) return NULL;

  const char* trackVariableNames = {
    // Note the black at the end of each name!
    "Track_pt "
    "Track_phi "
    "Track_eta "
    "Track_p "
    "Track_theta "
    "Track_TPCclus "
    "Track_ITSclus "
    "Track_status "
    "Track_charge "
    "Track_DCAr "
    "Track_DCAz "
    "Track_dEdx "
  };

  const char* trackIntVariableNames = {
    // Note the black at the end of each name!
    "Track_status "
  };

  const char* V0VariableNames = {
    // Note the black at the end of each name!
    "V0_AP "
    "V0_pt "
    "clust1 "
    "clust2 "
    "dev1 "
    "dev2 "
    "devPrim "
    "length "
    "sigmaLength "
    "r "
  };

  if((iResult=fTrackVariables.Init(fMaxTrackCount, trackVariableNames))<0){
    HLTError("failed to initialize internal structure for track properties (float)");
  }
  if((iResult=fTrackVariablesInt.Init(fMaxTrackCount, trackIntVariableNames))<0){
    HLTError("failed to initialize internal structure for track properties (int)");
  }
  if((iResult=fV0Variables.Init(fMaxV0Count, V0VariableNames))<0){
      HLTError("failed to initialize internal structure for V0 properties (float)");
  }

  if(iResult>=0){
     pTree->Branch("event",	   &fEvent,	      "event/I");
     pTree->Branch("trackcount",   &fNofTracks,       "trackcount/I");
     pTree->Branch("vertexX",	   &fVertexX,	      "vertexX/F");
     pTree->Branch("vertexY",	   &fVertexY,	      "vertexY/F");
     pTree->Branch("vertexZ",	   &fVertexZ,	      "vertexZ/F");
     pTree->Branch("nContributors",&fNofContributors, "nContributors/I");
     pTree->Branch("vertexStatus", &fVertexStatus,    "vertexStatus/I");
     if(fFillV0==kTRUE) pTree->Branch("V0", &fNofV0s, "V0/I");

     int i=0;
     // FIXME: this is a bit ugly since type 'f' and 'i' are specified
     // explicitely. Would be better to use a function like
     // AliHLTGlobalHistoVariables::GetType but could not get this working

     for(i=0; i<fTrackVariables.Variables(); i++){
         TString specifier=fTrackVariables.GetKey(i);
         float* pArray=fTrackVariables.GetArray(specifier);
         specifier+="[trackcount]/f";
         pTree->Branch(fTrackVariables.GetKey(i), pArray, specifier.Data());
     }
     for(i=0; i<fTrackVariablesInt.Variables(); i++){
         TString specifier=fTrackVariablesInt.GetKey(i);
         int* pArray=fTrackVariablesInt.GetArray(specifier);
         specifier+="[trackcount]/i";
         pTree->Branch(fTrackVariablesInt.GetKey(i), pArray, specifier.Data());
     }
     if(fFillV0==kTRUE){
        for(i=0; i<fV0Variables.Variables(); i++){
            TString specifier=fV0Variables.GetKey(i);
            float* pArray=fV0Variables.GetArray(specifier);
            specifier+="[V0]/f";
            pTree->Branch(fV0Variables.GetKey(i), pArray, specifier.Data());
        }
     }
  } else {
    delete pTree;
    pTree = NULL;
  }

  return pTree;
}

void AliHLTGlobalHistoComponent::FillHistogramDefinitions(){
  /// default histogram definitions
}

int AliHLTGlobalHistoComponent::FillTree(TTree* pTree, const AliHLTComponentEventData& /*evtData*/, AliHLTComponentTriggerData& /*trigData*/ ){

  /// fill the tree from the ESD
  int iResult=0;
  if (!IsDataEvent()) return 0;

  ResetVariables();

  // fetch ESD from input stream
  const TObject *obj = GetFirstInputObject(kAliHLTAllDataTypes, "AliESDEvent");
  AliESDEvent *esd = dynamic_cast<AliESDEvent*>(const_cast<TObject*>(obj));
  if(!esd) return 0;
  esd->GetStdContent();

  // fill track variables
  fNofTracks       = esd->GetNumberOfTracks();
  fVertexX         = esd->GetPrimaryVertexTracks()->GetX();
  fVertexY         = esd->GetPrimaryVertexTracks()->GetY();
  fVertexZ         = esd->GetPrimaryVertexTracks()->GetZ();
  fNofContributors = esd->GetPrimaryVertexTracks()->GetNContributors();
  fVertexStatus    = esd->GetPrimaryVertexTracks()->GetStatus();
  fNofV0s          = esd->GetNumberOfV0s();

  if(fFillV0==kTRUE && (fNofV0s > fMaxV0Count)){
     HLTWarning("Found V0s are %d, while component argument is %d, the respective TTree branch is not filled properly. Need to reconfigure.\n", fNofV0s, fMaxV0Count);
  }

  for(int i=0; i<fNofTracks; i++){
      AliESDtrack *esdTrack = esd->GetTrack(i);
      if (!esdTrack) continue;

      Float_t DCAr, DCAz = -99;
      esdTrack->GetImpactParametersTPC(DCAr, DCAz);

      fTrackVariables.Fill("Track_pt"	     , esdTrack->Pt()			   );
      fTrackVariables.Fill("Track_phi"       , esdTrack->Phi()*TMath::RadToDeg()   );
      fTrackVariables.Fill("Track_eta"       , esdTrack->Eta()   		   );
      fTrackVariables.Fill("Track_p"	     , esdTrack->P()			   );
      fTrackVariables.Fill("Track_theta"     , esdTrack->Theta()*TMath::RadToDeg() );
      fTrackVariables.Fill("Track_TPCclus"   , esdTrack->GetTPCNcls()		   );
      fTrackVariables.Fill("Track_ITSclus"   , esdTrack->GetNcls(0)		   );
      fTrackVariables.Fill("Track_status"    , esdTrack->GetStatus()		   );
      fTrackVariables.Fill("Track_charge"    , esdTrack->Charge()		   );
      fTrackVariables.Fill("Track_DCAr"      , DCAr				   );
      fTrackVariables.Fill("Track_DCAz"      , DCAz				   );
      fTrackVariables.Fill("Track_dEdx"      , esdTrack->GetTPCsignal() 	   );
      fTrackVariablesInt.Fill("Track_status" , esdTrack->GetStatus()		   );
  }

  if(fFillV0==kTRUE){
     for(int i=0; i<fNofV0s; i++){
   	 AliESDv0 *esdV0 = esd->GetV0(i);
   	 if(!esdV0) continue;

   	//fV0Variables.Fill("V0_AP", ap);
   	//fV0Variables.Fill("V0_pt", pt);
   	//fV0Variables.Fill("clust1", t1->GetTPCNcls());
   	//fV0Variables.Fill("clust2", t2->GetTPCNcls());
   	//fV0Variables.Fill("dev1", dev1);
   	//fV0Variables.Fill("dev2", dev2);
   	//fV0Variables.Fill("devPrim", devPrim);
   	//fV0Variables.Fill("length", length);
   	//fV0Variables.Fill("sigmaLength", sigmaLength);
   	//fV0Variables.Fill("r", r);

     } // end of loop over V0s
  }

  if(iResult<0){
    // fill an empty event
    ResetVariables();
  }

  fEvent++;
  pTree->Fill();
  return iResult;
}

int AliHLTGlobalHistoComponent::ResetVariables(){
/// reset all filling variables
  fNofTracks=0;
  fNofV0s=0;
  fTrackVariables.ResetCount();
  fTrackVariablesInt.ResetCount();
  fV0Variables.ResetCount();
  return 0;
}

AliHLTComponentDataType AliHLTGlobalHistoComponent::GetOriginDataType() const{
// get the origin of the output data
  return kAliHLTDataTypeHistogram|kAliHLTDataOriginHLT;
}

int AliHLTGlobalHistoComponent::ScanConfigurationArgument(int argc, const char** argv){
/// inherited from AliHLTComponent, scan argument

  if (argv==NULL || argc<1) return 0;

  int i=0;
  TString argument = argv[i];

  // -max-track-count
  if(argument.CompareTo("-max-track-count")==0){
     if (++i>=argc) return -EPROTO; // missing parameter
     argument = argv[i];
     fMaxTrackCount = argument.Atoi();
     HLTInfo("got %s with parameter %s", argument.Data(), argv[i]);
     return ++i;
  }

  // -max-V0-count
  if(argument.CompareTo("-max-V0-count")==0){
     if (++i>=argc) return -EPROTO; // missing parameter
     argument = argv[i];
     fMaxV0Count = argument.Atoi();
     HLTInfo("got %s with parameter %s", argument.Data(), argv[i]);
     return ++i;
  }

  // -fill-V0
  if(argument.CompareTo("-fill-V0")==0){
     fFillV0 = kTRUE;
     HLTInfo("got %s", argument.Data());
     return ++i;
  }
  // no recognized argument, forward to base class
  return AliHLTTTreeProcessor::ScanConfigurationArgument(argc, argv);
}

int AliHLTGlobalHistoComponent::Reconfigure(const char* cdbEntry, const char* /*chainId*/){
// see header file for class documentation

  TString cdbPath;
  if (cdbEntry) {
    cdbPath=cdbEntry;
  } else {
    cdbPath="HLT/ConfigHLT/";
    cdbPath+=GetComponentID();
  }

  return ConfigureFromCDBTObjString(cdbPath.Data());
}

<|endoftext|>


<commit_before>/*
 * Copyright 2008 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
// .SECTION Thanks
// Thanks to Philippe Pebay and David Thompson from Sandia National Laboratories
// for implementing this test.

#include "vtkDoubleArray.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkPCAStatistics.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTestUtilities.h"

#include "vtksys/SystemTools.hxx"

//=============================================================================
int TestPCAStatistics( int argc, char* argv[] )
{
  char* normScheme = vtkTestUtilities::GetArgOrEnvOrDefault(
    "-normalize-covariance", argc, argv, "VTK_NORMALIZE_COVARIANCE", "None" );
  int testStatus = 0;

  /* */
  double mingledData[] =
    {
    46, 45,
    47, 49,
    46, 47,
    46, 46,
    47, 46,
    47, 49,
    49, 49,
    47, 45,
    50, 50,
    46, 46,
    51, 50,
    48, 48,
    52, 54,
    48, 47,
    52, 52,
    49, 49,
    53, 54,
    50, 50,
    53, 54,
    50, 52,
    53, 53,
    50, 51,
    54, 54,
    49, 49,
    52, 52,
    50, 51,
    52, 52,
    49, 47,
    48, 48,
    48, 50,
    46, 48,
    47, 47
    };
  int nVals = 32;

  const char m0Name[] = "M0";
  vtkDoubleArray* dataset1Arr = vtkDoubleArray::New();
  dataset1Arr->SetNumberOfComponents( 1 );
  dataset1Arr->SetName( m0Name );

  const char m1Name[] = "M1";
  vtkDoubleArray* dataset2Arr = vtkDoubleArray::New();
  dataset2Arr->SetNumberOfComponents( 1 );
  dataset2Arr->SetName( m1Name );

  const char m2Name[] = "M2";
  vtkDoubleArray* dataset3Arr = vtkDoubleArray::New();
  dataset3Arr->SetNumberOfComponents( 1 );
  dataset3Arr->SetName( m2Name );

  for ( int i = 0; i < nVals; ++ i )
    {
    int ti = i << 1;
    dataset1Arr->InsertNextValue( mingledData[ti] );
    dataset2Arr->InsertNextValue( mingledData[ti + 1] );
    dataset3Arr->InsertNextValue( i != 12 ? -1. : -1.001 );
    }

  vtkTable* datasetTable = vtkTable::New();
  datasetTable->AddColumn( dataset1Arr );
  dataset1Arr->Delete();
  datasetTable->AddColumn( dataset2Arr );
  dataset2Arr->Delete();
  datasetTable->AddColumn( dataset3Arr );
  dataset3Arr->Delete();

  // Set PCA statistics algorithm and its input data port
  vtkPCAStatistics* pcas = vtkPCAStatistics::New();

  // First verify that absence of input does not cause trouble
  cout << "## Verifying that absence of input does not cause trouble... ";
  pcas->Update();
  cout << "done.\n";

  // Prepare first test with data
  pcas->SetInput( vtkStatisticsAlgorithm::INPUT_DATA, datasetTable );
  pcas->SetNormalizationSchemeByName( normScheme );
  pcas->SetBasisSchemeByName( "FixedBasisEnergy" );
  pcas->SetFixedBasisEnergy( 1. - 1e-8 );

  datasetTable->Delete();

  // -- Select Column Pairs of Interest ( Learn Mode ) --
  pcas->SetColumnStatus( m0Name, 1 );
  pcas->SetColumnStatus( m1Name, 1 );
  pcas->RequestSelectedColumns();
  pcas->ResetAllColumnStates();
  pcas->SetColumnStatus( m0Name, 1 );
  pcas->SetColumnStatus( m1Name, 1 );
  pcas->SetColumnStatus( m2Name, 1 );
  pcas->SetColumnStatus( m2Name, 0 );
  pcas->SetColumnStatus( m2Name, 1 );
  pcas->RequestSelectedColumns();
  pcas->RequestSelectedColumns(); // Try a duplicate entry. This should have no effect.
  pcas->SetColumnStatus( m0Name, 0 );
  pcas->SetColumnStatus( m2Name, 0 );
  pcas->SetColumnStatus( "Metric 3", 1 ); // An invalid name. This should result in a request for metric 1's self-correlation.
  // pcas->RequestSelectedColumns(); will get called in RequestData()

  // -- Test Learn Mode --
  pcas->SetLearnOption( true );
  pcas->SetDeriveOption( true );
  pcas->SetAssessOption( false );

  pcas->Update();
  vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast( pcas->GetOutputDataObject( vtkStatisticsAlgorithm::OUTPUT_MODEL ) );
  for ( unsigned int b = 0; b < outputMetaDS->GetNumberOfBlocks(); ++ b )
    {
    vtkTable* outputMeta = vtkTable::SafeDownCast( outputMetaDS->GetBlock( b ) );

    if ( b == 0 )
      {
      cout << "Primary Model\n";
      }
    else
      {
      cout << "Derived Model " << ( b - 1 ) << "\n";
      }

    outputMeta->Dump();
    }

  // -- Test Assess Mode --
  vtkMultiBlockDataSet* paramsTables = vtkMultiBlockDataSet::New();
  paramsTables->ShallowCopy( outputMetaDS );

  pcas->SetInput( vtkStatisticsAlgorithm::INPUT_MODEL, paramsTables );
  paramsTables->Delete();

  // Test Assess only (Do not recalculate nor rederive a model)
  // Use SetParameter method
  pcas->SetParameter( "Learn", 0, false );
  pcas->SetParameter( "Derive", 0, false );
  pcas->SetParameter( "Assess", 0, true );
  pcas->Update();

  vtkTable* outputData = pcas->GetOutput();
  outputData->Dump();

  pcas->Delete();
  delete [] normScheme;

  return testStatus;
}
<commit_msg>ENH: extended test (for Test option) and fixed older stuff in it.<commit_after>/*
 * Copyright 2008 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
// .SECTION Thanks
// Thanks to Philippe Pebay and David Thompson from Sandia National Laboratories
// for implementing this test.

#include "vtkDoubleArray.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkPCAStatistics.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTestUtilities.h"

#include "vtksys/SystemTools.hxx"

//=============================================================================
int TestPCAStatistics( int argc, char* argv[] )
{
  char* normScheme = vtkTestUtilities::GetArgOrEnvOrDefault(
    "-normalize-covariance", argc, argv, "VTK_NORMALIZE_COVARIANCE", "None" );
  int testStatus = 0;

  /* */
  double mingledData[] =
    {
    46, 45,
    47, 49,
    46, 47,
    46, 46,
    47, 46,
    47, 49,
    49, 49,
    47, 45,
    50, 50,
    46, 46,
    51, 50,
    48, 48,
    52, 54,
    48, 47,
    52, 52,
    49, 49,
    53, 54,
    50, 50,
    53, 54,
    50, 52,
    53, 53,
    50, 51,
    54, 54,
    49, 49,
    52, 52,
    50, 51,
    52, 52,
    49, 47,
    48, 48,
    48, 50,
    46, 48,
    47, 47
    };
  int nVals = 32;

  const char m0Name[] = "M0";
  vtkDoubleArray* dataset1Arr = vtkDoubleArray::New();
  dataset1Arr->SetNumberOfComponents( 1 );
  dataset1Arr->SetName( m0Name );

  const char m1Name[] = "M1";
  vtkDoubleArray* dataset2Arr = vtkDoubleArray::New();
  dataset2Arr->SetNumberOfComponents( 1 );
  dataset2Arr->SetName( m1Name );

  const char m2Name[] = "M2";
  vtkDoubleArray* dataset3Arr = vtkDoubleArray::New();
  dataset3Arr->SetNumberOfComponents( 1 );
  dataset3Arr->SetName( m2Name );

  for ( int i = 0; i < nVals; ++ i )
    {
    int ti = i << 1;
    dataset1Arr->InsertNextValue( mingledData[ti] );
    dataset2Arr->InsertNextValue( mingledData[ti + 1] );
    dataset3Arr->InsertNextValue( i != 12 ? -1. : -1.001 );
    }

  vtkTable* datasetTable = vtkTable::New();
  datasetTable->AddColumn( dataset1Arr );
  dataset1Arr->Delete();
  datasetTable->AddColumn( dataset2Arr );
  dataset2Arr->Delete();
  datasetTable->AddColumn( dataset3Arr );
  dataset3Arr->Delete();

  // Set PCA statistics algorithm and its input data port
  vtkPCAStatistics* pcas = vtkPCAStatistics::New();

  // First verify that absence of input does not cause trouble
  cout << "## Verifying that absence of input does not cause trouble... ";
  pcas->Update();
  cout << "done.\n";

  // Prepare first test with data
  pcas->SetInput( vtkStatisticsAlgorithm::INPUT_DATA, datasetTable );
  pcas->SetNormalizationSchemeByName( normScheme );
  pcas->SetBasisSchemeByName( "FixedBasisEnergy" );
  pcas->SetFixedBasisEnergy( 1. - 1e-8 );

  datasetTable->Delete();

  // -- Select Column Pairs of Interest ( Learn Mode ) --
  pcas->SetColumnStatus( m0Name, 1 );
  pcas->SetColumnStatus( m1Name, 1 );
  pcas->RequestSelectedColumns();
  pcas->ResetAllColumnStates();
  pcas->SetColumnStatus( m0Name, 1 );
  pcas->SetColumnStatus( m1Name, 1 );
  pcas->SetColumnStatus( m2Name, 1 );
  pcas->SetColumnStatus( m2Name, 0 );
  pcas->SetColumnStatus( m2Name, 1 );
  pcas->RequestSelectedColumns();
  pcas->RequestSelectedColumns(); // Try a duplicate entry. This should have no effect.
  pcas->SetColumnStatus( m0Name, 0 );
  pcas->SetColumnStatus( m2Name, 0 );
  pcas->SetColumnStatus( "Metric 3", 1 ); // An invalid name. This should result in a request for metric 1's self-correlation.
  // pcas->RequestSelectedColumns(); will get called in RequestData()

  // Test all options but Assess
  pcas->SetLearnOption( true );
  pcas->SetDeriveOption( true );
  pcas->SetTestOption( true );
  pcas->SetAssessOption( false );
  pcas->Update();

  vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast( pcas->GetOutputDataObject( vtkStatisticsAlgorithm::OUTPUT_MODEL ) );
  vtkTable* outputTest = pcas->GetOutput( vtkStatisticsAlgorithm::OUTPUT_TEST );

  cout << "## Calculated the following statistics for first data set:\n";
  for ( unsigned int b = 0; b < outputMetaDS->GetNumberOfBlocks(); ++ b )
    {
    vtkTable* outputMeta = vtkTable::SafeDownCast( outputMetaDS->GetBlock( b ) );

    if ( b == 0 )
      {
      cout << "Primary Statistics\n";
      }
    else
      {
      cout << "Derived Statistics " << ( b - 1 ) << "\n";
      }

    outputMeta->Dump();
    }

  // Check some results of the Test option
  cout << "\n## Calculated the following Jarque-Bera-Srivastava statistics:\n";
  for ( vtkIdType r = 0; r < outputTest->GetNumberOfRows(); ++ r )
    {
    cout << "   ";
    for ( int i = 0; i < outputTest->GetNumberOfColumns(); ++ i )
      {
      cout << outputTest->GetColumnName( i )
           << "="
           << outputTest->GetValue( r, i ).ToString()
           << "  ";
      }

    cout << "\n";
    }

  // -- Test Assess Mode --
  vtkMultiBlockDataSet* paramsTables = vtkMultiBlockDataSet::New();
  paramsTables->ShallowCopy( outputMetaDS );

  pcas->SetInput( vtkStatisticsAlgorithm::INPUT_MODEL, paramsTables );
  paramsTables->Delete();

  // Test Assess only (Do not recalculate nor rederive nor retest a model)
  pcas->SetLearnOption( false );
  pcas->SetDeriveOption( false );
  pcas->SetTestOption( false );
  pcas->SetAssessOption( true );
  pcas->Update();

  cout << "\n## Assessment results:\n";
  vtkTable* outputData = pcas->GetOutput();
  outputData->Dump();

  pcas->Delete();
  delete [] normScheme;

  return testStatus;
}
<|endoftext|>


<commit_before>/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*             ********   ***                                 SparseLib++    */
/*          *******  **  ***       ***      ***                              */
/*           *****      ***     ******** ********                            */
/*            *****    ***     ******** ********              R. Pozo        */
/*       **  *******  ***   **   ***      ***                 K. Remington   */
/*        ********   ********                                 A. Lumsdaine   */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*                                                                           */
/*                                                                           */
/*                     SparseLib++ : Sparse Matrix Library                   */
/*                                                                           */
/*               National Institute of Standards and Technology              */
/*                        University of Notre Dame                           */
/*              Authors: R. Pozo, K. Remington, A. Lumsdaine                 */
/*                                                                           */
/*                                 NOTICE                                    */
/*                                                                           */
/* Permission to use, copy, modify, and distribute this software and         */
/* its documentation for any purpose and without fee is hereby granted       */
/* provided that the above notice appear in all copies and supporting        */
/* documentation.                                                            */
/*                                                                           */
/* Neither the Institutions (National Institute of Standards and Technology, */
/* University of Notre Dame) nor the Authors make any representations about  */
/* the suitability of this software for any purpose.  This software is       */
/* provided ``as is'' without expressed or implied warranty.                 */
/*                                                                           */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

// An adaptation of Schmidt's new quicksort (taken from GNU emacs)
// for MV++
// by Andrew Lumsdaine

#include "qsort_double.h"

#ifdef sparc
#include <alloca.h>
#endif

// Invoke the < comparison function
#define CMP(A, B) ( (A) < (B) )

// swap two items
//
static inline void SWAP_double(double & A, double & B)
{
  double tmp = A; A = B; B = tmp;

}

static inline void swap_int(int & a, int & b)
{
  int tmp = a; a = b; b = tmp;

}

// This should be replaced by a standard ANSI macro.
#define BYTES_PER_WORD 8

/* The next 4 #defines implement a very fast in-line stack abstraction. */
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long) )
#define PUSH(LOW, HIGH) do {top->lo = LOW; top++->hi = HIGH; } while( 0 )
#define POP(LOW, HIGH)  do {LOW = (--top)->lo; HIGH = top->hi; } while( 0 )
#define STACK_NOT_EMPTY (stack < top)

/* Discontinue quicksort algorithm when partition gets below this size.
   This particular magic number was chosen to work best on a Sun 4/260. */
#define MAX_THRESH 4

/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
  {
  int lo;
  int hi;
  } stack_node;

/* Order size using quicksort.  This implementation incorporates
   four optimizations discussed in Sedgewick:

   1. Non-recursive, using an explicit stack of pointer that store the
      next array partition to sort.  To save time, this maximum amount
      of space required to store an array of MAX_INT is allocated on the
      stack.  Assuming a 32-bit integer, this needs only 32 *
      sizeof (stack_node) == 136 bits.  Pretty cheap, actually.

   2. Chose the pivot element using a median-of-three decision tree.
      This reduces the probability of selecting a bad pivot value and
      eliminates certain extraneous comparisons.

   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
      insertion sort to order the MAX_THRESH items within each partition.
      This is a big win, since insertion sort is faster for small, mostly
      sorted array segments.

   4. The larger of the two sub-partitions is always pushed onto the
      stack first, with the algorithm then concentrating on the
      smaller partition.  This *guarantees* no more than log (n)
      stack size is needed (actually O(1) in this case)! */

int QSort(VECTOR_double& v, int base_ptr, int total_elems)
{
  double pivot_buffer;

  if( total_elems > MAX_THRESH )
    {

    int lo = base_ptr;
    int hi = lo + total_elems - 1;

    stack_node  stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
    stack_node *top = stack + 1;

    while( STACK_NOT_EMPTY )
      {
      int left_ptr;
      int right_ptr;
        {

          {

          /* Select median value from among LO, MID, and HI. Rearrange
             LO and HI so the three values are sorted. This lowers the
             probability of picking a pathological pivot value and
             skips a comparison for both the LEFT_PTR and RIGHT_PTR. */

          int mid = lo + (hi - lo) / 2;

          if( CMP(v[mid], v[lo]) )
            {
            SWAP_double(v[mid], v[lo]);
            }
          if( CMP(v[hi], v[mid]) )
            {
            SWAP_double(v[hi], v[mid]);
            }
          else
            {
            goto jump_over;
            }

          if( CMP(v[mid], v[lo]) )
            {
            SWAP_double(v[mid], v[lo]);
            }

jump_over:

          pivot_buffer = v[mid];
          }

        left_ptr  = lo + 1;
        right_ptr = hi - 1;

        /* Here's the famous ``collapse the walls'' section of quicksort.
           Gotta like those tight inner loops!  They are the main reason
           that this algorithm runs much faster than others. */
        do
          {
          while( CMP(v[left_ptr], pivot_buffer) )
            {
            left_ptr++;
            }

          while( CMP(pivot_buffer, v[right_ptr]) )
            {
            right_ptr--;
            }

          if( left_ptr < right_ptr )
            {
            SWAP_double(v[left_ptr], v[right_ptr]);
            left_ptr++;
            right_ptr--;
            }
          else if( left_ptr == right_ptr )
            {
            left_ptr++;
            right_ptr--;
            break;
            }
          }
        while( left_ptr <= right_ptr );
        }

      /* Set up pointers for next iteration.  First determine whether
     left and right partitions are below the threshold size. If so,
     ignore one or both.  Otherwise, push the larger partition's
     bounds on the stack and continue sorting the smaller one. */

      if( (right_ptr - lo) <= MAX_THRESH )
        {
        if( (hi - left_ptr) <= MAX_THRESH )
          {
          POP(lo, hi);
          }
        else
          {
          lo = left_ptr;
          }
        }
      else if( (hi - left_ptr) <= MAX_THRESH )
        {
        hi = right_ptr;
        }
      else if( (right_ptr - lo) > (hi - left_ptr) )
        {
        PUSH(lo, right_ptr);
        lo = left_ptr;
        }
      else
        {
        PUSH(left_ptr, hi);
        hi = right_ptr;
        }
      }
    }

  /* Once the BASE_PTR array is partially sorted by quicksort the rest
     is completely sorted using insertion sort, since this is efficient
     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
     of the array to sort, and END_PTR points at the very last element in
     the array (*not* one beyond it!). */

#define MIN(X, Y) ( (X) < (Y) ? (X) : (Y) )

    {
    int end_ptr = base_ptr + total_elems - 1;
    int run_ptr;
    int tmp_ptr = base_ptr;
    int thresh = MIN(end_ptr, base_ptr + MAX_THRESH);
    for( run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++ )
      {
      if( CMP(v[run_ptr], v[tmp_ptr]) )
        {
        tmp_ptr = run_ptr;
        }
      }

    if( tmp_ptr != base_ptr )
      {
      SWAP_double(v[tmp_ptr], v[base_ptr]);
      }
    for( run_ptr = base_ptr + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; )
      {

      while( CMP(v[run_ptr], v[tmp_ptr -= 1]) )
        {
        ;
        }

      if( (tmp_ptr += 1) != run_ptr )
        {
        int trav;
        for( trav = run_ptr + 1; --trav >= run_ptr; )
          {
          double c;
          c = v[trav];
          int hi, lo;
          for( hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo )
            {
            v[hi] = v[lo];
            }
          v[hi] = c;
          }
        }
      }
    }

  return 1;
}

int QSort(VECTOR_int & v, VECTOR_double& x, int base_ptr, int total_elems)
{
  int    pivot_buffer;
  double pixot_buffer;

  if( total_elems > MAX_THRESH )
    {

    int lo = base_ptr;
    int hi = lo + total_elems - 1;

    stack_node  stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
    stack_node *top = stack + 1;

    while( STACK_NOT_EMPTY )
      {
      int left_ptr;
      int right_ptr;
        {

          {

          /* Select median value from among LO, MID, and HI. Rearrange
             LO and HI so the three values are sorted. This lowers the
             probability of picking a pathological pivot value and
             skips a comparison for both the LEFT_PTR and RIGHT_PTR. */

          int mid = lo + (hi - lo) / 2;

          if( CMP(v[mid], v[lo]) )
            {
            swap_int(v[mid], v[lo]);
            SWAP_double(x[mid], x[lo]);
            }
          if( CMP(v[hi], v[mid]) )
            {
            swap_int(v[hi], v[mid]);
            SWAP_double(x[hi], x[mid]);
            }
          else
            {
            goto jump_over;
            }

          if( CMP(v[mid], v[lo]) )
            {
            swap_int(v[mid], v[lo]);
            SWAP_double(x[mid], x[lo]);
            }

jump_over:

          pivot_buffer = v[mid];
          pixot_buffer = x[mid];
          }

        left_ptr  = lo + 1;
        right_ptr = hi - 1;

        /* Here's the famous ``collapse the walls'' section of quicksort.
           Gotta like those tight inner loops!  They are the main reason
           that this algorithm runs much faster than others. */
        do
          {
          while( CMP(v[left_ptr], pivot_buffer) )
            {
            left_ptr++;
            }

          while( CMP(pivot_buffer, v[right_ptr]) )
            {
            right_ptr--;
            }

          if( left_ptr < right_ptr )
            {
            swap_int(v[left_ptr], v[right_ptr]);
            SWAP_double(x[left_ptr], x[right_ptr]);
            left_ptr++;
            right_ptr--;
            }
          else if( left_ptr == right_ptr )
            {
            left_ptr++;
            right_ptr--;
            break;
            }
          }
        while( left_ptr <= right_ptr );
        }

      /* Set up pointers for next iteration.  First determine whether
     left and right partitions are below the threshold size. If so,
     ignore one or both.  Otherwise, push the larger partition's
     bounds on the stack and continue sorting the smaller one. */

      if( (right_ptr - lo) <= MAX_THRESH )
        {
        if( (hi - left_ptr) <= MAX_THRESH )
          {
          POP(lo, hi);
          }
        else
          {
          lo = left_ptr;
          }
        }
      else if( (hi - left_ptr) <= MAX_THRESH )
        {
        hi = right_ptr;
        }
      else if( (right_ptr - lo) > (hi - left_ptr) )
        {
        PUSH(lo, right_ptr);
        lo = left_ptr;
        }
      else
        {
        PUSH(left_ptr, hi);
        hi = right_ptr;
        }
      }
    }

  /* Once the BASE_PTR array is partially sorted by quicksort the rest
     is completely sorted using insertion sort, since this is efficient
     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
     of the array to sort, and END_PTR points at the very last element in
     the array (*not* one beyond it!). */

#define MIN(X, Y) ( (X) < (Y) ? (X) : (Y) )

    {
    int end_ptr = base_ptr + total_elems - 1;
    int run_ptr;
    int tmp_ptr = base_ptr;
    int thresh = MIN(end_ptr, base_ptr + MAX_THRESH);
    for( run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++ )
      {
      if( CMP(v[run_ptr], v[tmp_ptr]) )
        {
        tmp_ptr = run_ptr;
        }
      }

    if( tmp_ptr != base_ptr )
      {
      swap_int(v[tmp_ptr], v[base_ptr]);
      SWAP_double(x[tmp_ptr], x[base_ptr]);
      }
    for( run_ptr = base_ptr + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; )
      {

      while( CMP(v[run_ptr], v[tmp_ptr -= 1]) )
        {
        ;
        }

      if( (tmp_ptr += 1) != run_ptr )
        {
        int trav;
        for( trav = run_ptr + 1; --trav >= run_ptr; )
          {
          int    c;
          double d;
          c = v[trav];
          d = x[trav];
          int hi, lo;
          for( hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo )
            {
            v[hi] = v[lo];
            x[hi] = x[lo];
            }
          v[hi] = c;
          x[hi] = d;
          }
        }
      }
    }

  return 1;
}
<commit_msg>COMP: Fix -Wunused-but-set-variable in qsort_double.cxx<commit_after>/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*             ********   ***                                 SparseLib++    */
/*          *******  **  ***       ***      ***                              */
/*           *****      ***     ******** ********                            */
/*            *****    ***     ******** ********              R. Pozo        */
/*       **  *******  ***   **   ***      ***                 K. Remington   */
/*        ********   ********                                 A. Lumsdaine   */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*                                                                           */
/*                                                                           */
/*                     SparseLib++ : Sparse Matrix Library                   */
/*                                                                           */
/*               National Institute of Standards and Technology              */
/*                        University of Notre Dame                           */
/*              Authors: R. Pozo, K. Remington, A. Lumsdaine                 */
/*                                                                           */
/*                                 NOTICE                                    */
/*                                                                           */
/* Permission to use, copy, modify, and distribute this software and         */
/* its documentation for any purpose and without fee is hereby granted       */
/* provided that the above notice appear in all copies and supporting        */
/* documentation.                                                            */
/*                                                                           */
/* Neither the Institutions (National Institute of Standards and Technology, */
/* University of Notre Dame) nor the Authors make any representations about  */
/* the suitability of this software for any purpose.  This software is       */
/* provided ``as is'' without expressed or implied warranty.                 */
/*                                                                           */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

// An adaptation of Schmidt's new quicksort (taken from GNU emacs)
// for MV++
// by Andrew Lumsdaine

#include "qsort_double.h"

#ifdef sparc
#include <alloca.h>
#endif

// Invoke the < comparison function
#define CMP(A, B) ( (A) < (B) )

// swap two items
//
static inline void SWAP_double(double & A, double & B)
{
  double tmp = A; A = B; B = tmp;

}

static inline void swap_int(int & a, int & b)
{
  int tmp = a; a = b; b = tmp;

}

// This should be replaced by a standard ANSI macro.
#define BYTES_PER_WORD 8

/* The next 4 #defines implement a very fast in-line stack abstraction. */
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long) )
#define PUSH(LOW, HIGH) do {top->lo = LOW; top++->hi = HIGH; } while( 0 )
#define POP(LOW, HIGH)  do {LOW = (--top)->lo; HIGH = top->hi; } while( 0 )
#define STACK_NOT_EMPTY (stack < top)

/* Discontinue quicksort algorithm when partition gets below this size.
   This particular magic number was chosen to work best on a Sun 4/260. */
#define MAX_THRESH 4

/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
  {
  int lo;
  int hi;
  } stack_node;

/* Order size using quicksort.  This implementation incorporates
   four optimizations discussed in Sedgewick:

   1. Non-recursive, using an explicit stack of pointer that store the
      next array partition to sort.  To save time, this maximum amount
      of space required to store an array of MAX_INT is allocated on the
      stack.  Assuming a 32-bit integer, this needs only 32 *
      sizeof (stack_node) == 136 bits.  Pretty cheap, actually.

   2. Chose the pivot element using a median-of-three decision tree.
      This reduces the probability of selecting a bad pivot value and
      eliminates certain extraneous comparisons.

   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
      insertion sort to order the MAX_THRESH items within each partition.
      This is a big win, since insertion sort is faster for small, mostly
      sorted array segments.

   4. The larger of the two sub-partitions is always pushed onto the
      stack first, with the algorithm then concentrating on the
      smaller partition.  This *guarantees* no more than log (n)
      stack size is needed (actually O(1) in this case)! */

int QSort(VECTOR_double& v, int base_ptr, int total_elems)
{
  double pivot_buffer;

  if( total_elems > MAX_THRESH )
    {

    int lo = base_ptr;
    int hi = lo + total_elems - 1;

    stack_node  stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
    stack_node *top = stack + 1;

    while( STACK_NOT_EMPTY )
      {
      int left_ptr;
      int right_ptr;
        {

          {

          /* Select median value from among LO, MID, and HI. Rearrange
             LO and HI so the three values are sorted. This lowers the
             probability of picking a pathological pivot value and
             skips a comparison for both the LEFT_PTR and RIGHT_PTR. */

          int mid = lo + (hi - lo) / 2;

          if( CMP(v[mid], v[lo]) )
            {
            SWAP_double(v[mid], v[lo]);
            }
          if( CMP(v[hi], v[mid]) )
            {
            SWAP_double(v[hi], v[mid]);
            }
          else
            {
            goto jump_over;
            }

          if( CMP(v[mid], v[lo]) )
            {
            SWAP_double(v[mid], v[lo]);
            }

jump_over:

          pivot_buffer = v[mid];
          }

        left_ptr  = lo + 1;
        right_ptr = hi - 1;

        /* Here's the famous ``collapse the walls'' section of quicksort.
           Gotta like those tight inner loops!  They are the main reason
           that this algorithm runs much faster than others. */
        do
          {
          while( CMP(v[left_ptr], pivot_buffer) )
            {
            left_ptr++;
            }

          while( CMP(pivot_buffer, v[right_ptr]) )
            {
            right_ptr--;
            }

          if( left_ptr < right_ptr )
            {
            SWAP_double(v[left_ptr], v[right_ptr]);
            left_ptr++;
            right_ptr--;
            }
          else if( left_ptr == right_ptr )
            {
            left_ptr++;
            right_ptr--;
            break;
            }
          }
        while( left_ptr <= right_ptr );
        }

      /* Set up pointers for next iteration.  First determine whether
     left and right partitions are below the threshold size. If so,
     ignore one or both.  Otherwise, push the larger partition's
     bounds on the stack and continue sorting the smaller one. */

      if( (right_ptr - lo) <= MAX_THRESH )
        {
        if( (hi - left_ptr) <= MAX_THRESH )
          {
          POP(lo, hi);
          }
        else
          {
          lo = left_ptr;
          }
        }
      else if( (hi - left_ptr) <= MAX_THRESH )
        {
        hi = right_ptr;
        }
      else if( (right_ptr - lo) > (hi - left_ptr) )
        {
        PUSH(lo, right_ptr);
        lo = left_ptr;
        }
      else
        {
        PUSH(left_ptr, hi);
        hi = right_ptr;
        }
      }
    }

  /* Once the BASE_PTR array is partially sorted by quicksort the rest
     is completely sorted using insertion sort, since this is efficient
     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
     of the array to sort, and END_PTR points at the very last element in
     the array (*not* one beyond it!). */

#define MIN(X, Y) ( (X) < (Y) ? (X) : (Y) )

    {
    int end_ptr = base_ptr + total_elems - 1;
    int run_ptr;
    int tmp_ptr = base_ptr;
    int thresh = MIN(end_ptr, base_ptr + MAX_THRESH);
    for( run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++ )
      {
      if( CMP(v[run_ptr], v[tmp_ptr]) )
        {
        tmp_ptr = run_ptr;
        }
      }

    if( tmp_ptr != base_ptr )
      {
      SWAP_double(v[tmp_ptr], v[base_ptr]);
      }
    for( run_ptr = base_ptr + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; )
      {

      while( CMP(v[run_ptr], v[tmp_ptr -= 1]) )
        {
        ;
        }

      if( (tmp_ptr += 1) != run_ptr )
        {
        int trav;
        for( trav = run_ptr + 1; --trav >= run_ptr; )
          {
          double c;
          c = v[trav];
          int hi, lo;
          for( hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo )
            {
            v[hi] = v[lo];
            }
          v[hi] = c;
          }
        }
      }
    }

  return 1;
}

int QSort(VECTOR_int & v, VECTOR_double& x, int base_ptr, int total_elems)
{
  int    pivot_buffer;

  if( total_elems > MAX_THRESH )
    {

    int lo = base_ptr;
    int hi = lo + total_elems - 1;

    stack_node  stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
    stack_node *top = stack + 1;

    while( STACK_NOT_EMPTY )
      {
      int left_ptr;
      int right_ptr;
        {

          {

          /* Select median value from among LO, MID, and HI. Rearrange
             LO and HI so the three values are sorted. This lowers the
             probability of picking a pathological pivot value and
             skips a comparison for both the LEFT_PTR and RIGHT_PTR. */

          int mid = lo + (hi - lo) / 2;

          if( CMP(v[mid], v[lo]) )
            {
            swap_int(v[mid], v[lo]);
            SWAP_double(x[mid], x[lo]);
            }
          if( CMP(v[hi], v[mid]) )
            {
            swap_int(v[hi], v[mid]);
            SWAP_double(x[hi], x[mid]);
            }
          else
            {
            goto jump_over;
            }

          if( CMP(v[mid], v[lo]) )
            {
            swap_int(v[mid], v[lo]);
            SWAP_double(x[mid], x[lo]);
            }

jump_over:

          pivot_buffer = v[mid];
          }

        left_ptr  = lo + 1;
        right_ptr = hi - 1;

        /* Here's the famous ``collapse the walls'' section of quicksort.
           Gotta like those tight inner loops!  They are the main reason
           that this algorithm runs much faster than others. */
        do
          {
          while( CMP(v[left_ptr], pivot_buffer) )
            {
            left_ptr++;
            }

          while( CMP(pivot_buffer, v[right_ptr]) )
            {
            right_ptr--;
            }

          if( left_ptr < right_ptr )
            {
            swap_int(v[left_ptr], v[right_ptr]);
            SWAP_double(x[left_ptr], x[right_ptr]);
            left_ptr++;
            right_ptr--;
            }
          else if( left_ptr == right_ptr )
            {
            left_ptr++;
            right_ptr--;
            break;
            }
          }
        while( left_ptr <= right_ptr );
        }

      /* Set up pointers for next iteration.  First determine whether
     left and right partitions are below the threshold size. If so,
     ignore one or both.  Otherwise, push the larger partition's
     bounds on the stack and continue sorting the smaller one. */

      if( (right_ptr - lo) <= MAX_THRESH )
        {
        if( (hi - left_ptr) <= MAX_THRESH )
          {
          POP(lo, hi);
          }
        else
          {
          lo = left_ptr;
          }
        }
      else if( (hi - left_ptr) <= MAX_THRESH )
        {
        hi = right_ptr;
        }
      else if( (right_ptr - lo) > (hi - left_ptr) )
        {
        PUSH(lo, right_ptr);
        lo = left_ptr;
        }
      else
        {
        PUSH(left_ptr, hi);
        hi = right_ptr;
        }
      }
    }

  /* Once the BASE_PTR array is partially sorted by quicksort the rest
     is completely sorted using insertion sort, since this is efficient
     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
     of the array to sort, and END_PTR points at the very last element in
     the array (*not* one beyond it!). */

#define MIN(X, Y) ( (X) < (Y) ? (X) : (Y) )

    {
    int end_ptr = base_ptr + total_elems - 1;
    int run_ptr;
    int tmp_ptr = base_ptr;
    int thresh = MIN(end_ptr, base_ptr + MAX_THRESH);
    for( run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++ )
      {
      if( CMP(v[run_ptr], v[tmp_ptr]) )
        {
        tmp_ptr = run_ptr;
        }
      }

    if( tmp_ptr != base_ptr )
      {
      swap_int(v[tmp_ptr], v[base_ptr]);
      SWAP_double(x[tmp_ptr], x[base_ptr]);
      }
    for( run_ptr = base_ptr + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; )
      {

      while( CMP(v[run_ptr], v[tmp_ptr -= 1]) )
        {
        ;
        }

      if( (tmp_ptr += 1) != run_ptr )
        {
        int trav;
        for( trav = run_ptr + 1; --trav >= run_ptr; )
          {
          int    c;
          double d;
          c = v[trav];
          d = x[trav];
          int hi, lo;
          for( hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo )
            {
            v[hi] = v[lo];
            x[hi] = x[lo];
            }
          v[hi] = c;
          x[hi] = d;
          }
        }
      }
    }

  return 1;
}
<|endoftext|>