text: /*=========================================================================
  
  Program:   Visualization Toolkit
  Module:    vtkNIFTIImageHeader.cxx
  
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/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 notice for more information.
  
  =========================================================================*/
  
  #include "vtkNIFTIImageHeader.h"
  #include "vtkNIFTIImagePrivate.h"
  
  #include "vtkObjectFactory.h"
  
  #include <string.h>
  #include <float.h>
  #include <math.h>
  #include <ctype.h>
  
  vtkStandardNewMacro(vtkNIFTIImageHeader);
  
  //----------------------------------------------------------------------------
  namespace {
  
  // utility function to normalize floats that are close to zero
  double vtkNIFTINormalizeFloat(double d)
  {
    return (fabs(d) < FLT_MIN ? 0.0 : d);
  }
  
  double vtkNIFTINormalizeDouble(double d)
  {
    return (fabs(d) < DBL_MIN ? 0.0 : d);
  }
  } // end anonymous namespace
  
  //----------------------------------------------------------------------------
  vtkNIFTIImageHeader::vtkNIFTIImageHeader()
  {
    this->Initialize();
  }
  
  //----------------------------------------------------------------------------
  vtkNIFTIImageHeader::~vtkNIFTIImageHeader()
  {
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::Initialize()
  {
    memset(this->Magic, '\0', sizeof(this->Magic));
    this->VoxOffset = 0;
    this->DataType = 0;
    this->BitPix = 0;
    for (int i = 0; i < 8; i++)
      {
      this->Dim[i] = 0;
      this->PixDim[i] = 0.0;
      }
    this->IntentCode = 0;
    memset(this->IntentName, '\0', sizeof(this->IntentName));
    this->IntentP1 = 0.0;
    this->IntentP2 = 0.0;
    this->IntentP3 = 0.0;
    this->SclSlope = 0.0;
    this->SclInter = 0.0;
    this->CalMin = 0.0;
    this->CalMax = 0.0;
    this->SliceDuration = 0.0;
    this->TOffset = 0.0;
    this->SliceStart = 0;
    this->SliceEnd = 0;
    this->SliceCode = 0;
    this->XYZTUnits = 0;
    this->DimInfo = 0;
    memset(this->Descrip, '\0', sizeof(this->Descrip));
    memset(this->AuxFile, '\0', sizeof(this->AuxFile));
    this->QFormCode = 0;
    this->SFormCode = 0;
    this->QuaternB = 0.0;
    this->QuaternC = 0.0;
    this->QuaternD = 0.0;
    this->QOffsetX = 0.0;
    this->QOffsetY = 0.0;
    this->QOffsetZ = 0.0;
    for (int i = 0; i < 4; i++)
      {
      this->SRowX[i] = 0.0;
      this->SRowY[i] = 0.0;
      this->SRowZ[i] = 0.0;
      }
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetHeader(const nifti_1_header *hdr)
  {
    // clear all fields (in case supplied header is Analyze 7.5)
    this->Initialize();
  
    // check if header is NIfTI (vs. Analyze 7.5)
    bool isnifti = (hdr->magic[0] == 'n' &&
                    (hdr->magic[1] == '+' || hdr->magic[1] == 'i') &&
                    hdr->magic[2] == '1' &&
                    hdr->magic[3] == '\0');
  
    if (isnifti)
      {
      memcpy(this->Magic, hdr->magic, sizeof(hdr->magic));
      }
    this->VoxOffset = static_cast<vtkTypeInt64>(hdr->vox_offset);
    this->DataType = hdr->datatype;
    this->BitPix = hdr->bitpix;
    for (int i = 0; i < 8; i++)
      {
      this->Dim[i] = hdr->dim[i];
      this->PixDim[i] = hdr->pixdim[i];
      }
    if (isnifti)
      {
      this->IntentCode = hdr->intent_code;
      strncpy(this->IntentName, hdr->intent_name, sizeof(hdr->intent_name));
      this->IntentP1 = hdr->intent_p1;
      this->IntentP2 = hdr->intent_p2;
      this->IntentP3 = hdr->intent_p3;
      this->SclSlope = hdr->scl_slope;
      this->SclInter = hdr->scl_inter;
      }
    this->CalMin = hdr->cal_min;
    this->CalMax = hdr->cal_max;
    if (isnifti)
      {
      this->SliceDuration = hdr->slice_duration;
      this->TOffset = hdr->toffset;
      this->SliceStart = hdr->slice_start;
      this->SliceEnd = hdr->slice_end;
      this->SliceCode = hdr->slice_code;
      }
    this->XYZTUnits = hdr->xyzt_units;
    this->DimInfo = hdr->dim_info;
    strncpy(this->Descrip, hdr->descrip, sizeof(hdr->descrip));
    strncpy(this->AuxFile, hdr->aux_file, sizeof(hdr->aux_file));
    if (isnifti)
      {
      this->QFormCode = hdr->qform_code;
      this->SFormCode = hdr->sform_code;
      this->QuaternB = hdr->quatern_b;
      this->QuaternC = hdr->quatern_c;
      this->QuaternD = hdr->quatern_d;
      this->QOffsetX = hdr->qoffset_x;
      this->QOffsetY = hdr->qoffset_y;
      this->QOffsetZ = hdr->qoffset_z;
      for (int i = 0; i < 4; i++)
        {
        this->SRowX[i] = hdr->srow_x[i];
        this->SRowY[i] = hdr->srow_y[i];
        this->SRowZ[i] = hdr->srow_z[i];
        }
      }
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::GetHeader(nifti_1_header *hdr)
  {
    hdr->sizeof_hdr = NIFTI1HeaderSize;
    memcpy(hdr->magic, this->Magic, sizeof(hdr->magic));
    memset(hdr->data_type, '\0', 10);
    memset(hdr->db_name, '\0', 18);
    hdr->extents = 0;
    hdr->session_error = 0;
    hdr->regular = 0;
    hdr->dim_info = this->DimInfo;
    hdr->intent_p1 = vtkNIFTINormalizeFloat(this->IntentP1);
    hdr->intent_p2 = vtkNIFTINormalizeFloat(this->IntentP2);
    hdr->intent_p3 = vtkNIFTINormalizeFloat(this->IntentP3);
    hdr->intent_code = static_cast<short>(this->IntentCode);
    hdr->datatype = static_cast<short>(this->DataType);
    hdr->bitpix = static_cast<short>(this->BitPix);
    hdr->slice_start = this->SliceStart;
    for (int i = 0; i < 8; i++)
      {
      hdr->dim[i] = static_cast<short>(this->Dim[i]);
      hdr->pixdim[i] = vtkNIFTINormalizeFloat(this->PixDim[i]);
      }
    hdr->vox_offset = static_cast<float>(this->VoxOffset);
    strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
    hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
    hdr->scl_slope = vtkNIFTINormalizeFloat(this->SclSlope);
    hdr->scl_inter = vtkNIFTINormalizeFloat(this->SclInter);
    hdr->cal_min = vtkNIFTINormalizeFloat(this->CalMin);
    hdr->cal_max = vtkNIFTINormalizeFloat(this->CalMax);
    hdr->slice_duration = vtkNIFTINormalizeFloat(this->SliceDuration);
    hdr->toffset = vtkNIFTINormalizeFloat(this->TOffset);
    hdr->glmax = 0;
    hdr->glmin = 0;
    hdr->slice_end = this->SliceEnd;
    hdr->slice_code = this->SliceCode;
    hdr->xyzt_units = this->XYZTUnits;
    strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
    hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
    strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
    hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
    hdr->qform_code = static_cast<short>(this->QFormCode);
    hdr->sform_code = static_cast<short>(this->SFormCode);
    hdr->quatern_b = vtkNIFTINormalizeFloat(this->QuaternB);
    hdr->quatern_c = vtkNIFTINormalizeFloat(this->QuaternC);
    hdr->quatern_d = vtkNIFTINormalizeFloat(this->QuaternD);
    hdr->qoffset_x = vtkNIFTINormalizeFloat(this->QOffsetX);
    hdr->qoffset_y = vtkNIFTINormalizeFloat(this->QOffsetY);
    hdr->qoffset_z = vtkNIFTINormalizeFloat(this->QOffsetZ);
    for (int i = 0; i < 4; i++)
      {
      hdr->srow_x[i] = vtkNIFTINormalizeFloat(this->SRowX[i]);
      hdr->srow_y[i] = vtkNIFTINormalizeFloat(this->SRowY[i]);
      hdr->srow_z[i] = vtkNIFTINormalizeFloat(this->SRowZ[i]);
      }
  }
  
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetHeader(const nifti_2_header *hdr)
  {
    memcpy(this->Magic, hdr->magic, sizeof(hdr->magic));
    this->VoxOffset = hdr->vox_offset;
    this->DataType = hdr->datatype;
    this->BitPix = hdr->bitpix;
    for (int i = 0; i < 8; i++)
      {
      this->Dim[i] = hdr->dim[i];
      this->PixDim[i] = hdr->pixdim[i];
      }
    this->IntentCode = hdr->intent_code;
    strncpy(this->IntentName, hdr->intent_name, sizeof(hdr->intent_name));
    this->IntentP1 = hdr->intent_p1;
    this->IntentP2 = hdr->intent_p2;
    this->IntentP3 = hdr->intent_p3;
    this->SclSlope = hdr->scl_slope;
    this->SclInter = hdr->scl_inter;
    this->CalMin = hdr->cal_min;
    this->CalMax = hdr->cal_max;
    this->SliceDuration = hdr->slice_duration;
    this->TOffset = hdr->toffset;
    this->SliceStart = hdr->slice_start;
    this->SliceEnd = hdr->slice_end;
    this->SliceCode = hdr->slice_code;
    this->XYZTUnits = hdr->xyzt_units;
    this->DimInfo = hdr->dim_info;
    strncpy(this->Descrip, hdr->descrip, sizeof(hdr->descrip));
    strncpy(this->AuxFile, hdr->aux_file, sizeof(hdr->aux_file));
    this->QFormCode = hdr->qform_code;
    this->SFormCode = hdr->sform_code;
    this->QuaternB = hdr->quatern_b;
    this->QuaternC = hdr->quatern_c;
    this->QuaternD = hdr->quatern_d;
    this->QOffsetX = hdr->qoffset_x;
    this->QOffsetY = hdr->qoffset_y;
    this->QOffsetZ = hdr->qoffset_z;
    for (int i = 0; i < 4; i++)
      {
      this->SRowX[i] = hdr->srow_x[i];
      this->SRowY[i] = hdr->srow_y[i];
      this->SRowZ[i] = hdr->srow_z[i];
      }
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::GetHeader(nifti_2_header *hdr)
  {
    hdr->sizeof_hdr = NIFTI2HeaderSize;
    memcpy(hdr->magic, this->Magic, sizeof(hdr->magic));
    hdr->datatype = static_cast<short>(this->DataType);
    hdr->bitpix = static_cast<short>(this->BitPix);
    for (int i = 0; i < 8; i++)
      {
      hdr->dim[i] = static_cast<short>(this->Dim[i]);
      hdr->pixdim[i] = vtkNIFTINormalizeDouble(this->PixDim[i]);
      }
    hdr->intent_p1 = vtkNIFTINormalizeDouble(this->IntentP1);
    hdr->intent_p2 = vtkNIFTINormalizeDouble(this->IntentP2);
    hdr->intent_p3 = vtkNIFTINormalizeDouble(this->IntentP3);
    hdr->vox_offset = this->VoxOffset;
    hdr->scl_slope = vtkNIFTINormalizeDouble(this->SclSlope);
    hdr->scl_inter = vtkNIFTINormalizeDouble(this->SclInter);
    hdr->cal_min = vtkNIFTINormalizeDouble(this->CalMin);
    hdr->cal_max = vtkNIFTINormalizeDouble(this->CalMax);
    hdr->slice_duration = vtkNIFTINormalizeDouble(this->SliceDuration);
    hdr->toffset = vtkNIFTINormalizeDouble(this->TOffset);
    hdr->slice_start = this->SliceStart;
    hdr->slice_end = this->SliceEnd;
    strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
    hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
    strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
    hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
    hdr->qform_code = static_cast<short>(this->QFormCode);
    hdr->sform_code = static_cast<short>(this->SFormCode);
    hdr->quatern_b = vtkNIFTINormalizeDouble(this->QuaternB);
    hdr->quatern_c = vtkNIFTINormalizeDouble(this->QuaternC);
    hdr->quatern_d = vtkNIFTINormalizeDouble(this->QuaternD);
    hdr->qoffset_x = vtkNIFTINormalizeDouble(this->QOffsetX);
    hdr->qoffset_y = vtkNIFTINormalizeDouble(this->QOffsetY);
    hdr->qoffset_z = vtkNIFTINormalizeDouble(this->QOffsetZ);
    for (int i = 0; i < 4; i++)
      {
      hdr->srow_x[i] = vtkNIFTINormalizeDouble(this->SRowX[i]);
      hdr->srow_y[i] = vtkNIFTINormalizeDouble(this->SRowY[i]);
      hdr->srow_z[i] = vtkNIFTINormalizeDouble(this->SRowZ[i]);
      }
    hdr->slice_code = this->SliceCode;
    hdr->xyzt_units = this->XYZTUnits;
    hdr->intent_code = static_cast<short>(this->IntentCode);
    strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
    hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
    hdr->dim_info = static_cast<char>(this->DimInfo);
    memset(hdr->unused_str, '\0', 15);
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::DeepCopy(vtkNIFTIImageHeader *o)
  {
    if (o)
      {
      nifti_2_header hdr;
      o->GetHeader(&hdr);
      this->SetHeader(&hdr);
      }
    else
      {
      this->Initialize();
      }
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::PrintSelf(ostream& os, vtkIndent indent)
  {
    this->Superclass::PrintSelf(os, indent);
  
    os.setf(std::ios::hex, std::ios::basefield);
    os << indent << "DimInfo: 0x" << this->DimInfo << "\n";
    os.unsetf(std::ios::hex);
    os << indent << "Dim:";
    for (int i = 0; i < 8; i++)
      {
      os << " " << this->Dim[i];
      }
    os << indent << "\n";
    os << indent << "PixDim:";
    for (int i = 0; i < 8; i++)
      {
      os << " " << this->PixDim[i];
      }
    os << indent << "\n";
    os << indent << "VoxOffset:" << this->VoxOffset << "\n";
    os << indent << "IntentP1: " << this->IntentP1 << "\n";
    os << indent << "IntentP2: " << this->IntentP2 << "\n";
    os << indent << "IntentP3: " << this->IntentP3 << "\n";
    os << indent << "IntentCode: " << this->IntentCode << "\n";
    os << indent << "DataType: " << this->DataType << "\n";
    os << indent << "BitPix: " << this->BitPix << "\n";
    os << indent << "SliceStart: " << this->SliceStart << "\n";
    os << indent << "SclSlope: " << this->SclSlope << "\n";
    os << indent << "SclInter: " << this->SclInter << "\n";
    os << indent << "SliceEnd: " << this->SliceEnd << "\n";
    os << indent << "SliceCode: " << static_cast<int>(this->SliceCode) << "\n";
    os.setf(std::ios::hex, std::ios::basefield);
    os << indent << "XYZTUnits: 0x" << static_cast<int>(this->XYZTUnits) << "\n";
    os.unsetf(std::ios::hex);
    os << indent << "CalMax: " << this->CalMax << "\n";
    os << indent << "CalMin: " << this->CalMin << "\n";
    os << indent << "SliceDuration: " << this->SliceDuration << "\n";
    os << indent << "TOffset: " << this->TOffset << "\n";
    os << indent << "Descrip: \"";
    for (size_t j = 0; j < 80 && this->Descrip[j] != '\0'; j++)
      {
      os << (isprint(this->Descrip[j]) ? this->Descrip[j] : '?');
      }
    os << "\"\n";
    os << indent << "AuxFile: \"";
    for (size_t j = 0; j < 24 && this->AuxFile[j] != '\0'; j++)
      {
      os << (isprint(this->AuxFile[j]) ? this->AuxFile[j] : '?');
      }
    os << "\"\n";
    os << indent << "QFormCode: " << this->QFormCode << "\n";
    os << indent << "SFormCode: " << this->SFormCode << "\n";
    os << indent << "QuaternB: " << this->QuaternB << "\n";
    os << indent << "QuaternC: " << this->QuaternC << "\n";
    os << indent << "QuaternD: " << this->QuaternD << "\n";
    os << indent << "QOffsetX: " << this->QOffsetX << "\n";
    os << indent << "QOffsetY: " << this->QOffsetY << "\n";
    os << indent << "QOffsetZ: " << this->QOffsetZ << "\n";
    os << indent << "SRowX:";
    for (int i = 0; i < 4; i++)
      {
      os << " " << this->SRowX[i];
      }
    os << "\n";
    os << indent << "SRowY:";
    for (int i = 0; i < 4; i++)
      {
      os << " " << this->SRowY[i];
      }
    os << "\n";
    os << indent << "SRowZ:";
    for (int i = 0; i < 4; i++)
      {
      os << " " << this->SRowZ[i];
      }
    os << "\n";
    os << indent << "IntentName: \"";
    for (size_t j = 0; j < 16 && this->IntentName[j] != '\0'; j++)
      {
      os << (isprint(this->IntentName[j]) ? this->IntentName[j] : '?');
      }
    os << "\"\n";
    os << indent << "Magic: \"";
    for (size_t j = 0; j < 4 && this->Magic[j] != '\0'; j++)
      {
      os << (isprint(this->Magic[j]) ? this->Magic[j] : '?');
      }
    os << "\"\n";
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetStringValue(char *x, const char *y, size_t n)
  {
    if (y == 0)
      {
      y = "";
      }
    if (strncmp(x, y, n) != 0)
      {
      strncpy(x, y, n);
      x[n] = '\0';
      this->Modified();
      }
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetIntentName(const char *val)
  {
    this->SetStringValue(this->IntentName, val, 16);
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetDescrip(const char *val)
  {
    this->SetStringValue(this->Descrip, val, 80);
  }
  
  //----------------------------------------------------------------------------
  void vtkNIFTIImageHeader::SetAuxFile(const char *val)
  {
    this->SetStringValue(this->AuxFile, val, 24);
  }
  