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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center, 
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without 
even the implied warranty of MERCHANTABILITY or FITNESS FOR 
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkImage.h"

#include "mitkImageStatisticsHolder.h"
#include "mitkPixelTypeMultiplex.h"

#include <vtkImageData.h>

#define FILL_C_ARRAY( _arr, _size, _value) for(unsigned int i=0u; i<_size; i++) \
{ _arr[i] = _value; }


mitk::Image::Image() : 
m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL),
  m_ImageStatistics(NULL)
{
   m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS];
   FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u);

   m_Initialized = false;
}

mitk::Image::Image(const Image &other) : SlicedData(other), m_Dimension(0), m_Dimensions(NULL),
m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL)
{
  m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS];
  FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u);

  this->Initialize( other.GetPixelType(), other.GetDimension(), other.GetDimensions());

  //Since the above called "Initialize" method doesn't take the geometry into account we need to set it
  //here manually
  this->SetGeometry(dynamic_cast<mitk::Geometry3D*>(other.GetGeometry()->Clone().GetPointer()));

  if (this->GetDimension() > 3)
  {
    const unsigned int time_steps = this->GetDimension(3);

    for (unsigned int i = 0u; i < time_steps; ++i)
    {
      ImageDataItemPointer volume = const_cast<Image&>(other).GetVolumeData(i);

      this->SetVolume(volume->GetData(), i);
    }
  }
  else
  {
    ImageDataItemPointer volume = const_cast<Image&>(other).GetVolumeData(0);

    this->SetVolume(volume->GetData(), 0);
  }
}

mitk::Image::~Image()
{
  Clear();
  m_ReferenceCountLock.Lock();
  m_ReferenceCount = 3;
  m_ReferenceCountLock.Unlock();
  m_ReferenceCountLock.Lock();
  m_ReferenceCount = 0;
  m_ReferenceCountLock.Unlock();
  if(m_OffsetTable != NULL)
    delete [] m_OffsetTable;

  if(m_ImageStatistics != NULL)
    delete m_ImageStatistics;
}

const mitk::PixelType mitk::Image::GetPixelType(int n) const
{
  return this->m_ImageDescriptor->GetChannelTypeById(n);
}

unsigned int mitk::Image::GetDimension() const
{
  return m_Dimension;
}

unsigned int mitk::Image::GetDimension(int i) const
{
  if((i>=0) && (i<(int)m_Dimension))
    return m_Dimensions[i];
  return 1;
}

void* mitk::Image::GetData()
{
  if(m_Initialized==false)
  {
    if(GetSource().IsNull())
      return NULL;
    if(GetSource()->Updating()==false)
      GetSource()->UpdateOutputInformation();
  }
  m_CompleteData=GetChannelData();

  // update channel's data
  // if data was not available at creation point, the m_Data of channel descriptor is NULL
  // if data present, it won't be overwritten
  m_ImageDescriptor->GetChannelDescriptor(0).SetData(m_CompleteData->GetData());

  return m_CompleteData->GetData();
}


template <class T>
void AccessPixel( const mitk::PixelType ptype, void* data, const unsigned int offset, double& value )
{
  value = 0.0;
  if( data == NULL ) return;

  if(ptype.GetBpe() != 24)
  {
    value = (double) (((T*) data)[ offset ]);
 }
  else
  {
    const unsigned int rgboffset = 3 * offset;

    double returnvalue = (((T*) data)[rgboffset ]);
    returnvalue += (((T*) data)[rgboffset + 1]);
    returnvalue += (((T*) data)[rgboffset + 2]);
    value = returnvalue;
  }

}

double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep)
{
  double value = 0;
  if (this->GetTimeSteps() < timestep)
  {
    timestep = this->GetTimeSteps();
  }

  value = 0.0;

  const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions();
  const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0);

  // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int
  // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0)
  // &&
  if ( (unsigned int)position[0] < imageDims[0] && (unsigned int)position[1] < imageDims[1] &&
       ( (imageDims[2] == 0) || (unsigned int)position[2] < imageDims[2]) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail
    /*&& (unsigned int)timestep < imageDims[3]*/ )
  {
    const unsigned int offset = position[0] + position[1]*imageDims[0] + position[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2];

    mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value );
  }

  return value;
}

double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep)
{
  double value = 0.0;
  if (this->GetTimeSteps() < timestep)
  {
    timestep = this->GetTimeSteps();
  }

  Index3D itkIndex;
  this->GetGeometry()->WorldToIndex(position, itkIndex);

  const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions();
  const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0);

  //if ( (itkIndex[0]>=0 && itkIndex[1] >=0 && itkIndex[2]>=0 && timestep>=0)
  //     &&
  // lines above taken from comparison since always true due to unsigned type
  if (((unsigned int)itkIndex[0] < imageDims[0] && 
        (unsigned int)itkIndex[1] < imageDims[1] &&
          (imageDims[2] == 0) ) || ((unsigned int)itkIndex[2] < imageDims[2])) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail
  {
    const unsigned int offset = itkIndex[0] + itkIndex[1]*imageDims[0] + itkIndex[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2];

    mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value );
  }

  return value;
}

vtkImageData* mitk::Image::GetVtkImageData(int t, int n)
{
  if(m_Initialized==false)
  {
    if(GetSource().IsNull())<commit_msg>Added negative index value checking<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center, 
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without 
even the implied warranty of MERCHANTABILITY or FITNESS FOR 
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkImage.h"

#include "mitkImageStatisticsHolder.h"
#include "mitkPixelTypeMultiplex.h"

#include <vtkImageData.h>

#define FILL_C_ARRAY( _arr, _size, _value) for(unsigned int i=0u; i<_size; i++) \
{ _arr[i] = _value; }


mitk::Image::Image() : 
m_Dimension(0), m_Dimensions(NULL), m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL),
  m_ImageStatistics(NULL)
{
   m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS];
   FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u);

   m_Initialized = false;
}

mitk::Image::Image(const Image &other) : SlicedData(other), m_Dimension(0), m_Dimensions(NULL),
m_ImageDescriptor(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_ImageStatistics(NULL)
{
  m_Dimensions = new unsigned int[MAX_IMAGE_DIMENSIONS];
  FILL_C_ARRAY( m_Dimensions, MAX_IMAGE_DIMENSIONS, 0u);

  this->Initialize( other.GetPixelType(), other.GetDimension(), other.GetDimensions());

  //Since the above called "Initialize" method doesn't take the geometry into account we need to set it
  //here manually
  this->SetGeometry(dynamic_cast<mitk::Geometry3D*>(other.GetGeometry()->Clone().GetPointer()));

  if (this->GetDimension() > 3)
  {
    const unsigned int time_steps = this->GetDimension(3);

    for (unsigned int i = 0u; i < time_steps; ++i)
    {
      ImageDataItemPointer volume = const_cast<Image&>(other).GetVolumeData(i);

      this->SetVolume(volume->GetData(), i);
    }
  }
  else
  {
    ImageDataItemPointer volume = const_cast<Image&>(other).GetVolumeData(0);

    this->SetVolume(volume->GetData(), 0);
  }
}

mitk::Image::~Image()
{
  Clear();
  m_ReferenceCountLock.Lock();
  m_ReferenceCount = 3;
  m_ReferenceCountLock.Unlock();
  m_ReferenceCountLock.Lock();
  m_ReferenceCount = 0;
  m_ReferenceCountLock.Unlock();
  if(m_OffsetTable != NULL)
    delete [] m_OffsetTable;

  if(m_ImageStatistics != NULL)
    delete m_ImageStatistics;
}

const mitk::PixelType mitk::Image::GetPixelType(int n) const
{
  return this->m_ImageDescriptor->GetChannelTypeById(n);
}

unsigned int mitk::Image::GetDimension() const
{
  return m_Dimension;
}

unsigned int mitk::Image::GetDimension(int i) const
{
  if((i>=0) && (i<(int)m_Dimension))
    return m_Dimensions[i];
  return 1;
}

void* mitk::Image::GetData()
{
  if(m_Initialized==false)
  {
    if(GetSource().IsNull())
      return NULL;
    if(GetSource()->Updating()==false)
      GetSource()->UpdateOutputInformation();
  }
  m_CompleteData=GetChannelData();

  // update channel's data
  // if data was not available at creation point, the m_Data of channel descriptor is NULL
  // if data present, it won't be overwritten
  m_ImageDescriptor->GetChannelDescriptor(0).SetData(m_CompleteData->GetData());

  return m_CompleteData->GetData();
}


template <class T>
void AccessPixel( const mitk::PixelType ptype, void* data, const unsigned int offset, double& value )
{
  value = 0.0;
  if( data == NULL ) return;

  if(ptype.GetBpe() != 24)
  {
    value = (double) (((T*) data)[ offset ]);
 }
  else
  {
    const unsigned int rgboffset = 3 * offset;

    double returnvalue = (((T*) data)[rgboffset ]);
    returnvalue += (((T*) data)[rgboffset + 1]);
    returnvalue += (((T*) data)[rgboffset + 2]);
    value = returnvalue;
  }

}

double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep)
{
  double value = 0;
  if (this->GetTimeSteps() < timestep)
  {
    timestep = this->GetTimeSteps();
  }

  value = 0.0;

  const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions();
  const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0);

  // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int
  // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0)
  // bug-11978 : we still need to catch index with negative values
  if ( position[0] < 0 ||
       position[1] < 0 ||
       position[2] < 0 )
  {
    MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ;
  }
  // check if the given position is inside the index range of the image, the 3rd dimension needs to be compared only if the dimension is not 0
  else if ( (unsigned int)position[0] >= imageDims[0] ||
            (unsigned int)position[1] >= imageDims[1] ||
            ( imageDims[2] && (unsigned int)position[2] >= imageDims[2] ))
  {
    MITK_WARN << "Given position ("<< position << ") is out of image range, returning 0." ;
  }
  else
  {
    const unsigned int offset = position[0] + position[1]*imageDims[0] + position[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2];

    mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value );
  }

  return value;
}

double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep)
{
  double value = 0.0;
  if (this->GetTimeSteps() < timestep)
  {
    timestep = this->GetTimeSteps();
  }

  Index3D itkIndex;
  this->GetGeometry()->WorldToIndex(position, itkIndex);

  const unsigned int* imageDims = this->m_ImageDescriptor->GetDimensions();
  const mitk::PixelType ptype = this->m_ImageDescriptor->GetChannelTypeById(0);

  //if ( (itkIndex[0]>=0 && itkIndex[1] >=0 && itkIndex[2]>=0 && timestep>=0)
  //     &&
  // lines above taken from comparison since always true due to unsigned type
  // bug-11978 : we still need to catch index with negative values
  if ( itkIndex[0] < 0 || itkIndex[1] < 0 || itkIndex[2] < 0 )
  {
    MITK_WARN << "Given position points transforms to a negative index value ( "<< itkIndex << ") returning 0." ;
  }
  if (((unsigned int)itkIndex[0] < imageDims[0] &&
        (unsigned int)itkIndex[1] < imageDims[1] &&
          (imageDims[2] == 0) ) || ((unsigned int)itkIndex[2] < imageDims[2])) // in case a 2D Image passed in, the third dimension could be set to 0 causing the if() to fail
  {
    const unsigned int offset = itkIndex[0] + itkIndex[1]*imageDims[0] + itkIndex[2]*imageDims[0]*imageDims[1] + timestep*imageDims[0]*imageDims[1]*imageDims[2];

    mitkPixelTypeMultiplex3( AccessPixel, ptype, this->GetData(), offset, value );
  }

  return value;
}

vtkImageData* mitk::Image::GetVtkImageData(int t, int n)
{
  if(m_Initialized==false)
  {
    if(GetSource().IsNull())
{'fraction_non_alphanumeric': 0.16106764841233318, 'fraction_numerical': 0.015416474919466176, 'mean_word_length': 4.622682190599396, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 102, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5613478', 'n_tokens_mistral': 4448, 'n_tokens_neox': 4340, 'n_words': 1033}